From 2328d8dbb5a8c774afb99d363b6e98cd25ee304d Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sun, 9 Jul 2017 16:35:38 -0400 Subject: Handle ENOTDIR the same as ENOENT For a/b/c, ENOTDIR is returned instead of ENOENT if a or b are not directories. Handle this uniformly when detecting broken symlinks, readdir races, etc. --- bftw.c | 2 +- eval.c | 4 ++-- printf.c | 1 + tests.sh | 10 ++++++++++ tests/test_L.out | 1 + tests/test_L_depth.out | 1 + tests/test_L_xtype_l.out | 1 + tests/test_colors.out | 1 + tests/test_follow.out | 1 + tests/test_printf_types.out | 1 + tests/test_xtype_l.out | 1 + 11 files changed, 21 insertions(+), 3 deletions(-) diff --git a/bftw.c b/bftw.c index 991176a..baf7e65 100644 --- a/bftw.c +++ b/bftw.c @@ -836,7 +836,7 @@ static void bftw_init_buffers(struct bftw_state *state, const struct dirent *de) || (ftwbuf->typeflag == BFTW_LNK && follow) || (ftwbuf->typeflag == BFTW_DIR && (detect_cycles || xdev))) { int ret = ftwbuf_stat(ftwbuf, &state->statbuf); - if (ret != 0 && follow && errno == ENOENT) { + if (ret != 0 && follow && (errno == ENOENT || errno == ENOTDIR)) { // Could be a broken symlink, retry without following ftwbuf->at_flags = AT_SYMLINK_NOFOLLOW; ret = ftwbuf_stat(ftwbuf, &state->statbuf); diff --git a/eval.c b/eval.c index 90b854e..daee9d6 100644 --- a/eval.c +++ b/eval.c @@ -51,7 +51,7 @@ struct eval_state { */ static bool eval_should_ignore(const struct eval_state *state, int error) { return state->cmdline->ignore_races - && error == ENOENT + && (error == ENOENT || errno == ENOTDIR) && state->ftwbuf->depth > 0; } @@ -788,7 +788,7 @@ bool eval_xtype(const struct expr *expr, struct eval_state *state) { struct stat sb; if (fstatat(ftwbuf->at_fd, ftwbuf->at_path, &sb, at_flags) != 0) { - if (!follow && errno == ENOENT) { + if (!follow && (errno == ENOENT || errno == ENOTDIR)) { // Broken symlink return eval_type(expr, state); } else { diff --git a/printf.c b/printf.c index 888fecb..9b284b4 100644 --- a/printf.c +++ b/printf.c @@ -371,6 +371,7 @@ static int bfs_printf_Y(FILE *file, const struct bfs_printf_directive *directive type = "L"; break; case ENOENT: + case ENOTDIR: type = "N"; break; } diff --git a/tests.sh b/tests.sh index c8aeb63..b150046 100755 --- a/tests.sh +++ b/tests.sh @@ -74,6 +74,7 @@ function make_links() { ln -s ../../d "$1/d/e/g" ln -s d/e "$1/h" ln -s q "$1/d/e/i" + ln -s b/c "$1/j" } make_links "$TMP/links" @@ -299,6 +300,7 @@ gnu_tests=( test_flag_double_dash test_ignore_readdir_race test_ignore_readdir_race_root + test_ignore_readdir_race_notdir test_perm_222_slash test_perm_644_slash test_perm_symbolic_slash @@ -797,6 +799,14 @@ function test_ignore_readdir_race_root() { ! $BFS basic/nonexistent -ignore_readdir_race 2>/dev/null } +function test_ignore_readdir_race_notdir() { + # Check -ignore_readdir_race handling when a directory is replaced with a file + rm -rf scratch/* + touchp scratch/foo/bar + + $BFS scratch -mindepth 1 -ignore_readdir_race -execdir rm -r '{}' \; -execdir touch '{}' \; +} + function test_perm_222() { bfs_diff perms -perm 222 } diff --git a/tests/test_L.out b/tests/test_L.out index 36087e8..f9ded0a 100644 --- a/tests/test_L.out +++ b/tests/test_L.out @@ -4,6 +4,7 @@ links/b links/c links/d links/h +links/j links/d/e links/h/f links/h/g diff --git a/tests/test_L_depth.out b/tests/test_L_depth.out index 36087e8..f9ded0a 100644 --- a/tests/test_L_depth.out +++ b/tests/test_L_depth.out @@ -4,6 +4,7 @@ links/b links/c links/d links/h +links/j links/d/e links/h/f links/h/g diff --git a/tests/test_L_xtype_l.out b/tests/test_L_xtype_l.out index 1052fc0..57bee1b 100644 --- a/tests/test_L_xtype_l.out +++ b/tests/test_L_xtype_l.out @@ -1,5 +1,6 @@ links/b links/h +links/j links/h/g links/h/i links/d/e/i diff --git a/tests/test_colors.out b/tests/test_colors.out index a9ab84a..8c8b244 100644 --- a/tests/test_colors.out +++ b/tests/test_colors.out @@ -2,6 +2,7 @@ links/d links/b links/h +links/j links/a links/c links/d/e diff --git a/tests/test_follow.out b/tests/test_follow.out index 36087e8..f9ded0a 100644 --- a/tests/test_follow.out +++ b/tests/test_follow.out @@ -4,6 +4,7 @@ links/b links/c links/d links/h +links/j links/d/e links/h/f links/h/g diff --git a/tests/test_printf_types.out b/tests/test_printf_types.out index 94fa833..bd89b47 100644 --- a/tests/test_printf_types.out +++ b/tests/test_printf_types.out @@ -5,6 +5,7 @@ (links/d) () d d (links/d/e) () d d (links/h) (d/e) l d +(links/j) (b/c) l N (links/d/e/f) () d d (links/d/e/i) (q) l N (links/d/e/g) (../../d) l d diff --git a/tests/test_xtype_l.out b/tests/test_xtype_l.out index e5e13fc..2d1293f 100644 --- a/tests/test_xtype_l.out +++ b/tests/test_xtype_l.out @@ -1 +1,2 @@ +links/j links/d/e/i -- cgit v1.2.3