Bug 272120 - touch(1) -r modifies file's birthtime
Summary: touch(1) -r modifies file's birthtime
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: 13.2-RELEASE
Hardware: Any Any
: --- Affects Some People
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-06-21 02:47 UTC by Alexey Dokuchaev
Modified: 2024-03-05 00:16 UTC (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Alexey Dokuchaev freebsd_committer freebsd_triage 2023-06-21 02:47:25 UTC
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?!
Comment 1 Tatsuki Makino 2023-06-21 05:52:14 UTC
(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.
Comment 2 Mark Peek freebsd_committer freebsd_triage 2024-03-05 00:16:25 UTC
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.