I have a bunch of files that were backed up to a usb drive using the cp -r command without my having specifed to preserve timestamp (cp command without the -p. Dumb mistake, I know).
Luckily however, most of these files have a certain header from which can be read the date (in UTC) when the file was created. I would like to set the modified timestamp of these files to the local version of that timestamp (which happens to be UTC-07:00).
But my python script to do this is failing with Permission error.
PermissionError: [Errno 1] Operation not permitted
The files in question reside on a USB drive that was written from another system. The owner user of these files is not a user on the system I am running the command from. They are in a directory with execute permission and have the 777 mode.
The script that does this will succeed if run under sudo (even if the file has normal privileges): sudo python myscript
but fail if not run as super user python myscript
I’ve already solved this problem (just run as sudo) but I’d still like to know the reason for this behavior. What sort of permission scheme is the python os module running under?
The behavior is inherited from the underlying utime() system call (Python itself doesn’t really get a say). The relevant bits from the manpage seem to be
Changing timestamps is permitted when: either the process has
appropriate privileges, or the effective user ID equals the user
ID of the file, or times is NULL and the process has write
permission for the file.
and
ERRORS
EACCES: times is NULL, the caller’s effective user ID does not
match the owner of the file, the caller does not have write
access to the file, and the caller is not privileged
(Linux: does not have either the CAP_DAC_OVERRIDE or the CAP_FOWNER capability).
So in particular, the fact that your user ID didn’t match the owner of the file seems to be an issue (regardless of the file’s permissions).
Thanks for your informed response, which is exactly what I wanted to know. I tried asking the same question on Stack Overflow and had the moderator gestapo all over me. Good to know there are still places to get questions answered.
Broadly. os is normally a fairly thin shim to the OS calls. But not
everything is 1-1.
You can write a small python programme with some os call in it and
trace it:
strace python3 tiny_os_script.py
There’ll be a heap of stuff at the top, but the os call of interest
should be down the bottom. See what’s _actually_ happening at the OS
level. This is surprisingly useful even for higher level things.