Skip to content

Commit 6e35431

Browse files
committed
Merge pull request git-for-windows#443 from kblees/kb/nanosecond-file-times-v2.5.3
nanosecond file times for v2.5.3
2 parents 706b555 + a379b71 commit 6e35431

File tree

3 files changed

+76
-38
lines changed

3 files changed

+76
-38
lines changed

compat/mingw.c

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -587,9 +587,11 @@ static inline long long filetime_to_hnsec(const FILETIME *ft)
587587
return winTime - 116444736000000000LL;
588588
}
589589

590-
static inline time_t filetime_to_time_t(const FILETIME *ft)
590+
static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
591591
{
592-
return (time_t)(filetime_to_hnsec(ft) / 10000000);
592+
long long hnsec = filetime_to_hnsec(ft);
593+
ts->tv_sec = (time_t)(hnsec / 10000000);
594+
ts->tv_nsec = (hnsec % 10000000) * 100;
593595
}
594596

595597
/**
@@ -648,9 +650,9 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
648650
buf->st_size = fdata.nFileSizeLow |
649651
(((off_t)fdata.nFileSizeHigh)<<32);
650652
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
651-
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
652-
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
653-
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
653+
filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
654+
filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
655+
filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
654656
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
655657
WIN32_FIND_DATAW findbuf;
656658
HANDLE handle = FindFirstFileW(wfilename, &findbuf);
@@ -731,6 +733,29 @@ static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
731733
return do_lstat(follow, alt_name, buf);
732734
}
733735

736+
static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
737+
{
738+
BY_HANDLE_FILE_INFORMATION fdata;
739+
740+
if (!GetFileInformationByHandle(hnd, &fdata)) {
741+
errno = err_win_to_posix(GetLastError());
742+
return -1;
743+
}
744+
745+
buf->st_ino = 0;
746+
buf->st_gid = 0;
747+
buf->st_uid = 0;
748+
buf->st_nlink = 1;
749+
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
750+
buf->st_size = fdata.nFileSizeLow |
751+
(((off_t)fdata.nFileSizeHigh)<<32);
752+
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
753+
filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
754+
filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
755+
filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
756+
return 0;
757+
}
758+
734759
int mingw_lstat(const char *file_name, struct stat *buf)
735760
{
736761
return do_stat_internal(0, file_name, buf);
@@ -743,32 +768,31 @@ int mingw_stat(const char *file_name, struct stat *buf)
743768
int mingw_fstat(int fd, struct stat *buf)
744769
{
745770
HANDLE fh = (HANDLE)_get_osfhandle(fd);
746-
BY_HANDLE_FILE_INFORMATION fdata;
771+
DWORD avail, type = GetFileType(fh) & ~FILE_TYPE_REMOTE;
747772

748-
if (fh == INVALID_HANDLE_VALUE) {
749-
errno = EBADF;
750-
return -1;
751-
}
752-
/* direct non-file handles to MS's fstat() */
753-
if (GetFileType(fh) != FILE_TYPE_DISK)
754-
return _fstati64(fd, buf);
773+
switch (type) {
774+
case FILE_TYPE_DISK:
775+
return get_file_info_by_handle(fh, buf);
755776

756-
if (GetFileInformationByHandle(fh, &fdata)) {
757-
buf->st_ino = 0;
758-
buf->st_gid = 0;
759-
buf->st_uid = 0;
777+
case FILE_TYPE_CHAR:
778+
case FILE_TYPE_PIPE:
779+
/* initialize stat fields */
780+
memset(buf, 0, sizeof(*buf));
760781
buf->st_nlink = 1;
761-
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
762-
buf->st_size = fdata.nFileSizeLow |
763-
(((off_t)fdata.nFileSizeHigh)<<32);
764-
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
765-
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
766-
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
767-
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
782+
783+
if (type == FILE_TYPE_CHAR) {
784+
buf->st_mode = _S_IFCHR;
785+
} else {
786+
buf->st_mode = _S_IFIFO;
787+
if (PeekNamedPipe(fh, NULL, 0, NULL, &avail, NULL))
788+
buf->st_size = avail;
789+
}
768790
return 0;
791+
792+
default:
793+
errno = EBADF;
794+
return -1;
769795
}
770-
errno = EBADF;
771-
return -1;
772796
}
773797

774798
static inline void time_t_to_filetime(time_t t, FILETIME *ft)

compat/mingw.h

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -351,18 +351,41 @@ static inline int getrlimit(int resource, struct rlimit *rlp)
351351
}
352352

353353
/*
354-
* Use mingw specific stat()/lstat()/fstat() implementations on Windows.
354+
* Use mingw specific stat()/lstat()/fstat() implementations on Windows,
355+
* including our own struct stat with 64 bit st_size and nanosecond-precision
356+
* file times.
355357
*/
356358
#ifndef __MINGW64_VERSION_MAJOR
357359
#define off_t off64_t
358360
#define lseek _lseeki64
361+
struct timespec {
362+
time_t tv_sec;
363+
long tv_nsec;
364+
};
359365
#endif
360366

361-
/* use struct stat with 64 bit st_size */
367+
struct mingw_stat {
368+
_dev_t st_dev;
369+
_ino_t st_ino;
370+
_mode_t st_mode;
371+
short st_nlink;
372+
short st_uid;
373+
short st_gid;
374+
_dev_t st_rdev;
375+
off64_t st_size;
376+
struct timespec st_atim;
377+
struct timespec st_mtim;
378+
struct timespec st_ctim;
379+
};
380+
381+
#define st_atime st_atim.tv_sec
382+
#define st_mtime st_mtim.tv_sec
383+
#define st_ctime st_ctim.tv_sec
384+
362385
#ifdef stat
363386
#undef stat
364387
#endif
365-
#define stat _stati64
388+
#define stat mingw_stat
366389
int mingw_lstat(const char *file_name, struct stat *buf);
367390
int mingw_stat(const char *file_name, struct stat *buf);
368391
int mingw_fstat(int fd, struct stat *buf);
@@ -375,13 +398,6 @@ int mingw_fstat(int fd, struct stat *buf);
375398
#endif
376399
#define lstat mingw_lstat
377400

378-
#ifndef _stati64
379-
# define _stati64(x,y) mingw_stat(x,y)
380-
#elif defined (_USE_32BIT_TIME_T)
381-
# define _stat32i64(x,y) mingw_stat(x,y)
382-
#else
383-
# define _stat64(x,y) mingw_stat(x,y)
384-
#endif
385401

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

config.mak.uname

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,6 @@ ifeq ($(uname_S),Windows)
370370
RUNTIME_PREFIX = YesPlease
371371
HAVE_WPGMPTR = YesWeDo
372372
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
373-
NO_NSEC = YesPlease
374373
USE_WIN32_MMAP = YesPlease
375374
MMAP_PREVENTS_DELETE = UnfortunatelyYes
376375
# USE_NED_ALLOCATOR = YesPlease
@@ -518,7 +517,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
518517
RUNTIME_PREFIX = YesPlease
519518
HAVE_WPGMPTR = YesWeDo
520519
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
521-
NO_NSEC = YesPlease
522520
USE_WIN32_MMAP = YesPlease
523521
MMAP_PREVENTS_DELETE = UnfortunatelyYes
524522
USE_NED_ALLOCATOR = YesPlease

0 commit comments

Comments
 (0)