mirror of
https://github.com/coreutils/coreutils.git
synced 2024-11-24 10:23:31 +08:00
ls: issue error message on removed directory
If the current directory has been removed, then "ls" confusingly produced no output and no error message, indistinguishable from running on an empty directory. * src/ls.c (print_dir): Report ENOENT on GNU/Linux if readdir finds no directory entries at all, not even "." or "..", and a recheck with the getdents syscall returns ENOENT. We recheck with getdents() as POSIX states that "The directory entries for dot and dot-dot are optional". * tests/ls/removed-directory.sh: New file. * tests/local.mk (all_tests): Add new test. * NEWS: Mention the change in behavior. Reported by Owen Thomas.
This commit is contained in:
parent
93db70867d
commit
05a99f7d7f
4
NEWS
4
NEWS
@ -65,6 +65,10 @@ GNU coreutils NEWS -*- outline -*-
|
||||
[The old behavior was introduced in sh-utils 2.0.15 ca. 1999, predating
|
||||
coreutils package.]
|
||||
|
||||
ls issues an error message on a removed directory, on GNU/Linux systems.
|
||||
Previously no error and no entries were output, and so indistinguishable
|
||||
from an empty directory, with default ls options.
|
||||
|
||||
uniq no longer uses strcoll() to determine string equivalence,
|
||||
and so will operate more efficiently and consistently.
|
||||
|
||||
|
22
src/ls.c
22
src/ls.c
@ -49,6 +49,10 @@
|
||||
# include <sys/ptem.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
# include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <setjmp.h>
|
||||
@ -2892,6 +2896,7 @@ print_dir (char const *name, char const *realname, bool command_line_arg)
|
||||
struct dirent *next;
|
||||
uintmax_t total_blocks = 0;
|
||||
static bool first = true;
|
||||
bool found_any_entries = false;
|
||||
|
||||
errno = 0;
|
||||
dirp = opendir (name);
|
||||
@ -2967,6 +2972,7 @@ print_dir (char const *name, char const *realname, bool command_line_arg)
|
||||
next = readdir (dirp);
|
||||
if (next)
|
||||
{
|
||||
found_any_entries = true;
|
||||
if (! file_ignored (next->d_name))
|
||||
{
|
||||
enum filetype type = unknown;
|
||||
@ -3012,6 +3018,22 @@ print_dir (char const *name, char const *realname, bool command_line_arg)
|
||||
if (errno != EOVERFLOW)
|
||||
break;
|
||||
}
|
||||
#ifdef __linux__
|
||||
else if (! found_any_entries)
|
||||
{
|
||||
/* If readdir finds no directory entries at all, not even "." or
|
||||
"..", then double check that the directory exists. */
|
||||
if (syscall (SYS_getdents, dirfd (dirp), NULL, 0) == -1
|
||||
&& errno != EINVAL)
|
||||
{
|
||||
/* We exclude EINVAL as that pertains to buffer handling,
|
||||
and we've passed NULL as the buffer for simplicity.
|
||||
ENOENT is returned if appropriate before buffer handling. */
|
||||
file_failure (command_line_arg, _("reading directory %s"), name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
break;
|
||||
|
||||
|
@ -615,6 +615,7 @@ all_tests = \
|
||||
tests/ls/quote-align.sh \
|
||||
tests/ls/readdir-mountpoint-inode.sh \
|
||||
tests/ls/recursive.sh \
|
||||
tests/ls/removed-directory.sh \
|
||||
tests/ls/root-rel-symlink-color.sh \
|
||||
tests/ls/rt-1.sh \
|
||||
tests/ls/slink-acl.sh \
|
||||
|
45
tests/ls/removed-directory.sh
Executable file
45
tests/ls/removed-directory.sh
Executable file
@ -0,0 +1,45 @@
|
||||
#!/bin/sh
|
||||
# If ls is asked to list a removed directory (e.g. the parent process's
|
||||
# current working directory that has been removed by another process), it
|
||||
# emits an error message.
|
||||
|
||||
# Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
|
||||
print_ver_ ls
|
||||
|
||||
case $host_triplet in
|
||||
*linux*) ;;
|
||||
*) skip_ 'non linux kernel' ;;
|
||||
esac
|
||||
|
||||
LS_FAILURE=2
|
||||
|
||||
cat <<\EOF >exp-err || framework_failure_
|
||||
ls: reading directory '.': No such file or directory
|
||||
EOF
|
||||
|
||||
cwd=$(pwd)
|
||||
mkdir d || framework_failure_
|
||||
cd d || framework_failure_
|
||||
rmdir ../d || framework_failure_
|
||||
|
||||
returns_ $LS_FAILURE ls >../out 2>../err || fail=1
|
||||
cd "$cwd" || framework_failure_
|
||||
compare /dev/null out || fail=1
|
||||
compare exp-err err || fail=1
|
||||
|
||||
Exit $fail
|
Loading…
Reference in New Issue
Block a user