-a

Not sure why you wouldn't want to preserve timestamps, links, etc. by default.

This is rather missing the point. The headlined article isn't really about how to achieve a goal, but about the weird history and evolution of a tool that leads us to the rather odd situation that we are in today. And it's far from being the only tool that has a weird history, that looks rather nutty if one looks at it from the point of view of a novice having to learn this stuff.

It's also not even completely covering the weird case of -r and -R for the cp command. On HP-UX, for example, the twain were different, but not in the way that they were in old GNU Core Utilities. That would be too easy. (-:

The AIX manual for cp explains its difference between -r and -R:

* https://ibm.com/docs/en/aix/7.1.0?topic=c-cp-command

Illumos also treats the two differently, but in a subtly different way:

* https://illumos.org/man/1/cp

That's why, just as fork(2) is a primitive for the process creation, copy(2) should've been the primitive for the file creation — creates an exact copy of the file under a new name, but with the exact same content and all of the metadata (except for the name, obviously), including its kind, permissions, timestamps, etc. And no, it wouldn't be prohibitively expensive because all filesystems can quite easily support CoW; after all, most of the created files will be truncate(2)d almost immediately, so there is no point to eagerly duplicate the file contents.

The "metadata is atomically copied" part would support very nicely the usual text editor's idiom of rename(2)ing a temporary file over the source after fully writing it out — you still need to accurately replicate the permissions and extended attributes. And just as shells are important enough programs to have fork(2) almost exactly suited for them, it would make sense to have copy(2), suited for the text editors.

When cp was invented, 'most filesystems' did not have the first clue about copy on write.

However, I should note that possibly the first company to invent what you describe was Microsoft.

Novell Netware 386 had an NCOPY command which invoked a Netware extension to the DOS API that told the server to perform the entire copy on the server.

But even earlier, OS/2 1.x had a proper DosCopy() system call. Since it could be passed down to the installable filesystem drivers for intra-volume copies, something like the Netware client for OS/2 could in theory turn it into the same protocol call that did server-side copies. There was a NET COPY command in LAN Manager (and LAN Server, if memory serves) that did the same optimization.

* https://www.edm2.com/index.php/DosCopy_(OS/2_1.x)

* https://www.edm2.com/index.php/FS_COPY

> When cp was invented, 'most filesystems' did not have the first clue about copy on write.

Eh, when fork was invented, most (virtual) memory systems did not have the first clue about copy-on-write either. And honestly, it's really not that difficult to support — it's essentially hard links, just with slightly different semantics.

In theory, I agree that it shouldn't be tricky. However, in practice, it is a bit tricky since all the different implementations have different ways to perform reflinks.

Linux has FICLONE [1], which I prefer because it operates on two file descriptors, allowing you to safely modify file metadata after the fact. macOS has clonefile, clonefileat, and fclonefileat [2]. Sadly, there is no way to operate on two file descriptors. The best you get is fclonefileat, which operates on a source file descriptor. Solaris has reflink and reflinkat, which operate on two paths, the latter relative to file descriptors [3]. In that case, one needs to be careful opening the destination to make changes to the metadata.

GNU coreutils has support for reflinks on Linux and macOS. But I've been thinking about adding support for Solaris as of late [4]. Sadly, I don't use it enough to test it as much as I would like.

Hopefully, a few years down the line the interfaces converge, and it is as simple as hard linking.

[1] https://man7.org/linux/man-pages/man2/FICLONE.2const.html [2] https://www.manpagez.com/man/2/clonefile/ [3] https://docs.oracle.com/cd/E86824_01/html/E54766/reflinkat-3... [4] https://lists.gnu.org/archive/html/coreutils/2026-09/msg0012...

old cp didn't have `-a`

Anyway, just use rsync.

> just use rsync

You still need to specify --archive (or --times for the individual option) to preserve mtime in the target copy.

But yeah, I tend to rsync more than I cp.