{"thread":{"id":"18406","subject":"[PATCH] Add a fast version of fstat to cygwin port","startedAt":"2009-03-19T14:30:12Z","lastAt":"2009-03-19T15:14:31Z","messageCount":3,"participants":["Alex Riesen","Johannes Sixt"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"108528","messageId":"81b0412b0903190730s40589291iea9a861ddeedcc0@mail.gmail.com","threadId":"18406","inReplyTo":null,"subject":"[PATCH] Add a fast version of fstat to cygwin port","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-03-19T14:30:12Z","receivedAt":"2009-03-19T14:30:12Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"Besides, the output of the fast stat and lstat is not compatible\nwith cygwin's fstat with regard to uid, gid and ctime fields.\n\nSigned-off-by: Alex Riesen <raa.lkml@gmail.com>\n---\n\nThis is not strictly related to the other stat patches. The fstat\ncode is shamelessly stolen from the mingw port, sorry.\n\nBTW, why do we have to #undef fstat, but not stat/lstat?\n\n compat/cygwin.c |   60 +++++++++++++++++++++++++++++++++++++++++++++++++++---\n compat/cygwin.h |    2 +\n 2 files changed, 58 insertions(+), 4 deletions(-)\n\ndiff --git a/compat/cygwin.c b/compat/cygwin.c\nindex ebac148..e91af4f 100644\n--- a/compat/cygwin.c\n+++ b/compat/cygwin.c\n@@ -15,6 +15,18 @@ static inline void filetime_to_timespec(const\nFILETIME *ft, struct timespec *ts)\n\n #define size_to_blocks(s) (((s)+511)/512)\n\n+/*\n+ * Initialize the fields of struct stat which this implementation\n+ * considers constant on this platform. See also mingw.c\n+ */\n+static void dosify_statbuf(struct stat *buf)\n+{\n+\tbuf->st_dev = buf->st_rdev = 0; /* not used by Git */\n+\tbuf->st_ino = 0;\n+\tbuf->st_nlink = 1;\n+\tbuf->st_uid = buf->st_gid = 0;\n+}\n+\n /* do_stat is a common implementation for cygwin_lstat and cygwin_stat.\n  *\n  * To simplify its logic, in the case of cygwin symlinks, this implementation\n@@ -41,11 +53,8 @@ static int do_stat(const char *file_name, struct\nstat *buf, stat_fn_t cygstat)\n \t\t\treturn cygstat(file_name, buf);\n\n \t\t/* fill out the stat structure */\n-\t\tbuf->st_dev = buf->st_rdev = 0; /* not used by Git */\n-\t\tbuf->st_ino = 0;\n+\t\tdosify_statbuf(buf);\n \t\tbuf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);\n-\t\tbuf->st_nlink = 1;\n-\t\tbuf->st_uid = buf->st_gid = 0;\n #ifdef __CYGWIN_USE_BIG_TYPES__\n \t\tbuf->st_size = ((_off64_t)fdata.nFileSizeHigh << 32) +\n \t\t\tfdata.nFileSizeLow;\n@@ -85,6 +94,41 @@ static int cygwin_stat(const char *path, struct stat *buf)\n \treturn do_stat(path, buf, stat);\n }\n\n+#undef fstat\n+static int cygwin_fstat(int fd, struct stat *buf)\n+{\n+\tHANDLE fh = (HANDLE)_get_osfhandle(fd);\n+\tBY_HANDLE_FILE_INFORMATION fdata;\n+\n+\tif (fh == INVALID_HANDLE_VALUE) {\n+\t\terrno = EBADF;\n+\t\treturn -1;\n+\t}\n+\t/* direct non-file handles to cygwin's fstat() */\n+\tif (GetFileType(fh) != FILE_TYPE_DISK)\n+\t\treturn fstat(fd, buf);\n+\n+\tif (!buf) {\n+\t\terrno = EINVAL;\n+\t\treturn -1;\n+\t}\n+\tif (GetFileInformationByHandle(fh, &fdata)) {\n+\t\tdosify_statbuf(buf);\n+\t\tbuf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);\n+#ifdef __CYGWIN_USE_BIG_TYPES__\n+\t\tbuf->st_size = ((_off64_t)fdata.nFileSizeHigh << 32) +\n+\t\t\tfdata.nFileSizeLow;\n+#else\n+\t\tbuf->st_size = (off_t)fdata.nFileSizeLow;\n+#endif\n+\t\tfiletime_to_timespec(&fdata.ftLastAccessTime, &buf->st_atim);\n+\t\tfiletime_to_timespec(&fdata.ftLastWriteTime, &buf->st_mtim);\n+\t\tfiletime_to_timespec(&fdata.ftCreationTime, &buf->st_ctim);\n+\t\treturn 0;\n+\t}\n+\terrno = EBADF;\n+\treturn -1;\n+}\n\n /*\n  * At start up, we are trying to determine whether Win32 API or cygwin stat\n@@ -119,9 +163,11 @@ static int init_stat(void)\n \t\tif (!core_filemode && native_stat) {\n \t\t\tcygwin_stat_fn = cygwin_stat;\n \t\t\tcygwin_lstat_fn = cygwin_lstat;\n+\t\t\tcygwin_fstat_fn = cygwin_fstat;\n \t\t} else {\n \t\t\tcygwin_stat_fn = stat;\n \t\t\tcygwin_lstat_fn = lstat;\n+\t\t\tcygwin_fstat_fn = fstat;\n \t\t}\n \t\treturn 0;\n \t}\n@@ -138,6 +184,12 @@ static int cygwin_lstat_stub(const char\n*file_name, struct stat *buf)\n \treturn (init_stat() ? lstat : *cygwin_lstat_fn)(file_name, buf);\n }\n\n+static int cygwin_fstat_stub(int fd, struct stat *buf)\n+{\n+\treturn (init_stat() ? fstat : *cygwin_fstat_fn)(fd, buf);\n+}\n+\n stat_fn_t cygwin_stat_fn = cygwin_stat_stub;\n stat_fn_t cygwin_lstat_fn = cygwin_lstat_stub;\n+int (*cygwin_fstat_fn)(int fd, struct stat *) = cygwin_fstat_stub;\n\ndiff --git a/compat/cygwin.h b/compat/cygwin.h\nindex a3229f5..fd54c82 100644\n--- a/compat/cygwin.h\n+++ b/compat/cygwin.h\n@@ -4,6 +4,8 @@\n typedef int (*stat_fn_t)(const char*, struct stat*);\n extern stat_fn_t cygwin_stat_fn;\n extern stat_fn_t cygwin_lstat_fn;\n+extern int (*cygwin_fstat_fn)(int fd, struct stat *);\n\n #define stat(path, buf) (*cygwin_stat_fn)(path, buf)\n #define lstat(path, buf) (*cygwin_lstat_fn)(path, buf)\n+#define fstat(fd, buf) (*cygwin_fstat_fn)(fd, buf)\n-- \n1.6.2.142.gaf8db\n\n\nFrom 47a66bf7f03106e5c48f7002a67a95bbc6959794 Mon Sep 17 00:00:00 2001\nFrom: Alex Riesen <raa.lkml@gmail.com>\nDate: Thu, 19 Mar 2009 15:18:00 +0100\nSubject: [PATCH] Add a fast version of fstat to cygwin port\n\nBesides, the output of the fast stat and lstat is not compatible\nwith cygwin's fstat with regard to uid, gid and ctime fields.\n\nSigned-off-by: Alex Riesen <raa.lkml@gmail.com>\n---\n compat/cygwin.c |   60 +++++++++++++++++++++++++++++++++++++++++++++++++++---\n compat/cygwin.h |    2 +\n 2 files changed, 58 insertions(+), 4 deletions(-)\n\ndiff --git a/compat/cygwin.c b/compat/cygwin.c\nindex ebac148..e91af4f 100644\n--- a/compat/cygwin.c\n+++ b/compat/cygwin.c\n@@ -15,6 +15,18 @@ static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)\n \n #define size_to_blocks(s) (((s)+511)/512)\n \n+/*\n+ * Initialize the fields of struct stat which this implementation\n+ * considers constant on this platform. See also mingw.c\n+ */\n+static void dosify_statbuf(struct stat *buf)\n+{\n+\tbuf->st_dev = buf->st_rdev = 0; /* not used by Git */\n+\tbuf->st_ino = 0;\n+\tbuf->st_nlink = 1;\n+\tbuf->st_uid = buf->st_gid = 0;\n+}\n+\n /* do_stat is a common implementation for cygwin_lstat and cygwin_stat.\n  *\n  * To simplify its logic, in the case of cygwin symlinks, this implementation\n@@ -41,11 +53,8 @@ static int do_stat(const char *file_name, struct stat *buf, stat_fn_t cygstat)\n \t\t\treturn cygstat(file_name, buf);\n \n \t\t/* fill out the stat structure */\n-\t\tbuf->st_dev = buf->st_rdev = 0; /* not used by Git */\n-\t\tbuf->st_ino = 0;\n+\t\tdosify_statbuf(buf);\n \t\tbuf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);\n-\t\tbuf->st_nlink = 1;\n-\t\tbuf->st_uid = buf->st_gid = 0;\n #ifdef __CYGWIN_USE_BIG_TYPES__\n \t\tbuf->st_size = ((_off64_t)fdata.nFileSizeHigh << 32) +\n \t\t\tfdata.nFileSizeLow;\n@@ -85,6 +94,41 @@ static int cygwin_stat(const char *path, struct stat *buf)\n \treturn do_stat(path, buf, stat);\n }\n \n+#undef fstat\n+static int cygwin_fstat(int fd, struct stat *buf)\n+{\n+\tHANDLE fh = (HANDLE)_get_osfhandle(fd);\n+\tBY_HANDLE_FILE_INFORMATION fdata;\n+\n+\tif (fh == INVALID_HANDLE_VALUE) {\n+\t\terrno = EBADF;\n+\t\treturn -1;\n+\t}\n+\t/* direct non-file handles to cygwin's fstat() */\n+\tif (GetFileType(fh) != FILE_TYPE_DISK)\n+\t\treturn fstat(fd, buf);\n+\n+\tif (!buf) {\n+\t\terrno = EINVAL;\n+\t\treturn -1;\n+\t}\n+\tif (GetFileInformationByHandle(fh, &fdata)) {\n+\t\tdosify_statbuf(buf);\n+\t\tbuf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);\n+#ifdef __CYGWIN_USE_BIG_TYPES__\n+\t\tbuf->st_size = ((_off64_t)fdata.nFileSizeHigh << 32) +\n+\t\t\tfdata.nFileSizeLow;\n+#else\n+\t\tbuf->st_size = (off_t)fdata.nFileSizeLow;\n+#endif\n+\t\tfiletime_to_timespec(&fdata.ftLastAccessTime, &buf->st_atim);\n+\t\tfiletime_to_timespec(&fdata.ftLastWriteTime, &buf->st_mtim);\n+\t\tfiletime_to_timespec(&fdata.ftCreationTime, &buf->st_ctim);\n+\t\treturn 0;\n+\t}\n+\terrno = EBADF;\n+\treturn -1;\n+}\n \n /*\n  * At start up, we are trying to determine whether Win32 API or cygwin stat\n@@ -119,9 +163,11 @@ static int init_stat(void)\n \t\tif (!core_filemode && native_stat) {\n \t\t\tcygwin_stat_fn = cygwin_stat;\n \t\t\tcygwin_lstat_fn = cygwin_lstat;\n+\t\t\tcygwin_fstat_fn = cygwin_fstat;\n \t\t} else {\n \t\t\tcygwin_stat_fn = stat;\n \t\t\tcygwin_lstat_fn = lstat;\n+\t\t\tcygwin_fstat_fn = fstat;\n \t\t}\n \t\treturn 0;\n \t}\n@@ -138,6 +184,12 @@ static int cygwin_lstat_stub(const char *file_name, struct stat *buf)\n \treturn (init_stat() ? lstat : *cygwin_lstat_fn)(file_name, buf);\n }\n \n+static int cygwin_fstat_stub(int fd, struct stat *buf)\n+{\n+\treturn (init_stat() ? fstat : *cygwin_fstat_fn)(fd, buf);\n+}\n+\n stat_fn_t cygwin_stat_fn = cygwin_stat_stub;\n stat_fn_t cygwin_lstat_fn = cygwin_lstat_stub;\n+int (*cygwin_fstat_fn)(int fd, struct stat *) = cygwin_fstat_stub;\n \ndiff --git a/compat/cygwin.h b/compat/cygwin.h\nindex a3229f5..fd54c82 100644\n--- a/compat/cygwin.h\n+++ b/compat/cygwin.h\n@@ -4,6 +4,8 @@\n typedef int (*stat_fn_t)(const char*, struct stat*);\n extern stat_fn_t cygwin_stat_fn;\n extern stat_fn_t cygwin_lstat_fn;\n+extern int (*cygwin_fstat_fn)(int fd, struct stat *);\n \n #define stat(path, buf) (*cygwin_stat_fn)(path, buf)\n #define lstat(path, buf) (*cygwin_lstat_fn)(path, buf)\n+#define fstat(fd, buf) (*cygwin_fstat_fn)(fd, buf)\n-- \n1.6.2.142.gaf8db\n\n"},{"id":"108530","messageId":"49C25CAE.6000003@viscovery.net","threadId":"18406","inReplyTo":"81b0412b0903190730s40589291iea9a861ddeedcc0@mail.gmail.com","subject":"Re: [PATCH] Add a fast version of fstat to cygwin port","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-03-19T14:54:38Z","receivedAt":"2009-03-19T14:54:38Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Alex Riesen schrieb:\n> Besides, the output of the fast stat and lstat is not compatible\n> with cygwin's fstat with regard to uid, gid and ctime fields.\n\nWhy do you need this? I don't think that fstat() is used in a critical\npath. Do you see problems with the incompatible fields?\n\n> This is not strictly related to the other stat patches. The fstat\n> code is shamelessly stolen from the mingw port, sorry.\n\nI wouldn't call it \"stolen\", but \"copied\". Because if you copy it, it\nbecomes your responsibility and all copied bugs are yours ;)\n\n> BTW, why do we have to #undef fstat, but not stat/lstat?\n\nBecause stat and lstat are #defined with an argument list, but in those\ninstances where the cygwin version of stat/lstat is meant, they are used\n*without* argument list (see cygwin_stat/lstat_stub), and no macro\nexpansion happens, and therefore we don't need to #undef the macro.\n\nOTOH, do_fstat calls into cygwin's fstat() if the file handle is not a\nfile and uses an argument list that would cause a macro expansion if it\nwere not #undef'd:\n\n> +#undef fstat\n> +static int cygwin_fstat(int fd, struct stat *buf)\n> +{\n> +\tHANDLE fh = (HANDLE)_get_osfhandle(fd);\n> +\tBY_HANDLE_FILE_INFORMATION fdata;\n> +\n> +\tif (fh == INVALID_HANDLE_VALUE) {\n> +\t\terrno = EBADF;\n> +\t\treturn -1;\n> +\t}\n> +\t/* direct non-file handles to cygwin's fstat() */\n> +\tif (GetFileType(fh) != FILE_TYPE_DISK)\n> +\t\treturn fstat(fd, buf);\n\nWe never do that for stat/lstat.\n\n-- Hannes\n"},{"id":"108535","messageId":"81b0412b0903190814i254ee2d1yc39035e78d7ad3d8@mail.gmail.com","threadId":"18406","inReplyTo":"49C25CAE.6000003@viscovery.net","subject":"Re: [PATCH] Add a fast version of fstat to cygwin port","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-03-19T15:14:31Z","receivedAt":"2009-03-19T15:14:31Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"2009/3/19 Johannes Sixt <j.sixt@viscovery.net>:\n> Alex Riesen schrieb:\n>> BTW, why do we have to #undef fstat, but not stat/lstat?\n>\n> Because stat and lstat are #defined with an argument list, but in those\n> instances where the cygwin version of stat/lstat is meant, they are used\n> *without* argument list (see cygwin_stat/lstat_stub), and no macro\n> expansion happens, and therefore we don't need to #undef the macro.\n>\n> OTOH, do_fstat calls into cygwin's fstat() if the file handle is not a\n> file and uses an argument list that would cause a macro expansion if it\n> were not #undef'd:\n>\n...\n>> +     /* direct non-file handles to cygwin's fstat() */\n>> +     if (GetFileType(fh) != FILE_TYPE_DISK)\n>> +             return fstat(fd, buf);\n>\n> We never do that for stat/lstat.\n\nI see. Not immediately obvious :)\nThanks!\n"}]}