summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1997-05-26 04:46:47 +0000
committerJim Meyering <jim@meyering.net>1997-05-26 04:46:47 +0000
commit8805ede31bceb3712adb8eafe519897112685ffa (patch)
treeac2fec8de6f9097fc37252a0386994e77b9d7a45
parentcd29ba84ab6ef32f72c508c98599fc81cc6a617f (diff)
downloadcoreutils-8805ede31bceb3712adb8eafe519897112685ffa.tar.xz
(copy_internal): When preserving symlinks (--no-dereference) and the
destination file is a symlink, use stat (not xstat) to see if it points back to the source. Reported by James <james@albion.glarp.com>.
-rw-r--r--src/copy.c34
1 files changed, 27 insertions, 7 deletions
diff --git a/src/copy.c b/src/copy.c
index 14e488d69..9dac6de96 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -362,9 +362,26 @@ copy_internal (const char *src_path, const char *dst_path,
}
else
{
- /* The file exists already. */
+ int same;
- if (src_sb.st_ino == dst_sb.st_ino && src_sb.st_dev == dst_sb.st_dev)
+ /* The destination file exists already. */
+
+ same = (src_sb.st_ino == dst_sb.st_ino
+ && src_sb.st_dev == dst_sb.st_dev);
+
+ /* If we're preserving symlinks (--no-dereference) and the
+ destination file is a symlink, use stat (not xstat) to
+ see if it points back to the source. */
+ if (!same && !x->dereference && S_ISLNK (dst_sb.st_mode))
+ {
+ struct stat dst2_sb;
+ if (stat (dst_path, &dst2_sb) == 0
+ && (src_sb.st_ino == dst2_sb.st_ino &&
+ src_sb.st_dev == dst2_sb.st_dev))
+ same = 1;
+ }
+
+ if (same)
{
if (x->hard_link)
return 0;
@@ -630,14 +647,14 @@ copy_internal (const char *src_path, const char *dst_path,
{
/* Preserve the owner and group of the just-`copied'
symbolic link, if possible. */
-#ifdef HAVE_LCHOWN
+# ifdef HAVE_LCHOWN
if (DO_CHOWN (lchown, dst_path, src_sb.st_uid, src_sb.st_gid))
{
error (0, errno, _("preserving ownership for %s"), dst_path);
goto un_backup;
}
-#else
-# ifdef ROOT_CHOWN_AFFECTS_SYMLINKS
+# else
+# ifdef ROOT_CHOWN_AFFECTS_SYMLINKS
if (x->myeuid == 0)
{
if (DO_CHOWN (chown, dst_path, src_sb.st_uid, src_sb.st_gid))
@@ -651,13 +668,13 @@ copy_internal (const char *src_path, const char *dst_path,
/* FIXME: maybe give a diagnostic: you must be root
to preserve ownership and group of symlinks. */
}
-# else
+# else
/* Can't preserve ownership of symlinks.
FIXME: maybe give a warning or even error for symlinks
in directories with the sticky bit set -- there, not
preserving owner/group is a potential security problem. */
+# endif
# endif
-#endif
}
return 0;
@@ -726,8 +743,11 @@ un_backup:
static int
valid_options (const struct cp_options *co)
{
+ assert (co != NULL);
+
/* FIXME: make sure xstat and dereference are consistent. */
assert (co->xstat);
+
assert (co->sparse_mode != SPARSE_UNUSED);
}