Skip to content

Commit dc97f2f

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 17a2fa0 + 45d38aa commit dc97f2f

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
@@ -592,9 +592,11 @@ static inline long long filetime_to_hnsec(const FILETIME *ft)
592592
return winTime - 116444736000000000LL;
593593
}
594594

595-
static inline time_t filetime_to_time_t(const FILETIME *ft)
595+
static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
596596
{
597-
return (time_t)(filetime_to_hnsec(ft) / 10000000);
597+
long long hnsec = filetime_to_hnsec(ft);
598+
ts->tv_sec = (time_t)(hnsec / 10000000);
599+
ts->tv_nsec = (hnsec % 10000000) * 100;
598600
}
599601

600602
/**
@@ -653,9 +655,9 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
653655
buf->st_size = fdata.nFileSizeLow |
654656
(((off_t)fdata.nFileSizeHigh)<<32);
655657
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
656-
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
657-
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
658-
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
658+
filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
659+
filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
660+
filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
659661
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
660662
WIN32_FIND_DATAW findbuf;
661663
HANDLE handle = FindFirstFileW(wfilename, &findbuf);
@@ -736,6 +738,29 @@ static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
736738
return do_lstat(follow, alt_name, buf);
737739
}
738740

741+
static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
742+
{
743+
BY_HANDLE_FILE_INFORMATION fdata;
744+
745+
if (!GetFileInformationByHandle(hnd, &fdata)) {
746+
errno = err_win_to_posix(GetLastError());
747+
return -1;
748+
}
749+
750+
buf->st_ino = 0;
751+
buf->st_gid = 0;
752+
buf->st_uid = 0;
753+
buf->st_nlink = 1;
754+
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
755+
buf->st_size = fdata.nFileSizeLow |
756+
(((off_t)fdata.nFileSizeHigh)<<32);
757+
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
758+
filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
759+
filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
760+
filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
761+
return 0;
762+
}
763+
739764
int mingw_lstat(const char *file_name, struct stat *buf)
740765
{
741766
return do_stat_internal(0, file_name, buf);
@@ -748,32 +773,31 @@ int mingw_stat(const char *file_name, struct stat *buf)
748773
int mingw_fstat(int fd, struct stat *buf)
749774
{
750775
HANDLE fh = (HANDLE)_get_osfhandle(fd);
751-
BY_HANDLE_FILE_INFORMATION fdata;
776+
DWORD avail, type = GetFileType(fh) & ~FILE_TYPE_REMOTE;
752777

753-
if (fh == INVALID_HANDLE_VALUE) {
754-
errno = EBADF;
755-
return -1;
756-
}
757-
/* direct non-file handles to MS's fstat() */
758-
if (GetFileType(fh) != FILE_TYPE_DISK)
759-
return _fstati64(fd, buf);
778+
switch (type) {
779+
case FILE_TYPE_DISK:
780+
return get_file_info_by_handle(fh, buf);
760781

761-
if (GetFileInformationByHandle(fh, &fdata)) {
762-
buf->st_ino = 0;
763-
buf->st_gid = 0;
764-
buf->st_uid = 0;
782+
case FILE_TYPE_CHAR:
783+
case FILE_TYPE_PIPE:
784+
/* initialize stat fields */
785+
memset(buf, 0, sizeof(*buf));
765786
buf->st_nlink = 1;
766-
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
767-
buf->st_size = fdata.nFileSizeLow |
768-
(((off_t)fdata.nFileSizeHigh)<<32);
769-
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
770-
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
771-
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
772-
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
787+
788+
if (type == FILE_TYPE_CHAR) {
789+
buf->st_mode = _S_IFCHR;
790+
} else {
791+
buf->st_mode = _S_IFIFO;
792+
if (PeekNamedPipe(fh, NULL, 0, NULL, &avail, NULL))
793+
buf->st_size = avail;
794+
}
773795
return 0;
796+
797+
default:
798+
errno = EBADF;
799+
return -1;
774800
}
775-
errno = EBADF;
776-
return -1;
777801
}
778802

779803
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
@@ -330,18 +330,41 @@ static inline int getrlimit(int resource, struct rlimit *rlp)
330330
}
331331

332332
/*
333-
* Use mingw specific stat()/lstat()/fstat() implementations on Windows.
333+
* Use mingw specific stat()/lstat()/fstat() implementations on Windows,
334+
* including our own struct stat with 64 bit st_size and nanosecond-precision
335+
* file times.
334336
*/
335337
#ifndef __MINGW64_VERSION_MAJOR
336338
#define off_t off64_t
337339
#define lseek _lseeki64
340+
struct timespec {
341+
time_t tv_sec;
342+
long tv_nsec;
343+
};
338344
#endif
339345

340-
/* use struct stat with 64 bit st_size */
346+
struct mingw_stat {
347+
_dev_t st_dev;
348+
_ino_t st_ino;
349+
_mode_t st_mode;
350+
short st_nlink;
351+
short st_uid;
352+
short st_gid;
353+
_dev_t st_rdev;
354+
off64_t st_size;
355+
struct timespec st_atim;
356+
struct timespec st_mtim;
357+
struct timespec st_ctim;
358+
};
359+
360+
#define st_atime st_atim.tv_sec
361+
#define st_mtime st_mtim.tv_sec
362+
#define st_ctime st_ctim.tv_sec
363+
341364
#ifdef stat
342365
#undef stat
343366
#endif
344-
#define stat _stati64
367+
#define stat mingw_stat
345368
int mingw_lstat(const char *file_name, struct stat *buf);
346369
int mingw_stat(const char *file_name, struct stat *buf);
347370
int mingw_fstat(int fd, struct stat *buf);
@@ -354,13 +377,6 @@ int mingw_fstat(int fd, struct stat *buf);
354377
#endif
355378
#define lstat mingw_lstat
356379

357-
#ifndef _stati64
358-
# define _stati64(x,y) mingw_stat(x,y)
359-
#elif defined (_USE_32BIT_TIME_T)
360-
# define _stat32i64(x,y) mingw_stat(x,y)
361-
#else
362-
# define _stat64(x,y) mingw_stat(x,y)
363-
#endif
364380

365381
int mingw_utime(const char *file_name, const struct utimbuf *times);
366382
#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
@@ -520,7 +519,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
520519
RUNTIME_PREFIX = YesPlease
521520
HAVE_WPGMPTR = YesWeDo
522521
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
523-
NO_NSEC = YesPlease
524522
USE_WIN32_MMAP = YesPlease
525523
MMAP_PREVENTS_DELETE = UnfortunatelyYes
526524
USE_NED_ALLOCATOR = YesPlease

0 commit comments

Comments
 (0)