bug#62572: cp --no-clobber behavior has changed

2023-12-17 Thread Dominique Martinet
Paul Eggert wrote on Fri, Dec 15, 2023 at 11:21:06AM -0800:
> The cat is to some extent out of the bag. Unless one insists on (FreeBSD |
> coreutils 9.2-9.4), or insist on coreutils 7.1-9.1, one should not rely on
> cp -n failing or silently succeeding when the destination already exists.
> This will remain true regardless of whether coreutils reverts to its 7.1-9.1
> behavior.

This. Scripts that want to be portable already can't assume cp -n will
do what they want, so at this point it doesn't really matter what
coreutils does in the grand scheme of things.

For distros like debian since even -testing hasn't seen coreutils 9.2,
there's still value in reverting locally (with a warning that it's not
reliable perhaps?), but in general coreutils 9.2 has been out for 9
months (2023 March 20), so many systems can already be considered
affected; but it's a disservice to users to just try to hide the problem
under the rug.


(To give a data point, this did bite us as well, and I was annoyed
enough that I went to look for the old bug report back in September, but
at that point 9.3 had already been out and I had given up without
reporting anything as nothing would change the fact that my scripts
would need updating. For the gory details I also need compatibility
with busybox cp (where -n silently ignores existing files), so
--update=none is not an option, but I for this particular usage I
settled for '-u' (--update=older, that busybox also support as short
option only...), and I since hurried to forget about it)

-- 
Dominique Martinet | Asmadeus





bug#62572: cp --no-clobber behavior has changed

2023-12-17 Thread Michael Stone

On Sun, Dec 17, 2023 at 12:34:11AM -0800, Paul Eggert wrote:

On 2023-12-16 13:46, Bernhard Voelker wrote:

Whether the implementation is race-prone or not is an internal thing.


I wasn't referring to the internal implementation. I was referring to 
cp users. With the newer Coreutils (FreeBSD) behavior, you can 
reliably write a script to do something if cp -n didn't copy the file 
because the destination already existed. With the older Coreutils 
behavior you cannot do that reliably; there will always be a race 
condition.


You can now reliably write a script using the new long option. Changing 
the behavior of the short option helped nobody.






bug#62572: cp --no-clobber behavior has changed

2023-12-17 Thread Pádraig Brady

On 16/12/2023 21:46, Bernhard Voelker wrote:

On 12/15/23 21:13, Michael Stone wrote:

On Fri, Dec 15, 2023 at 11:21:06AM -0800, Paul Eggert wrote:

Stlll, Pádraig gave a reasonable summary of why the change was made,


To clarify my summary a little, there I said that -n now _immediately_ fails.
I should have said _silently_ fails.  I.e. the complete copy operation
proceeds as before, and only the exit status is at issue here.


despite its incompatibility with previous behavior. (One thing I'd add
is that the FreeBSD behavior is inherently less race-prone.)


Whether the implementation is race-prone or not is an internal thing.
I think we're currently discussing more on a user-perspective level.

IIUC then the question is whether `cp -n` should continue to behave like
the (new) `cp --update=none` which returns EXIT_SUCCESS.

Regardless what other implementations do, when reading the -n description
from a user's point of view:

-n, --no-clobber do not overwrite an existing file (overrides a
   -u or previous -i option). See also --update

then I'd expect the tool to just skip existing files like `rsync 
--ignore-existing`
does.  In that regard I would be surprised if skipping files would result in an 
error.
Well, I would understand if there'd be a '--no-clobber=fail' option.


Agreed we should improve the docs a bit for this option.
I'll apply this at least:

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 1f8b356d1..bf0f424d3 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -9057,6 +9057,8 @@ Do not overwrite an existing file; silently fail instead.
 This option overrides a previous
 @option{-i} option.  This option is mutually exclusive with @option{-b} or
 @option{--backup} option.
+See also the @option{--update=none} option which will
+skip existing files but not fail.

 @item -P
 @itemx --no-dereference
diff --git a/src/cp.c b/src/cp.c
index 04a5cbee3..3ccc4c4e6 100644
--- a/src/cp.c
+++ b/src/cp.c
@@ -192,8 +192,8 @@ Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n\
   -L, --dereferencealways follow symbolic links in SOURCE\n\
 "), stdout);
   fputs (_("\
-  -n, --no-clobber do not overwrite an existing file (overrides 
a\n\
- -u or previous -i option). See also 
--update\n\
+  -n, --no-clobber ensure no existing files overwritten, and 
fail\n\
+ silently instead. See also --update\n\
 "), stdout);
   fputs (_("\
   -P, --no-dereference never follow symbolic links in SOURCE\n\



As Kamil added the option in 2009, I'd assume that the same patch was already
active in RHEL versions for quite some longer time.
Now changing the exit code feels kind of rough.


Well RHEL 6 came out a bit after (2010), and had the --no-clobber change,
while RHEL 5 before that did not.

Taking about distros, it's worth noting that the change is Fedora 39
which has been released for a month now.
We'll keep a close eye on issues, but haven't heard much as
of yet at least.


Therefore, from a pure user's perspective and regarding many years of 
precedence,
I am 80:20 for reverting the exit code change.


Thanks for your thoughts,
appreciated as always.

cheers,
Pádraig






bug#62572: cp --no-clobber behavior has changed

2023-12-17 Thread Paul Eggert

On 2023-12-16 13:46, Bernhard Voelker wrote:

Whether the implementation is race-prone or not is an internal thing.


I wasn't referring to the internal implementation. I was referring to cp 
users. With the newer Coreutils (FreeBSD) behavior, you can reliably 
write a script to do something if cp -n didn't copy the file because the 
destination already existed. With the older Coreutils behavior you 
cannot do that reliably; there will always be a race condition.