When "cp --parents --preserve /dir/file /target/" needs to create /target/dir/, it appears to try to Fstat information from relative path "dir", not the actual parent path "/dir".
E.g., "cd /tmp && mkdir NewDir && cp -a --parents /etc/passwd NewDir" will fail, as (1) below - unless (2) /tmp/etc exists, or (3) use "cd /", or (4) omit "--preserve". My enclosed cp-par-pres-demo.sh shows that: (1) Cp --parents --preserve /dir/file /target/" will * log ENOENT for relative "dir" for a missing /target/dir; * create that missing parent /target/dir with mode 700; * create a missing non-parent output correctly; and * return error status 1. (2) If ./dir exists, Cp takes /target/dir mode from it, not /dir. (3) With "cd /", this works normally, since "dir" is /dir. (4) Without --preserve, there is no error. This happens for Debian 12.9 coreutils 9.1-1, under linux 6.1.115 amd64, on an ext4 partition, for root and other users, e.g. nobody. And for an ext3 copy Chroot under linux 5.10.226. (md5sum --check verifies coreutils.md5sums lib*.msd5sums et al.) This does not happen for Debian 11.11 coreutils 8.32-4+b1, under linux 5.10.226 amd64 on ext4, nor for earlier versions on i386 ext3. I enclose logs from those good Debian 11 and wrong Debian 12 runs. My other tests show this not happening for relative input paths. Hope this helps. Alan J. Goalby
cp-par-pres-demo.sh
Description: Bourne shell script
* export LC_ALL=C * uname -a Linux tp3 6.1.0-27-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.115-1 (2024-11-01) x86_64 GNU/Linux * hostname tp3 * cat /etc/debian_version 12.9 * umask 022 * mkdir /tmp/cp-par-pres-demo-out (1) deb12 Cp gives no-such, ?=1, root.root.700! * mkdir /tmp/cp-par-pres-demo-out/run1 * cd /home * cp --parents --preserve /etc/passwd /tmp/cp-par-pres-demo-out/run1 cp: 'etc': No such file or directory *** cp gave STATUS 1 *** > root.root.755 /tmp/cp-par-pres-demo-out/run1 okay. > root.root.700 /tmp/cp-par-pres-demo-out/run1/etc *** IFFY 700 *** > root.root.644 /tmp/cp-par-pres-demo-out/run1/etc/passwd okay. * mkdir --mode=751 /tmp/cp-par-pres-demo-out/etc (2) deb12 Cp wrongly uses relative 'etc' not '/etc'! * mkdir /tmp/cp-par-pres-demo-out/run2 * cd /tmp/cp-par-pres-demo-out * cp --parents --preserve /etc/passwd /tmp/cp-par-pres-demo-out/run2 > root.root.755 /tmp/cp-par-pres-demo-out/run2 okay. > root.root.751 /tmp/cp-par-pres-demo-out/run2/etc *** IFFY 751 *** > root.root.644 /tmp/cp-par-pres-demo-out/run2/etc/passwd okay. (3) Okay in / (so relative equals absolute). * mkdir /tmp/cp-par-pres-demo-out/run3 * cd / * cp --parents --preserve /etc/passwd /tmp/cp-par-pres-demo-out/run3 > root.root.755 /tmp/cp-par-pres-demo-out/run3 okay. > root.root.755 /tmp/cp-par-pres-demo-out/run3/etc okay. > root.root.644 /tmp/cp-par-pres-demo-out/run3/etc/passwd okay. (4) Okay without --preserve. * mkdir /tmp/cp-par-pres-demo-out/run4 * cd /home * cp --parents /etc/passwd /tmp/cp-par-pres-demo-out/run4 > root.root.755 /tmp/cp-par-pres-demo-out/run4 okay. > root.root.755 /tmp/cp-par-pres-demo-out/run4/etc okay. > root.root.644 /tmp/cp-par-pres-demo-out/run4/etc/passwd okay. * rm --interactive=once --recursive /tmp/cp-par-pres-demo-out rm: remove 1 argument recursively?
* export LC_ALL=C * uname -a Linux li4 5.10.0-33-amd64 #1 SMP Debian 5.10.226-1 (2024-10-03) x86_64 GNU/Linux * hostname li4 * cat /etc/debian_version 11.11 * umask 022 * mkdir /tmp/cp-par-pres-demo-out (1) deb12 Cp gives no-such, ?=1, root.root.700! * mkdir /tmp/cp-par-pres-demo-out/run1 * cd /home * cp --parents --preserve /etc/passwd /tmp/cp-par-pres-demo-out/run1 > root.root.755 /tmp/cp-par-pres-demo-out/run1 okay. > root.root.755 /tmp/cp-par-pres-demo-out/run1/etc okay. > root.root.644 /tmp/cp-par-pres-demo-out/run1/etc/passwd okay. * mkdir --mode=751 /tmp/cp-par-pres-demo-out/etc (2) deb12 Cp wrongly uses relative 'etc' not '/etc'! * mkdir /tmp/cp-par-pres-demo-out/run2 * cd /tmp/cp-par-pres-demo-out * cp --parents --preserve /etc/passwd /tmp/cp-par-pres-demo-out/run2 > root.root.755 /tmp/cp-par-pres-demo-out/run2 okay. > root.root.755 /tmp/cp-par-pres-demo-out/run2/etc okay. > root.root.644 /tmp/cp-par-pres-demo-out/run2/etc/passwd okay. (3) Okay in / (so relative equals absolute). * mkdir /tmp/cp-par-pres-demo-out/run3 * cd / * cp --parents --preserve /etc/passwd /tmp/cp-par-pres-demo-out/run3 > root.root.755 /tmp/cp-par-pres-demo-out/run3 okay. > root.root.755 /tmp/cp-par-pres-demo-out/run3/etc okay. > root.root.644 /tmp/cp-par-pres-demo-out/run3/etc/passwd okay. (4) Okay without --preserve. * mkdir /tmp/cp-par-pres-demo-out/run4 * cd /home * cp --parents /etc/passwd /tmp/cp-par-pres-demo-out/run4 > root.root.755 /tmp/cp-par-pres-demo-out/run4 okay. > root.root.755 /tmp/cp-par-pres-demo-out/run4/etc okay. > root.root.644 /tmp/cp-par-pres-demo-out/run4/etc/passwd okay. * rm --interactive=once --recursive /tmp/cp-par-pres-demo-out rm: remove 1 argument recursively?