diff options
-rw-r--r-- | bftw.c | 2 | ||||
-rw-r--r-- | eval.c | 13 | ||||
-rw-r--r-- | parse.c | 2 | ||||
-rw-r--r-- | util.c | 10 | ||||
-rw-r--r-- | util.h | 4 |
5 files changed, 18 insertions, 13 deletions
@@ -551,7 +551,7 @@ static void bftw_queue_destroy(struct bftw_queue *queue) { /** Call stat() and use the results. */ static int ftwbuf_stat(struct BFTW *ftwbuf, struct stat *sb) { - int ret = xfstatat(ftwbuf->at_fd, ftwbuf->at_path, sb, &ftwbuf->at_flags); + int ret = xfstatat(ftwbuf->at_fd, ftwbuf->at_path, sb, ftwbuf->at_flags); if (ret == 0) { ftwbuf->statbuf = sb; ftwbuf->typeflag = mode_to_typeflag(sb->st_mode); @@ -76,7 +76,7 @@ static void eval_error(struct eval_state *state) { static const struct stat *fill_statbuf(struct eval_state *state) { struct BFTW *ftwbuf = state->ftwbuf; if (!ftwbuf->statbuf) { - if (xfstatat(ftwbuf->at_fd, ftwbuf->at_path, &state->statbuf, &ftwbuf->at_flags) == 0) { + if (xfstatat(ftwbuf->at_fd, ftwbuf->at_path, &state->statbuf, ftwbuf->at_flags) == 0) { ftwbuf->statbuf = &state->statbuf; } else { eval_error(state); @@ -831,9 +831,14 @@ bool eval_xtype(const struct expr *expr, struct eval_state *state) { int at_flags = ftwbuf->at_flags ^ AT_SYMLINK_NOFOLLOW; struct stat sb; - if (xfstatat(ftwbuf->at_fd, ftwbuf->at_path, &sb, &at_flags) != 0) { - eval_error(state); - return false; + if (fstatat(ftwbuf->at_fd, ftwbuf->at_path, &sb, at_flags) != 0) { + if (!follow && (errno == ENOENT || errno == ENOTDIR)) { + // Broken symlink + return eval_type(expr, state); + } else { + eval_error(state); + return false; + } } return mode_to_typeflag(sb.st_mode) & expr->idata; @@ -345,7 +345,7 @@ static int stat_arg(const struct parser_state *state, struct expr *expr, struct bool follow = cmdline->flags & (BFTW_COMFOLLOW | BFTW_LOGICAL); int flags = follow ? 0 : AT_SYMLINK_NOFOLLOW; - int ret = xfstatat(AT_FDCWD, expr->sdata, sb, &flags); + int ret = xfstatat(AT_FDCWD, expr->sdata, sb, flags); if (ret != 0) { cfprintf(cmdline->cerr, "%{er}error: '%s': %s%{rs}\n", expr->sdata, strerror(errno)); } @@ -226,12 +226,12 @@ const char *xbasename(const char *path) { return i; } -int xfstatat(int fd, const char *path, struct stat *buf, int *flags) { - int ret = fstatat(fd, path, buf, *flags); +int xfstatat(int fd, const char *path, struct stat *buf, int flags) { + int ret = fstatat(fd, path, buf, flags); - if (ret != 0 && !(*flags & AT_SYMLINK_NOFOLLOW) && (errno == ENOENT || errno == ENOTDIR)) { - *flags |= AT_SYMLINK_NOFOLLOW; - ret = fstatat(fd, path, buf, *flags); + if (ret != 0 && !(flags & AT_SYMLINK_NOFOLLOW) && (errno == ENOENT || errno == ENOTDIR)) { + flags |= AT_SYMLINK_NOFOLLOW; + ret = fstatat(fd, path, buf, flags); } return ret; @@ -152,10 +152,10 @@ const char *xbasename(const char *path); * @param buf * The stat buffer to fill. * @param flags - * AT_* flags for this call. Will be updated if a fallback happens. + * AT_* flags for this call. * @return 0 on success, -1 on failure. */ -int xfstatat(int fd, const char *path, struct stat *buf, int *flags); +int xfstatat(int fd, const char *path, struct stat *buf, int flags); /** * Convert a stat() st_mode to a bftw() typeflag. |