bug#79446: 9.7: cp(1): Unnecessary writes / incorrect logging messages

Martin D Kealey <[email protected]>
Newsgroups gmane.comp.gnu.core-utils.bugs
Message-ID <CAN_U6MVaUYZsA4nHD6rgZPKqvPFp+bBYXk+QWYhVGsygLS0n_A@mail.gmail.com>
Just to expand a little on Paul's response

On Tue, 16 Sept 2025 at 10:14, Paul Eggert <[email protected]> wrote:

> > 2. The other odd thing in the trace is that there are some kind of odd
> >     shenanigans going on with the two identical binary files, and a
> >     third temporary file that cp makes and then removes.
>

The point is that they're not *supposed* to be "identical binaries";
they're supposed to be multiple names for ONE file, because you specified
--preserve=all, which includes replicating the original pattern of (hard)
links in the target.


> >     I don't really
> >     follow the logic of the series of "linkat"s, "renameat"s, and
> >     "unlinkat"s around lines 70-80 of the trace, but while I could
> >     accept that they're somehow useful,



The "link" and "linkat" syscalls won't overwrite an existing target, as
this line shows in the strace output:

linkat(3, "./build-script-build", 3,
"./build_script_build-ed34004021de38b5", 0) = -1 EEXIST (File exists)


To work around this, it follows up this sequence:

linkat(3, "./build-script-build", 3, "./CuYCWUCU", 0) = 0
renameat(3, "./CuYCWUCU", 3, "./build_script_build-ed34004021de38b5") = 0


This works because the "rename" & "renameat" syscalls *will* overwrite a
target, and moreover, they guarantee atomicity while doing so (though
that's arguably not relevant here).

(You might like to submit a Linux kernel feature request to implement an
extra option flag for 'linkat' to do the same, perhaps AT_REPLACE.)

I have to admit I'm a bit puzzled by

unlinkat(3, "./CuYCWUCU", 0)            = 0

which would appear to be successfully removing a filename that no longer
exists.

>     the trace doesn't show any equivalent writes to the target
> >     directory, only the ones in the source directory


Note that all the "*at" syscalls above reference filedescriptor 3, which
was obtained earlier:

openat(AT_FDCWD, "/home/kye/test", O_RDONLY|O_PATH|O_DIRECTORY) = 3


meaning, they're all relative to /home/kye/test. This contrasts with the
ones that use 'AT_FDCWD' which treats relative paths as relative to the
calling process's cwd.

-Martin
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.