ls: check fts_children() for errors that may not surface otherwise
In particular, if one simply does a non-recursive `ls` on a directory that is not accessible, there are some classes of errors that may cause it to fail that wouldn't be surfaced unless we do an fts_read() that will recurse into the inaccessible directory. Catch those kinds of errors here since we cannot expect to an FTS_ERR/FTS_DNR entry to follow up on them. PR: 287451 Reviewed by: kib Discusssed with: des Differential Revision: https://reviews.freebsd.org/D51056
This commit is contained in:
+17
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user