This question is neither meant as a philosophical headscratcher or a question about storage technology. Using cp you get a file (destination) that has the same contents as the old (source), that much is clear. That doesn’t answer these questions, though:
- What permissions is the destination file born with?
- What group does it belong to?
To my mind there were two good answers, equally logical in their own way. Either cp creates a new file or it creates a copy.
If it’s new-file-creation then – I thought – the file should belong to
user_primary_group and start with whatever permissions
user‘s umask allows, similar to how, e.g.
touch would create a new file. If it’s a copy, then it should inherit the source file’s permissions and be shared with the same group as the source file.
Place your bets now.
Or just guess.
Don’t test in a terminal. That’s cheating.
All set for the reveal?
Ok, here we go.
It was a trick question. Neither of those two options are the actual
[ /tmp/test $ ] cp rootfile copyfile [ /tmp/test $ ] ls -lh total 0 -rw-r----- 1 mads mads 0 May 27 12:55 copyfile -rw-r----- 1 root media 0 May 27 12:54 rootfile
It’s a bit of both.
copyfile has inherited the permissions of the source file but it belongs to my user’s primary group, not
media as the original.
There are flags to change these defaults to either of my two suggestions. For the “file creation” approach I need to specify that the permissions of the original should not be preserved:
[ /tmp/test $ ] ls -lh total 0 -rw-rw-r-- 1 root docker 0 May 27 12:54 rootfile [ /tmp/test $ ] cp --no-preserve=mode rootfile copyfile [ /tmp/test $ ] ls -lh total 0 -rw-r--r-- 1 mads mads 0 May 27 13:22 copyfile -rw-rw-r-- 1 root docker 0 May 27 12:54 rootfile test
-rw-r--r-- corresponds to
644 and rhymes with my umask of
022. Note that execute permissions on files are never set on file creation for security reasons – you always have to do that explicitly.
For the “copy” approach, I can make explicit what additional information from the source file I do want to preserve:
[ /tmp/test $ ] ls -lh total 0 -rw-rw-r-- 1 root docker 0 May 27 12:54 rootfile [ /tmp/test $ ] cp --preserve=mode,ownership,timestamps rootfile copyfile [ /tmp/test $ ] ls -lh total 0 -rw-rw-r-- 1 mads mads 0 May 27 12:54 copyfile -rw-rw-r-- 1 root docker 0 May 27 12:54 rootfile [ /tmp/test $ ]
One thing sticks out here, though. Did I not ask cp to preserve ownership? This ought to have made the file belong to
The problem is my primary user does not belong to the
docker group. A non-root user is not allowed to share one of their own files with a group they do not belong to:
[ /tmp/test $ ] touch sharefile [ /tmp/test $ ] chown mads:docker sharefile chown: changing ownership of 'sharefile': Operation not permitted [ /tmp/test $ ] chown mads:media sharefile [ /tmp/test $ ]
My primary user does not belong to the docker group, but it does belong to the media group. So the former command fails where the latter succeeds.
As we have seen, though, where
cp perseveres, silently ignoring the
preserve=ownership flag. Not even a non-zero exit status code to tell me that there was an issue. Odd? Certainly. A bug? Maybe.
To answer the question at the top: cp is by default run with implicit
--preserve=mode --no-preserve=ownership,timestamps flags. There might be other attributes preserved but certainly not ownership or timestamps.
At any rate, I hope this deep dive has been illuminating. I have used cp for the better part of two decades and never stopped to think of what a copy actually is before today.