Subject: bug#7823: Rm -f fails on non-existant file

From: Eric Blake <[email-masked]>
Date: Tue, 11 Jan 2011 07:56:31 -0700

On 01/11/2011 05:58 AM, Nadav Har'El wrote:
> Unfortunately, I found a rare case where this is not happening.
> 
> It appears that when mounting a Windows filesystem using Samba, if I try
> running:
> command
> 
> 	#!/bin/sh
> 	mkdir emptydir
> 	rm -f emptydir/*
> 
> The shell leaves this "*" unchanged, and rm gives this name to unlink(2),
> which oddly enough returns EINVAL (invalid argument) instead of the expected
> ENOENT (no such file or directory!).

Thanks for tracking this down.

> 
> I'm guessing the smbfs people chose to give this as a special error when
> "invalid" characters are used in the file name (this is a concept that doesn't
> exist in Unix), but I'm not sure why it was so important to them to not
> just return ENOENT in this case... But still, I think "rm" should behave
> well in this case.

Feel free to file a bug report to the smbfs people.  POSIX does not
specify EINVAL (except for bad flags to unlinkat), but does have a
global clause that states that any errno not specifically listed may be
returned if it is a better fit than any mandated error.  On the other
hand, the next version of POSIX will be mandating that the case of an
unsupported byte in a filename ('*' in the case of smbfs) shall fail
with EILSEQ, not EINVAL (that is, if they don't return the equally valid
ENOENT failure).  See http://austingroupbugs.net/view.php?id=293, for
justification why smbfs ought to change their errno value away from EINVAL.

> Anyway, in remove.c, you have
> 
> static inline bool
> nonexistent_file_errno (int errnum)
> {
>   switch (errnum)
>     {
>     case ENOENT:
>     case ENOTDIR:
>       return true;
>     default:
>       return false;
>     }
> }
> 
> And I wonder whether EINVAL shouldn't also be added to it.

Yes, since POSIX doesn't specify EINVAL for any other situation, I see
no harm in globally exempting it (with a comment why) in our source
code; likewise, I see no problem in also adding EILSEQ to that list,
whether or not smbfs also fixes their bug.

Is it okay if I push this patch in your name?

From 3201907296fd18084b68f062709d589c18e3ffe6 Mon Sep 17 00:00:00 2001
From: Nadav Har'El <nyh AT math.technion.ac.il>
Date: Tue, 11 Jan 2011 07:53:07 -0700
Subject: [PATCH] rm: ignore errno related to invalid file names

* src/remove.c (nonexistent_file_errno): Also skip EINVAL and
EILSEQ, for at least smbfs rejection of '*' in file names.
---
 src/remove.c |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/src/remove.c b/src/remove.c
index f7b00c6..3814232 100644
--- a/src/remove.c
+++ b/src/remove.c
@@ -378,10 +378,18 @@ nonexistent_file_errno (int errnum)
      exist, but be (in)accessible only via too long a symlink chain.
      Likewise for ENAMETOOLONG, since rm -f ./././.../foo may fail
      if the "..." part expands to a long enough sequence of "./"s,
-     even though ./foo does indeed exist.  */
+     even though ./foo does indeed exist.
+
+     Another case to consider is when a particular name is invalid for
+     a given file system.  In 2011, smbfs returns EINVAL, but the next
+     revision of POSIX will require EILSEQ for that situation:
+     http://austingroupbugs.net/view.php?id=293
+  */

   switch (errnum)
     {
+    case EILSEQ:
+    case EINVAL:
     case ENOENT:
     case ENOTDIR:
       return true;
-- 
1.7.3.4

-- 
Eric Blake   [email-masked]    +1-801-349-2682
Libvirt virtualization library http://libvirt.org