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

Attachment: 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? 

Reply via email to