Merge branch 'js/mingw-perl5lib'
[git/git.git] / compat / mingw.c
index 181e74c..e8e538a 100644 (file)
@@ -648,9 +648,11 @@ static inline long long filetime_to_hnsec(const FILETIME *ft)
        return winTime - 116444736000000000LL;
 }
 
-static inline time_t filetime_to_time_t(const FILETIME *ft)
+static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
 {
-       return (time_t)(filetime_to_hnsec(ft) / 10000000);
+       long long hnsec = filetime_to_hnsec(ft);
+       ts->tv_sec = (time_t)(hnsec / 10000000);
+       ts->tv_nsec = (hnsec % 10000000) * 100;
 }
 
 /**
@@ -709,9 +711,9 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
                buf->st_size = fdata.nFileSizeLow |
                        (((off_t)fdata.nFileSizeHigh)<<32);
                buf->st_dev = buf->st_rdev = 0; /* not used by Git */
-               buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
-               buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
-               buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
+               filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
+               filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
+               filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
                if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
                        WIN32_FIND_DATAW findbuf;
                        HANDLE handle = FindFirstFileW(wfilename, &findbuf);
@@ -792,6 +794,29 @@ static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
        return do_lstat(follow, alt_name, buf);
 }
 
+static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
+{
+       BY_HANDLE_FILE_INFORMATION fdata;
+
+       if (!GetFileInformationByHandle(hnd, &fdata)) {
+               errno = err_win_to_posix(GetLastError());
+               return -1;
+       }
+
+       buf->st_ino = 0;
+       buf->st_gid = 0;
+       buf->st_uid = 0;
+       buf->st_nlink = 1;
+       buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
+       buf->st_size = fdata.nFileSizeLow |
+               (((off_t)fdata.nFileSizeHigh)<<32);
+       buf->st_dev = buf->st_rdev = 0; /* not used by Git */
+       filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
+       filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
+       filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
+       return 0;
+}
+
 int mingw_lstat(const char *file_name, struct stat *buf)
 {
        return do_stat_internal(0, file_name, buf);
@@ -804,32 +829,31 @@ int mingw_stat(const char *file_name, struct stat *buf)
 int mingw_fstat(int fd, struct stat *buf)
 {
        HANDLE fh = (HANDLE)_get_osfhandle(fd);
-       BY_HANDLE_FILE_INFORMATION fdata;
+       DWORD avail, type = GetFileType(fh) & ~FILE_TYPE_REMOTE;
 
-       if (fh == INVALID_HANDLE_VALUE) {
-               errno = EBADF;
-               return -1;
-       }
-       /* direct non-file handles to MS's fstat() */
-       if (GetFileType(fh) != FILE_TYPE_DISK)
-               return _fstati64(fd, buf);
+       switch (type) {
+       case FILE_TYPE_DISK:
+               return get_file_info_by_handle(fh, buf);
 
-       if (GetFileInformationByHandle(fh, &fdata)) {
-               buf->st_ino = 0;
-               buf->st_gid = 0;
-               buf->st_uid = 0;
+       case FILE_TYPE_CHAR:
+       case FILE_TYPE_PIPE:
+               /* initialize stat fields */
+               memset(buf, 0, sizeof(*buf));
                buf->st_nlink = 1;
-               buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
-               buf->st_size = fdata.nFileSizeLow |
-                       (((off_t)fdata.nFileSizeHigh)<<32);
-               buf->st_dev = buf->st_rdev = 0; /* not used by Git */
-               buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
-               buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
-               buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
+
+               if (type == FILE_TYPE_CHAR) {
+                       buf->st_mode = _S_IFCHR;
+               } else {
+                       buf->st_mode = _S_IFIFO;
+                       if (PeekNamedPipe(fh, NULL, 0, NULL, &avail, NULL))
+                               buf->st_size = avail;
+               }
                return 0;
+
+       default:
+               errno = EBADF;
+               return -1;
        }
-       errno = EBADF;
-       return -1;
 }
 
 static inline void time_t_to_filetime(time_t t, FILETIME *ft)