summaryrefslogtreecommitdiff
path: root/src/copy.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2007-06-10 14:56:39 +0200
committerJim Meyering <jim@meyering.net>2007-06-10 15:01:18 +0200
commitb1b0f5c556f5b4080bf16525c309264de73084b7 (patch)
treede1c561b0b228d0495a310358844ae6b87133599 /src/copy.c
parent6c95b3f2bf3edfa913a76f83da0c329f1bf0e1ea (diff)
downloadcoreutils-b1b0f5c556f5b4080bf16525c309264de73084b7.tar.xz
bug-fix: cp would fail to write through a dangling symlink
* NEWS: Mention the bug fix. * src/copy.c (copy_reg): When open fails with EEXIST, the destination is lstat'able, and a symlink, call open again, but now without O_EXCL. * tests/cp/thru-dangling: New file, to test for the above fix. * tests/cp/Makefile.am (TESTS): Add thru-dangling. * THANKS: Add Michael McLagan. Bug report from Michael McLagan in <http://bugzilla.redhat.com/243588>.
Diffstat (limited to 'src/copy.c')
-rw-r--r--src/copy.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/src/copy.c b/src/copy.c
index f4e3b174b..b46221c01 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -352,8 +352,24 @@ copy_reg (char const *src_name, char const *dst_name,
}
if (*new_dst)
- dest_desc = open (dst_name, O_WRONLY | O_CREAT | O_EXCL | O_BINARY,
- dst_mode & ~omitted_permissions);
+ {
+ int open_flags = O_WRONLY | O_CREAT | O_BINARY;
+ dest_desc = open (dst_name, open_flags | O_EXCL,
+ dst_mode & ~omitted_permissions);
+
+ /* When trying to copy through a dangling destination symlink,
+ the above open fails with EEXIST. If that happens, and
+ lstat'ing the DST_NAME shows that it is a symlink, repeat
+ the open call, but this time without O_EXCL. */
+ if (dest_desc < 0 && errno == EEXIST)
+ {
+ struct stat dangling_link_sb;
+ if (lstat (dst_name, &dangling_link_sb) == 0
+ && S_ISLNK (dangling_link_sb.st_mode))
+ dest_desc = open (dst_name, open_flags,
+ dst_mode & ~omitted_permissions);
+ }
+ }
else
omitted_permissions = 0;