From: Eric Blake Date: Fri, 4 Sep 2009 18:40:39 +0000 (-0600) Subject: mv, cp: tweak LINK_FOLLOWS_SYMLINKS logic X-Git-Tag: v7.6~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3346c0af;p=thirdparty%2Fcoreutils.git mv, cp: tweak LINK_FOLLOWS_SYMLINKS logic * gnulib: Update to latest gnulib. * src/copy.c (copy_internal): Adjust comment in light of POSIX 2008, and deal with macro now being tri-state. --- diff --git a/gnulib b/gnulib index 9b740ea4bc..ee67d8ea6b 160000 --- a/gnulib +++ b/gnulib @@ -1 +1 @@ -Subproject commit 9b740ea4bcb104eeceb0c847a376d2b7dbb77d1b +Subproject commit ee67d8ea6bd183f5ce32d90a6764705d766c3d6b diff --git a/src/copy.c b/src/copy.c index e604ec55a0..178a6404b2 100644 --- a/src/copy.c +++ b/src/copy.c @@ -1974,21 +1974,23 @@ copy_internal (char const *src_name, char const *dst_name, } } + /* POSIX 2008 states that it is implementation-defined whether + link() on a symlink creates a hard-link to the symlink, or only + to the referent (effectively dereferencing the symlink) (POSIX + 2001 required the latter behavior, although many systems provided + the former). Yet cp, invoked with `--link --no-dereference', + should not follow the link. We can approximate the desired + behavior by skipping this hard-link creating block and instead + copying the symlink, via the `S_ISLNK'- copying code below. + LINK_FOLLOWS_SYMLINKS is tri-state; if it is -1, we don't know + how link() behaves, so we use the fallback case for safety. + + FIXME - use a gnulib linkat emulation for more fine-tuned + emulation, particularly when LINK_FOLLOWS_SYMLINKS is -1. */ else if (x->hard_link -#ifdef LINK_FOLLOWS_SYMLINKS - /* A POSIX-conforming link syscall dereferences a symlink, yet cp, - invoked with `--link --no-dereference', should not. Thus, with - a POSIX-conforming link system call, we can't use link() here, - since that would create a hard link to the referent (effectively - dereferencing the symlink), rather than to the symlink itself. - We can approximate the desired behavior by skipping this hard-link - creating block and instead copying the symlink, via the `S_ISLNK'- - copying code below. - When link operates on the symlinks themselves, we use this block - and just call link(). */ - && !(S_ISLNK (src_mode) && x->dereference == DEREF_NEVER) -#endif - ) + && (!LINK_FOLLOWS_SYMLINKS + || !S_ISLNK (src_mode) + || x->dereference != DEREF_NEVER)) { if (link (src_name, dst_name)) {