--- Begin Message ---
Subject: |
mv fails to clobber target if it's a hardlink of a source |
Date: |
Fri, 26 Jul 2019 18:43:51 +0100 |
The below is a bug initially reported by Xuefer at
https://bugs.gentoo.org/646412.
Reproducer:
$ mv --version
mv (GNU coreutils) 8.31
Packaged by Gentoo (8.31 (p0))
$ touch a.aa
$ ln a.aa b.bb
$ mv a.aa b.bb
mv: 'a.aa' and 'b.bb' are the same file
For comparison if fines are unrelated 'mv' just works:
$ touch a.aa
$ touch b.bb
$ mv a.aa b.bb
$ echo $?
0
Fun fact: busybox does not complain about hardlinked files:
$ touch a.aa
$ ln a.aa b.bb
$ busybox mv a.aa b.bb
$ echo $?
$ echo $?
0
Some context on where these accidentally hardlinked files come from:
gdb build system simplistically does the following:
$ gcc a.c -o a.tmp.o && mv a.tmp.o a.o
ccache has a mode to create a resulting file by hardlinking
if possible instead of copying data round.
If the above command is ran without ccache wrapper 'a.tmp.o'
is always a new file. Otherwise if it's ran via ccache with
CCACHE_HARDLINK=1 then 'a.tmp.o' and 'a.o' and both
hardlinks of a file stored in cache originally.
Is it an 'mv's bug or a feature to prevent hardlinked file clobbering?
If feels like an unnecessary restriction.
Thank you!
--
Sergei
--- End Message ---
--- Begin Message ---
Subject: |
Re: bug#36818: mv fails to clobber target if it's a hardlink of a source |
Date: |
Fri, 26 Jul 2019 19:23:22 +0100 |
On Fri, 26 Jul 2019 13:01:44 -0500
Eric Blake <address@hidden> wrote:
> On 7/26/19 12:43 PM, Sergei Trofimovich wrote:
>
> > Is it an 'mv's bug or a feature to prevent hardlinked file clobbering?
> > If feels like an unnecessary restriction.
>
> It's a POSIX (mis-)feature that for hard links, rename("file1", "file2")
> is a mandatory no-op (no error, but also no change to the existence or
> contents of either file1 or file2). Back under POSIX 2001, mv was
> required to behave identically to the rename() syscall. But this was
> confusing enough that POSIX 2008 relaxed the wording as follows,
> inspired in part by complaint from GNU coreutils:
>
> https://pubs.opengroup.org/onlinepubs/9699919799/utilities/mv.html
>
> "If the source_file operand and destination path resolve to either the
> same existing directory entry or different directory entries for the
> same existing file, then the destination path shall not be removed, and
> one of the following shall occur:
>
> No change is made to source_file, no error occurs, and no diagnostic
> is issued.
>
> No change is made to source_file, a diagnostic is issued to standard
> error identifying the two names, and the exit status is affected.
>
> 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 difference between GNU coreutils and busybox both appear to be
> compliant behaviors (you didn't actually show after the 'mv' command
> whether a.aa still exists, so I can't tell whether busybox implemented
> option 1 or option 3;
Oh, I did not realize source file did not disappear.
Looks like busybox's behaviour is an 'option 1':
$ ls -i a.aa b.bb
208636260 a.aa 208636260 b.bb
$ strace -f busybox mv a.aa b.bb
...
stat("b.bb", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
access("b.bb", W_OK) = 0
rename("a.aa", "b.bb") = 0
exit_group(0) = ?
+++ exited with 0 +++
$ ls -i a.aa b.bb
208636260 a.aa 208636260 b.bb
> but it appears GNU implemented option 2). Option
> 1 is probably the least intuitive but is the historical behavior when
> you use rename() without any checking. Option 2 at least points out the
> issue that your usage is not going to be universally portable. Option 3
> is closest to what happens when there are no hard links.
Thank you for the quick response. The bug can be closed as WAI then.
--
Sergei
pgpoNo3VP6_Bx.pgp
Description: Цифровая подпись OpenPGP
--- End Message ---