touch(1) goes beyond what would one expect and what is documented in the manpage: -m Change the modification time of the file. The access time of the file is not changed unless the -a flag is also specified. -r Use the access and modifications times from the specified file instead of the current time of day. I'm seeing this on both UFS and ZFS: $ cp -ai /some/real/file somefile $ stat -x somefile | tail -4 Access: Sun Aug 11 22:06:44 2019 Modify: Sun Aug 11 22:06:48 2019 <-- created, written, closed Change: Wed Jun 21 10:30:56 2023 Birth: Sun Aug 11 22:06:48 2019 <-- it's an old file $ echo blah >> somefile $ stat -x somefile | tail -4 Access: Sun Aug 11 22:06:44 2019 Modify: Wed Jun 21 10:31:21 2023 <-- we've just modified it Change: Wed Jun 21 10:31:21 2023 Birth: Sun Aug 11 22:06:48 2019 <-- remains the same (correct) $ touch -m -r /.rnd somefile <-- /.rnd is from 2014 $ stat -x somefile | tail -4 Access: Sun Aug 11 22:06:44 2019 Modify: Mon Jan 13 17:19:43 2014 <-- this is fine (expected) Change: Wed Jun 21 10:31:42 2023 Birth: Mon Jan 13 17:19:43 2014 <-- WTF?!
(In reply to Alexey Dokuchaev from comment #0) > <-- WTF?! F that the row does not exist in 12.4-STABLE :) If ls -Ul somefile result is also changed, then it is F for touch. If not, then it is F for stat.
I looked into this a little bit and here is what I discovered. Running "touch -m" uses utimensat(2) and passes in just the modification date. This system call then calls an internal setutimes() https://github.com/freebsd/freebsd-src/blob/main/sys/kern/vfs_syscalls.c#L3211. In 2002 this change was added: https://github.com/freebsd/freebsd-src/commit/fb36a3d8472e3b7c446b5501635ec34eb1ebaa00 Change utimes to set the file creation time (for filesystems that support creation times such as UFS2) to the value of the modification time if the value of the modification time is older than the current creation time. See utimes(2) for further details. If a birthtime is not passed into setutimes() and the birthtime is younger than the modification time, then the birthtime is set to the modification time. The utimensat(2) man page documents this behavior. This makes a little bit of sense given a modification time usually should not be older than the birthtime of the file. But the utimes man page does talk about the need for a new system call allowing for setting access, modification, *and* birthtime so that might be an alternative. Options: 1. Document this behavior in the touch(1) man page. 2. Add a new system call to allow setting all three times and modify touch(1) to use it.