Subject: bug#6960: mv refuses to move a symlink over a hard link to the same file

From: Davide Brini <[email-masked]>
Date: Wed, 1 Sep 2010 00:50:38 +0100

On Tue, 31 Aug 2010 17:30:19 -0600 Eric Blake <[email-masked]> wrote:

> Not quite.  POSIX specifies that:
> http://www.opengroup.org/onlinepubs/9699919799/utilities/mv.html
> 
> If the source_file operand and destination path name the same existing 
> file, then the destination path shall not be removed, and one of the 
> following shall occur:
> 
>     1. No change is made to source_file, no error occurs, and no 
> diagnostic is issued.
>     2. No change is made to source_file, a diagnostic is issued to 
> standard error identifying the two names, and the exit status is affected.
>     3. If the source_file operand and destination path name distinct 
> directory entries, then the source_file operand is removed, no error 
> occurs, and no diagnostic is issued.
> 
> The question boils down to whether "New_York" and "New_York.sym" name 
> the same file (stat semantics), or whether, since mv generally operates 
> on symlinks rather than dereferencing them, they are distinct files 
> (lstat semantics).
> 
> Solaris /usr/xpg4/bin/mv (which is supposedly POSIX-compliant, although 
> we could debate that) goes ahead with the move:
> $ touch a
> $ ln -s a b
> $ /usr/xpg4/bin/mv b a
> $ echo $? ?
> 0 a
> $ readlink a
> a

So they are saying that, since "a" and "b" do not "name the same existing
file", this has to be a perfectly normal rename, although this causes loss
of data. (but then, if one does "mv a b" and "a" and "b" are two different
regular files, there also is a loss of data because the contents of "b" are
overwritten, so from that point of view our example isn't special)

> Certainly, the underlying rename() call is allowed to replace a file 
> with a symlink

Thanks, this was actually my doubt (although now I recognize it wasn't
at all apparent from my previous message).

> even if the symlink was to the file that it was 
> replacing (and thus will create an ELOOP situation on the symlink while 
> losing the contents that were pointed to).

Creating ELOOP is already possible (eg "ln -s a a", although this does not
cause any loss of data).

> So, in that regards, you 
> could argue that Solaris' behavior is dangerous (it lost data) while 
> coreutils is playing it safe, when the destination has a link count of 1 
> in this simplified example.  But when the destination has a link count 
> of 2, there is no data loss, so the original example seems like it is 
> pointing out a case where coreutils is over-strict.
> 
> And I would argue that the strict POSIX wording says that we should only 
> be refusing to move if the two files have the same inode; in both the 
> original and simplified examples, the symlink has a different inode than 
> the file it would be overwriting, so I think POSIX mandates that the 
> data destruction happen rather than the coreutils behavior.

Given that rename() can replace a file with a symlink, I would say so,
but I have no authority on the subject :) 

> Maybe this would argue for a POSIXLY_CORRECT behavior choice?  :(
> 
> Maybe we need to raise this as a question to the Austin Group to argue 
> that coreutils behavior should be permitted?

This sounds like a good idea. Perhaps first get the interpretation of the
standard clarified, and if it turns out to be the destructive one as it
would seem, either always behave that way, or only when POSIXLY_CORRECT.
If instead the current coreutils behavior is already allowed by POSIX, all
the better.

-- 
D.