diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2017-08-22 18:34:36 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2017-08-22 18:37:23 -0400 |
commit | d548b86e120db7e1327eea957a698d4bb874a1fb (patch) | |
tree | 874e34926ee12fbbf076a834d6822ab751cf378b /eval.c | |
parent | 2a561b66f48ab4deafb0a031cad3ad541ea79449 (diff) | |
download | bfs-d548b86e120db7e1327eea957a698d4bb874a1fb.tar.xz |
Avoid multiple extra stat()s of broken symlinks for -xtype
Diffstat (limited to 'eval.c')
-rw-r--r-- | eval.c | 13 |
1 files changed, 9 insertions, 4 deletions
@@ -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; |