diff options
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | src/remove.c | 38 | ||||
-rw-r--r-- | tests/rm/Makefile.am | 2 | ||||
-rwxr-xr-x | tests/rm/ignorable | 49 | ||||
-rwxr-xr-x | tests/rm/ignore-name-too-long | 48 |
6 files changed, 148 insertions, 7 deletions
@@ -1,4 +1,14 @@ -2006-10-02 Jim Meyering <jim@meyering.net> +2006-10-03 Jim Meyering <jim@meyering.net> + + With --force (-f), rm no longer fails for ENOTDIR. + * src/remove.c (ignorable_missing): New function. + Use it everywhere, rather than open-coding the test. + Andreas Schwab reported the ENOTDIR problem. + (ignorable_missing): Similarly, don't fail for ENAMETOOLONG. + * NEWS: Mention the bug fix. + * tests/rm/ignorable: New file. Test for the ENOTDIR case. + * tests/rm/ignore-name-too-long: New file. Test for ENAMETOOLONG. + * tests/rm/Makefile.am (TESTS): Add the new file names. * bootstrap: Undo last change to this file, since now gnulib-tool sticks with the automake default in generating dependencies. @@ -2,6 +2,12 @@ GNU coreutils NEWS -*- outline -*- * Major changes in release 6.4-cvs (2006-??-??) [?????] +** Bug fixes + + With --force (-f), rm no longer fails for ENOTDIR or ENAMETOOLONG. + For example, "rm -f existing-non-directory/anything" now exits + successfully, ignoring the error about a nonexistent file. + * Major changes in release 6.3 (2006-09-30) [stable] diff --git a/src/remove.c b/src/remove.c index 1fcf79ff3..ed2c846e9 100644 --- a/src/remove.c +++ b/src/remove.c @@ -899,7 +899,7 @@ is_dir_lstat (char const *filename, struct stat *st) return RM_OK; \ } \ \ - if (errno == ENOENT && (X)->ignore_missing_files) \ + if (ignorable_missing (X, errno)) \ return RM_OK; \ } \ while (0) @@ -915,7 +915,7 @@ is_dir_lstat (char const *filename, struct stat *st) return RM_OK; \ } \ \ - if (errno == ENOENT && (X)->ignore_missing_files) \ + if (ignorable_missing (X, errno)) \ return RM_OK; \ \ if (errno == ENOTEMPTY || errno == EEXIST) \ @@ -923,6 +923,32 @@ is_dir_lstat (char const *filename, struct stat *st) } \ while (0) +/* When a function like unlink, rmdir, or fstatat fails with an errno + value of ERRNUM, return true if the specified file system object + is guaranteed not to exist; otherwise, return false. */ +static inline bool +nonexistent_file_errno (int errnum) +{ + /* Do not include ELOOP here, since the specified file may indeed + exist, but be (in)accessible only via too long a symlink chain. */ + switch (errnum) + { + case ENAMETOOLONG: + case ENOENT: + case ENOTDIR: + return true; + default: + return false; + } +} + +/* Encapsulate the test for whether the errno value, ERRNUM, is ignorable. */ +static inline bool +ignorable_missing (struct rm_options const *x, int errnum) +{ + return x->ignore_missing_files && nonexistent_file_errno (errnum); +} + /* Remove the file or directory specified by FILENAME. Return RM_OK if it is removed, and RM_ERROR or RM_USER_DECLINED if not. But if FILENAME specifies a non-empty directory, return RM_NONEMPTY_DIR. */ @@ -1014,7 +1040,7 @@ remove_entry (int fd_cwd, Dirstack_state const *ds, char const *filename, { if (fstatat (fd_cwd, filename, st, AT_SYMLINK_NOFOLLOW)) { - if (errno == ENOENT && x->ignore_missing_files) + if (ignorable_missing (x, errno)) return RM_OK; error (0, errno, _("cannot remove %s"), @@ -1195,7 +1221,7 @@ remove_cwd_entries (DIR **dirp, /* CAUTION: this test and diagnostic are identical to those following the other use of fd_to_subdirp. */ - if (errno == ENOENT && x->ignore_missing_files) + if (ignorable_missing (x, errno)) { /* With -f, don't report "file not found". */ } @@ -1281,7 +1307,7 @@ remove_dir (int fd_cwd, Dirstack_state *ds, char const *dir, { /* CAUTION: this test and diagnostic are identical to those following the other use of fd_to_subdirp. */ - if (errno == ENOENT && x->ignore_missing_files) + if (ignorable_missing (x, errno)) { /* With -f, don't report "file not found". */ } @@ -1426,7 +1452,7 @@ rm_1 (Dirstack_state *ds, char const *filename, { if (cache_fstatat (AT_FDCWD, filename, &st, AT_SYMLINK_NOFOLLOW) != 0) { - if (errno == ENOENT && x->ignore_missing_files) + if (ignorable_missing (x, errno)) return RM_OK; error (0, errno, _("cannot remove %s"), quote (filename)); return RM_ERROR; diff --git a/tests/rm/Makefile.am b/tests/rm/Makefile.am index 8fc7bcab8..2a1339e72 100644 --- a/tests/rm/Makefile.am +++ b/tests/rm/Makefile.am @@ -21,6 +21,8 @@ AUTOMAKE_OPTIONS = 1.1 gnits TESTS = \ + ignore-name-too-long \ + ignorable \ readdir-bug \ empty-inacc \ dir-nonrecur \ diff --git a/tests/rm/ignorable b/tests/rm/ignorable new file mode 100755 index 000000000..7c2b2ba9a --- /dev/null +++ b/tests/rm/ignorable @@ -0,0 +1,49 @@ +#!/bin/sh +# Ensure that rm -f existing-non-dir/anything exits successfully + +# Copyright (C) 2006 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 2 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +if test "$VERBOSE" = yes; then + set -x + rm --version +fi + +PRIV_CHECK_ARG=require-non-root . $srcdir/../priv-check + +pwd=`pwd` +t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$ +trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0 +trap '(exit $?); exit $?' 1 2 13 15 + +framework_failure=0 +mkdir -p $tmp || framework_failure=1 +cd $tmp || framework_failure=1 +touch existing-non-dir || framework_failure=1 + +if test $framework_failure = 1; then + echo "$0: failure in testing framework" 1>&2 + (exit 1); exit 1 +fi + +fail=0 + +# With coreutils-6.3, this would exit nonzero. It should not. +# Example from Andreas Schwab. +rm -f existing-non-dir/f > out 2>&1 || fail=1 + +(exit $fail); exit $fail diff --git a/tests/rm/ignore-name-too-long b/tests/rm/ignore-name-too-long new file mode 100755 index 000000000..78d4e557e --- /dev/null +++ b/tests/rm/ignore-name-too-long @@ -0,0 +1,48 @@ +#!/bin/sh +# Ensure that rm -f name_longer_than_FILENAME_MAX exits successfully + +# Copyright (C) 2006 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 2 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +if test "$VERBOSE" = yes; then + set -x + rm --version +fi + +PRIV_CHECK_ARG=require-non-root . $srcdir/../priv-check + +pwd=`pwd` +t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$ +trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0 +trap '(exit $?); exit $?' 1 2 13 15 + +framework_failure=0 +mkdir -p $tmp || framework_failure=1 +cd $tmp || framework_failure=1 + +if test $framework_failure = 1; then + echo "$0: failure in testing framework" 1>&2 + (exit 1); exit 1 +fi + +fail=0 + +# With coreutils-6.3, this would exit nonzero. It should not. +long_name=$(printf %0513d 0) +rm -f $long_name > out 2>&1 || fail=1 + +(exit $fail); exit $fail |