Steven Drake wrote: > Summary: rm -f gives an error when trying to delete a non-existent > file on a read-only filesystem > > Eg: > /bin/rm: cannot remove `non-existent-file': Read-only file system. > > On a linux/glibc system the unlinkat syscall will set errno to EROFS and > nonexistent_file_errno() does not perform any checks > for this case. (Another rm does an fts_open/fts_read and ignores > the file if fts_info is FST_NS before trying to unlink it.)
Thanks for reporting that. It also affected the very latest versions. I expect to fix it with this patch once I've added a test. >From 77b6a86cf1cc87635793202ec869528f07f5fba3 Mon Sep 17 00:00:00 2001 From: Jim Meyering <[email protected]> Date: Tue, 3 Nov 2009 12:01:40 +0100 Subject: [PATCH] rm -f: ignore EROFS when it's really ENOENT rm -f must not print a diagnostic for a nonexistent file. However, most linux-based kernel unlinkat functions set errno to EROFS when the named file (regardless of whether it exists) would lie on a read-only file system. remove.c now performs an extra fstatat call in that case, to determine whether the file exists. * src/remove.c (excise): Map EROFS to ENOENT, if a file is nonexistent. Reported by Steven Drake in <http://savannah.gnu.org/bugs/?27923>. * NEWS (Changes in behavior): Mention it. --- NEWS | 6 ++++++ src/remove.c | 12 ++++++++++++ 2 files changed, 18 insertions(+), 0 deletions(-) diff --git a/NEWS b/NEWS index 0760775..03ed83f 100644 --- a/NEWS +++ b/NEWS @@ -49,6 +49,12 @@ GNU coreutils NEWS -*- outline -*- echo and printf now interpret \e as the Escape character (0x1B). + rm -f /read-only-fs/nonexistent now succeeds and prints no diagnostic + on systems with an unlinkat syscall that sets errno to EROFS in that case. + Before, it would fail with a "Read-only file system" diagnostic. + Also, "rm /read-only-fs/nonexistent" now reports "file not found" rather + than the less precise "Read-only file system" error. + ** New features env and printenv now accept the option --null (-0), as a means to diff --git a/src/remove.c b/src/remove.c index 87fb32b..a234829 100644 --- a/src/remove.c +++ b/src/remove.c @@ -437,6 +437,18 @@ excise (FTS *fts, FTSENT *ent, struct rm_options const *x, bool is_dir) return RM_OK; } + /* The unlinkat from kernels like linux-2.6.32 reports EROFS even for + nonexistent files. When the file is indeed missing, map that to ENOENT, + so that rm -f ignores it, as required. Even without -f, this is useful + because it makes rm print the more precise diagnostic. */ + if (errno == EROFS) + { + struct stat st; + if ( ! (fstatat (fts->fts_cwd_fd, ent->fts_accpath, &st, + AT_SYMLINK_NOFOLLOW) && errno == ENOENT)) + errno = EROFS; + } + if (ignorable_missing (x, errno)) return RM_OK; -- 1.6.5.2.292.g1cda2
