Improve "rmdir --ignore-fail-on-non-empty"

* src/rmdir.c (remove_parents, main): With --ignore-fail-on-non-empty,
suppress a diagnostic also for other errno values, which can arise
with read-only media or when the parent directory has the immutable
attribute (set via chattr +i).
(errno_may_be_empty, ignorable_failure): New functions.
* src/remove.c (is_empty_dir): Move function to ...
* src/system.h (is_empty_dir): ...here, and make it inline.
Suggested by Josselin Mouette in <http://bugs.debian.org/363011>
via Bob Proulx.
* NEWS: Mention the improvement.
This commit is contained in:
Jim Meyering 2008-01-30 13:43:15 +01:00
parent 194ca7b3f9
commit ed5c4e770a
6 changed files with 86 additions and 37 deletions

View File

@ -1,3 +1,17 @@
2008-01-30 Jim Meyering <meyering@redhat.com>
Improve "rmdir --ignore-fail-on-non-empty"
* src/rmdir.c (remove_parents, main): With --ignore-fail-on-non-empty,
suppress a diagnostic also for other errno values, which can arise
with read-only media or when the parent directory has the immutable
attribute (set via chattr +i).
(errno_may_be_empty, ignorable_failure): New functions.
* src/remove.c (is_empty_dir): Move function to ...
* src/system.h (is_empty_dir): ...here, and make it inline.
Suggested by Josselin Mouette in <http://bugs.debian.org/363011>
via Bob Proulx.
* NEWS: Mention the improvement.
2008-01-29 Paul Eggert <eggert@cs.ucla.edu>
Don't modify argv in dd.

10
NEWS
View File

@ -1,12 +1,20 @@
GNU coreutils NEWS -*- outline -*-
* Noteworthy changes in release 6.10 (2008-01-22) [stable]
* Noteworthy changes in release 6.?? (2008-??-??) [stable]
** Bug fixes
ls no longer segfaults on files in /proc when linked with an older version
of libselinux. E.g., ls -l /proc/sys would dereference a NULL pointer.
"rmdir --ignore-fail-on-non-empty" detects and ignores the failure
in more cases when a directory is empty.
* Noteworthy changes in release 6.10 (2008-01-22) [stable]
** Bug fixes
Fix a non-portable use of sed in configure.ac.
[bug introduced in coreutils-6.9.92]

1
THANKS
View File

@ -264,6 +264,7 @@ Joost van Baal joostvb@xs4all.nl
Jorge Stolfi stolfi@ic.unicamp.br
Joseph S. Myers jsm28@cam.ac.uk
Joshua Hudson joshudson@gmail.com
Josselin Mouette joss@debian.org
Juan F. Codagnone juam@arnet.com.ar
Juan M. Guerrero st001906@hrz1.hrz.tu-darmstadt.de
Jungshik Shin jshin@pantheon.yale.edu

View File

@ -1,5 +1,5 @@
/* remove.c -- core functions for removing files and directories
Copyright (C) 88, 90, 91, 1994-2007 Free Software Foundation, Inc.
Copyright (C) 88, 90, 91, 1994-2008 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
@ -726,36 +726,6 @@ AD_is_removable (Dirstack_state const *ds, char const *file)
return ! (top->unremovable && hash_lookup (top->unremovable, file));
}
/* Return true if DIR is determined to be an empty directory. */
static bool
is_empty_dir (int fd_cwd, char const *dir)
{
DIR *dirp;
struct dirent const *dp;
int saved_errno;
int fd = openat (fd_cwd, dir,
(O_RDONLY | O_DIRECTORY
| O_NOCTTY | O_NOFOLLOW | O_NONBLOCK));
if (fd < 0)
return false;
dirp = fdopendir (fd);
if (dirp == NULL)
{
close (fd);
return false;
}
errno = 0;
dp = readdir_ignoring_dot_and_dotdot (dirp);
saved_errno = errno;
closedir (dirp);
if (dp != NULL)
return false;
return saved_errno == 0 ? true : false;
}
/* Return -1 if FILE is an unwritable non-symlink,
0 if it is writable or some other type of file,
a positive error number if there is some problem in determining the answer.

View File

@ -74,13 +74,41 @@ static struct option const longopts[] =
/* Return true if ERROR_NUMBER is one of the values associated
with a failed rmdir due to non-empty target directory. */
static bool
errno_rmdir_non_empty (int error_number)
{
return (error_number == RMDIR_ERRNO_NOT_EMPTY);
}
/* Return true if when rmdir fails with errno == ERROR_NUMBER
the directory may be empty. */
static bool
errno_may_be_empty (int error_number)
{
switch (error_number)
{
case EACCES:
case EPERM:
case EROFS:
case EEXIST:
case EBUSY:
return true;
default:
return false;
}
}
/* Return true if an rmdir failure with errno == error_number
for DIR is ignorable. */
static bool
ignorable_failure (int error_number, char const *dir)
{
return (ignore_fail_on_non_empty
&& (errno_rmdir_non_empty (error_number)
|| (errno_may_be_empty (error_number)
&& is_empty_dir (AT_FDCWD, dir))));
}
/* Remove any empty parent directories of DIR.
If DIR contains slash characters, at least one of them
(beginning with the rightmost) is replaced with a NUL byte.
@ -113,8 +141,7 @@ remove_parents (char *dir)
if (!ok)
{
/* Stop quietly if --ignore-fail-on-non-empty. */
if (ignore_fail_on_non_empty
&& errno_rmdir_non_empty (errno))
if (ignorable_failure (errno, dir))
{
ok = true;
}
@ -210,8 +237,7 @@ main (int argc, char **argv)
if (rmdir (dir) != 0)
{
if (ignore_fail_on_non_empty
&& errno_rmdir_non_empty (errno))
if (ignorable_failure (errno, dir))
continue;
/* Here, the diagnostic is less precise, since we have no idea

View File

@ -384,6 +384,36 @@ readdir_ignoring_dot_and_dotdot (DIR *dirp)
}
}
/* Return true if DIR is determined to be an empty directory. */
static inline bool
is_empty_dir (int fd_cwd, char const *dir)
{
DIR *dirp;
struct dirent const *dp;
int saved_errno;
int fd = openat (fd_cwd, dir,
(O_RDONLY | O_DIRECTORY
| O_NOCTTY | O_NOFOLLOW | O_NONBLOCK));
if (fd < 0)
return false;
dirp = fdopendir (fd);
if (dirp == NULL)
{
close (fd);
return false;
}
errno = 0;
dp = readdir_ignoring_dot_and_dotdot (dirp);
saved_errno = errno;
closedir (dirp);
if (dp != NULL)
return false;
return saved_errno == 0 ? true : false;
}
/* Factor out some of the common --help and --version processing code. */
/* These enum values cannot possibly conflict with the option values