Skip to content

Commit e75ef6b

Browse files
kbleesGit for Windows Build Agent
authored andcommitted
Win32: implement nanosecond-precision file times
We no longer use any of MSVCRT's stat-functions, so there's no need to stick to a CRT-compatible 'struct stat' either. Define and use our own POSIX-2013-compatible 'struct stat' with nanosecond- precision file times. Note: Due to performance issues when using git variants with different file time resolutions, this patch does *not* yet enable nanosecond precision in the Makefile (use 'make USE_NSEC=1'). Signed-off-by: Karsten Blees <[email protected]>
1 parent 3275a28 commit e75ef6b

File tree

4 files changed

+48
-32
lines changed

4 files changed

+48
-32
lines changed

compat/mingw.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -732,9 +732,9 @@ int mingw_lstat(const char *file_name, struct stat *buf)
732732
buf->st_size = S_ISLNK(buf->st_mode) ? MAX_LONG_PATH :
733733
fdata.nFileSizeLow | (((off_t) fdata.nFileSizeHigh) << 32);
734734
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
735-
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
736-
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
737-
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
735+
filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
736+
filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
737+
filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
738738
return 0;
739739
}
740740
error:
@@ -779,9 +779,9 @@ static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
779779
buf->st_nlink = 1;
780780
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes, 0);
781781
buf->st_size = fdata.nFileSizeLow | (((off_t) fdata.nFileSizeHigh) << 32);
782-
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
783-
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
784-
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
782+
filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
783+
filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
784+
filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
785785
return 0;
786786
}
787787

compat/mingw.h

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -335,24 +335,49 @@ static inline long long filetime_to_hnsec(const FILETIME *ft)
335335
return winTime - 116444736000000000LL;
336336
}
337337

338-
static inline time_t filetime_to_time_t(const FILETIME *ft)
339-
{
340-
return (time_t)(filetime_to_hnsec(ft) / 10000000);
341-
}
342-
343338
/*
344-
* Use mingw specific stat()/lstat()/fstat() implementations on Windows.
339+
* Use mingw specific stat()/lstat()/fstat() implementations on Windows,
340+
* including our own struct stat with 64 bit st_size and nanosecond-precision
341+
* file times.
345342
*/
346343
#ifndef __MINGW64_VERSION_MAJOR
347344
#define off_t off64_t
348345
#define lseek _lseeki64
346+
struct timespec {
347+
time_t tv_sec;
348+
long tv_nsec;
349+
};
349350
#endif
350351

351-
/* use struct stat with 64 bit st_size */
352+
static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
353+
{
354+
long long hnsec = filetime_to_hnsec(ft);
355+
ts->tv_sec = (time_t)(hnsec / 10000000);
356+
ts->tv_nsec = (hnsec % 10000000) * 100;
357+
}
358+
359+
struct mingw_stat {
360+
_dev_t st_dev;
361+
_ino_t st_ino;
362+
_mode_t st_mode;
363+
short st_nlink;
364+
short st_uid;
365+
short st_gid;
366+
_dev_t st_rdev;
367+
off64_t st_size;
368+
struct timespec st_atim;
369+
struct timespec st_mtim;
370+
struct timespec st_ctim;
371+
};
372+
373+
#define st_atime st_atim.tv_sec
374+
#define st_mtime st_mtim.tv_sec
375+
#define st_ctime st_ctim.tv_sec
376+
352377
#ifdef stat
353378
#undef stat
354379
#endif
355-
#define stat _stati64
380+
#define stat mingw_stat
356381
int mingw_lstat(const char *file_name, struct stat *buf);
357382
int mingw_stat(const char *file_name, struct stat *buf);
358383
int mingw_fstat(int fd, struct stat *buf);
@@ -365,13 +390,6 @@ int mingw_fstat(int fd, struct stat *buf);
365390
#endif
366391
extern int (*lstat)(const char *file_name, struct stat *buf);
367392

368-
#ifndef _stati64
369-
# define _stati64(x,y) mingw_stat(x,y)
370-
#elif defined (_USE_32BIT_TIME_T)
371-
# define _stat32i64(x,y) mingw_stat(x,y)
372-
#else
373-
# define _stat64(x,y) mingw_stat(x,y)
374-
#endif
375393

376394
int mingw_utime(const char *file_name, const struct utimbuf *times);
377395
#define utime mingw_utime

compat/win32/fscache.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ struct fsentry {
3838
struct {
3939
/* More stat members (only used for file entries). */
4040
off64_t st_size;
41-
time_t st_atime;
42-
time_t st_mtime;
43-
time_t st_ctime;
41+
struct timespec st_atim;
42+
struct timespec st_mtim;
43+
struct timespec st_ctim;
4444
};
4545
};
4646
};
@@ -151,9 +151,9 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
151151
fdata->dwReserved0);
152152
fse->st_size = S_ISLNK(fse->st_mode) ? MAX_LONG_PATH :
153153
fdata->nFileSizeLow | (((off_t) fdata->nFileSizeHigh) << 32);
154-
fse->st_atime = filetime_to_time_t(&(fdata->ftLastAccessTime));
155-
fse->st_mtime = filetime_to_time_t(&(fdata->ftLastWriteTime));
156-
fse->st_ctime = filetime_to_time_t(&(fdata->ftCreationTime));
154+
filetime_to_timespec(&(fdata->ftLastAccessTime), &(fse->st_atim));
155+
filetime_to_timespec(&(fdata->ftLastWriteTime), &(fse->st_mtim));
156+
filetime_to_timespec(&(fdata->ftCreationTime), &(fse->st_ctim));
157157

158158
return fse;
159159
}
@@ -432,9 +432,9 @@ int fscache_lstat(const char *filename, struct stat *st)
432432
st->st_nlink = 1;
433433
st->st_mode = fse->st_mode;
434434
st->st_size = fse->st_size;
435-
st->st_atime = fse->st_atime;
436-
st->st_mtime = fse->st_mtime;
437-
st->st_ctime = fse->st_ctime;
435+
st->st_atim = fse->st_atim;
436+
st->st_mtim = fse->st_mtim;
437+
st->st_ctim = fse->st_ctim;
438438

439439
/* don't forget to release fsentry */
440440
fsentry_release(fse);

config.mak.uname

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,6 @@ ifeq ($(uname_S),Windows)
359359
NO_SVN_TESTS = YesPlease
360360
RUNTIME_PREFIX = YesPlease
361361
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
362-
NO_NSEC = YesPlease
363362
USE_WIN32_MMAP = YesPlease
364363
# USE_NED_ALLOCATOR = YesPlease
365364
UNRELIABLE_FSTAT = UnfortunatelyYes
@@ -509,7 +508,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
509508
NO_SVN_TESTS = YesPlease
510509
RUNTIME_PREFIX = YesPlease
511510
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
512-
NO_NSEC = YesPlease
513511
USE_WIN32_MMAP = YesPlease
514512
USE_NED_ALLOCATOR = YesPlease
515513
UNRELIABLE_FSTAT = UnfortunatelyYes

0 commit comments

Comments
 (0)