diff options
Diffstat (limited to 'tests/mv')
43 files changed, 2434 insertions, 0 deletions
diff --git a/tests/mv/acl.sh b/tests/mv/acl.sh new file mode 100755 index 0000000..8065a3a --- /dev/null +++ b/tests/mv/acl.sh @@ -0,0 +1,67 @@ +#!/bin/sh +# move files/directories across file system boundaries +# and make sure acls are preserved + +# Copyright (C) 2005-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + +require_acl_ + +# Skip this test if cp was built without ACL support: +grep '^#define USE_ACL 1' $CONFIG_HEADER > /dev/null || + skip_ "insufficient ACL support" + +cleanup_() { rm -rf "$other_partition_tmpdir"; } +. "$abs_srcdir/tests/other-fs-tmpdir" + +touch file || framework_failure_ +t1=$other_partition_tmpdir/t1 +touch $t1 || framework_failure_ + +skip_partition=none +# Ensure that setfacl and getfacl work on this file system. +setfacl -m user:bin:rw- file 2> /dev/null || skip_partition=. +# And on the destination file system. +setfacl -m user:bin:rw- $t1 || skip_partition=$other_partition_tmpdir +acl1=$(getfacl file) || skip_partition=. + +test $skip_partition != none && + skip_ "'$skip_partition' is not on a suitable file system for this test" + +# move the access acl of a file +mv file "$other_partition_tmpdir" || fail=1 +acl2=$(cd "$other_partition_tmpdir" && getfacl file) || framework_failure_ +test "$acl1" = "$acl2" || fail=1 + +# move the access acl of a directory +mkdir dir || framework_failure_ +setfacl -m user:bin:rw- dir || framework_failure_ +acl1=$(getfacl dir) || framework_failure_ +mv dir "$other_partition_tmpdir" || fail=1 +acl2=$(cd "$other_partition_tmpdir" && getfacl dir) || framework_failure_ +test "$acl1" = "$acl2" || fail=1 + +# move the default acl of a directory +mkdir dir2 || framework_failure_ +setfacl -d -m user:bin:rw- dir2 || framework_failure_ +acl1=$(getfacl dir2) || framework_failure_ +mv dir2 "$other_partition_tmpdir" || fail=1 +acl2=$(cd "$other_partition_tmpdir" && getfacl dir2) || framework_failure_ +test "$acl1" = "$acl2" || fail=1 + +Exit $fail diff --git a/tests/mv/atomic.sh b/tests/mv/atomic.sh new file mode 100755 index 0000000..145e89d --- /dev/null +++ b/tests/mv/atomic.sh @@ -0,0 +1,46 @@ +#!/bin/sh +# ensure that mv doesn't first unlink its destination in one particular case + +# Copyright (C) 2006-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +require_strace_ unlink + +# Before the fix, mv would unnecessarily unlink the destination symlink: +# $ rm -rf s[12]; ln -s / s1; ln -s /tmp s2 +# $ strace -qe unlink /bin/mv -T s1 s2 +# unlink("s2") = 0 +# +# With the fix, it doesn't call unlink: +# $ rm -rf s[12]; ln -s / s1; ln -s /tmp s2 +# $ strace -qe unlink ./mv -T s1 s2 +# $ + +ln -s t1 s1 || framework_failure_ +ln -s t2 s2 || framework_failure_ + + +strace -qe unlink mv -T s1 s2 > out 2>&1 || fail=1 +$EGREP 'unlink.*"s1"' out && fail=1 + +# Ensure that the source, s1, is gone. +ls -dl s1 > /dev/null 2>&1 && fail=1 + +# Ensure that the destination, s2, contains the link from s1. +test "$(readlink s2)" = t1 || fail=1 + +Exit $fail diff --git a/tests/mv/atomic2.sh b/tests/mv/atomic2.sh new file mode 100755 index 0000000..fedf392 --- /dev/null +++ b/tests/mv/atomic2.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# ensure that mv doesn't first unlink a multi-hard-linked destination + +# Copyright (C) 2008-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +require_strace_ unlink + +# Before the fix, mv would unnecessarily unlink the destination symlink: +# $ rm -f a b b2; touch a b; ln b b2; strace -e unlink /p/bin/mv a b +# unlink("b") = 0 +# +# With the fix, it doesn't call unlink: +# $ rm -f a b b2; touch a b; ln b b2; strace -e unlink ./mv a b +# $ + +touch a b || framework_failure_ +ln b b2 || framework_failure_ + + +strace -qe unlink mv a b > out 2>&1 || fail=1 +$EGREP 'unlink.*"b"' out && fail=1 + +# Ensure that the source, "a", is gone. +ls -dl a > /dev/null 2>&1 && fail=1 + +# Ensure that the destination, "b", has link count 1. +n_links=$(stat --printf=%h b) || fail=1 +test "$n_links" = 1 || fail=1 + +Exit $fail diff --git a/tests/mv/backup-dir.sh b/tests/mv/backup-dir.sh new file mode 100755 index 0000000..d967b45 --- /dev/null +++ b/tests/mv/backup-dir.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# Ensure "mv --verbose --backup" works the same for dirs and non-dirs. + +# Copyright (C) 2006-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + +mkdir A B || framework_failure_ +touch X Y || framework_failure_ + + +# Before coreutils-6.2, the " (backup: 'B.~1~')" suffix was not printed. +mv --verbose --backup=numbered -T A B > out || fail=1 +cat <<\EOF > exp || framework_failure_ +renamed 'A' -> 'B' (backup: 'B.~1~') +EOF + +compare exp out || fail=1 + +# Bug#52410 +mkdir C D E || framework_failure_ +mv -T --backup=numbered C E/ || fail=1 +mv -T --backup=numbered D E/ || fail=1 + +# Bug#55029 +mkdir F && echo 1 >1 && echo 2 >2 && cp 1 F/X && cp 2 X || framework_failure_ +mv --backup=simple X F/ || fail=1 +compare 1 F/X~ || fail=1 +compare 2 F/X || fail=1 + +Exit $fail diff --git a/tests/mv/backup-is-src.sh b/tests/mv/backup-is-src.sh new file mode 100755 index 0000000..0a4110c --- /dev/null +++ b/tests/mv/backup-is-src.sh @@ -0,0 +1,46 @@ +#!/bin/sh +# Force mv to use the copying code. + +# Copyright (C) 1998-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +cleanup_() { rm -rf "$other_partition_tmpdir"; } +. "$abs_srcdir/tests/other-fs-tmpdir" + +a="$other_partition_tmpdir/a" +a2="$other_partition_tmpdir/a~" + +rm -f "$a" "$a2" || framework_failure_ +echo a > "$a" || framework_failure_ +echo a2 > "$a2" || framework_failure_ + +# This mv command should exit nonzero. +mv --b=simple "$a2" "$a" > out 2>&1 && fail=1 + +sed \ + -e "s,mv:,XXX:," \ + -e "s,$a,YYY," \ + -e "s,$a2,ZZZ," \ + out > out2 + +cat > exp <<\EOF +XXX: backing up 'YYY' might destroy source; 'ZZZ' not moved +EOF + +compare exp out2 || fail=1 + +Exit $fail diff --git a/tests/mv/childproof.sh b/tests/mv/childproof.sh new file mode 100755 index 0000000..a5a830e --- /dev/null +++ b/tests/mv/childproof.sh @@ -0,0 +1,83 @@ +#!/bin/sh +# Ensure that cp/mv/ln don't clobber a just-copied/moved/linked file. +# With fileutils-4.1 and earlier, this test would fail for cp and mv. +# With coreutils-6.9 and earlier, this test would fail for ln. + +# Copyright (C) 2001-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ cp mv ln + +skip_if_root_ + +mkdir a b c || framework_failure_ +echo a > a/f || framework_failure_ +echo b > b/f || framework_failure_ + + +returns_ 1 cp a/f b/f c 2> /dev/null || fail=1 +test -f a/f || fail=1 +test -f b/f || fail=1 +test -f c/f || fail=1 +test "$(cat c/f)" = a || fail=1 +rm -f c/f + +# With --backup=numbered, it should succeed +cp --backup=numbered a/f b/f c || fail=1 +test -f a/f || fail=1 +test -f b/f || fail=1 +test -f c/f || fail=1 +test -f c/f.~1~ || fail=1 +rm -f c/f* + +returns_ 1 mv a/f b/f c 2> /dev/null || fail=1 +test -f a/f && fail=1 +test -f b/f || fail=1 +test -f c/f || fail=1 +test "$(cat c/f)" = a || fail=1 + +# Make sure mv still works when moving hard links. +# This is where the same_file test is necessary, and why +# we save file names in addition to dev/ino. +rm -f c/f* b/f +touch a/f +ln a/f b/g +mv a/f b/g c || fail=1 +test -f a/f && fail=1 +test -f b/g && fail=1 +test -f c/f || fail=1 +test -f c/g || fail=1 + +touch a/f b/f b/g +returns_ 1 mv a/f b/f b/g c 2> /dev/null || fail=1 +test -f a/f && fail=1 # a/f should have been moved +test -f b/f || fail=1 # b/f should remain +test -f b/g && fail=1 # b/g should have been moved +test -f c/f || fail=1 +test -f c/g || fail=1 + +# Test ln -f. + +rm -f a/f b/f c/f +echo a > a/f || framework_failure_ +echo b > b/f || framework_failure_ +returns_ 1 ln -f a/f b/f c 2> /dev/null || fail=1 +# a/f and c/f must be linked +test $(stat --format %i a/f) = $(stat --format %i c/f) || fail=1 +# b/f and c/f must not be linked +test $(stat --format %i b/f) = $(stat --format %i c/f) && fail=1 + +Exit $fail diff --git a/tests/mv/diag.sh b/tests/mv/diag.sh new file mode 100755 index 0000000..abcb335 --- /dev/null +++ b/tests/mv/diag.sh @@ -0,0 +1,48 @@ +#!/bin/sh +# make sure we get proper diagnostics: e.g., with --target-dir=d but no args + +# Copyright (C) 2000-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + +touch f1 || framework_failure_ +touch f2 || framework_failure_ +touch d || framework_failure_ + +# These mv commands should all exit nonzero. + +# Too few args. This first one did fail, but with an incorrect diagnostic +# until fileutils-4.0u. +mv --target=. >> out 2>&1 && fail=1 +mv no-file >> out 2>&1 && fail=1 + +# Target is not a directory. +mv f1 f2 f1 >> out 2>&1 && fail=1 +mv --target=f2 f1 >> out 2>&1 && fail=1 + +cat > exp <<\EOF +mv: missing file operand +Try 'mv --help' for more information. +mv: missing destination file operand after 'no-file' +Try 'mv --help' for more information. +mv: target 'f1': Not a directory +mv: target directory 'f2': Not a directory +EOF + +compare exp out || fail=1 + +Exit $fail diff --git a/tests/mv/dir-file.sh b/tests/mv/dir-file.sh new file mode 100755 index 0000000..e70f63e --- /dev/null +++ b/tests/mv/dir-file.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# mv must fail when src and dest are mismatched directory/non-directory. + +# Copyright (C) 2000-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + +mkdir -p dir/file || framework_failure_ +> file || framework_failure_ + + +# These should both fail, but until fileutils-4.0q only the second one did. +returns_ 1 mv dir file > /dev/null 2>&1 || fail=1 +returns_ 1 mv file dir > /dev/null 2>&1 || fail=1 + +Exit $fail diff --git a/tests/mv/dir2dir.sh b/tests/mv/dir2dir.sh new file mode 100755 index 0000000..da6a518 --- /dev/null +++ b/tests/mv/dir2dir.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# Ensure that mv prints the right diagnostic for a dir->dir move +# where the destination directory is not empty. + +# Copyright (C) 2006-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + +mkdir -p a/t b/t || framework_failure_ +touch a/t/f || framework_failure_ + + +# Expect this to fail with the expected diagnostic. +# For an interim (pre-6.0) release, it would give an erroneous +# diagnostic about moving one directory to a subdirectory of itself. +mv b/t a 2> out && fail=1 + +# Accept any of these: EEXIST, ENOTEMPTY, EBUSY. +sed 's/: File exists/: Directory not empty/'<out>o1;mv o1 out +sed 's/: Device or resource busy/: Directory not empty/'<out>o1;mv o1 out + +cat <<\EOF > exp || framework_failure_ +mv: cannot overwrite 'a/t': Directory not empty +EOF + +compare exp out || fail=1 + +Exit $fail diff --git a/tests/mv/dup-source.sh b/tests/mv/dup-source.sh new file mode 100755 index 0000000..7f95086 --- /dev/null +++ b/tests/mv/dup-source.sh @@ -0,0 +1,91 @@ +#!/bin/sh +# Ensure that cp merely warns when a non-directory source file is +# listed on the command line more than once. fileutils-4.1.1 +# made this fail: cp a a d/ +# Ensure that mv fails with a similar command. + +# Copyright (C) 2001-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ cp mv + +skip_if_root_ + +reset_files() { rm -fr a b d; touch a; mkdir b d; } + +for i in cp; do + + # cp may not fail in this case. + reset_files + $i a a d/ 2> out || fail=1 + reset_files + $i ./a a d/ 2>> out || fail=1 + + # Similarly for directories, but handle + # source == dest appropriately. + reset_files + $i -a ./b b d/ 2>> out || fail=1 + reset_files + returns_ 1 $i -a ./b b b/ 2>> out || fail=1 + + # cp succeeds with --backup=numbered. + reset_files + $i --backup=numbered a a d/ 2>> out || fail=1 + + # But not with plain '--backup' + reset_files + returns_ 1 $i --backup a a d/ 2>> out || fail=1 + + cat <<EOF > exp +$i: warning: source file 'a' specified more than once +$i: warning: source file 'a' specified more than once +$i: warning: source directory 'b' specified more than once +$i: cannot copy a directory, './b', into itself, 'b/b' +$i: warning: source directory 'b' specified more than once +$i: will not overwrite just-created 'd/a' with 'a' +EOF + compare exp out || fail=1 +done + +for i in mv; do + # But mv *does* fail in this case (it has to). + reset_files + returns_ 1 $i a a d/ 2> out || fail=1 + returns_ 1 test -e a || fail=1 + reset_files + returns_ 1 $i ./a a d/ 2>> out || fail=1 + returns_ 1 test -e a || fail=1 + + # Similarly for directories, also handling + # source == dest appropriately. + reset_files + returns_ 1 $i ./b b d/ 2>> out || fail=1 + returns_ 1 test -e b || fail=1 + reset_files + returns_ 1 $i --verbose ./b b b/ 2>> out || fail=1 + test -d b || fail=1 + + cat <<EOF > exp +$i: cannot stat 'a': No such file or directory +$i: cannot stat 'a': No such file or directory +$i: cannot stat 'b': No such file or directory +$i: cannot move './b' to a subdirectory of itself, 'b/b' +$i: warning: source directory 'b' specified more than once +EOF + compare exp out || fail=1 +done + +Exit $fail diff --git a/tests/mv/force.sh b/tests/mv/force.sh new file mode 100755 index 0000000..427cc88 --- /dev/null +++ b/tests/mv/force.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# move a file onto itself + +# Copyright (C) 1999-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + +ff=mvforce +ff2=mvforce2 + +echo force-contents > $ff || framework_failure_ +ln $ff $ff2 || framework_failure_ + +# mv should fail for the same name, or separate hardlinks as in +# both cases rename() will do nothing and return success. +# One could unlink(src) in the hardlink case, but that would +# introduce races with overlapping mv instances removing both hardlinks. + +for dest in $ff $ff2; do + # This mv command should exit nonzero. + mv $ff $dest > out 2>&1 && fail=1 + + printf "mv: '$ff' and '$dest' are the same file\n" > exp + compare exp out || fail=1 + + test $(cat $ff) = force-contents || fail=1 +done + +Exit $fail diff --git a/tests/mv/hard-2.sh b/tests/mv/hard-2.sh new file mode 100755 index 0000000..f0a683e --- /dev/null +++ b/tests/mv/hard-2.sh @@ -0,0 +1,77 @@ +#!/bin/sh +# Ensure that moving hard-linked arguments onto existing destinations works. +# Likewise when using cp --preserve=link. + +# Copyright (C) 2003-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ cp mv + +skip_if_root_ + +mkdir dst || framework_failure_ +(cd dst && touch a b c) || framework_failure_ +touch a || framework_failure_ +ln a b || framework_failure_ +ln a c || framework_failure_ + + +# ====================================== +cp --preserve=link a b c dst || fail=1 +# The source files must remain. +test -f a || fail=1 +test -f b || fail=1 +test -f c || fail=1 +cd dst + +# Three destination files must exist. +test -f a || fail=1 +test -f b || fail=1 +test -f c || fail=1 + +# The three i-node numbers must be the same. +ia=$(ls -i a|sed 's/ a//') +ib=$(ls -i b|sed 's/ b//') +ic=$(ls -i c|sed 's/ c//') +test $ia = $ib || fail=1 +test $ia = $ic || fail=1 + +cd .. +rm -f dst/[abc] +(cd dst && touch a b c) + +# ====================================== +mv a b c dst || fail=1 + +# The source files must be gone. +test -f a && fail=1 +test -f b && fail=1 +test -f c && fail=1 +cd dst + +# Three destination files must exist. +test -f a || fail=1 +test -f b || fail=1 +test -f c || fail=1 + +# The three i-node numbers must be the same. +ia=$(ls -i a|sed 's/ a//') +ib=$(ls -i b|sed 's/ b//') +ic=$(ls -i c|sed 's/ c//') +test $ia = $ib || fail=1 +test $ia = $ic || fail=1 + +Exit $fail diff --git a/tests/mv/hard-3.sh b/tests/mv/hard-3.sh new file mode 100755 index 0000000..2d22c40 --- /dev/null +++ b/tests/mv/hard-3.sh @@ -0,0 +1,69 @@ +#!/bin/sh +# Ensure that using 'cp --preserve=link' to copy hard-linked arguments +# onto existing destinations works, even when one of the link operations fails. + +# Copyright (C) 2003-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + + +# This bug was fixed in coreutils-4.5.9. +# To exercise this bug is non-trivial: +# Set-up requires at least three hard-linked files. In copying them, +# while preserving links, the initial copy must succeed, the attempt +# to create the second file via 'link' must fail, and the final 'link' +# (to create the third) must succeed. Before the corresponding fix, +# the first and third destination files would not be linked. +# +# Note that this is nominally a test of 'cp', yet it is in the tests/mv +# directory, because it requires use of the --preserve=link option that +# mv enables by default. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ cp +skip_if_root_ + +mkdir -p x dst/x || framework_failure_ +touch dst/x/b || framework_failure_ +chmod a-w dst/x +touch a || framework_failure_ +ln a x/b || framework_failure_ +ln a c || framework_failure_ + + +# ====================================== +# This must fail -- because x/b cannot be unlinked. +cp --preserve=link --parents a x/b c dst 2> /dev/null && fail=1 + +# Source files must remain. +test -f a || fail=1 +test -f x/b || fail=1 +test -f c || fail=1 +cd dst + +# Three destination files must exist. +test -f a || fail=1 +test -f x/b || fail=1 +test -f c || fail=1 + +# The i-node numbers of a and c must be the same. +ia=$(ls -i a) || fail=1; set x $ia; ia=$2 +ic=$(ls -i c) || fail=1; set x $ic; ic=$2 +test "$ia" = "$ic" || fail=1 + +# The i-node number of x/b must be different. +ib=$(ls -i x/b) || fail=1; set x $ib; ib=$2 +test "$ia" = "$ib" && fail=1 + +Exit $fail diff --git a/tests/mv/hard-4.sh b/tests/mv/hard-4.sh new file mode 100755 index 0000000..7621f6d --- /dev/null +++ b/tests/mv/hard-4.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# ensure that mv maintains a in this case: touch a; ln a b; mv a b + +# Copyright (C) 2003-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +touch a || framework_failure_ +ln a b || framework_failure_ + +# Between coreutils-5.0 and coreutils-8.24, 'a' would be removed. +# Before coreutils-5.0.1 the issue would not have been diagnosed. +# We don't emulate the rename(a,b) with unlink(a) as that would +# introduce races with overlapping mv instances removing both links. +mv a b 2>err && fail=1 +printf "mv: 'a' and 'b' are the same file\n" > exp +compare exp err || fail=1 + +test -r a || fail=1 +test -r b || fail=1 + +# Make sure it works with --backup. +mv --backup=simple a b || fail=1 +test -r a && fail=1 +test -r b || fail=1 +test -r b~ || fail=1 + +Exit $fail diff --git a/tests/mv/hard-link-1.sh b/tests/mv/hard-link-1.sh new file mode 100755 index 0000000..94599f2 --- /dev/null +++ b/tests/mv/hard-link-1.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# move a directory containing hard-linked files and +# make sure the links are preserved + +# Copyright (C) 1998-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +cleanup_() { rm -rf "$other_partition_tmpdir"; } +. "$abs_srcdir/tests/other-fs-tmpdir" + +dir=hlink + +mkdir $dir || framework_failure_ +> $dir/a || framework_failure_ +ln $dir/a $dir/b || framework_failure_ + +mv $dir "$other_partition_tmpdir" || fail=1 + +# Display inode numbers, one per line. +ls -1i "$other_partition_tmpdir/$dir" > out || fail=1 + +# Make sure the inode numbers are the same. +a=$(sed -n 's/ a$//p' out) +b=$(sed -n 's/ b$//p' out) +test "$a" = "$b" || fail=1 + +Exit $fail diff --git a/tests/mv/hardlink-case.sh b/tests/mv/hardlink-case.sh new file mode 100755 index 0000000..ad0cfdf --- /dev/null +++ b/tests/mv/hardlink-case.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# Ensure multi-hardlinked files are not lost on case insensitive file systems + +# Copyright (C) 2014-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +require_root_ + +cwd=$(pwd) +cleanup_() { cd /; umount "$cwd/mnt"; } + +truncate -s100M hfs.img || framework_failure_ +mkfs -t hfsplus hfs.img || skip_ 'failed to create hfs file system' +mkdir mnt || framework_failure_ +mount hfs.img mnt || skip_ 'failed to mount hfs file system' + +cd mnt +touch foo +ln foo whatever +returns_ 1 mv foo Foo || fail=1 +test -r foo || fail=1 + +Exit $fail diff --git a/tests/mv/i-1.pl b/tests/mv/i-1.pl new file mode 100755 index 0000000..f2ee0e9 --- /dev/null +++ b/tests/mv/i-1.pl @@ -0,0 +1,44 @@ +#!/usr/bin/perl +# Make sure a 'n' reply to 'mv -i...' aborts the move operation. + +# Copyright (C) 2001-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +use strict; + +(my $program_name = $0) =~ s|.*/||; + +# Turn off localization of executable's output. +@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; + +my $test_a = 'a'; + +my @Tests = + ( + # Make sure a 'n' reply to 'mv -i...' aborts the move operation. + [$test_a, '-i', + {IN => {src => "a\n"}}, {IN => {dst => "b\n"}}, '<', {IN => "n\n"}, + {ERR => "mv: overwrite 'dst'? "}, + {POST => sub { -r 'src' or die "test $test_a failed\n"}}, + {EXIT => 1}, + ], + ); + +my $save_temps = $ENV{DEBUG}; +my $verbose = $ENV{VERBOSE}; + +my $prog = 'mv'; +my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose); +exit $fail; diff --git a/tests/mv/i-2.sh b/tests/mv/i-2.sh new file mode 100755 index 0000000..d8e0524 --- /dev/null +++ b/tests/mv/i-2.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# Test both cp and mv for their behavior with -if and -fi +# The standards (POSIX and SuS) dictate annoyingly inconsistent behavior. + +# Copyright (C) 2000-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ cp mv + +skip_if_root_ + +for i in a b c d e f g h; do + echo $i > $i || framework_failure_ +done +chmod 0 b d f h || framework_failure_ +echo y > y || framework_failure_ + +mv -if a b || fail=1 +mv -fi c d < y >/dev/null 2>&1 || fail=1 + +# Before 4.0s, this would not prompt. +cp -if e f < y > out 2>&1 || fail=1 + +# Make sure out contains the prompt. +case "$(cat out)" in + "cp: replace 'f', overriding mode 0000 (---------)?"*) ;; + *) fail=1 ;; +esac + +test -f e || fail=1 +test -f f || fail=1 +compare e f || fail=1 + +cp -fi g h < y > out 2>&1 || fail=1 +test -f g || fail=1 +test -f h || fail=1 +compare g h || fail=1 + +Exit $fail diff --git a/tests/mv/i-3.sh b/tests/mv/i-3.sh new file mode 100755 index 0000000..4162d16 --- /dev/null +++ b/tests/mv/i-3.sh @@ -0,0 +1,72 @@ +#!/bin/sh +# Make sure that 'mv file unwritable-file' prompts the user +# and that 'mv -f file unwritable-file' doesn't. + +# Copyright (C) 2001-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +require_controlling_input_terminal_ +skip_if_root_ +trap '' TTIN # Ignore SIGTTIN + +uname -s | grep 'BSD$' && skip_ 'known spurious failure on *BSD' + +touch f g h i || framework_failure_ +chmod 0 g i || framework_failure_ + + +ls /dev/stdin >/dev/null 2>&1 \ + || skip_ 'there is no /dev/stdin file' + +# work around a dash bug when redirecting +# from symlinked ttys in the background +tty=$(readlink -f /dev/stdin) + +test -r "$tty" 2>&1 \ + || skip_ '/dev/stdin is not readable' + +# Terminate any background processes +cleanup_() { kill $pid 2>/dev/null && wait $pid; } + +mv f g < $tty > out 2>&1 & pid=$! + +# Test for the expected prompt; sleep upon non-match. +check_overwrite_prompt() +{ + local delay="$1" + case "$(cat out)" in + "mv: replace 'g', overriding mode 0000"*) ;; + *) sleep $delay; return 1;; + esac +} + +# Wait for up to 12.7 seconds for the expected prompt. +retry_delay_ check_overwrite_prompt .1 7 || { fail=1; cat out; } + +cleanup_ + +mv -f h i > out 2>&1 || fail=1 +test -f i || fail=1 +test -f h && fail=1 + +# Make sure there was no prompt. +case "$(cat out)" in + '') ;; + *) fail=1 ;; +esac + +Exit $fail diff --git a/tests/mv/i-4.sh b/tests/mv/i-4.sh new file mode 100755 index 0000000..4b90342 --- /dev/null +++ b/tests/mv/i-4.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# make sure 'mv -i a b' does its job with a positive response + +# Copyright (C) 2001-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + +for i in a b; do + echo $i > $i || framework_failure_ +done +echo y > y || framework_failure_ +echo n > n || framework_failure_ + +mv -i a b < y >/dev/null 2>&1 || fail=1 + +# Make sure out contains the prompt. +case "$(cat b)" in + a) ;; + *) fail=1 ;; +esac + +# Ensure that mv -i a b works properly with 'n' and 'y' responses, +# when a and b are hard links to the same file. +rm -f a b +echo a > a +ln a b +mv -i a b < y 2>err && fail=1 +test -r a || fail=1 +test -r b || fail=1 +printf "mv: 'a' and 'b' are the same file\n" > exp +compare exp err || fail=1 + +Exit $fail diff --git a/tests/mv/i-5.sh b/tests/mv/i-5.sh new file mode 100755 index 0000000..fabb275 --- /dev/null +++ b/tests/mv/i-5.sh @@ -0,0 +1,29 @@ +#!/bin/sh +# Make sure 'mv -i dir file' prompts before failing. + +# Copyright (C) 2006-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + +mkdir a || framework_failure_ +touch b || framework_failure_ + + +# coreutils 6.2 mv would neglect to prompt in this case. +echo n | returns_ 1 mv -i a b 2>/dev/null || fail=1 + +Exit $fail diff --git a/tests/mv/i-link-no.sh b/tests/mv/i-link-no.sh new file mode 100755 index 0000000..747c542 --- /dev/null +++ b/tests/mv/i-link-no.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# Show that mv doesn't preserve links to files the user has declined to move. + +# Copyright (C) 2002-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + +mkdir a b || framework_failure_ +echo foo > a/foo || framework_failure_ +ln a/foo a/bar || framework_failure_ +echo FUBAR > b/FUBAR || framework_failure_ +ln b/FUBAR b/bar || framework_failure_ +chmod a-w b/bar || framework_failure_ +echo n > no || framework_failure_ + + +mv a/bar a/foo b < no > out 2> err || fail=1 +touch exp +touch exp_err + +compare exp out || fail=1 +compare exp_err err || fail=1 + +case "$(cat b/foo)" in + foo) ;; + *) fail=1;; +esac + +Exit $fail diff --git a/tests/mv/into-self-2.sh b/tests/mv/into-self-2.sh new file mode 100755 index 0000000..337d2b2 --- /dev/null +++ b/tests/mv/into-self-2.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# Force mv to use the copying code. +# Consider the case where SRC and DEST are on different +# partitions and DEST is a symlink to SRC. + +# Copyright (C) 1998-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +cleanup_() { rm -rf "$other_partition_tmpdir"; } +. "$abs_srcdir/tests/other-fs-tmpdir" + +file="$other_partition_tmpdir/file" +symlink=symlink + + +echo whatever > $file || framework_failure_ +ln -s $file $symlink || framework_failure_ + +# This mv command should exit nonzero. +mv $symlink $file > out 2>&1 && fail=1 + +# This should succeed. +mv $file $symlink || fail=1 + +sed \ + -e "s,mv:,XXX:," \ + -e "s,$file,YYY," \ + -e "s,$symlink,ZZZ," \ + out > out2 + +cat > exp <<\EOF +XXX: 'ZZZ' and 'YYY' are the same file +EOF +#' + +compare exp out2 || fail=1 + +Exit $fail diff --git a/tests/mv/into-self-3.sh b/tests/mv/into-self-3.sh new file mode 100755 index 0000000..31612d6 --- /dev/null +++ b/tests/mv/into-self-3.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# move a directory into itself, with a twist + +# Copyright (C) 1998-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + +dir1=is3-dir1 +dir2=is3-dir2 + +mkdir $dir1 $dir2 || framework_failure_ + +# This mv command should exit nonzero. +mv $dir1 $dir2 $dir2 > out 2>&1 && fail=1 + +sed \ + -e "s,mv:,XXX:,g" \ + -e "s,$dir2,ZZZ,g" \ + out > out2 + +cat > exp <<\EOF +XXX: cannot move 'ZZZ' to a subdirectory of itself, 'ZZZ/ZZZ' +EOF + +compare exp out2 || fail=1 + +Exit $fail diff --git a/tests/mv/into-self-4.sh b/tests/mv/into-self-4.sh new file mode 100755 index 0000000..0b2664a --- /dev/null +++ b/tests/mv/into-self-4.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# confirm that 'mv symlink symlink' doesn't remove symlink +# Based on an example from David Luyer. + +# Copyright (C) 2001-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + +touch file || framework_failure_ +ln -s file s || framework_failure_ + + +# This must fail. +returns_ 1 mv s s 2> /dev/null || fail=1 + +# But the symlink, s, must not be removed. +# Before 4.0.36, 's' would have been removed. +test -f s || fail=1 + +Exit $fail diff --git a/tests/mv/into-self.sh b/tests/mv/into-self.sh new file mode 100755 index 0000000..66b65ce --- /dev/null +++ b/tests/mv/into-self.sh @@ -0,0 +1,53 @@ +#!/bin/sh +# Demonstrate how mv fails when it tries to move a directory into itself. + +# Copyright (C) 1998-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + +dir=toself-dir +file=toself-file + +rm -rf $dir $file || framework_failure_ +mkdir -p $dir/a/b || framework_failure_ +touch $file || framework_failure_ + + +# This mv command should fail. +mv $dir $file $dir > out 2>&1 && fail=1 + +sed \ + -e "s,mv:,XXX:," \ + -e "s,$dir,SRC," \ + -e "s,$dir/$dir,DEST," \ + out > out2 + +cat > exp <<\EOF +XXX: cannot move 'SRC' to a subdirectory of itself, 'DEST' +EOF + +compare exp out2 || fail=1 + +# Make sure the file is gone. +test -f $file && fail=1 +# Make sure the directory is *not* moved. +test -d $dir || fail=1 +test -d $dir/$dir && fail=1 +# Make sure the file has been moved to the right place. +test -f $dir/$file || fail=1 + +Exit $fail diff --git a/tests/mv/leak-fd.sh b/tests/mv/leak-fd.sh new file mode 100755 index 0000000..d976627 --- /dev/null +++ b/tests/mv/leak-fd.sh @@ -0,0 +1,55 @@ +#!/bin/sh +# Exercise mv's file-descriptor-leak bug, reported against coreutils-5.2.1 +# and fixed (properly) on 2004-10-21. + +# Copyright (C) 2004-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# limit so don't run it by default. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +skip_if_root_ +cleanup_() { rm -rf "$other_partition_tmpdir"; } +. "$abs_srcdir/tests/other-fs-tmpdir" + +# This test is relatively expensive, and might well evoke a +# framework-failure on systems with a smaller command-line length +expensive_ + +b="0 1 2 3 4 5 6 7 8 9 +a b c d e f g h i j k l m n o p q r s t u v w x y z +_A _B _C _D _E _F _G _H _I _J _K _L _M _N _O _P _Q _R _S _T _U _V _W _X _Y _Z" + +for i in $(echo $b); do + echo $i + for j in $b; do + echo $i$j + done +done > .dirs +mkdir $(cat .dirs) || framework_failure_ +sed 's,$,/f,' .dirs | xargs touch + +last_file=$(tail -n1 .dirs)/f +test -f $last_file || framework_failure_ + + +mv * "$other_partition_tmpdir" || fail=1 +test -f $last_file/f && fail=1 +rm .dirs + +out=$(ls -A) || fail=1 +test -z "$out" || fail=1 + +Exit $fail diff --git a/tests/mv/mv-n.sh b/tests/mv/mv-n.sh new file mode 100755 index 0000000..6054780 --- /dev/null +++ b/tests/mv/mv-n.sh @@ -0,0 +1,64 @@ +#!/bin/sh +# Test whether mv -n works as documented (not overwrite target). + +# Copyright (C) 2006-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + + +# test miscellaneous combinations of -f -i -n parameters +touch a b || framework_failure_ +echo "renamed 'a' -> 'b'" > out_move +echo "mv: not replacing 'b'" > err_skip || framework_failure_ +> out_empty + +# ask for overwrite, answer no +touch a b || framework_failure_ +echo n | returns_ 1 mv -vi a b 2>/dev/null > out1 || fail=1 +compare out1 out_empty || fail=1 + +# ask for overwrite, answer yes +touch a b || framework_failure_ +echo y | mv -vi a b 2>/dev/null > out2 || fail=1 +compare out2 out_move || fail=1 + +# -n wins (as the last option) +touch a b || framework_failure_ +echo y | returns_ 1 mv -vin a b 2>/dev/null > out3 || fail=1 +compare out3 out_empty || fail=1 + +# -n wins (non verbose) +touch a b || framework_failure_ +echo y | returns_ 1 mv -in a b 2>err3 > out3 || fail=1 +compare out3 out_empty || fail=1 +compare err3 err_skip || fail=1 + +# -n wins (as the last option) +touch a b || framework_failure_ +echo y | returns_ 1 mv -vfn a b 2>/dev/null > out4 || fail=1 +compare out4 out_empty || fail=1 + +# -n wins (as the last option) +touch a b || framework_failure_ +echo y | returns_ 1 mv -vifn a b 2>/dev/null > out5 || fail=1 +compare out5 out_empty || fail=1 + +# options --backup and --no-clobber are mutually exclusive +touch a || framework_failure_ +returns_ 1 mv -bn a b 2>/dev/null || fail=1 + +Exit $fail diff --git a/tests/mv/mv-special-1.sh b/tests/mv/mv-special-1.sh new file mode 100755 index 0000000..af1b793 --- /dev/null +++ b/tests/mv/mv-special-1.sh @@ -0,0 +1,75 @@ +#!/bin/sh +# Test "mv" with special files. + +# Copyright (C) 1998-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +cleanup_() { rm -rf "$other_partition_tmpdir"; } +. "$abs_srcdir/tests/other-fs-tmpdir" + +null=mv-null +dir=mv-dir + +rm -f $null || framework_failure_ +mknod $null p || framework_failure_ +test -p $null || framework_failure_ +mkdir -p $dir/a/b/c $dir/d/e/f || framework_failure_ +touch $dir/a/b/c/file1 $dir/d/e/f/file2 || framework_failure_ + +# We used to... +# exit 77 here to indicate that we couldn't run the test. +# At least running on SunOS 4.1.4, using a directory NFS mounted +# from an OpenBSD system, the above mknod fails. +# It's not worth making an exception any more. + +mv --verbose $null $dir "$other_partition_tmpdir" > out || fail=1 +# Make sure the files are gone. +test -p $null && fail=1 +test -d $dir && fail=1 +# Make sure they were moved. +test -p "$other_partition_tmpdir/$null" || fail=1 +test -d "$other_partition_tmpdir/$dir/a/b/c" || fail=1 + +# POSIX says rename (A, B) can succeed if A and B are on different file systems, +# so ignore chatter about when files are removed and copied rather than renamed. +sed " + /^removed /d + s,renamed ,, + s,copied ,, + s,$other_partition_tmpdir,XXX, + s,created directory 'XXX/\(.*\)','\1' -> 'XXX/\1', +" out | sort > out2 + +cat <<EOF | sort > exp +'$null' -> 'XXX/$null' +'$dir' -> 'XXX/$dir' +'$dir/a' -> 'XXX/$dir/a' +'$dir/a/b' -> 'XXX/$dir/a/b' +'$dir/a/b/c' -> 'XXX/$dir/a/b/c' +'$dir/a/b/c/file1' -> 'XXX/$dir/a/b/c/file1' +'$dir/d' -> 'XXX/$dir/d' +'$dir/d/e' -> 'XXX/$dir/d/e' +'$dir/d/e/f' -> 'XXX/$dir/d/e/f' +'$dir/d/e/f/file2' -> 'XXX/$dir/d/e/f/file2' +EOF + +compare exp out2 || fail=1 + +# cd "$other_partition_tmpdir" +# ls -l -A -R "$other_partition_tmpdir" + +Exit $fail diff --git a/tests/mv/no-copy.sh b/tests/mv/no-copy.sh new file mode 100755 index 0000000..5a55fdf --- /dev/null +++ b/tests/mv/no-copy.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# Test mv --no-copy. + +# Copyright (C) 2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +cleanup_() { rm -rf "$other_partition_tmpdir"; } +. "$abs_srcdir/tests/other-fs-tmpdir" + +mkdir dir || framework_failure_ +> dir/a || framework_failure_ +> file || framework_failure_ + +returns_ 1 mv --no-copy dir "$other_partition_tmpdir" || fail=1 +returns_ 1 mv --no-copy file "$other_partition_tmpdir" || fail=1 +mv dir "$other_partition_tmpdir" || fail=1 +mv file "$other_partition_tmpdir" || fail=1 + +Exit $fail diff --git a/tests/mv/no-target-dir.sh b/tests/mv/no-target-dir.sh new file mode 100755 index 0000000..82df49b --- /dev/null +++ b/tests/mv/no-target-dir.sh @@ -0,0 +1,51 @@ +#!/bin/sh +# ensure that --no-target-directory (-T) works when the destination is +# an empty directory. + +# Copyright (C) 2006-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + +LS_FAILURE=2 + +mkdir -p d/sub empty src d2/sub e2 || framework_failure_ +touch f || framework_failure_ + +# Skip this test if there's an underlying kernel bug. +mkdir a b b/a || framework_failure_ + +mv a b || + skip_ "your kernel's rename syscall is buggy" + + +# This should succeed, since both src and dest are directories, +# and the dest dir is empty. +mv -fT d empty || fail=1 + +# Ensure that the source, d, is gone. +returns_ $LS_FAILURE ls -d d > /dev/null 2>&1 || fail=1 + +# Ensure that the dest dir now has a subdirectory. +test -d empty/sub || fail=1 + +# rename must fail, since the dest is non-empty. +returns_ 1 mv -fT src d2 2> /dev/null || fail=1 + +# rename must fail, since the src is not a directory. +returns_ 1 mv -fT f e2 2> /dev/null || fail=1 + +Exit $fail diff --git a/tests/mv/part-fail.sh b/tests/mv/part-fail.sh new file mode 100755 index 0000000..19c4140 --- /dev/null +++ b/tests/mv/part-fail.sh @@ -0,0 +1,55 @@ +#!/bin/sh +# Make sure we give a sensible diagnostic when a cross-device 'mv' +# fails, e.g., because the destination cannot be unlinked. +# This is a bit fragile since it relies on the string used +# for EPERM: 'permission denied'. + +# Copyright (C) 2002-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +skip_if_root_ +cleanup_() { t=$other_partition_tmpdir; chmod -R 700 "$t"; rm -rf "$t"; } +. "$abs_srcdir/tests/other-fs-tmpdir" + +touch k "$other_partition_tmpdir/k" || framework_failure_ +chmod u-w "$other_partition_tmpdir" || framework_failure_ + + +mv -f k "$other_partition_tmpdir" 2> out && fail=1 +printf \ +"mv: inter-device move failed: '%s' to '%s';"\ +' unable to remove target: Permission denied\n' \ + k "$other_partition_tmpdir/k" >exp + +# On some (less-compliant) systems, we get EPERM in this case. +# Accept either diagnostic. +cat <<EOF > exp2 +mv: cannot move 'k' to '$other_partition_tmpdir/k': Permission denied +EOF + +if cmp out exp >/dev/null 2>&1; then + : +else + if cmp out exp2; then + : + else + fail=1 + fi +fi +test $fail = 1 && compare exp out + +Exit $fail diff --git a/tests/mv/part-hardlink.sh b/tests/mv/part-hardlink.sh new file mode 100755 index 0000000..9c65684 --- /dev/null +++ b/tests/mv/part-hardlink.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# Ensure that hard links are preserved when moving between partitions +# and when the links are in separate command line arguments. +# For additional constraints, see the comment in copy.c. +# Before coreutils-5.2.1, this test would fail. + +# Copyright (C) 2004-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +cleanup_() { rm -rf "$other_partition_tmpdir"; } +. "$abs_srcdir/tests/other-fs-tmpdir" + +touch f || framework_failure_ +ln f g || framework_failure_ +mkdir a b || framework_failure_ +touch a/1 || framework_failure_ +ln a/1 b/1 || framework_failure_ + + +mv f g "$other_partition_tmpdir" || fail=1 +mv a b "$other_partition_tmpdir" || fail=1 + +cd "$other_partition_tmpdir" +set $(ls -Ci f g) +test $1 = $3 || fail=1 +set $(ls -Ci a/1 b/1) +test $1 = $3 || fail=1 + +Exit $fail diff --git a/tests/mv/part-rename.sh b/tests/mv/part-rename.sh new file mode 100755 index 0000000..5f88550 --- /dev/null +++ b/tests/mv/part-rename.sh @@ -0,0 +1,57 @@ +#!/bin/sh +# Test various cases for moving directories across file systems + +# Copyright (C) 2000-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +cleanup_() { rm -rf "$other_partition_tmpdir"; } +. "$abs_srcdir/tests/other-fs-tmpdir" + + +# Moving a directory specified with a trailing slash from one partition to +# another, and giving it a different name at the destination would cause mv +# to get a failed assertion. +mkdir foo || framework_failure_ +mv foo/ "$other_partition_tmpdir/bar" || fail=1 + + +# Moving a non directory from source shouldn't replace empty dir in dest +touch bar || framework_failure_ +returns_ 1 mv bar "$other_partition_tmpdir/" || fail=1 + + +# Moving a directory from source shouldn't replace non directory in dest +mkdir bar2 +touch "$other_partition_tmpdir/bar2" +returns_ 1 mv bar2 "$other_partition_tmpdir/" || fail=1 + + +# As per POSIX moving directory from source should replace empty dir in dest +mkdir bar3 +touch bar3/file +mkdir "$other_partition_tmpdir/bar3" +mv bar3 "$other_partition_tmpdir/" || fail=1 +test -e "$other_partition_tmpdir/bar3/file" || fail=1 + + +# As per POSIX moving directory from source shouldn't update dir in dest +mkdir bar3 +touch bar3/file2 +returns_ 1 mv bar3 "$other_partition_tmpdir/" || fail=1 +test -e "$other_partition_tmpdir/bar3/file2" && fail=1 + +Exit $fail diff --git a/tests/mv/part-symlink.sh b/tests/mv/part-symlink.sh new file mode 100755 index 0000000..d6cd836 --- /dev/null +++ b/tests/mv/part-symlink.sh @@ -0,0 +1,262 @@ +#!/bin/sh +# make sure cp and mv can handle many combinations of local and +# other-partition regular/symlink'd files. + +# Copyright (C) 2000-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ cp mv + +cleanup_() { rm -rf "$other_partition_tmpdir"; } +. "$abs_srcdir/tests/other-fs-tmpdir" + +# On NFS on Linux 2.6.9 at least we get: +# mv: preserving permissions for 'rem_sl': Operation not supported +require_local_dir_ + +pwd_tmp=$(pwd) + +# Unset CDPATH. Otherwise, output from the 'cd dir' command +# can make this test fail. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# Four cases: +# local regular file w/symlink on another partition +# (loc_reg, rem_sl) +# (rem_sl, loc_reg) +# local symlink to regular file on another partition +# (loc_sl, rem_reg) +# (rem_reg, loc_sl) + +# Exercise those four cases for each of +# cp and mv, with lots of combinations of options. + +exec 1> actual + +# FIXME: This should be bigger: like more than 8k +contents=XYZ + +loc_reg=loc_reg +loc_sl=loc_sl +rem_reg=$other_partition_tmpdir/rem_reg +rem_sl=$other_partition_tmpdir/rem_sl + +for copy in cp mv; do + for args in \ + 'loc_reg rem_sl' \ + 'rem_sl loc_reg' \ + 'loc_sl rem_reg' \ + 'rem_reg loc_sl' \ + ; do + for options in '' --rem '--rem -d' '--rem -b' -b -bd -d; do + case "$options" in *d*|*--rem*) test $copy = mv && continue;; esac + rm -rf dir || fail=1 + rm -f "$other_partition_tmpdir"/* || fail=1 + mkdir dir || fail=1 + cd dir || fail=1 + case "$args" in *loc_reg*) reg_abs="$(pwd)/$loc_reg" ;; esac + case "$args" in *rem_reg*) reg_abs=$rem_reg ;; esac + case "$args" in *loc_sl*) slink=$loc_sl ;; esac + case "$args" in *rem_sl*) slink=$rem_sl ;; esac + + echo $contents > "$reg_abs" || framework_failure_ + ln -nsf "$reg_abs" $slink || fail=1 + actual_args=$(echo $args|sed 's,^,$,;s/ / $/') + actual_args=$(eval echo $actual_args) + + ( + ( + # echo 1>&2 cp $options $args + $copy $options $actual_args 2>.err + copy_status=$? + echo $copy_status $copy $options $args + + # Normalize the program name in the error output, + # remove any site-dependent part of other-partition file name, + # and put brackets around the output. + test -s .err \ + && { + echo ' [' | tr -d '\n' + sed 's/^[^:][^:]*\(..\):/\1:/;s,'"$other_partition_tmpdir/,," .err | + tr -d '\n' + echo ']' + } + # Strip off all but the file names. + # Remove any site-dependent part of each file name. + ls=$(ls -gG --ignore=.err . \ + | sed \ + -e '/^total /d' \ + -e "s,$other_partition_tmpdir/,," \ + -e "s,$pwd_tmp/,," \ + -e 's/^[^ ]* *[^ ]* *[^ ]* *[^ ]* *[^ ]* *[^ ]* *//') + ls2=$(cd "$other_partition_tmpdir" && ls -gG --ignore=.err . \ + | sed \ + -e '/^total /d' \ + -e "s,$other_partition_tmpdir/,," \ + -e "s,$pwd_tmp/,," \ + -e 's/^[^ ]* *[^ ]* *[^ ]* *[^ ]* *[^ ]* *[^ ]* *//') + echo " ("$ls") ("$ls2")" + + # If the command failed, then it must not have changed the files. + if test $copy_status != 0; then + for f in $actual_args; do + test -f $f || + { echo " $copy FAILED but removed $f"; continue; } + case "$(cat $f)" in + "$contents") ;; + *) echo " $copy FAILED but modified $f";; + esac + done + fi + + if test $copy = cp; then + # Make sure the original is unchanged and that + # the destination is a copy. + for f in $actual_args; do + if test -f $f; then + if test $copy_status != 0; then + test + fi + case "$(cat $f)" in + "$contents") ;; + *) echo " $copy FAILED";; + esac + else + echo " symlink-loop" + fi + done + fi + ) + ) | sed 's/ *$//' + cd .. + done + echo + done +done + +test $fail = 1 && + { (exit 1); exit; } + +cat <<\EOF > expected || framework_failure_ +1 cp loc_reg rem_sl + [cp: 'loc_reg' and 'rem_sl' are the same file] + (loc_reg) (rem_sl -> dir/loc_reg) +0 cp --rem loc_reg rem_sl + (loc_reg) (rem_sl) +0 cp --rem -d loc_reg rem_sl + (loc_reg) (rem_sl) +0 cp --rem -b loc_reg rem_sl + (loc_reg) (rem_sl rem_sl~ -> dir/loc_reg) +0 cp -b loc_reg rem_sl + (loc_reg) (rem_sl rem_sl~ -> dir/loc_reg) +0 cp -bd loc_reg rem_sl + (loc_reg) (rem_sl rem_sl~ -> dir/loc_reg) +1 cp -d loc_reg rem_sl + [cp: 'loc_reg' and 'rem_sl' are the same file] + (loc_reg) (rem_sl -> dir/loc_reg) + +1 cp rem_sl loc_reg + [cp: 'rem_sl' and 'loc_reg' are the same file] + (loc_reg) (rem_sl -> dir/loc_reg) +1 cp --rem rem_sl loc_reg + [cp: 'rem_sl' and 'loc_reg' are the same file] + (loc_reg) (rem_sl -> dir/loc_reg) +1 cp --rem -d rem_sl loc_reg + [cp: 'rem_sl' and 'loc_reg' are the same file] + (loc_reg) (rem_sl -> dir/loc_reg) +1 cp --rem -b rem_sl loc_reg + [cp: 'rem_sl' and 'loc_reg' are the same file] + (loc_reg) (rem_sl -> dir/loc_reg) +1 cp -b rem_sl loc_reg + [cp: 'rem_sl' and 'loc_reg' are the same file] + (loc_reg) (rem_sl -> dir/loc_reg) +0 cp -bd rem_sl loc_reg + (loc_reg -> dir/loc_reg loc_reg~) (rem_sl -> dir/loc_reg) + symlink-loop + symlink-loop +1 cp -d rem_sl loc_reg + [cp: 'rem_sl' and 'loc_reg' are the same file] + (loc_reg) (rem_sl -> dir/loc_reg) + +1 cp loc_sl rem_reg + [cp: 'loc_sl' and 'rem_reg' are the same file] + (loc_sl -> rem_reg) (rem_reg) +1 cp --rem loc_sl rem_reg + [cp: 'loc_sl' and 'rem_reg' are the same file] + (loc_sl -> rem_reg) (rem_reg) +1 cp --rem -d loc_sl rem_reg + [cp: 'loc_sl' and 'rem_reg' are the same file] + (loc_sl -> rem_reg) (rem_reg) +1 cp --rem -b loc_sl rem_reg + [cp: 'loc_sl' and 'rem_reg' are the same file] + (loc_sl -> rem_reg) (rem_reg) +1 cp -b loc_sl rem_reg + [cp: 'loc_sl' and 'rem_reg' are the same file] + (loc_sl -> rem_reg) (rem_reg) +0 cp -bd loc_sl rem_reg + (loc_sl -> rem_reg) (rem_reg -> rem_reg rem_reg~) + symlink-loop + symlink-loop +1 cp -d loc_sl rem_reg + [cp: 'loc_sl' and 'rem_reg' are the same file] + (loc_sl -> rem_reg) (rem_reg) + +1 cp rem_reg loc_sl + [cp: 'rem_reg' and 'loc_sl' are the same file] + (loc_sl -> rem_reg) (rem_reg) +0 cp --rem rem_reg loc_sl + (loc_sl) (rem_reg) +0 cp --rem -d rem_reg loc_sl + (loc_sl) (rem_reg) +0 cp --rem -b rem_reg loc_sl + (loc_sl loc_sl~ -> rem_reg) (rem_reg) +0 cp -b rem_reg loc_sl + (loc_sl loc_sl~ -> rem_reg) (rem_reg) +0 cp -bd rem_reg loc_sl + (loc_sl loc_sl~ -> rem_reg) (rem_reg) +1 cp -d rem_reg loc_sl + [cp: 'rem_reg' and 'loc_sl' are the same file] + (loc_sl -> rem_reg) (rem_reg) + +0 mv loc_reg rem_sl + () (rem_sl) +0 mv -b loc_reg rem_sl + () (rem_sl rem_sl~ -> dir/loc_reg) + +1 mv rem_sl loc_reg + [mv: 'rem_sl' and 'loc_reg' are the same file] + (loc_reg) (rem_sl -> dir/loc_reg) +0 mv -b rem_sl loc_reg + (loc_reg -> dir/loc_reg loc_reg~) () + +1 mv loc_sl rem_reg + [mv: 'loc_sl' and 'rem_reg' are the same file] + (loc_sl -> rem_reg) (rem_reg) +0 mv -b loc_sl rem_reg + () (rem_reg -> rem_reg rem_reg~) + +0 mv rem_reg loc_sl + (loc_sl) () +0 mv -b rem_reg loc_sl + (loc_sl loc_sl~ -> rem_reg) () + +EOF + +# Redirect to stderr, since stdout is already taken. +compare expected actual 1>&2 || fail=1 + +Exit $fail diff --git a/tests/mv/partition-perm.sh b/tests/mv/partition-perm.sh new file mode 100755 index 0000000..566346c --- /dev/null +++ b/tests/mv/partition-perm.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# Make sure permissions are preserved when moving from one partition to another. + +# Copyright (C) 1999-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +cleanup_() { rm -rf "$other_partition_tmpdir"; } +. "$abs_srcdir/tests/other-fs-tmpdir" + +> file || framework_failure_ +chmod a=rwx file || framework_failure_ + +umask 077 +mv file "$other_partition_tmpdir" || framework_failure_ + +test -f file && fail=1 +test -f "$other_partition_tmpdir/file" || fail=1 + +# This would have failed with the mv from fileutils-4.0i. +mode=$(ls -l "$other_partition_tmpdir/file" | cut -b-10) +test "$mode" = "-rwxrwxrwx" || fail=1 + +Exit $fail diff --git a/tests/mv/perm-1.sh b/tests/mv/perm-1.sh new file mode 100755 index 0000000..50eb0a2 --- /dev/null +++ b/tests/mv/perm-1.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# ensure that mv gives one diagnostic, not two, when failing +# due to lack of permissions + +# Copyright (C) 2002-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +skip_if_root_ + +mkdir -p no-write/dir || framework_failure_ +chmod ug-w no-write || framework_failure_ + + +mv no-write/dir . > out 2>&1 && fail=1 +cat <<\EOF > exp +mv: cannot move 'no-write/dir' to './dir': Permission denied +EOF + +compare exp out || fail=1 + +Exit $fail diff --git a/tests/mv/sticky-to-xpart.sh b/tests/mv/sticky-to-xpart.sh new file mode 100755 index 0000000..860ddd3 --- /dev/null +++ b/tests/mv/sticky-to-xpart.sh @@ -0,0 +1,68 @@ +#!/bin/sh +# A cross-partition move of a file in a sticky tmpdir and owned by +# someone else would evoke an invalid diagnostic: +# mv: cannot remove 'x': Operation not permitted +# Affects coreutils-6.0-6.9. + +# Copyright (C) 2007-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +require_root_ + +cleanup_() { rm -rf "$other_partition_tmpdir"; } +. "$abs_srcdir/tests/other-fs-tmpdir" + +# Set up to run a test where non-root user tries to move a root-owned +# file from a sticky tmpdir to a directory owned by that user on +# a different partition. + +mkdir t || framework_failure_ +chmod a=rwx,o+t t || framework_failure_ +echo > t/root-owned || framework_failure_ +chmod a+r t/root-owned || framework_failure_ +chown "$NON_ROOT_USERNAME" "$other_partition_tmpdir" || framework_failure_ + +# We have to allow $NON_ROOT_USERNAME access to ".". +chmod go+x . || framework_failure_ + + +# Ensure that $NON_ROOT_USERNAME can access the required version of mv. +version=$( + chroot --skip-chdir --user=$NON_ROOT_USERNAME / env PATH="$PATH" \ + mv --version | + sed -n '1s/.* //p' +) +case $version in + $PACKAGE_VERSION) ;; + *) skip_ "cannot access just-built mv as user $NON_ROOT_USERNAME";; +esac + +chroot --skip-chdir --user=$NON_ROOT_USERNAME / env PATH="$PATH" \ + mv t/root-owned "$other_partition_tmpdir" 2> out-t && fail=1 + +# On some systems, we get 'Not owner'. Convert it. +# On other systems (HPUX), we get 'Permission denied'. Convert it, too. +onp='Operation not permitted' +sed "s/Not owner/$onp/;s/Permission denied/$onp/" out-t > out + +cat <<\EOF > exp +mv: cannot remove 't/root-owned': Operation not permitted +EOF + +compare exp out || fail=1 + +Exit $fail diff --git a/tests/mv/symlink-onto-hardlink-to-self.sh b/tests/mv/symlink-onto-hardlink-to-self.sh new file mode 100755 index 0000000..b53a41a --- /dev/null +++ b/tests/mv/symlink-onto-hardlink-to-self.sh @@ -0,0 +1,63 @@ +#!/bin/sh +# Demonstrate that when moving a symlink onto a hardlink-to-that-symlink, +# an error is presented. Depending on your kernel (e.g., Linux, Solaris, +# but not NetBSD), prior to coreutils-8.16, the mv would successfully perform +# a no-op. I.e., surprisingly, mv s1 s2 would succeed, yet fail to remove s1. + +# Copyright (C) 2012-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + +# Create a file f, and a symlink s1 to that file. +touch f || framework_failure_ +ln -s f s2 || framework_failure_ + +# Attempt to create a hard link to that symlink. +# On some systems, it's not possible: they create a hard link to the referent. +ln s2 s1 || framework_failure_ + +# If s1 is not a symlink, skip this test. +test -h s1 \ + || skip_ your kernel or file system cannot create a hard link to a symlink + +for opt in '' --backup; do + + if test "$opt" = --backup; then + mv $opt s1 s2 > out 2>&1 || fail=1 + compare /dev/null out || fail=1 + + # Ensure that s1 is gone. + test -e s1 && fail=1 + + # With --backup, ensure that the backup file was created. + ref=$(readlink s2~) || fail=1 + test "$ref" = f || fail=1 + else + echo "mv: 's1' and 's2' are the same file" > exp + mv $opt s1 s2 2>err && fail=1 + compare exp err || fail=1 + + # Ensure that s1 is still present. + test -e s1 || fail=1 + + # Without --backup, ensure there is no backup file. + test -e s2~ && fail=1 + fi + +done + +Exit $fail diff --git a/tests/mv/symlink-onto-hardlink.sh b/tests/mv/symlink-onto-hardlink.sh new file mode 100755 index 0000000..01c138a --- /dev/null +++ b/tests/mv/symlink-onto-hardlink.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# Ensure that mv works with a few symlink-onto-hard-link cases. + +# Copyright (C) 2012-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + +touch f || framework_failure_ +ln f h || framework_failure_ +ln -s f s || framework_failure_ + +# Given two links f and h to some important content, and a symlink s to f, +# "mv s f" must fail because it might then be hard to find the link, h. +# "mv s l" may succeed because then, s (now "l") still points to f. +# Of course, if the symlink were being moved into a different destination +# directory, things would be very different, and, I suspect, implausible. + +echo "mv: 's' and 'f' are the same file" > exp || framework_failure_ +mv s f > out 2> err && fail=1 +compare /dev/null out || fail=1 +compare exp err || fail=1 + +mv s l > out 2> err || fail=1 +compare /dev/null out || fail=1 +compare /dev/null err || fail=1 + +Exit $fail diff --git a/tests/mv/to-symlink.sh b/tests/mv/to-symlink.sh new file mode 100755 index 0000000..018bfe2 --- /dev/null +++ b/tests/mv/to-symlink.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# Make sure that the copying code used in an inter-partition +# move unlinks a destination symlink before opening it. + +# Copyright (C) 1999-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv +cleanup_() { rm -rf "$other_partition_tmpdir"; } +. "$abs_srcdir/tests/other-fs-tmpdir" + +rem_file="$other_partition_tmpdir/file" +rem_symlink="$other_partition_tmpdir/symlink" +file=to-sym + +echo local > $file || framework_failure_ +echo remote > $rem_file || framework_failure_ +ln -s $rem_file $rem_symlink || framework_failure_ + +# This mv command should succeed, unlinking the symlink +# before copying. +mv $file $rem_symlink || fail=1 + +# Make sure $file is gone. +test -f $file && fail=1 + +# Make sure $rem_file is unmodified. +test $(cat $rem_file) = remote || fail=1 + +Exit $fail diff --git a/tests/mv/trailing-slash.sh b/tests/mv/trailing-slash.sh new file mode 100755 index 0000000..3d41085 --- /dev/null +++ b/tests/mv/trailing-slash.sh @@ -0,0 +1,65 @@ +#!/bin/sh +# On some operating systems, e.g. SunOS-4.1.1_U1 on sun3x, +# rename() doesn't accept trailing slashes. +# Also, ensure that "mv dir non-exist-dir/" works. +# Also, ensure that "cp dir non-exist-dir/" works. + +# Copyright (C) 2004-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ mv + +mkdir foo || framework_failure_ + + +mv foo/ bar || fail=1 + +# mv and cp would misbehave for coreutils versions [5.3.0..5.97], 6.0 and 6.1 +for cmd in mv 'cp -r'; do + for opt in '' -T -u; do + rm -rf d e || framework_failure_ + mkdir d || framework_failure_ + + $cmd $opt d e/ || fail=1 + if test "$cmd" = mv; then + test -d d && fail=1 + else + test -d d || fail=1 + fi + test -d e || fail=1 + done +done + +# We would like the erroneous-looking "mv any non-dir/" to fail, +# but with the current implementation, it depends on how the +# underlying rename syscall handles the trailing slash. +# It does fail, as desired, on recent Linux and Solaris systems. +#touch a a2 +#returns_ 1 mv a a2/ || fail=1 + +# Test for a cp-specific diagnostic introduced after coreutils-8.7: +printf '%s\n' \ + "cp: cannot create regular file 'no-such/': Not a directory" \ +> expected-err +touch b +cp b no-such/ 2> err + +# Map "No such file..." diagnostic to the expected "Not a directory" +sed 's/No such file or directory/Not a directory/' err > k && mv k err + +compare expected-err err || fail=1 + +Exit $fail diff --git a/tests/mv/update.sh b/tests/mv/update.sh new file mode 100755 index 0000000..ab7309f --- /dev/null +++ b/tests/mv/update.sh @@ -0,0 +1,69 @@ +#!/bin/sh +# make sure --update works as advertised + +# Copyright (C) 2001-2023 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ cp mv + +test_reset() { + echo old > old || framework_failure_ + touch -d yesterday old || framework_failure_ + echo new > new || framework_failure_ +} + +test_reset +for interactive in '' -i; do + for cp_or_mv in cp mv; do + # This is a no-op, with no prompt. + # With coreutils-6.9 and earlier, using --update with -i would + # mistakenly elicit a prompt. + $cp_or_mv $interactive --update old new < /dev/null > out 2>&1 || fail=1 + compare /dev/null out || fail=1 + case "$(cat new)" in new) ;; *) fail=1 ;; esac + case "$(cat old)" in old) ;; *) fail=1 ;; esac + done +done + +# These should perform the rename / copy +for update_option in '--update' '--update=older' '--update=all' \ + '--update=none --update=all'; do + test_reset + mv $update_option new old || fail=1 + test -f new && fail=1 + case "$(cat old)" in new) ;; *) fail=1 ;; esac + + test_reset + cp $update_option new old || fail=1 + case "$(cat old)" in new) ;; *) fail=1 ;; esac + case "$(cat new)" in new) ;; *) fail=1 ;; esac +done + +# These should not perform the rename / copy +for update_option in '--update=none' \ + '--update=all --update=none'; do + test_reset + mv $update_option new old || fail=1 + case "$(cat new)" in new) ;; *) fail=1 ;; esac + case "$(cat old)" in old) ;; *) fail=1 ;; esac + + test_reset + cp $update_option new old || fail=1 + case "$(cat new)" in new) ;; *) fail=1 ;; esac + case "$(cat old)" in old) ;; *) fail=1 ;; esac +done + +Exit $fail |