diff options
| author | Kyle Evans <kevans@FreeBSD.org> | 2026-02-11 19:55:55 +0000 |
|---|---|---|
| committer | Kyle Evans <kevans@FreeBSD.org> | 2026-02-11 19:56:37 +0000 |
| commit | 7bf81e39d83087dc7f984077b5eed5a48df794d4 (patch) | |
| tree | e54a9a6ac96b1dcc4ab6f825a1679b92308dfb1c /bin | |
| parent | e89454417b2bfecce9daee10dece2f49632640d3 (diff) | |
Diffstat (limited to 'bin')
| -rw-r--r-- | bin/ls/ls.c | 17 | ||||
| -rwxr-xr-x | bin/ls/tests/ls_tests.sh | 30 |
2 files changed, 47 insertions, 0 deletions
diff --git a/bin/ls/ls.c b/bin/ls/ls.c index b3d0a508d714..c33d4d38c359 100644 --- a/bin/ls/ls.c +++ b/bin/ls/ls.c @@ -707,6 +707,23 @@ traverse(int argc, char *argv[], int options) output = 1; } chp = fts_children(ftsp, ch_options); + if (chp == NULL && errno != 0) { + warn("%s", p->fts_path); + rval = 1; + + /* + * Avoid further errors on this entry. We won't + * always get an FTS_ERR/FTS_DNR for errors + * in fts_children(), because opendir could + * have failed early on and that only flags an + * error for fts_read() when we try to recurse + * into it. We catch both the non-recursive and + * the recursive case here. + */ + (void)fts_set(ftsp, p, FTS_SKIP); + break; + } + display(p, chp, options); if (!f_recursive && chp != NULL) diff --git a/bin/ls/tests/ls_tests.sh b/bin/ls/tests/ls_tests.sh index c732b60b21a4..be662b75695d 100755 --- a/bin/ls/tests/ls_tests.sh +++ b/bin/ls/tests/ls_tests.sh @@ -476,6 +476,35 @@ b_flag_body() atf_check -e empty -o match:'y\\vz' -s exit:0 ls -b } +atf_test_case childerr +childerr_head() +{ + atf_set "descr" "Verify that fts_children() in pre-order errors are checked" + atf_set "require.user" "unprivileged" +} + +childerr_body() +{ + atf_check mkdir -p root/dir root/edir + atf_check touch root/c + + # Check that listing an empty directory hasn't regressed into being + # called an error. + atf_check -o match:"total 0" -e empty ls -l root/dir + + atf_check chmod 0 root/dir + + # If we did not abort after fts_children() properly, then stdout would + # have an output of the total files enumerated (0). Thus, assert that + # it's empty and that we see the correct error on stderr. + atf_check -s not-exit:0 -e match:"Permission denied" ls -l root/dir + + # Now ensure that we didn't just stop there, we printed out a directory + # that would've been enumerated later. + atf_check -s not-exit:0 -o match:"^root/edir" \ + -e match:"Permission denied" ls -lR root +} + atf_test_case d_flag d_flag_head() { @@ -971,6 +1000,7 @@ atf_init_test_cases() #atf_add_test_case Z_flag atf_add_test_case a_flag atf_add_test_case b_flag + atf_add_test_case childerr #atf_add_test_case c_flag atf_add_test_case d_flag atf_add_test_case f_flag |
