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
This commit is contained in:
Bojan Novković 2025-03-24 16:47:35 +01:00
parent c8ffb90b1d
commit fba91af3b0
5 changed files with 41 additions and 19 deletions

View file

@ -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

View file

@ -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)

View file

@ -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 *);

View file

@ -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);

View file

@ -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);
}