aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xtests/cp.test8
-rw-r--r--toys/posix/cp.c3
2 files changed, 6 insertions, 5 deletions
diff --git a/tests/cp.test b/tests/cp.test
index c7d445c0..9ee6cd0e 100755
--- a/tests/cp.test
+++ b/tests/cp.test
@@ -90,12 +90,12 @@ testing "-r dir1/* dir2" \
rm -rf one dir dir2
mkdir one; touch one/two; cp one/two one/three
-cp -r one/ one_ # Succeeds twice in a row
-testing "-r dir/." "cp -r one/. one_ && echo yes" "yes\n" "" ""
+cp -pr one/ one_ # Succeeds twice in a row
+testing "-pr dir/." "cp -pr one/. one_ && echo yes" "yes\n" "" ""
rm -rf one one_
mkdir one; touch one/two; ln -s two one/three
-cp -r one/ one_ # First time ok, but second will fail with "File exists"
-testing "-r dir/. symlink child" "cp -r one/. one_ && echo yes" "yes\n" "" ""
+cp -pr one/ one_ # First time ok, second mustn't fail with "File exists"
+testing "-pr dir/. symlink child" "cp -pr one/. one_ && echo yes" "yes\n" "" ""
rm -rf one one_
touch walrus
diff --git a/toys/posix/cp.c b/toys/posix/cp.c
index e37b360d..681af025 100644
--- a/toys/posix/cp.c
+++ b/toys/posix/cp.c
@@ -252,7 +252,8 @@ static int cp_node(struct dirtree *try)
// make symlink, or make block/char/fifo/socket
if (S_ISLNK(try->st.st_mode)
? ((i = readlinkat0(tfd, try->name, toybuf, sizeof(toybuf))) &&
- !symlinkat(toybuf, cfd, catch))
+ ((!unlinkat(cfd, catch, 0) || ENOENT == errno) &&
+ !symlinkat(toybuf, cfd, catch)))
: !mknodat(cfd, catch, try->st.st_mode, try->st.st_rdev))
{
err = 0;