diff options
author | Eric Blake <ebb9@byu.net> | 2009-09-04 12:40:39 -0600 |
---|---|---|
committer | Eric Blake <ebb9@byu.net> | 2009-09-04 14:54:52 -0600 |
commit | 3346c0afbc5fcf68322dccd69fb291854c269935 (patch) | |
tree | 179b257812ebbac4bd30548f4a469ef6d95c1b24 /src | |
parent | a23afe7b726cabd70f1afa7c4164fc8d36fe1c17 (diff) | |
download | coreutils-3346c0afbc5fcf68322dccd69fb291854c269935.tar.xz |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/copy.c | 30 |
1 files changed, 16 insertions, 14 deletions
diff --git a/src/copy.c b/src/copy.c index e604ec55a..178a6404b 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)) { |