bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

semantics of cp -R


From: ericblake
Subject: semantics of cp -R
Date: Tue, 05 Oct 2004 20:24:46 +0000

I have a question on POSIX compliance with recursive copies, going from the 
latest specification of cp at:
http://www.opengroup.org/onlinepubs/009695399/utilities/cp.html

Consider the following sequence:

$ cd /tmp
$ cp --version
cp (coreutils) 5.2.1
Written by Torbjorn Granlund, David MacKenzie, and Jim Meyering.

Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ ls
$ mkdir c
$ ln -s c a
$ cp -RPv a b
`a' -> `b'

At this point, cp correctly follows POSIX - step 4.b applies, and ./b is
created as a symbolic link to the directory c.  However, attempting to
repeat the command:

$ cp -RPv a b
`a' -> `b/a'

violates POSIX by my reading, since the target 'b' exists and is of type
symlink (not directory).
"It shall be an error ... if target exists and is a file of a type defined
by the System Interfaces volume of IEEE Std 1003.1-2001, but is not a file
of type directory."

Note that the actual created file, '/tmp/c/a', is a dangling symlink to the 
non-existant '/tmp/c/c'.  The command should have failed (although when -u is 
also specified, a reasonable alternative might be doing nothing, since -u is an 
extension and the symlink b is newer than the symlink a).

Is this a bug in coreutils, or a weakness in the POSIX specification that
needs to be brought up to the Open Group?  Although it seems like a goal of
coreutils is to minimize the effect of POSIXLY_CORRECT, perhaps the decision
to dereference a symlink destination should be one of those places where the
environment affects behavior?

The behavior for
$ cp -RPv c d
`c' -> `d'
$ cp -RPv c d
`c' -> `d/c'

is correct (POSIX does give a different destination path depending on
whether directory 'd' exists).  Similarly,

$ ln -sv c e
create symbolic link `e' to `c'
$ ln -sv c e
create symbolic link `e/c' to `c'

appears to be valid (note that the second invocation creates the infinitely
recursive symlink `/tmp/c/c'), because the POSIX wording for the ln command
decides whether the last argument "does not name an existing directory",
rather than "is a file of type directory"; and you can argue that a
directory symlink names a directory.

I also found it odd that the --no-dereference option (-n in ln, -P in cp)
behaves differently:
$ ln -snv c f
create symbolic link `f' to `c'
$ ln -snv c f
ln: `f': File exists

I already showed that cp -P dereferences a destination symlink to a
directory, even though the similar ln -n does not.  Maybe it would make
sense for cp to have:
-n --no-target-dereference   Don't dereference target
-P --no-source-dereference   Don't dereference sources
--no-dereference             Same as -nP


My intent was to do something like:
LIST='foo_file bar_dir blah/my_file blah/my_dir'
SRC=src
DST=dst
CP='ln -sn'
for file in $LIST; do
  $CP ${SRC}/$file ${DST}/$file
done

to keep the dst subtree up-to-date with the subset of the SRC tree called
out by $LIST, whether or not the dst subtree already had files/directories
by that name, for some definition of $CP involving cp instead of ln.  I
guess the same could be done by using /bin/test to decide whether $file was
a file or directory, and then changing the invocation of cp accordingly, but
that is more verbose.

--
Eric Blake






reply via email to

[Prev in Thread] Current Thread [Next in Thread]