git: fba91af3b09b - main - makefs: Honor -T timestamps when creating images from mtree manifests

From: Bojan Novković <bnovkov_at_FreeBSD.org>
Date: Tue, 20 May 2025 09:50:52 UTC
The branch main has been updated by bnovkov:

URL: https://cgit.FreeBSD.org/src/commit/?id=fba91af3b09b0cb021a50da2bc78e44dfd49b69a

commit fba91af3b09b0cb021a50da2bc78e44dfd49b69a
Author:     Bojan Novković <bnovkov@FreeBSD.org>
AuthorDate: 2025-03-24 15:47:35 +0000
Commit:     Bojan Novković <bnovkov@FreeBSD.org>
CommitDate: 2025-05-20 09:50:22 +0000

    makefs: Honor -T timestamps when creating images from mtree manifests
    
    makefs backends rely on the fsnode structure to derive most
    of the information about the underlying filesystem objects.
    Depending on how the image is built, the fsnode structures
    are initialized in the walk_dir or read_mtree functions.
    However, read_mtree fails to take timestamps passed by -T into account,
    leading to nonreproducible images in backends that do not check for -T.
    Fix this and make -T backend-agnostic by adding an appropriate check
    in read_mtree_keywords while making sure that mtree entries can
    still override -T timestamps.
    
    PR:             285630
    Sponsored by:   Klara, Inc.
    Sponsored by:   The FreeBSD Foundation
    Reviewed by:    markj, emaste
    Differential Revision:  https://reviews.freebsd.org/D49531
---
 usr.sbin/makefs/makefs.8 |  8 ++++++--
 usr.sbin/makefs/makefs.c | 16 ++++++++++++++++
 usr.sbin/makefs/makefs.h |  1 +
 usr.sbin/makefs/mtree.c  | 19 ++++++++++++++++---
 usr.sbin/makefs/walk.c   | 16 ++--------------
 5 files changed, 41 insertions(+), 19 deletions(-)

diff --git a/usr.sbin/makefs/makefs.8 b/usr.sbin/makefs/makefs.8
index ae11309953e4..a11eaf8206e9 100644
--- a/usr.sbin/makefs/makefs.8
+++ b/usr.sbin/makefs/makefs.8
@@ -259,9 +259,13 @@ can be a
 .Pa pathname ,
 where the timestamps are derived from that file, or an integer
 value interpreted as the number of seconds from the Epoch.
-Note that timestamps specified in an
+Timestamps in a
 .Xr mtree 5
-spec file, override the default timestamp.
+specfile (specified with
+.Fl F )
+are used even if a default timestamp is specified.
+However, the timestamps in an mtree manifest are ignored
+if a default timestamp is specified.
 .It Fl t Ar fs-type
 Create an
 .Ar fs-type
diff --git a/usr.sbin/makefs/makefs.c b/usr.sbin/makefs/makefs.c
index d85b9c2668e7..46e513e22b25 100644
--- a/usr.sbin/makefs/makefs.c
+++ b/usr.sbin/makefs/makefs.c
@@ -436,6 +436,22 @@ set_option_var(const option_t *options, const char *var, const char *val,
 	return -1;
 }
 
+void
+set_tstamp(fsnode *cur)
+{
+	cur->inode->st.st_atime = stampst.st_atime;
+	cur->inode->st.st_mtime = stampst.st_mtime;
+	cur->inode->st.st_ctime = stampst.st_ctime;
+#if HAVE_STRUCT_STAT_ST_MTIMENSEC
+	cur->inode->st.st_atimensec = stampst.st_atimensec;
+	cur->inode->st.st_mtimensec = stampst.st_mtimensec;
+	cur->inode->st.st_ctimensec = stampst.st_ctimensec;
+#endif
+#if HAVE_STRUCT_STAT_BIRTHTIME
+	cur->inode->st.st_birthtime = stampst.st_birthtime;
+	cur->inode->st.st_birthtimensec = stampst.st_birthtimensec;
+#endif
+}
 
 static fstype_t *
 get_fstype(const char *type)
diff --git a/usr.sbin/makefs/makefs.h b/usr.sbin/makefs/makefs.h
index 62c7e430a00c..3cd56a036670 100644
--- a/usr.sbin/makefs/makefs.h
+++ b/usr.sbin/makefs/makefs.h
@@ -188,6 +188,7 @@ fsnode *	read_mtree(const char *, fsnode *);
 int		set_option(const option_t *, const char *, char *, size_t);
 int		set_option_var(const option_t *, const char *, const char *,
     char *, size_t);
+void		set_tstamp(fsnode *);
 fsnode *	walk_dir(const char *, const char *, fsnode *, fsnode *);
 void		free_fsnodes(fsnode *);
 option_t *	copy_opts(const option_t *);
diff --git a/usr.sbin/makefs/mtree.c b/usr.sbin/makefs/mtree.c
index 83e207b07402..4f3c3f85dcc3 100644
--- a/usr.sbin/makefs/mtree.c
+++ b/usr.sbin/makefs/mtree.c
@@ -631,6 +631,9 @@ read_mtree_keywords(FILE *fp, fsnode *node)
 				}
 				/* Ignore. */
 			} else if (strcmp(keyword, "time") == 0) {
+				/* Ignore if a default timestamp is present. */
+				if (stampst.st_ino != 0)
+					break;
 				if (value == NULL) {
 					error = ENOATTR;
 					break;
@@ -720,7 +723,9 @@ read_mtree_keywords(FILE *fp, fsnode *node)
 		return (error);
 
 	st->st_mode = (st->st_mode & ~S_IFMT) | node->type;
-
+	/* Store default timestamp, if present. */
+	if (stampst.st_ino != 0)
+		set_tstamp(node);
 	/* Nothing more to do for the global defaults. */
 	if (node->name == NULL)
 		return (0);
@@ -1051,8 +1056,16 @@ read_mtree(const char *fname, fsnode *node)
 	mtree_global.inode = &mtree_global_inode;
 	mtree_global_inode.nlink = 1;
 	mtree_global_inode.st.st_nlink = 1;
-	mtree_global_inode.st.st_atime = mtree_global_inode.st.st_ctime =
-	    mtree_global_inode.st.st_mtime = time(NULL);
+	if (stampst.st_ino != 0) {
+		set_tstamp(&mtree_global);
+	} else {
+#if HAVE_STRUCT_STAT_BIRTHTIME
+		mtree_global_inode.st.st_birthtime =
+#endif
+		    mtree_global_inode.st.st_atime =
+		    mtree_global_inode.st.st_ctime =
+		    mtree_global_inode.st.st_mtime = time(NULL);
+	}
 	errors = warnings = 0;
 
 	setgroupent(1);
diff --git a/usr.sbin/makefs/walk.c b/usr.sbin/makefs/walk.c
index dc03a16cf2c6..65ba3f41fe02 100644
--- a/usr.sbin/makefs/walk.c
+++ b/usr.sbin/makefs/walk.c
@@ -248,20 +248,8 @@ create_fsnode(const char *root, const char *path, const char *name,
 	cur->type = stbuf->st_mode & S_IFMT;
 	cur->inode->nlink = 1;
 	cur->inode->st = *stbuf;
-	if (stampst.st_ino) {
-		cur->inode->st.st_atime = stampst.st_atime;
-		cur->inode->st.st_mtime = stampst.st_mtime;
-		cur->inode->st.st_ctime = stampst.st_ctime;
-#if HAVE_STRUCT_STAT_ST_MTIMENSEC
-		cur->inode->st.st_atimensec = stampst.st_atimensec;
-		cur->inode->st.st_mtimensec = stampst.st_mtimensec;
-		cur->inode->st.st_ctimensec = stampst.st_ctimensec;
-#endif
-#if HAVE_STRUCT_STAT_BIRTHTIME
-		cur->inode->st.st_birthtime = stampst.st_birthtime;
-		cur->inode->st.st_birthtimensec = stampst.st_birthtimensec;
-#endif
-	}
+	if (stampst.st_ino != 0)
+		set_tstamp(cur);
 	return (cur);
 }