fstat: use our custom `stat`
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
diff --git a/src/win32/posix.h b/src/win32/posix.h
index 732128b..5fab267 100644
--- a/src/win32/posix.h
+++ b/src/win32/posix.h
@@ -17,9 +17,10 @@
typedef SOCKET GIT_SOCKET;
#define p_lseek(f,n,w) _lseeki64(f, n, w)
-#define p_fstat(f,b) _fstat64(f, b)
+
+extern int p_fstat(int fd, struct stat *buf);
extern int p_lstat(const char *file_name, struct stat *buf);
-extern int p_stat(const char* path, struct stat* buf);
+extern int p_stat(const char* path, struct stat *buf);
extern int p_utimes(const char *filename, const struct p_timeval times[2]);
extern int p_futimes(int fd, const struct p_timeval times[2]);
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index d743e8f..fea634b 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -398,6 +398,22 @@ static int follow_and_lstat_link(git_win32_path path, struct stat* buf)
return lstat_w(target_w, buf, false);
}
+int p_fstat(int fd, struct stat *buf)
+{
+ BY_HANDLE_FILE_INFORMATION fhInfo;
+
+ HANDLE fh = (HANDLE)_get_osfhandle(fd);
+
+ if (fh == INVALID_HANDLE_VALUE ||
+ !GetFileInformationByHandle(fh, &fhInfo)) {
+ errno = EBADF;
+ return -1;
+ }
+
+ git_win32__file_information_to_stat(buf, &fhInfo);
+ return 0;
+}
+
int p_stat(const char* path, struct stat* buf)
{
git_win32_path path_w;
diff --git a/src/win32/w32_util.h b/src/win32/w32_util.h
index b095939..2e475e5 100644
--- a/src/win32/w32_util.h
+++ b/src/win32/w32_util.h
@@ -105,19 +105,25 @@ GIT_INLINE(void) git_win32__timeval_to_filetime(
ft->dwLowDateTime = (ticks & 0xffffffffLL);
}
-GIT_INLINE(int) git_win32__file_attribute_to_stat(
+GIT_INLINE(void) git_win32__stat_init(
struct stat *st,
- const WIN32_FILE_ATTRIBUTE_DATA *attrdata,
- const wchar_t *path)
+ DWORD dwFileAttributes,
+ DWORD nFileSizeHigh,
+ DWORD nFileSizeLow,
+ FILETIME ftCreationTime,
+ FILETIME ftLastAccessTime,
+ FILETIME ftLastWriteTime)
{
mode_t mode = S_IREAD;
- if (attrdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ memset(st, 0, sizeof(struct stat));
+
+ if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
mode |= S_IFDIR;
else
mode |= S_IFREG;
- if ((attrdata->dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
+ if ((dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
mode |= S_IWRITE;
st->st_ino = 0;
@@ -125,12 +131,39 @@ GIT_INLINE(int) git_win32__file_attribute_to_stat(
st->st_uid = 0;
st->st_nlink = 1;
st->st_mode = mode;
- st->st_size = ((git_off_t)attrdata->nFileSizeHigh << 32) + attrdata->nFileSizeLow;
+ st->st_size = ((git_off_t)nFileSizeHigh << 32) + nFileSizeLow;
st->st_dev = _getdrive() - 1;
st->st_rdev = st->st_dev;
- git_win32__filetime_to_timespec(&(attrdata->ftLastAccessTime), &(st->st_atim));
- git_win32__filetime_to_timespec(&(attrdata->ftLastWriteTime), &(st->st_mtim));
- git_win32__filetime_to_timespec(&(attrdata->ftCreationTime), &(st->st_ctim));
+ git_win32__filetime_to_timespec(&ftLastAccessTime, &(st->st_atim));
+ git_win32__filetime_to_timespec(&ftLastWriteTime, &(st->st_mtim));
+ git_win32__filetime_to_timespec(&ftCreationTime, &(st->st_ctim));
+}
+
+GIT_INLINE(void) git_win32__file_information_to_stat(
+ struct stat *st,
+ const BY_HANDLE_FILE_INFORMATION *fileinfo)
+{
+ git_win32__stat_init(st,
+ fileinfo->dwFileAttributes,
+ fileinfo->nFileSizeHigh,
+ fileinfo->nFileSizeLow,
+ fileinfo->ftCreationTime,
+ fileinfo->ftLastAccessTime,
+ fileinfo->ftLastWriteTime);
+}
+
+GIT_INLINE(int) git_win32__file_attribute_to_stat(
+ struct stat *st,
+ const WIN32_FILE_ATTRIBUTE_DATA *attrdata,
+ const wchar_t *path)
+{
+ git_win32__stat_init(st,
+ attrdata->dwFileAttributes,
+ attrdata->nFileSizeHigh,
+ attrdata->nFileSizeLow,
+ attrdata->ftCreationTime,
+ attrdata->ftLastAccessTime,
+ attrdata->ftLastWriteTime);
if (attrdata->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && path) {
git_win32_path target;
@@ -139,7 +172,7 @@ GIT_INLINE(int) git_win32__file_attribute_to_stat(
st->st_mode = (st->st_mode & ~S_IFMT) | S_IFLNK;
/* st_size gets the UTF-8 length of the target name, in bytes,
- * not counting the NULL terminator */
+ * not counting the NULL terminator */
if ((st->st_size = git__utf16_to_8(NULL, 0, target)) < 0) {
giterr_set(GITERR_OS, "Could not convert reparse point name for '%s'", path);
return -1;