[PATCH 2/4] erofs-utils: support $SOURCE_DATE_EPOCH

Gao Xiang hsiangkao at redhat.com
Fri Oct 30 23:30:18 AEDT 2020


Currently, we use -T to set a given UNIX timestamp for all
files, yet reproducible builds [1] requires what is called
"timestamp clamping", IOW, a timestamp must be used no later
than the value of this variable.

Let's support $SOURCE_DATE_EPOCH as well.

[1] https://reproducible-builds.org/specs/source-date-epoch/
Suggested-by: nl6720 <nl6720 at gmail.com>
Signed-off-by: Gao Xiang <hsiangkao at redhat.com>
---
 include/erofs/config.h |  7 +++++++
 lib/inode.c            | 15 +++++++++++++--
 mkfs/main.c            | 34 ++++++++++++++++++++++++++++++++++
 3 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/include/erofs/config.h b/include/erofs/config.h
index e425ce2..02ddf59 100644
--- a/include/erofs/config.h
+++ b/include/erofs/config.h
@@ -29,11 +29,18 @@ enum {
 	FORCE_INODE_EXTENDED,
 };
 
+enum {
+	TIMESTAMP_NONE,
+	TIMESTAMP_FIXED,
+	TIMESTAMP_CLAMPING,
+};
+
 struct erofs_configure {
 	const char *c_version;
 	int c_dbg_lvl;
 	bool c_dry_run;
 	bool c_legacy_compress;
+	char c_timeinherit;
 
 #ifdef HAVE_LIBSELINUX
 	struct selabel_handle *sehnd;
diff --git a/lib/inode.c b/lib/inode.c
index 5695bbc..fee5c96 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -729,8 +729,19 @@ int erofs_fill_inode(struct erofs_inode *inode,
 	inode->i_mode = st->st_mode;
 	inode->i_uid = st->st_uid;
 	inode->i_gid = st->st_gid;
-	inode->i_ctime = sbi.build_time;
-	inode->i_ctime_nsec = sbi.build_time_nsec;
+	inode->i_ctime = st->st_ctime;
+	inode->i_ctime_nsec = st->st_ctim.tv_nsec;
+
+	switch (cfg.c_timeinherit) {
+	case TIMESTAMP_CLAMPING:
+		if (st->st_ctime < sbi.build_time)
+			break;
+	case TIMESTAMP_FIXED:
+		inode->i_ctime = sbi.build_time;
+		inode->i_ctime_nsec = sbi.build_time_nsec;
+	default:
+		break;
+	}
 	inode->i_nlink = 1;	/* fix up later if needed */
 
 	switch (inode->i_mode & S_IFMT) {
diff --git a/mkfs/main.c b/mkfs/main.c
index 6dda9e3..5c41fc0 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -198,6 +198,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 				erofs_err("invalid UNIX timestamp %s", optarg);
 				return -EINVAL;
 			}
+			cfg.c_timeinherit = TIMESTAMP_FIXED;
 			break;
 		case 2:
 			opt = erofs_parse_exclude_path(optarg, false);
@@ -381,6 +382,33 @@ static void erofs_mkfs_generate_uuid(void)
 	erofs_info("filesystem UUID: %s", uuid_str);
 }
 
+/* https://reproducible-builds.org/specs/source-date-epoch/ for more details */
+int parse_source_date_epoch(void)
+{
+	char *source_date_epoch;
+	unsigned long long epoch = -1ULL;
+	char *endptr;
+
+	source_date_epoch = getenv("SOURCE_DATE_EPOCH");
+	if (!source_date_epoch)
+		return 0;
+
+	epoch = strtoull(source_date_epoch, &endptr, 10);
+	if (epoch == -1ULL || *endptr != '\0') {
+		erofs_err("Environment variable $SOURCE_DATE_EPOCH %s is invalid",
+			  source_date_epoch);
+		return -EINVAL;
+	}
+
+	if (cfg.c_force_inodeversion != FORCE_INODE_EXTENDED)
+		erofs_info("SOURCE_DATE_EPOCH is set, forcely generate extended inodes instead");
+
+	cfg.c_force_inodeversion = FORCE_INODE_EXTENDED;
+	cfg.c_unix_timestamp = epoch;
+	cfg.c_timeinherit = TIMESTAMP_CLAMPING;
+	return 0;
+}
+
 int main(int argc, char **argv)
 {
 	int err = 0;
@@ -405,6 +433,12 @@ int main(int argc, char **argv)
 		return 1;
 	}
 
+	err = parse_source_date_epoch();
+	if (err) {
+		usage();
+		return 1;
+	}
+
 	err = lstat64(cfg.c_src_path, &st);
 	if (err)
 		return 1;
-- 
2.18.1



More information about the Linux-erofs mailing list