[PATCH] Add a fast version of fstat to cygwin port
From: Alex Riesen <hidden>
Date: 2016-06-15 22:46:25
Besides, the output of the fast stat and lstat is not compatible with cygwin's fstat with regard to uid, gid and ctime fields. Signed-off-by: Alex Riesen <redacted> --- This is not strictly related to the other stat patches. The fstat code is shamelessly stolen from the mingw port, sorry. BTW, why do we have to #undef fstat, but not stat/lstat? compat/cygwin.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++--- compat/cygwin.h | 2 + 2 files changed, 58 insertions(+), 4 deletions(-)
diff --git a/compat/cygwin.c b/compat/cygwin.c
index ebac148..e91af4f 100644
--- a/compat/cygwin.c
+++ b/compat/cygwin.c@@ -15,6 +15,18 @@ static inline void filetime_to_timespec(constFILETIME *ft, struct timespec *ts)
#define size_to_blocks(s) (((s)+511)/512)
+/*
+ * Initialize the fields of struct stat which this implementation
+ * considers constant on this platform. See also mingw.c
+ */
+static void dosify_statbuf(struct stat *buf)
+{
+ buf->st_dev = buf->st_rdev = 0; /* not used by Git */
+ buf->st_ino = 0;
+ buf->st_nlink = 1;
+ buf->st_uid = buf->st_gid = 0;
+}
+
/* do_stat is a common implementation for cygwin_lstat and cygwin_stat.
*
* To simplify its logic, in the case of cygwin symlinks, this implementation@@ -41,11 +53,8 @@ static int do_stat(const char *file_name, structstat *buf, stat_fn_t cygstat) return cygstat(file_name, buf); /* fill out the stat structure */ - buf->st_dev = buf->st_rdev = 0; /* not used by Git */ - buf->st_ino = 0; + dosify_statbuf(buf); buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); - buf->st_nlink = 1; - buf->st_uid = buf->st_gid = 0; #ifdef __CYGWIN_USE_BIG_TYPES__ buf->st_size = ((_off64_t)fdata.nFileSizeHigh << 32) + fdata.nFileSizeLow;
@@ -85,6 +94,41 @@ static int cygwin_stat(const char *path, struct stat *buf) return do_stat(path, buf, stat); } +#undef fstat +static int cygwin_fstat(int fd, struct stat *buf) +{ + HANDLE fh = (HANDLE)_get_osfhandle(fd); + BY_HANDLE_FILE_INFORMATION fdata; + + if (fh == INVALID_HANDLE_VALUE) { + errno = EBADF; + return -1; + } + /* direct non-file handles to cygwin's fstat() */ + if (GetFileType(fh) != FILE_TYPE_DISK) + return fstat(fd, buf); + + if (!buf) { + errno = EINVAL; + return -1; + } + if (GetFileInformationByHandle(fh, &fdata)) { + dosify_statbuf(buf); + buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); +#ifdef __CYGWIN_USE_BIG_TYPES__ + buf->st_size = ((_off64_t)fdata.nFileSizeHigh << 32) + + fdata.nFileSizeLow; +#else + buf->st_size = (off_t)fdata.nFileSizeLow; +#endif + 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; + } + errno = EBADF; + return -1; +} /* * At start up, we are trying to determine whether Win32 API or cygwin stat
@@ -119,9 +163,11 @@ static int init_stat(void) if (!core_filemode && native_stat) { cygwin_stat_fn = cygwin_stat; cygwin_lstat_fn = cygwin_lstat; + cygwin_fstat_fn = cygwin_fstat; } else { cygwin_stat_fn = stat; cygwin_lstat_fn = lstat; + cygwin_fstat_fn = fstat; } return 0; }
@@ -138,6 +184,12 @@ static int cygwin_lstat_stub(const char*file_name, struct stat *buf)
return (init_stat() ? lstat : *cygwin_lstat_fn)(file_name, buf);
}
+static int cygwin_fstat_stub(int fd, struct stat *buf)
+{
+ return (init_stat() ? fstat : *cygwin_fstat_fn)(fd, buf);
+}
+
stat_fn_t cygwin_stat_fn = cygwin_stat_stub;
stat_fn_t cygwin_lstat_fn = cygwin_lstat_stub;
+int (*cygwin_fstat_fn)(int fd, struct stat *) = cygwin_fstat_stub;
diff --git a/compat/cygwin.h b/compat/cygwin.h
index a3229f5..fd54c82 100644
--- a/compat/cygwin.h
+++ b/compat/cygwin.h@@ -4,6 +4,8 @@ typedef int (*stat_fn_t)(const char*, struct stat*); extern stat_fn_t cygwin_stat_fn; extern stat_fn_t cygwin_lstat_fn; +extern int (*cygwin_fstat_fn)(int fd, struct stat *); #define stat(path, buf) (*cygwin_stat_fn)(path, buf) #define lstat(path, buf) (*cygwin_lstat_fn)(path, buf) +#define fstat(fd, buf) (*cygwin_fstat_fn)(fd, buf)
--
1.6.2.142.gaf8db