Subject: bug#61386: [PATCH] cp,mv,install: Disable sparse copy on macOS

From: George Valkov <[email-masked]>
Date: Sat, 11 Feb 2023 03:21:44 +0200

> On 2023-02-10, at 11:50 PM, Paul Eggert <[email-masked]> wrote:
> 
> On 2/10/23 13:35, George Valkov wrote:
> 
>> Since the source and it’s clone have separate metadata,
>> it should be possible to change it on the clone, to comply with standards.
> 
> Attached is a hacky patch to do that. It also uses the new CLONE_ACL flag. The old code apparently mishandled ACLs; the new code tries to do a better job.

Hint: remember to trace all code paths errors.
The program may and does steer in directions other than what you expected.

Without CLONE_ACL, UNIX permissions and macOS extended attributes
from the source file are preserved, timestamp is updated:
cp A B
-rw-------@   1 g     staff       332 Feb 11 01:57 A
-rw-------@   1 g     staff       332 Feb 11 02:19 B

With CLONE_ACL, I get 22 Invalid argument. Then falls-back to something else,
UNIX permissions and timestamp are preserved, extended attributes are lost:
cp -p A B
-rw-------@   1 g     staff       332 Feb 11 01:57 A
-rw-------    1 g     staff       332 Feb 11 01:57 B

fclonefileat also requires that the target does not exist, if it does we have to remove it,
otherwise it fails: 17 File exists. With your patch, cp does not print anything.

Now the question here is:
do we want to go the quick route of unlinking the destination and creating a fresh clone?
Or do we consider the possibility of multiple hard-links in which case if we want to update
a hard-link, we must overwrite the entire file and not use unlink, fclonefileat.
If we are absolutely certain that only one link exists, the first approach is safe
and more efficient.
If more than one link exist, we must always overwrite the existing data, to keep
hard-links consistent.

> This whole area is a mess, but the patch should improve correctness on macOS, while also being efficient in the usual case.

We need to resolve the issues described above first.

>> It feels more natural when the metadata is kept intact for the two files.
> 
> That depends on the application. The longstanding tradition for cp is to preserve metadata if you use 'cp -p', and to not preserve with plain cp. For interactive use you can use an alias or a little script if you prefer -p to be enabled by default.

Thank you for clarifying!
I used the sample I wrote in a previous message to test fclonefileat independently
of coreutils: the default behaviour is to preserve everything.
The manpage installed on macOS is from June 3, 2021. While it does describe the
behaviour of CLONE_ACL, reality shows it is not supported. CLONE_ACL fails with
22 Invalid argument. Which means additional code would be required to
create what cp thinks as default metadata, which might be prone to errors

>> Here is a good example: I create a tarball on my OpenWRT router. Extract on the Mac.
> 
> That's fine, because 'tar' historically has preserved the timestamp and (if you're root) permissions. Plain cp has not.

Fair enough. For comparison, here is the behaviour of coreutils 9.1 cp release:

copy UNIX permissions, without extended attributes or timestamp
cp A B
-rw-------@   1 g     staff       332 Feb 11 01:57 A
-rw-------    1 g     staff       332 Feb 11 02:40 B

copy UNIX permissions, extended attributes and timestamp
cp -p A B
-rw-------@   1 g     staff       332 Feb 11 01:57 A
-rw-------@   1 g     staff       332 Feb 11 01:57 B

Good luck!

Georgi Valkov
httpstorm.com
nano RTOS