diff options
author | Gian Piero Carrubba <gpiero@rm-rf.it> | 2013-11-07 23:35:52 +0100 |
---|---|---|
committer | Bernhard Voelker <mail@bernhard-voelker.de> | 2013-11-07 23:45:22 +0100 |
commit | bf6bf52dce37832b03ecfbe1b3a3b104f532df42 (patch) | |
tree | c62463b576c33400b029667a0991367c9da47b7c /tests/cp | |
parent | 2c6736f92fc7d2f310714473ea84ceff57e01da2 (diff) | |
download | coreutils-bf6bf52dce37832b03ecfbe1b3a3b104f532df42.tar.xz |
cp: fix --link regarding the dereferencing of symbolic links
* src/copy.c (create_hard_link): Add a bool 'dereference' parameter,
and pass AT_SYMLINK_FOLLOW as 'flags' to linkat() when dereference
is true.
(should_dereference): Add new 'bool' function to determine if a
file should be dereferenced or not.
(copy_internal): Use the above new should_dereference() and remember
its return value in a new local bool 'dereference' variable. Use that
in all three calls to create_hard_link().
* src/cp.c (main): after parsing the options, if x.dereference is
still DEFEF_UNDEFINED and the x.recursive is true, then only set
x.dereference to DEREF_NEVER iff --link was not specified.
* doc/coreutils.texi (cp invocation): Mention that cp(1) does not
follow symbolic links in the source when --link is specified.
Likewise in the description of the -R option when used together with
that option.
* tests/cp/same-file.sh: Adapt the expected results for the -fl,
the -bl and the -bfl tests.
* tests/cp/link-deref.sh: Add a new test.
* tests/local.mk (all_tests): Reference the above new test.
* NEWS (Changes in behavior): Mention the change.
This fixes http://bugs.gnu.org/15173
Co-authored-by: Bernhard Voelker <mail@bernhard-voelker.de>
Diffstat (limited to 'tests/cp')
-rwxr-xr-x | tests/cp/link-deref.sh | 110 | ||||
-rwxr-xr-x | tests/cp/same-file.sh | 6 |
2 files changed, 113 insertions, 3 deletions
diff --git a/tests/cp/link-deref.sh b/tests/cp/link-deref.sh new file mode 100755 index 000000000..91a6c5de3 --- /dev/null +++ b/tests/cp/link-deref.sh @@ -0,0 +1,110 @@ +#!/bin/sh +# Exercise cp --link's behavior regarding the dereferencing of symbolic links. + +# Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ cp + +mkdir dir || framework_failure_ +: > file || framework_failure_ +ln -s dir dirlink || framework_failure_ +ln -s file filelink || framework_failure_ +ln -s nowhere danglink || framework_failure_ + +# printf format of the output line. +outformat='%s|result=%s|inode=%s|type=%s|error=%s\n' + +for src in dirlink filelink danglink; do + # Get symlink's target. + tgt=$(readlink $src) || framework_failure_ + # Get inodes and file type of the symlink (src) and its target (tgt). + # Note: this will fail for 'danglink'; catch it. + ino_src="$(stat -c '%i' $src)" || framework_failure_ + typ_src="$(stat -c '%F' $src)" || framework_failure_ + ino_tgt="$(stat -c '%i' $tgt 2>/dev/null)" || ino_tgt= + typ_tgt="$(stat -c '%F' $tgt 2>/dev/null)" || typ_tgt= + + for o in '' -L -H -P; do + for r in '' -R; do + + command="cp --link $o $r $src dst" + $command 2> err + result=$? + + # Get inode and file type of the destination (which may fail, too). + ino_dst="$(stat -c '%i' dst 2>/dev/null)" || ini_dst= + typ_dst="$(stat -c '%F' dst 2>/dev/null)" || typ_dst= + + # Print the actual result in a certain format. + printf "$outformat" \ + "$command" \ + "$result" \ + "$ino_dst" \ + "$typ_dst" \ + "$(< err)" \ + > out + + # What was expected? + if [ "$o" = "-P" ]; then + # cp --link should not dereference if -P is given. + exp_result=0 + exp_inode=$ino_src + exp_ftype=$typ_src + exp_error= + elif [ "$src" = 'danglink' ]; then + # Dereferencing should fail for the 'danglink'. + exp_result=1 + exp_inode= + exp_ftype= + exp_error="cp: cannot stat 'danglink': No such file or directory" + elif [ "$src" = 'dirlink' ] && [ "$r" != '-R' ]; then + # Dereferencing should fail for the 'dirlink' without -R. + exp_result=1 + exp_inode= + exp_ftype= + exp_error="cp: omitting directory 'dirlink'" + elif [ "$src" = 'dirlink' ]; then + # cp --link -R 'dirlink' should create a new directory. + exp_result=0 + exp_inode=$ino_dst + exp_ftype=$typ_dst + exp_error= + else + # cp --link 'filelink' should create a hard link to the target. + exp_result=0 + exp_inode=$ino_tgt + exp_ftype=$typ_tgt + exp_error= + fi + + # Print the expected result in a certain format. + printf "$outformat" \ + "$command" \ + "$exp_result" \ + "$exp_inode" \ + "$exp_ftype" \ + "$exp_error" \ + > exp + + compare exp out || { ls -lid $src $tgt dst; fail=1; } + + rm -rf dst err exp out || framework_failure_ + done + done +done + +Exit $fail diff --git a/tests/cp/same-file.sh b/tests/cp/same-file.sh index 003a62ba7..326f9c6bd 100755 --- a/tests/cp/same-file.sh +++ b/tests/cp/same-file.sh @@ -189,9 +189,9 @@ cat <<\EOF | sed "$remove_these_sed" > expected 0 -bf (foo sl1 -> foo sl2 sl2.~1~ -> foo) 0 -bdf (foo sl1 -> foo sl2 -> foo sl2.~1~ -> foo) 1 -l [cp: cannot create hard link 'sl2' to 'sl1'] (foo sl1 -> foo sl2 -> foo) -0 -fl (foo sl1 -> foo sl2 -> foo) -0 -bl (foo sl1 -> foo sl2 -> foo sl2.~1~ -> foo) -0 -bfl (foo sl1 -> foo sl2 -> foo sl2.~1~ -> foo) +0 -fl (foo sl1 -> foo sl2) +0 -bl (foo sl1 -> foo sl2 sl2.~1~ -> foo) +0 -bfl (foo sl1 -> foo sl2 sl2.~1~ -> foo) 1 [cp: 'foo' and 'hardlink' are the same file] (foo hardlink) 1 -d [cp: 'foo' and 'hardlink' are the same file] (foo hardlink) |