diff options
author | Boris Ranto <branto@redhat.com> | 2014-11-18 20:20:50 +0100 |
---|---|---|
committer | Pádraig Brady <P@draigBrady.com> | 2014-11-21 02:48:45 +0000 |
commit | 222d7ac0c4f5f005438c534f3aba62fd94d96dc2 (patch) | |
tree | 55263d170dd91118391d3fddd0598311f33d43d7 /tests/cp | |
parent | f43c072a04ba881debf35ccdb509ee0a145b255c (diff) | |
download | coreutils-222d7ac0c4f5f005438c534f3aba62fd94d96dc2.tar.xz |
mv: fail when moving a file to a hardlink
We may run into a race condition if we treat hard links to the same file
as distinct files. If we do 'mv a b' and 'mv b a' in parallel, both a
and b can disappear from the file system. The reason is that in this
case the unlink on src is called and the system calls can end up being
run in the order where unlink(a) and unlink(b) are the last two system
calls. Therefore exit with an error code so that we avoid the potential
data loss.
* src/copy.c (same_file_ok): Don't set unlink_src that was used by mv,
and return false for two hardlinks to a file in move_mode.
*src/copy.c (copy_internal): No longer honor the unlink_src option,
used only by mv.
NEWS: Mention the change in behavior.
* tests/cp/same-file.sh: Augment to cover the `cp -a hlsl1 sl1` case.
* tests/mv/hard-verbose.sh: Remove no longer needed test.
* tests/local.mk: Remove the reference to hard-verbose.sh.
* tests/mv/hard-4.sh: Adjust so we fail in this case.
* tests/mv/i-4.sh: Likewise.
* tests/mv/symlink-onto-hardlink-to-self.sh: Likewise.
Diffstat (limited to 'tests/cp')
-rwxr-xr-x | tests/cp/same-file.sh | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/tests/cp/same-file.sh b/tests/cp/same-file.sh index f62a9a72a..54d23a50b 100755 --- a/tests/cp/same-file.sh +++ b/tests/cp/same-file.sh @@ -44,7 +44,8 @@ exec 3>&1 1> actual # FIXME: This should be bigger: like more than 8k contents=XYZ -for args in 'foo symlink' 'symlink foo' 'foo foo' 'sl1 sl2' 'foo hardlink'; do +for args in 'foo symlink' 'symlink foo' 'foo foo' 'sl1 sl2' \ + 'foo hardlink' 'hlsl sl2'; do for options in '' -d -f -df --rem -b -bd -bf -bdf \ -l -dl -fl -dfl -bl -bdl -bfl -bdfl; do case $args$options in @@ -70,11 +71,11 @@ for args in 'foo symlink' 'symlink foo' 'foo foo' 'sl1 sl2' 'foo hardlink'; do # cont'd Instead, skip them only on systems for which link does # dereference a symlink. Detect and skip such tests here. case $hard_link_to_symlink_does_the_deref:$args:$options in - 'yes:sl1 sl2:-fl') + yes:*sl2:-fl) continue ;; - 'yes:sl1 sl2:-bl') + yes:*sl2:-bl) continue ;; - 'yes:sl1 sl2:-bfl') + yes:*sl2:-bfl) continue ;; esac @@ -86,6 +87,7 @@ for args in 'foo symlink' 'symlink foo' 'foo foo' 'sl1 sl2' 'foo hardlink'; do case "$args" in *hardlink*) ln foo hardlink ;; esac case "$args" in *sl1*) ln -s foo sl1;; esac case "$args" in *sl2*) ln -s foo sl2;; esac + case "$args" in *hlsl*) ln sl2 hlsl;; esac ( ( # echo 1>&2 cp $options $args @@ -211,6 +213,24 @@ cat <<\EOF | sed "$remove_these_sed" > expected 0 -bfl (foo hardlink) 0 -bdfl (foo hardlink) +1 [cp: 'hlsl' and 'sl2' are the same file] (foo hlsl -> foo sl2 -> foo) +0 -d (foo hlsl -> foo sl2 -> foo) +1 -f [cp: 'hlsl' and 'sl2' are the same file] (foo hlsl -> foo sl2 -> foo) +0 -df (foo hlsl -> foo sl2 -> foo) +0 --rem (foo hlsl -> foo sl2) +0 -b (foo hlsl -> foo sl2 sl2.~1~ -> foo) +0 -bd (foo hlsl -> foo sl2 -> foo sl2.~1~ -> foo) +0 -bf (foo hlsl -> foo sl2 sl2.~1~ -> foo) +0 -bdf (foo hlsl -> foo sl2 -> foo sl2.~1~ -> foo) +1 -l [cp: cannot create hard link 'sl2' to 'hlsl'] (foo hlsl -> foo sl2 -> foo) +0 -dl (foo hlsl -> foo sl2 -> foo) +0 -fl (foo hlsl -> foo sl2) +0 -dfl (foo hlsl -> foo sl2 -> foo) +0 -bl (foo hlsl -> foo sl2 sl2.~1~ -> foo) +0 -bdl (foo hlsl -> foo sl2 -> foo) +0 -bfl (foo hlsl -> foo sl2 sl2.~1~ -> foo) +0 -bdfl (foo hlsl -> foo sl2 -> foo) + EOF exec 1>&3 3>&- |