diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | parse.c | 35 | ||||
-rw-r--r-- | util.c | 30 | ||||
-rw-r--r-- | util.h | 19 |
4 files changed, 62 insertions, 26 deletions
@@ -73,6 +73,10 @@ else DISTCHECK_FLAGS := TEST_FLAGS="--verbose" endif +ifeq ($(OS),NetBSD) +LOCAL_LDLIBS += -lutil +endif + ifneq ($(filter asan,$(MAKECMDGOALS)),) LOCAL_CFLAGS += $(ASAN_CFLAGS) SANITIZE := y @@ -1163,20 +1163,12 @@ static struct expr *parse_f(struct parser_state *state, int arg1, int arg2) { * Parse -flags FLAGS. */ static struct expr *parse_flags(struct parser_state *state, int arg1, int arg2) { -#if __APPLE__ || __FreeBSD__ struct expr *expr = parse_unary_test(state, eval_flags); if (!expr) { return NULL; } - // strtofflags() takes a non-const char * - char *copy = strdup(expr->sdata); - if (!copy) { - parse_perror(state, "strdup()"); - goto err; - } - - char *flags = copy; + const char *flags = expr->sdata; switch (flags[0]) { case '-': expr->mode_cmp = MODE_ALL; @@ -1191,26 +1183,17 @@ static struct expr *parse_flags(struct parser_state *state, int arg1, int arg2) break; } - unsigned long set, clear; - if (strtofflags(&flags, &set, &clear) != 0) { - parse_error(state, "${blu}%s${rs}: Invalid flags ${bld}%s${rs}.\n", expr->argv[0], flags); - goto err; + if (xstrtofflags(&flags, &expr->set_flags, &expr->clear_flags) != 0) { + if (errno == ENOTSUP) { + parse_error(state, "${blu}%s${rs} is missing platform support.\n", expr->argv[0]); + } else { + parse_error(state, "${blu}%s${rs}: Invalid flags ${bld}%s${rs}.\n", expr->argv[0], flags); + } + free_expr(expr); + return NULL; } - expr->set_flags = set; - expr->clear_flags = clear; - - free(copy); return expr; - -err: - free(copy); - free_expr(expr); - return NULL; -#else // !(__APPLE__ || __FreeBSD) - parse_error(state, "${blu}%s${rs} is missing platform support.\n", state->argv[0]); - return NULL; -#endif } /** @@ -39,6 +39,10 @@ # include <sys/mkdev.h> #endif +#if BFS_HAS_UTIL +# include <util.h> +#endif + char *xreadlinkat(int fd, const char *path, size_t size) { ssize_t len; char *name = NULL; @@ -232,6 +236,32 @@ int xfaccessat(int fd, const char *path, int amode) { return ret; } +int xstrtofflags(const char **str, unsigned long long *set, unsigned long long *clear) { +#if BSD + char *str_arg = (char *)*str; + unsigned long set_arg = 0; + unsigned long clear_arg = 0; + +#if __NetBSD__ + int ret = string_to_flags(&str_arg, &set_arg, &clear_arg); +#else + int ret = strtofflags(&str_arg, &set_arg, &clear_arg); +#endif + + *str = str_arg; + *set = set_arg; + *clear = clear_arg; + + if (ret != 0) { + errno = EINVAL; + } + return ret; +#else // !BSD + errno = ENOTSUP; + return -1; +#endif +} + bool is_nonexistence_error(int error) { return error == ENOENT || errno == ENOTDIR; } @@ -74,6 +74,10 @@ # define BFS_HAS_SYS_XATTR BFS_HAS_INCLUDE(<sys/xattr.h>, __linux__) #endif +#ifndef BFS_HAS_UTIL +# define BFS_HAS_UTIL BFS_HAS_INCLUDE(<util.h>, __NetBSD__) +#endif + #if !defined(FNM_CASEFOLD) && defined(FNM_IGNORECASE) # define FNM_CASEFOLD FNM_IGNORECASE #endif @@ -180,6 +184,21 @@ const char *xbasename(const char *path); int xfaccessat(int fd, const char *path, int amode); /** + * Portability wrapper for strtofflags(). + * + * @param str + * The string to parse. The pointee will be advanced to the first + * invalid position on error. + * @param set + * The flags that are set in the string. + * @param clear + * The flags that are cleared in the string. + * @return + * 0 on success, -1 on failure. + */ +int xstrtofflags(const char **str, unsigned long long *set, unsigned long long *clear); + +/** * Return whether an error code is due to a path not existing. */ bool is_nonexistence_error(int error); |