Subject: RE: bug#9823: request for more correct error reporting of mv

From: "Voelker, Bernhard" <[email-masked]>
Date: Tue, 25 Oct 2011 08:39:07 +0200

Eric Blake wrote:
> On 10/24/2011 02:06 AM, [email-masked] wrote:
> > Hello Eric,
> >
> > This is a sequence which reproduces my situation.
> >
> >> rm -rf ?
> >> mkdir -p a b/a
> >> touch b/a/file1 a/file2
> >> mv a b
> > mv: cannot move `a' to `b/a': Directory not empty
> 
> Thanks for your formula.  In fact, you don't even have to touch a/file2; 
> simply touching b/a/file1 is enough to reproduce the setup (and even 
> makes it more confusing, as then ./a is empty).  The problem is that the 
> recursion ends up trying to move the directory ./a (empty or otherwise) 
> from the source, and rename(2) it onto the existing directory ./b/a/ on 
> the destination; but rename(2) can only succeed if the destination 
> directory is empty.
> >
> > Ok, in this example it's very clear.
> > However in my situation it was power play with an account of 120GiB.
> > When mv says "Directory not empty" you interpret the error message
> > as that of rmdir, and you go looking at dir a, which of course isn't
> > empty. It's not immediatly apparent that you have to go looking
> > after the dir b/a.
> >
> > This is the problem I want to address. Would it not be possible
> > to add to the error image the following message: "Dir b/a already
> > exists" or something similar making the real problem clear right
> > from the start?
> 
> Like I said earlier, POSIX allows either ENOTEMPTY or EEXIST, and Linux 
> happened to choose ENOTEMPTY.  Maybe special-casing that error and 
> converting to EEXIST would produce better output.  But someone would 
> have to submit a patch.

I think mv is right to say "Directory not empty". Let's look at
the opposite example, i.e. where the destination _is_ empty:

  rm -rf a b
  mkdir -p a b/a
  strace -e trace=file ../src/mv a b
  ...
  stat("b", {st_mode=S_IFDIR|0750, st_size=4096, ...}) = 0
  lstat("a", {st_mode=S_IFDIR|0750, st_size=4096, ...}) = 0
  lstat("b/a", {st_mode=S_IFDIR|0750, st_size=4096, ...}) = 0
  access("b/a", W_OK)                     = 0
  rename("a", "b/a")                      = 0

The kernel returns success.

Have a nice day,
Berny