Skip to content

Commit 4f781a9

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 922e2a8 + a379b71 commit 4f781a9

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
@@ -617,9 +617,11 @@ static inline long long filetime_to_hnsec(const FILETIME *ft)
617617
return winTime - 116444736000000000LL;
618618
}
619619

620-
static inline time_t filetime_to_time_t(const FILETIME *ft)
620+
static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
621621
{
622-
return (time_t)(filetime_to_hnsec(ft) / 10000000);
622+
long long hnsec = filetime_to_hnsec(ft);
623+
ts->tv_sec = (time_t)(hnsec / 10000000);
624+
ts->tv_nsec = (hnsec % 10000000) * 100;
623625
}
624626

625627
/**
@@ -678,9 +680,9 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
678680
buf->st_size = fdata.nFileSizeLow |
679681
(((off_t)fdata.nFileSizeHigh)<<32);
680682
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
681-
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
682-
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
683-
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
683+
filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
684+
filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
685+
filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
684686
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
685687
WIN32_FIND_DATAW findbuf;
686688
HANDLE handle = FindFirstFileW(wfilename, &findbuf);
@@ -761,6 +763,29 @@ static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
761763
return do_lstat(follow, alt_name, buf);
762764
}
763765

766+
static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
767+
{
768+
BY_HANDLE_FILE_INFORMATION fdata;
769+
770+
if (!GetFileInformationByHandle(hnd, &fdata)) {
771+
errno = err_win_to_posix(GetLastError());
772+
return -1;
773+
}
774+
775+
buf->st_ino = 0;
776+
buf->st_gid = 0;
777+
buf->st_uid = 0;
778+
buf->st_nlink = 1;
779+
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
780+
buf->st_size = fdata.nFileSizeLow |
781+
(((off_t)fdata.nFileSizeHigh)<<32);
782+
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
783+
filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
784+
filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
785+
filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
786+
return 0;
787+
}
788+
764789
int mingw_lstat(const char *file_name, struct stat *buf)
765790
{
766791
return do_stat_internal(0, file_name, buf);
@@ -773,32 +798,31 @@ int mingw_stat(const char *file_name, struct stat *buf)
773798
int mingw_fstat(int fd, struct stat *buf)
774799
{
775800
HANDLE fh = (HANDLE)_get_osfhandle(fd);
776-
BY_HANDLE_FILE_INFORMATION fdata;
801+
DWORD avail, type = GetFileType(fh) & ~FILE_TYPE_REMOTE;
777802

778-
if (fh == INVALID_HANDLE_VALUE) {
779-
errno = EBADF;
780-
return -1;
781-
}
782-
/* direct non-file handles to MS's fstat() */
783-
if (GetFileType(fh) != FILE_TYPE_DISK)
784-
return _fstati64(fd, buf);
803+
switch (type) {
804+
case FILE_TYPE_DISK:
805+
return get_file_info_by_handle(fh, buf);
785806

786-
if (GetFileInformationByHandle(fh, &fdata)) {
787-
buf->st_ino = 0;
788-
buf->st_gid = 0;
789-
buf->st_uid = 0;
807+
case FILE_TYPE_CHAR:
808+
case FILE_TYPE_PIPE:
809+
/* initialize stat fields */
810+
memset(buf, 0, sizeof(*buf));
790811
buf->st_nlink = 1;
791-
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
792-
buf->st_size = fdata.nFileSizeLow |
793-
(((off_t)fdata.nFileSizeHigh)<<32);
794-
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
795-
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
796-
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
797-
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
812+
813+
if (type == FILE_TYPE_CHAR) {
814+
buf->st_mode = _S_IFCHR;
815+
} else {
816+
buf->st_mode = _S_IFIFO;
817+
if (PeekNamedPipe(fh, NULL, 0, NULL, &avail, NULL))
818+
buf->st_size = avail;
819+
}
798820
return 0;
821+
822+
default:
823+
errno = EBADF;
824+
return -1;
799825
}
800-
errno = EBADF;
801-
return -1;
802826
}
803827

804828
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
@@ -354,18 +354,41 @@ static inline int getrlimit(int resource, struct rlimit *rlp)
354354
}
355355

356356
/*
357-
* Use mingw specific stat()/lstat()/fstat() implementations on Windows.
357+
* Use mingw specific stat()/lstat()/fstat() implementations on Windows,
358+
* including our own struct stat with 64 bit st_size and nanosecond-precision
359+
* file times.
358360
*/
359361
#ifndef __MINGW64_VERSION_MAJOR
360362
#define off_t off64_t
361363
#define lseek _lseeki64
364+
struct timespec {
365+
time_t tv_sec;
366+
long tv_nsec;
367+
};
362368
#endif
363369

364-
/* use struct stat with 64 bit st_size */
370+
struct mingw_stat {
371+
_dev_t st_dev;
372+
_ino_t st_ino;
373+
_mode_t st_mode;
374+
short st_nlink;
375+
short st_uid;
376+
short st_gid;
377+
_dev_t st_rdev;
378+
off64_t st_size;
379+
struct timespec st_atim;
380+
struct timespec st_mtim;
381+
struct timespec st_ctim;
382+
};
383+
384+
#define st_atime st_atim.tv_sec
385+
#define st_mtime st_mtim.tv_sec
386+
#define st_ctime st_ctim.tv_sec
387+
365388
#ifdef stat
366389
#undef stat
367390
#endif
368-
#define stat _stati64
391+
#define stat mingw_stat
369392
int mingw_lstat(const char *file_name, struct stat *buf);
370393
int mingw_stat(const char *file_name, struct stat *buf);
371394
int mingw_fstat(int fd, struct stat *buf);
@@ -378,13 +401,6 @@ int mingw_fstat(int fd, struct stat *buf);
378401
#endif
379402
#define lstat mingw_lstat
380403

381-
#ifndef _stati64
382-
# define _stati64(x,y) mingw_stat(x,y)
383-
#elif defined (_USE_32BIT_TIME_T)
384-
# define _stat32i64(x,y) mingw_stat(x,y)
385-
#else
386-
# define _stat64(x,y) mingw_stat(x,y)
387-
#endif
388404

389405
int mingw_utime(const char *file_name, const struct utimbuf *times);
390406
#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)