summaryrefslogtreecommitdiff
path: root/src/rmdir.c
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2016-01-20 10:55:18 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2016-01-20 10:55:18 +0000
commit70e9163c9c18e995515598085cb824e554eb7ae7 (patch)
treea42dc8b2a6c031354bf31472de888bfc8a060132 /src/rmdir.c
parentcbf5993c43f49281173f185863577d86bfac6eae (diff)
downloadcoreutils-tarball-70e9163c9c18e995515598085cb824e554eb7ae7.tar.gz
Diffstat (limited to 'src/rmdir.c')
-rw-r--r--src/rmdir.c165
1 files changed, 95 insertions, 70 deletions
diff --git a/src/rmdir.c b/src/rmdir.c
index 39063b4..d86ab7a 100644
--- a/src/rmdir.c
+++ b/src/rmdir.c
@@ -1,12 +1,11 @@
/* rmdir -- remove directories
- Copyright (C) 90, 91, 1995-2002, 2004, 2005, 2006 Free Software
- Foundation, Inc.
+ Copyright (C) 1990-2016 Free Software Foundation, Inc.
- This program is free software; you can redistribute it and/or modify
+ 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 2, or (at your option)
- any later version.
+ 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
@@ -14,13 +13,12 @@
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, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Options:
-p, --parent Remove any parent dirs that are explicitly mentioned
- in an argument, if they become empty after the
- argument file is removed.
+ in an argument, if they become empty after the
+ argument file is removed.
David MacKenzie <djm@ai.mit.edu> */
@@ -31,15 +29,12 @@
#include "system.h"
#include "error.h"
-#include "quotearg.h"
+#include "prog-fprintf.h"
-/* The official name of this program (e.g., no `g' prefix). */
+/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "rmdir"
-#define AUTHORS "David MacKenzie"
-
-/* The name this program was run with. */
-char *program_name;
+#define AUTHORS proper_name ("David MacKenzie")
/* If true, remove empty parent directories. */
static bool remove_empty_parents;
@@ -60,7 +55,7 @@ enum
static struct option const longopts[] =
{
- /* Don't name this `--force' because it's not close enough in meaning
+ /* Don't name this '--force' because it's not close enough in meaning
to e.g. rm's -f option. */
{"ignore-fail-on-non-empty", no_argument, NULL,
IGNORE_FAIL_ON_NON_EMPTY_OPTION},
@@ -75,11 +70,39 @@ 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 error_number == ENOTEMPTY || error_number == EEXIST;
+}
+
+/* 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.
@@ -98,33 +121,34 @@ remove_parents (char *dir)
{
slash = strrchr (dir, '/');
if (slash == NULL)
- break;
+ break;
/* Remove any characters after the slash, skipping any extra
- slashes in a row. */
+ slashes in a row. */
while (slash > dir && *slash == '/')
- --slash;
+ --slash;
slash[1] = 0;
/* Give a diagnostic for each attempted removal if --verbose. */
if (verbose)
- error (0, 0, _("removing directory, %s"), dir);
+ prog_fprintf (stdout, _("removing directory, %s"), quoteaf (dir));
ok = (rmdir (dir) == 0);
if (!ok)
- {
- /* Stop quietly if --ignore-fail-on-non-empty. */
- if (ignore_fail_on_non_empty
- && errno_rmdir_non_empty (errno))
- {
- ok = true;
- }
- else
- {
- error (0, errno, "%s", quotearg_colon (dir));
- }
- break;
- }
+ {
+ /* Stop quietly if --ignore-fail-on-non-empty. */
+ if (ignorable_failure (errno, dir))
+ {
+ ok = true;
+ }
+ else
+ {
+ /* Barring race conditions, DIR is expected to be a directory. */
+ error (0, errno, _("failed to remove directory %s"),
+ quoteaf (dir));
+ }
+ break;
+ }
}
return ok;
}
@@ -133,8 +157,7 @@ void
usage (int status)
{
if (status != EXIT_SUCCESS)
- fprintf (stderr, _("Try `%s --help' for more information.\n"),
- program_name);
+ emit_try_help ();
else
{
printf (_("Usage: %s [OPTION]... DIRECTORY...\n"), program_name);
@@ -143,16 +166,17 @@ Remove the DIRECTORY(ies), if they are empty.\n\
\n\
--ignore-fail-on-non-empty\n\
ignore each failure that is solely because a directory\n\
- is non-empty\n\
+ is non-empty\n\
"), stdout);
fputs (_("\
- -p, --parents Remove DIRECTORY and its ancestors. E.g., `rmdir -p a/b/c' is\n\
- similar to `rmdir a/b/c a/b a'.\n\
+ -p, --parents remove DIRECTORY and its ancestors; e.g., 'rmdir -p a/b/c' is\
+\n\
+ similar to 'rmdir a/b/c a/b a'\n\
-v, --verbose output a diagnostic for every directory processed\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
- printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
+ emit_ancillary_info (PROGRAM_NAME);
}
exit (status);
}
@@ -164,7 +188,7 @@ main (int argc, char **argv)
int optc;
initialize_main (&argc, &argv);
- program_name = argv[0];
+ set_program_name (argv[0]);
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
@@ -176,21 +200,21 @@ main (int argc, char **argv)
while ((optc = getopt_long (argc, argv, "pv", longopts, NULL)) != -1)
{
switch (optc)
- {
- case 'p':
- remove_empty_parents = true;
- break;
- case IGNORE_FAIL_ON_NON_EMPTY_OPTION:
- ignore_fail_on_non_empty = true;
- break;
- case 'v':
- verbose = true;
- break;
- case_GETOPT_HELP_CHAR;
- case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
- default:
- usage (EXIT_FAILURE);
- }
+ {
+ case 'p':
+ remove_empty_parents = true;
+ break;
+ case IGNORE_FAIL_ON_NON_EMPTY_OPTION:
+ ignore_fail_on_non_empty = true;
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case_GETOPT_HELP_CHAR;
+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
+ default:
+ usage (EXIT_FAILURE);
+ }
}
if (optind == argc)
@@ -205,22 +229,23 @@ main (int argc, char **argv)
/* Give a diagnostic for each attempted removal if --verbose. */
if (verbose)
- error (0, 0, _("removing directory, %s"), dir);
+ prog_fprintf (stdout, _("removing directory, %s"), quoteaf (dir));
if (rmdir (dir) != 0)
- {
- if (ignore_fail_on_non_empty
- && errno_rmdir_non_empty (errno))
- continue;
-
- error (0, errno, "%s", quotearg_colon (dir));
- ok = false;
- }
+ {
+ if (ignorable_failure (errno, dir))
+ continue;
+
+ /* Here, the diagnostic is less precise, since we have no idea
+ whether DIR is a directory. */
+ error (0, errno, _("failed to remove %s"), quoteaf (dir));
+ ok = false;
+ }
else if (remove_empty_parents)
- {
- ok &= remove_parents (dir);
- }
+ {
+ ok &= remove_parents (dir);
+ }
}
- exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+ return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}