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

From: Eric Blake <[email-masked]>
Date: Wed, 04 Jan 2012 14:12:45 -0700

On 01/04/2012 02:00 PM, Jim Meyering wrote:
>>> mv --backup=numbered is not atomic; it expands to two rename() syscalls,
>>> between which the target doesn’t exist at all.
>>
>> Maybe we should fix that, to make mv --backup use link()/rename() rather
>> than rename()/rename(), so that there is no window where the target
>> doesn't exist.
> 
> Note that we can use link/rename only some of the time.
> E.g., the rename will always fail when they're on different partitions.

It's a two-edged sword - POSIX _requires_ mv(1) to be atomic (no period
where target does not exist) if no EXDEV would occur from rename(2), but
does _not_ require atomicity otherwise.  If rename(2) fails because you
cross partitions, then you already _expect_ a window where the target is
bogus, per the POSIX requirements on mv(1); so whether we
rename()/creat() or link()/unlink()/creat(), the behavior is the same.

Is it worth shaving off the extra syscall by using
rename(target,target-backup) instead of link()/unlink() when we can
detect a-priori that rename(source,target) would fail with EXDEV?  Or
should we _always_ favor link(target,target-backup), and only if the
rename(source,target) fails do we fall back to unlink(target) followed
by creating the file with the moved contents?

Or do we go one step further, and guarantee atomicity even where POSIX
does not require it in the EXDEV situation, by doing:
link(target,target-backup)
creat(temp) in dirname(target)
copy source to temp
rename(temp,target)
Then again, that takes up more disk space when there is no target-backup
created, so it seems like it might be worth providing that extra level
of atomicity guarantees only via a command line option.

-- 
Eric Blake   [email-masked]    +1-919-301-3266
Libvirt virtualization library http://libvirt.org