diff mbox series

[v2,1/6] object-file: use futimens rather than utime

Message ID fc3d5a7b63524647c4a0de53e41772a7eede4f2d.1630108177.git.gitgitgadget@gmail.com (mailing list archive)
State Superseded
Headers show
Series Implement a batched fsync option for core.fsyncObjectFiles | expand

Commit Message

Neeraj Singh (WINDOWS-SFS) Aug. 27, 2021, 11:49 p.m. UTC
From: Neeraj Singh <neerajsi@microsoft.com>

Make close_loose_object do all of the steps for syncing and correctly
naming a new loose object so that it can be reimplemented in the
upcoming bulk-fsync mode.

Use futimens, which is available in POSIX.1-2008 to update the file
timestamps. This should be slightly faster than utime, since we have
a file descriptor already available. This change allows us to update
the time before closing, renaming, and potentially fsyincing the file
being refreshed. This code is currently only invoked by git-pack-objects
via force_object_loose.

Implement a futimens shim for the Windows port of Git.

Signed-off-by: Neeraj Singh <neerajsi@microsoft.com>
---
 compat/mingw.c | 53 ++++++++++++++++++++++++++++++++++----------------
 compat/mingw.h |  2 ++
 object-file.c  | 17 ++++++++--------
 3 files changed, 46 insertions(+), 26 deletions(-)
diff mbox series

Patch

diff --git a/compat/mingw.c b/compat/mingw.c
index 9e0cd1e097f..ce14b21c182 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -734,11 +734,14 @@  int mingw_chmod(const char *filename, int mode)
  * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
  * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
  */
+
+#define UNIX_EPOCH_FILETIME 116444736000000000LL
+
 static inline long long filetime_to_hnsec(const FILETIME *ft)
 {
 	long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
 	/* Windows to Unix Epoch conversion */
-	return winTime - 116444736000000000LL;
+	return winTime - UNIX_EPOCH_FILETIME;
 }
 
 static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
@@ -748,6 +751,13 @@  static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
 	ts->tv_nsec = (hnsec % 10000000) * 100;
 }
 
+static inline void timespec_to_filetime(const struct timespec *t, FILETIME *ft)
+{
+	long long winTime = t->tv_sec * 10000000LL + t->tv_nsec / 100 + UNIX_EPOCH_FILETIME;
+	ft->dwLowDateTime = winTime;
+	ft->dwHighDateTime = winTime >> 32;
+}
+
 /**
  * Verifies that safe_create_leading_directories() would succeed.
  */
@@ -949,19 +959,33 @@  int mingw_fstat(int fd, struct stat *buf)
 	}
 }
 
-static inline void time_t_to_filetime(time_t t, FILETIME *ft)
+int mingw_futimens(int fd, const struct timespec times[2])
 {
-	long long winTime = t * 10000000LL + 116444736000000000LL;
-	ft->dwLowDateTime = winTime;
-	ft->dwHighDateTime = winTime >> 32;
+	FILETIME mft, aft;
+
+	if (times) {
+		timespec_to_filetime(&times[0], &aft);
+		timespec_to_filetime(&times[1], &mft);
+	} else {
+		GetSystemTimeAsFileTime(&mft);
+		aft = mft;
+	}
+
+	if (!SetFileTime((HANDLE)_get_osfhandle(fd), NULL, &aft, &mft)) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	return 0;
 }
 
-int mingw_utime (const char *file_name, const struct utimbuf *times)
+int mingw_utime(const char *file_name, const struct utimbuf *times)
 {
-	FILETIME mft, aft;
 	int fh, rc;
 	DWORD attrs;
 	wchar_t wfilename[MAX_PATH];
+	struct timespec ts[2];
+
 	if (xutftowcs_path(wfilename, file_name) < 0)
 		return -1;
 
@@ -979,17 +1003,12 @@  int mingw_utime (const char *file_name, const struct utimbuf *times)
 	}
 
 	if (times) {
-		time_t_to_filetime(times->modtime, &mft);
-		time_t_to_filetime(times->actime, &aft);
-	} else {
-		GetSystemTimeAsFileTime(&mft);
-		aft = mft;
+		memset(ts, 0, sizeof(ts));
+		ts[0].tv_sec = times->actime;
+		ts[1].tv_sec = times->modtime;
 	}
-	if (!SetFileTime((HANDLE)_get_osfhandle(fh), NULL, &aft, &mft)) {
-		errno = EINVAL;
-		rc = -1;
-	} else
-		rc = 0;
+
+	rc = mingw_futimens(fh, times ? ts : NULL);
 	close(fh);
 
 revert_attrs:
diff --git a/compat/mingw.h b/compat/mingw.h
index c9a52ad64a6..87944dfec72 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -398,6 +398,8 @@  int mingw_fstat(int fd, struct stat *buf);
 
 int mingw_utime(const char *file_name, const struct utimbuf *times);
 #define utime mingw_utime
+int mingw_futimens(int fd, const struct timespec times[2]);
+#define futimens mingw_futimens
 size_t mingw_strftime(char *s, size_t max,
 		   const char *format, const struct tm *tm);
 #define strftime mingw_strftime
diff --git a/object-file.c b/object-file.c
index a8be8994814..5421811273e 100644
--- a/object-file.c
+++ b/object-file.c
@@ -1860,12 +1860,13 @@  int hash_object_file(const struct git_hash_algo *algo, const void *buf,
 }
 
 /* Finalize a file on disk, and close it. */
-static void close_loose_object(int fd)
+static int close_loose_object(int fd, const char *tmpfile, const char *filename)
 {
 	if (fsync_object_files)
 		fsync_or_die(fd, "loose object file");
 	if (close(fd) != 0)
 		die_errno(_("error when closing loose object file"));
+	return finalize_object_file(tmpfile, filename);
 }
 
 /* Size of directory component, including the ending '/' */
@@ -1973,17 +1974,15 @@  static int write_loose_object(const struct object_id *oid, char *hdr,
 		die(_("confused by unstable object source data for %s"),
 		    oid_to_hex(oid));
 
-	close_loose_object(fd);
-
 	if (mtime) {
-		struct utimbuf utb;
-		utb.actime = mtime;
-		utb.modtime = mtime;
-		if (utime(tmp_file.buf, &utb) < 0)
-			warning_errno(_("failed utime() on %s"), tmp_file.buf);
+		struct timespec ts[2] = {0};
+		ts[0].tv_sec = mtime;
+		ts[1].tv_sec = mtime;
+		if (futimens(fd, ts) < 0)
+			warning_errno(_("failed futimes() on %s"), tmp_file.buf);
 	}
 
-	return finalize_object_file(tmp_file.buf, filename.buf);
+	return close_loose_object(fd, tmp_file.buf, filename.buf);
 }
 
 static int freshen_loose_object(const struct object_id *oid)