[PATCH] cp: fix `cp -aT` overwriting symlink to directories

2025-10-18 Thread Dominique Martinet
From: Dominique Martinet 

busybox cp refuses to overwrites another symlink to a directory due to
an incorrect stat() call that should be lstat():
```
$ mkdir dir
$ ln -s dir ln_src
$ ln -s dir ln_dst
$ busybox cp -aT ln_src ln_dst
cp: 'ln_dst' is a directory
```

When using -T, we want to consider the target argument directly without
resolving symlinks.
(Note `cp -rLT` which would copy the source symlink as a directory after
following the symlink still fails with `target ... is not a directory`)

function old new   delta
cp_main  367 397 +30
cp_mv_stat10   - -10
--
(add/remove: 0/1 grow/shrink: 1/0 up/down: 30/-10) Total: 20 bytes
   text   data bss dec hex  filename
  85493   16621424   88579   15a03  busybox_old
  85513   16621424   88599   15a17  busybox_unstripped
---
 coreutils/cp.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/coreutils/cp.c b/coreutils/cp.c
index ee40af50b944..961de5b4271a 100644
--- a/coreutils/cp.c
+++ b/coreutils/cp.c
@@ -215,7 +215,8 @@ int cp_main(int argc, char **argv)
(flags & FILEUTILS_DEREFERENCE) ? stat 
: lstat);
if (s_flags < 0) /* error other than ENOENT */
return EXIT_FAILURE;
-   d_flags = cp_mv_stat(last, &dest_stat);
+   d_flags = cp_mv_stat2(last, &dest_stat,
+   (flags & FILEUTILS_NO_TARGET_DIR) ? 
lstat : stat);
if (d_flags < 0) /* error other than ENOENT */
return EXIT_FAILURE;
 
-- 
2.47.3

___
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH] cp: fix `cp -aT` overwriting symlink to directories

2025-10-18 Thread Dominique Martinet
Dominique Martinet wrote on Tue, Sep 30, 2025 at 12:11:33PM +0900:
> When using -T, we want to consider the target argument directly without
> resolving symlinks.
> (Note `cp -rLT` which would copy the source symlink as a directory after
> following the symlink still fails with `target ... is not a directory`)

Ah, I forgot to write that this only works with
CONFIG_FEATURE_NON_POSIX_CP=y

When that is unset it fails at the top of ask_and_unlink() with
`cp: can't create 'ln_dst': File exists` without also setting `-f`

(But I don't know posix and assume that's the expected behaviour even if
coreutils with POSIXLY_CORRECT doesn't fail like that?
... And anyway, alpine sets the build config, so I didn't bother digging
further at this point)

Thanks,
-- 
Dominique Martinet | Asmadeus
___
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH] cp: fix `cp -aT` overwriting symlink to directories

2025-10-17 Thread Denys Vlasenko
Applied, thank you.

On Tue, Sep 30, 2025 at 6:29 AM Dominique Martinet
 wrote:
>
> Dominique Martinet wrote on Tue, Sep 30, 2025 at 12:11:33PM +0900:
> > When using -T, we want to consider the target argument directly without
> > resolving symlinks.
> > (Note `cp -rLT` which would copy the source symlink as a directory after
> > following the symlink still fails with `target ... is not a directory`)
>
> Ah, I forgot to write that this only works with
> CONFIG_FEATURE_NON_POSIX_CP=y
>
> When that is unset it fails at the top of ask_and_unlink() with
> `cp: can't create 'ln_dst': File exists` without also setting `-f`
>
> (But I don't know posix and assume that's the expected behaviour even if
> coreutils with POSIXLY_CORRECT doesn't fail like that?
> ... And anyway, alpine sets the build config, so I didn't bother digging
> further at this point)
>
> Thanks,
> --
> Dominique Martinet | Asmadeus
___
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox