Skip to content

Commit b9c3f06

Browse files
committed
Merge branch 'js/mingw-ns-filetime'
Windows port learned to use nano-second resolution file timestamps. * js/mingw-ns-filetime: mingw: implement nanosecond-precision file times mingw: replace MSVCRT's fstat() with a Win32-based implementation mingw: factor out code to set stat() data
2 parents a29b8bc + d7e8c87 commit b9c3f06

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

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

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

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

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

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

805829
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
@@ -327,18 +327,41 @@ static inline int getrlimit(int resource, struct rlimit *rlp)
327327
}
328328

329329
/*
330-
* Use mingw specific stat()/lstat()/fstat() implementations on Windows.
330+
* Use mingw specific stat()/lstat()/fstat() implementations on Windows,
331+
* including our own struct stat with 64 bit st_size and nanosecond-precision
332+
* file times.
331333
*/
332334
#ifndef __MINGW64_VERSION_MAJOR
333335
#define off_t off64_t
334336
#define lseek _lseeki64
337+
struct timespec {
338+
time_t tv_sec;
339+
long tv_nsec;
340+
};
335341
#endif
336342

337-
/* use struct stat with 64 bit st_size */
343+
struct mingw_stat {
344+
_dev_t st_dev;
345+
_ino_t st_ino;
346+
_mode_t st_mode;
347+
short st_nlink;
348+
short st_uid;
349+
short st_gid;
350+
_dev_t st_rdev;
351+
off64_t st_size;
352+
struct timespec st_atim;
353+
struct timespec st_mtim;
354+
struct timespec st_ctim;
355+
};
356+
357+
#define st_atime st_atim.tv_sec
358+
#define st_mtime st_mtim.tv_sec
359+
#define st_ctime st_ctim.tv_sec
360+
338361
#ifdef stat
339362
#undef stat
340363
#endif
341-
#define stat _stati64
364+
#define stat mingw_stat
342365
int mingw_lstat(const char *file_name, struct stat *buf);
343366
int mingw_stat(const char *file_name, struct stat *buf);
344367
int mingw_fstat(int fd, struct stat *buf);
@@ -351,13 +374,6 @@ int mingw_fstat(int fd, struct stat *buf);
351374
#endif
352375
#define lstat mingw_lstat
353376

354-
#ifndef _stati64
355-
# define _stati64(x,y) mingw_stat(x,y)
356-
#elif defined (_USE_32BIT_TIME_T)
357-
# define _stat32i64(x,y) mingw_stat(x,y)
358-
#else
359-
# define _stat64(x,y) mingw_stat(x,y)
360-
#endif
361377

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