[PATCH 2/3] treewide: use utimensat(2) instead of legacy utime(3p)

"Alexey Samsonov via GitGitGadget" <[email protected]>
Newsgroups org.kernel.vger.git
Message-ID <6f5bd13d8e41e02af92df0274dbd435a395d6835.1787322203.git.gitgitgadget@gmail.com>
From: Alexey Samsonov <[email protected]>

Now that a compatibility wrapper for utimensat(2) has been introduced,
migrate all call sites across the codebase to use utimensat(2) instead of
the legacy utime(3p) interface:

- In `commit-graph.c`, use utimensat(2) with UTIME_OMIT and the computed
  timestamp `now` to bump the commit-graph modification time consistently
  across all files without needing an extra stat(2) call to preserve atime.
- In `copy.c`, use utimensat(2) to copy full sub-second access and
  modification timestamps from the source file.
- In `odb/source-packed.c`, `odb/source-loose.c`, and `object-file.c`,
  use utimensat(2) with `struct timespec` to freshen file timestamps.
- In `builtin/pack-objects.c`, update the pack timestamp with
  utimensat(2).
- In `rerere.c`, touch the postimage file with utimensat(2) passing NULL
  to set both atime and mtime to current time.
- In `t/helper/test-chmtime.c`, update file modification times using
  utimensat(2).

Signed-off-by: Alexey Samsonov <[email protected]>
---
 builtin/pack-objects.c  | 12 +++++++-----
 commit-graph.c          | 17 ++++++-----------
 copy.c                  | 10 ++++++----
 object-file.c           | 12 +++++++-----
 odb/source-loose.c      | 10 +++++-----
 odb/source-packed.c     | 12 +++++++-----
 rerere.c                |  4 ++--
 t/helper/test-chmtime.c | 19 ++++++++++++-------
 8 files changed, 52 insertions(+), 44 deletions(-)

diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 1ec5b6f206..35bdbc2b6a 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1438,11 +1438,13 @@ static void write_pack_file(void)
 			} else if (!last_mtime) {
 				last_mtime = st.st_mtime;
 			} else {
-				struct utimbuf utb;
-				utb.actime = st.st_atime;
-				utb.modtime = --last_mtime;
-				if (utime(pack_tmp_name, &utb) < 0)
-					warning_errno(_("failed utime() on %s"), pack_tmp_name);
+				struct timespec times[2];
+				times[0].tv_sec = st.st_atime;
+				times[0].tv_nsec = ST_ATIME_NSEC(st);
+				times[1].tv_sec = --last_mtime;
+				times[1].tv_nsec = 0;
+				if (utimensat(AT_FDCWD, pack_tmp_name, times, 0) < 0)
+					warning_errno(_("failed utimensat() on %s"), pack_tmp_name);
 			}
 
 			strbuf_addf(&tmpname, "%s-%s.", base_name,
diff --git a/commit-graph.c b/commit-graph.c
index 49e8f63930..08bbba3d98 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -2484,18 +2484,13 @@ static void mark_commit_graphs(struct write_commit_graph_context *ctx)
 {
 	uint32_t i;
 	time_t now = time(NULL);
+	struct timespec times[2] = {
+		{ .tv_nsec = UTIME_OMIT },
+		{ .tv_sec = now, .tv_nsec = 0 },
+	};
 
-	for (i = ctx->num_commit_graphs_after - 1; i < ctx->num_commit_graphs_before; i++) {
-		struct stat st;
-		struct utimbuf updated_time;
-
-		if (stat(ctx->commit_graph_filenames_before[i], &st) < 0)
-			continue;
-
-		updated_time.actime = st.st_atime;
-		updated_time.modtime = now;
-		utime(ctx->commit_graph_filenames_before[i], &updated_time);
-	}
+	for (i = ctx->num_commit_graphs_after - 1; i < ctx->num_commit_graphs_before; i++)
+		utimensat(AT_FDCWD, ctx->commit_graph_filenames_before[i], times, 0);
 }
 
 static void expire_commit_graphs(struct write_commit_graph_context *ctx)
diff --git a/copy.c b/copy.c
index 6074132050..39673f7829 100644
--- a/copy.c
+++ b/copy.c
@@ -23,12 +23,14 @@ int copy_fd(int ifd, int ofd)
 static int copy_times(const char *dst, const char *src)
 {
 	struct stat st;
-	struct utimbuf times;
+	struct timespec times[2];
 	if (stat(src, &st) < 0)
 		return -1;
-	times.actime = st.st_atime;
-	times.modtime = st.st_mtime;
-	if (utime(dst, &times) < 0)
+	times[0].tv_sec = st.st_atime;
+	times[0].tv_nsec = ST_ATIME_NSEC(st);
+	times[1].tv_sec = st.st_mtime;
+	times[1].tv_nsec = ST_MTIME_NSEC(st);
+	if (utimensat(AT_FDCWD, dst, times, 0) < 0)
 		return -1;
 	return 0;
 }
diff --git a/object-file.c b/object-file.c
index ec35c318bc..5e4ccb36d5 100644
--- a/object-file.c
+++ b/object-file.c
@@ -69,15 +69,17 @@ const char *odb_loose_path(struct odb_source_loose *loose,
 /* Returns 1 if we have successfully freshened the file, 0 otherwise. */
 static int freshen_file(const char *fn, const time_t *mtime)
 {
-	struct utimbuf times, *timesp = NULL;
+	struct timespec times[2], *timesp = NULL;
 
 	if (mtime) {
-		times.actime = *mtime;
-		times.modtime = *mtime;
-		timesp = &times;
+		times[0].tv_sec = *mtime;
+		times[0].tv_nsec = 0;
+		times[1].tv_sec = *mtime;
+		times[1].tv_nsec = 0;
+		timesp = times;
 	}
 
-	return !utime(fn, timesp);
+	return !utimensat(AT_FDCWD, fn, timesp, 0);
 }
 
 /*
diff --git a/odb/source-loose.c b/odb/source-loose.c
index ef0e919277..1fdaa9f88f 100644
--- a/odb/source-loose.c
+++ b/odb/source-loose.c
@@ -807,14 +807,14 @@ static int write_loose_object(struct odb_source_loose *loose,
 	close_loose_object(loose, fd, tmp_file.buf);
 
 	if (mtime) {
-		struct utimbuf utb = {
-			.actime = *mtime,
-			.modtime = *mtime,
+		struct timespec times[2] = {
+			{ .tv_sec = *mtime },
+			{ .tv_sec = *mtime },
 		};
 
-		if (utime(tmp_file.buf, &utb) < 0 &&
+		if (utimensat(AT_FDCWD, tmp_file.buf, times, 0) < 0 &&
 		    !(flags & ODB_WRITE_OBJECT_SILENT))
-			warning_errno(_("failed utime() on %s"), tmp_file.buf);
+			warning_errno(_("failed utimensat() on %s"), tmp_file.buf);
 	}
 
 	return finalize_object_file_flags(loose->base.odb->repo, tmp_file.buf, filename.buf,
diff --git a/odb/source-packed.c b/odb/source-packed.c
index 0890704e76..64871ff8da 100644
--- a/odb/source-packed.c
+++ b/odb/source-packed.c
@@ -574,13 +574,15 @@ static int odb_source_packed_freshen_object(struct odb_source *source,
 					    const time_t *mtime)
 {
 	struct odb_source_packed *packed = odb_source_packed_downcast(source);
-	struct utimbuf times, *timesp = NULL;
+	struct timespec times[2], *timesp = NULL;
 	struct pack_entry e;
 
 	if (mtime) {
-		times.actime = *mtime;
-		times.modtime = *mtime;
-		timesp = &times;
+		times[0].tv_sec = *mtime;
+		times[0].tv_nsec = 0;
+		times[1].tv_sec = *mtime;
+		times[1].tv_nsec = 0;
+		timesp = times;
 	}
 
 	if (!find_pack_entry(packed, oid, &e))
@@ -589,7 +591,7 @@ static int odb_source_packed_freshen_object(struct odb_source *source,
 		return 0;
 	if (e.p->freshened)
 		return 1;
-	if (utime(e.p->pack_name, timesp))
+	if (utimensat(AT_FDCWD, e.p->pack_name, timesp, 0))
 		return 0;
 	e.p->freshened = 1;
 
diff --git a/rerere.c b/rerere.c
index 3d3bd0db16..b64771f57f 100644
--- a/rerere.c
+++ b/rerere.c
@@ -658,8 +658,8 @@ static int merge(struct index_state *istate, const struct rerere_id *id, const c
 	 * A successful replay of recorded resolution.
 	 * Mark that "postimage" was used to help gc.
 	 */
-	if (utime(rerere_path(&buf, id, "postimage"), NULL) < 0)
-		warning_errno(_("failed utime() on '%s'"),
+	if (utimensat(AT_FDCWD, rerere_path(&buf, id, "postimage"), NULL, 0) < 0)
+		warning_errno(_("failed utimensat() on '%s'"),
 			      rerere_path(&buf, id, "postimage"));
 
 	/* Update "path" with the resolution */
diff --git a/t/helper/test-chmtime.c b/t/helper/test-chmtime.c
index 0e5538833a..a9e6eb78b8 100644
--- a/t/helper/test-chmtime.c
+++ b/t/helper/test-chmtime.c
@@ -105,7 +105,8 @@ int cmd__chmtime(int argc, const char **argv)
 
 	for (; i < argc; i++) {
 		struct stat sb;
-		struct utimbuf utb;
+		struct timespec times[2];
+		int64_t mtime_sec;
 		uintmax_t mtime;
 
 		if (stat(argv[i], &sb) < 0) {
@@ -123,22 +124,26 @@ int cmd__chmtime(int argc, const char **argv)
 		}
 #endif
 
-		utb.actime = sb.st_atime;
-		utb.modtime = set_eq ? set_time : sb.st_mtime + set_time;
+		mtime_sec = set_eq ? set_time : sb.st_mtime + set_time;
 
-		mtime = utb.modtime < 0 ? 0: utb.modtime;
+		times[0].tv_sec = sb.st_atime;
+		times[0].tv_nsec = ST_ATIME_NSEC(sb);
+		times[1].tv_sec = mtime_sec;
+		times[1].tv_nsec = 0;
+
+		mtime = mtime_sec < 0 ? 0 : mtime_sec;
 		if (get) {
 			printf("%"PRIuMAX"\n", mtime);
 		} else if (verbose) {
 			printf("%"PRIuMAX"\t%s\n", mtime, argv[i]);
 		}
 
-		if (utb.modtime != sb.st_mtime && utime(argv[i], &utb) < 0) {
+		if (mtime_sec != sb.st_mtime && utimensat(AT_FDCWD, argv[i], times, 0) < 0) {
 #ifdef GIT_WINDOWS_NATIVE
 			if (S_ISDIR(sb.st_mode)) {
 				/*
-				 * NEEDSWORK: The Windows version of `utime()`
-				 * (aka `mingw_utime()`) does not correctly
+				 * NEEDSWORK: The Windows version of `utimensat()`
+				 * (aka `mingw_utimensat()`) does not correctly
 				 * handle directory arguments, since it uses
 				 * `_wopen()`.  Ignore it for now since this
 				 * is just a test.
-- 
gitgitgadget
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.