Why can touch change only all times, or nothing when not owner

filespermissionsstattimestampstouch

We have a file foobar not owned by me, but it is in my group:

$ ll
total 4,0K
-rw-rw-r-- 1 root hbogert 4 jan 19 12:27 foobar

I can touch it and it will update all times:

 $ stat foobar
  File: 'foobar'
  Size: 4           Blocks: 8          IO Block: 4096   regular file
Device: 801h/2049d  Inode: 4869333     Links: 1
Access: (0664/-rw-rw-r--)  Uid: (    0/    root)   Gid: ( 1000/ hbogert)
Access: 2017-01-19 12:27:04.499412133 +0100
Modify: 2017-01-19 12:27:04.499412133 +0100
Change: 2017-01-19 12:27:04.499412133 +0100
 Birth: -


 $ touch foobar


 $ stat foobar 
  File: 'foobar'
  Size: 4           Blocks: 8          IO Block: 4096   regular file
Device: 801h/2049d  Inode: 4869333     Links: 1
Access: (0664/-rw-rw-r--)  Uid: (    0/    root)   Gid: ( 1000/ hbogert)
Access: 2017-01-19 12:32:04.375412133 +0100
Modify: 2017-01-19 12:32:04.375412133 +0100
Change: 2017-01-19 12:32:04.375412133 +0100
 Birth: -

However, when I just want to change the modification time, it fails:

$ touch -m foobar
touch: setting times of 'foobar': Operation not permitted

Is this expected behaviour?

Best Answer

The behaviour is expected, if rather non-obvious. At least on my system, touch does

utimensat(0, NULL, NULL, 0)

in the first case (touch file), and

utimensat(0, NULL, [UTIME_OMIT, UTIME_NOW], 0)

in the second (touch -m file). The first call is short-hand for "set the access and modification times to the current time"; the second says "leave the access time alone and change the modification time to the current time".

POSIX says

Only a process with the effective user ID equal to the user ID of the file, or with write access to the file, or with appropriate privileges may use futimens() or utimensat() with a null pointer as the times argument or with both tv_nsec fields set to the special value UTIME_NOW. Only a process with the effective user ID equal to the user ID of the file or with appropriate privileges may use futimens() or utimensat() with a non-null times argument that does not have both tv_nsec fields set to UTIME_NOW and does not have both tv_nsec fields set to UTIME_OMIT.

(times is the third argument to utimensat()). touch file falls under the first set of access restrictions: any write access to the file allows the access and modification times to be changed to "now". touch -m file falls under the second set of access restrictions: you need to be root or the owner of the file to be able to change the access and modification times to values which are not either both "now" or both "unchanged".

There are other ways of changing the access and/or modification times to "now" on files you don't own but can read or write:

  • reading a file will update the access time only;
  • writing a file (without reading it) will update the modification time only.
Related Question