{"thread":{"id":"15635","subject":"[PATCH] add GIT_FAST_STAT mode for Cygwin","startedAt":"2008-09-23T14:06:17Z","lastAt":"2008-09-27T10:39:11Z","messageCount":25,"participants":["Dmitry Potapov","Alex Riesen","Shawn O. Pearce","Jakub Narebski","Johannes Sixt","Marcus Griep"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"91396","messageId":"20080923140144.GN21650@dpotapov.dyndns.org","threadId":"15635","inReplyTo":null,"subject":"[PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Dmitry Potapov","fromEmail":"dpotapov@gmail.com","sentAt":"2008-09-23T14:06:17Z","receivedAt":"2008-09-23T14:06:17Z","isPatch":true,"sender":{"key":"dpotapov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6568595?v=4"},"body":"This patch introduces the GIT_FAST_STAT environment variable. If this\nvariable is not set then Git will work as before. However, if it is set\nthen the Cygwin version of Git will try to use a Win32 API function if\nit is possible to speed up stat/lstat.\n\nThis fast mode works only for relative paths. It is assumed that the\nwhole repository is located inside one directory without using Cygwin\nmount to bind external paths inside of the current tree.\n\nSymbol links are supported by falling back on the cygwin version of\nthese functions.\n\nA very superficial testing shows 'git status' in the fast mode works more\nthan twice faster than in the normal mode, i.e. with about the same speed\nas the native MinGW version.\n\nSigned-off-by: Dmitry Potapov <dpotapov@gmail.com>\n---\n\nAfter getting used to how strikingly fast Git is on Linux, using Git on\nWindows (even only for a few hours) was not so pleasant. So, here is\nthis patch.\n\nFor those who wonder why I don't know use MinGW version of Git, the\nanswer is simple -- I have Cygwin install and I happy with it, while\nthe MinGW version comes with MSYS, so it cannot be used in Cygwin.\n\n Makefile          |    4 ++\n compat/cygwin.c   |  133 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n compat/cygwin.h   |    9 ++++\n git-compat-util.h |    1 +\n 4 files changed, 147 insertions(+), 0 deletions(-)\n create mode 100644 compat/cygwin.c\n create mode 100644 compat/cygwin.h\n\ndiff --git a/Makefile b/Makefile\nindex 3c0664a..0708390 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -347,6 +347,7 @@ LIB_H += cache.h\n LIB_H += cache-tree.h\n LIB_H += commit.h\n LIB_H += compat/mingw.h\n+LIB_H += compat/cygwin.h\n LIB_H += csum-file.h\n LIB_H += decorate.h\n LIB_H += delta.h\n@@ -747,6 +748,9 @@ ifeq ($(uname_S),HP-UX)\n \tNO_SYS_SELECT_H = YesPlease\n \tSNPRINTF_RETURNS_BOGUS = YesPlease\n endif\n+ifneq (,$(findstring CYGWIN,$(uname_S)))\n+\tCOMPAT_OBJS += compat/cygwin.o\n+endif\n ifneq (,$(findstring MINGW,$(uname_S)))\n \tNO_MMAP = YesPlease\n \tNO_PREAD = YesPlease\ndiff --git a/compat/cygwin.c b/compat/cygwin.c\nnew file mode 100644\nindex 0000000..0b63d2f\n--- /dev/null\n+++ b/compat/cygwin.c\n@@ -0,0 +1,133 @@\n+#define WIN32_LEAN_AND_MEAN\n+#include \"../git-compat-util.h\"\n+#include <windows.h>\n+\n+static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)\n+{\n+\tlong long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;\n+\twinTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */\n+\tts->tv_sec = (time_t)(winTime/10000000); /* 100-nanosecond interval to seconds */\n+\tts->tv_nsec = (long)(winTime - ts->tv_sec) * 100; /* nanoseconds */\n+}\n+\n+#define size_to_blocks(s) (((s)+511)/512)\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+ * falls back to the cygwin version of stat/lstat, which is provided as the\n+ * last argument.\n+ */\n+static int do_stat(const char *file_name, struct stat *buf, stat_fn_t cygstat)\n+{\n+\tWIN32_FILE_ATTRIBUTE_DATA fdata;\n+\n+\tif (file_name[0] == '/')\n+\t\treturn cygstat (file_name, buf);\n+\n+\tif (GetFileAttributesExA(file_name, GetFileExInfoStandard, &fdata)) {\n+\t\tint fMode = S_IREAD;\n+\t\t/*\n+\t\t * If the system attribute is set and it is not a directory then\n+\t\t * it could be a symbol link created in the nowinsymlinks mode.\n+\t\t * Normally, Cygwin works in the winsymlinks mode, so this situation\n+\t\t * is very unlikely. For the sake of simplicity of our code, let's\n+\t\t * Cygwin to handle it.\n+\t\t */\n+\t\tif ((fdata.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) &&\n+\t\t    !(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))\n+\t\t\treturn cygstat (file_name, buf);\n+\n+\t\tif (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)\n+\t\t\tfMode |= S_IFDIR;\n+\t\telse\n+\t\t\tfMode |= S_IFREG;\n+\t\tif (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))\n+\t\t\tfMode |= S_IWRITE;\n+\n+\t\t/* st_dev, st_rdev are not used by Git */\n+\t\tbuf->st_dev = buf->st_rdev = 0;\n+\t\t/* it is difficult to obtain the inode number on Windows,\n+\t\t * so let's set it to zero as MinGW Git does. */\n+\t\tbuf->st_ino = 0;\n+\t\tbuf->st_mode = fMode;\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+#else\n+\t\tbuf->st_size = (off_t)fdata.nFileSizeLow;\n+#endif\n+\t\tbuf->st_blocks = size_to_blocks(buf->st_size);\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\terrno = 0;\n+\t\treturn 0;\n+\t}\n+\n+\tswitch (GetLastError()) {\n+\tcase ERROR_ACCESS_DENIED:\n+\tcase ERROR_SHARING_VIOLATION:\n+\tcase ERROR_LOCK_VIOLATION:\n+\tcase ERROR_SHARING_BUFFER_EXCEEDED:\n+\t\terrno = EACCES;\n+\t\tbreak;\n+\tcase ERROR_BUFFER_OVERFLOW:\n+\t\terrno = ENAMETOOLONG;\n+\t\tbreak;\n+\tcase ERROR_NOT_ENOUGH_MEMORY:\n+\t\terrno = ENOMEM;\n+\t\tbreak;\n+\tdefault:\n+\t\t/* In the winsymlinks mode (which is the default), Cygwin\n+\t\t * emulates symbol links using Windows shortcut files. These\n+\t\t * files are formed by adding .lnk extension. So, if we have\n+\t\t * not found the specified file name, it could be that it is\n+\t\t * a symbol link. Let's Cygwin to deal with that.\n+\t\t */\n+\t\treturn cygstat (file_name, buf);\n+\t}\n+\treturn -1;\n+}\n+\n+/* We provide our own lstat/stat functions, since the provided Cygwin versions\n+ * of these functions are too slow. These stat functions are tailored for Git's\n+ * usage, and therefore they are not meant to be complete and correct emulation\n+ * of lstat/stat functionality.\n+ */\n+static int cygwin_lstat(const char *path, struct stat *buf)\n+{\n+\treturn do_stat(path, buf, lstat);\n+}\n+\n+static int cygwin_stat(const char *path, struct stat *buf)\n+{\n+\treturn do_stat(path, buf, stat);\n+}\n+\n+/*\n+ * This are startup stubs, which choose what implementation of lstat/stat\n+ * should be used. If GIT_FAST_STAT is not set then the standard functions\n+ * included in the cygwin library are used. If it is set then our fast and\n+ * dirty implementation is invoked, which should be 2-3 times faster than\n+ * cygwin functions.\n+ */\n+static int cygwin_stat_choice(const char *file_name, struct stat *buf)\n+{\n+\tcygwin_stat_fn = getenv(\"GIT_FAST_STAT\") ?\n+\t\tcygwin_stat : stat;\n+\treturn (*cygwin_stat_fn)(file_name, buf);\n+}\n+\n+static int cygwin_lstat_choice(const char *file_name, struct stat *buf)\n+{\n+\tcygwin_lstat_fn = getenv(\"GIT_FAST_STAT\") ?\n+\t\tcygwin_lstat : lstat;\n+\treturn (*cygwin_lstat_fn)(file_name, buf);\n+}\n+\n+stat_fn_t cygwin_stat_fn = cygwin_stat_choice;\n+stat_fn_t cygwin_lstat_fn = cygwin_lstat_choice;\n+\ndiff --git a/compat/cygwin.h b/compat/cygwin.h\nnew file mode 100644\nindex 0000000..a3229f5\n--- /dev/null\n+++ b/compat/cygwin.h\n@@ -0,0 +1,9 @@\n+#include <sys/types.h>\n+#include <sys/stat.h>\n+\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+\n+#define stat(path, buf) (*cygwin_stat_fn)(path, buf)\n+#define lstat(path, buf) (*cygwin_lstat_fn)(path, buf)\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex db2836f..cd9752c 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -85,6 +85,7 @@\n #undef _XOPEN_SOURCE\n #include <grp.h>\n #define _XOPEN_SOURCE 600\n+#include \"compat/cygwin.h\"\n #else\n #undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */\n #include <grp.h>\n-- \n1.6.0\n"},{"id":"91401","messageId":"81b0412b0809230737s7498e214w4c58991e79f76507@mail.gmail.com","threadId":"15635","inReplyTo":"20080923140144.GN21650@dpotapov.dyndns.org","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-09-23T14:37:14Z","receivedAt":"2008-09-23T14:37:14Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"2008/9/23 Dmitry Potapov <dpotapov@gmail.com>:\n> This patch introduces the GIT_FAST_STAT environment variable. If this\n> variable is not set then Git will work as before. However, if it is set\n> then the Cygwin version of Git will try to use a Win32 API function if\n> it is possible to speed up stat/lstat.\n>\n> This fast mode works only for relative paths. It is assumed that the\n> whole repository is located inside one directory without using Cygwin\n> mount to bind external paths inside of the current tree.\n\nWhy runtime conditional? Why conditional at all? Why not fallback\nto cygwin's slow stat on absolute pathnames like you do for symlinks?\n\n> +/*\n> + * This are startup stubs, which choose what implementation of lstat/stat\n\nwhy do you need two of them? Isn't one not enough?\n\n> +stat_fn_t cygwin_stat_fn = cygwin_stat_choice;\n> +stat_fn_t cygwin_lstat_fn = cygwin_lstat_choice;\n...\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\n    extern int (*cygwin_stat_fn)(const char *, struct stat *);\n\nIs shorter, easier to read and easier to understand (for a C person).\nYou don't even use the type anywhere else, it is just for the declaration sake!\n"},{"id":"91406","messageId":"20080923153148.GI3669@spearce.org","threadId":"15635","inReplyTo":"20080923140144.GN21650@dpotapov.dyndns.org","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-23T15:31:48Z","receivedAt":"2008-09-23T15:31:48Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Dmitry Potapov <dpotapov@gmail.com> wrote:\n> This patch introduces the GIT_FAST_STAT environment variable. If this\n> variable is not set then Git will work as before. However, if it is set\n> then the Cygwin version of Git will try to use a Win32 API function if\n> it is possible to speed up stat/lstat.\n> \n> This fast mode works only for relative paths. It is assumed that the\n> whole repository is located inside one directory without using Cygwin\n> mount to bind external paths inside of the current tree.\n...\n> +/*\n> + * This are startup stubs, which choose what implementation of lstat/stat\n> + * should be used. If GIT_FAST_STAT is not set then the standard functions\n> + * included in the cygwin library are used. If it is set then our fast and\n> + * dirty implementation is invoked, which should be 2-3 times faster than\n> + * cygwin functions.\n> + */\n> +static int cygwin_stat_choice(const char *file_name, struct stat *buf)\n> +{\n> +\tcygwin_stat_fn = getenv(\"GIT_FAST_STAT\") ?\n> +\t\tcygwin_stat : stat;\n> +\treturn (*cygwin_stat_fn)(file_name, buf);\n> +}\n> +\n> +static int cygwin_lstat_choice(const char *file_name, struct stat *buf)\n> +{\n> +\tcygwin_lstat_fn = getenv(\"GIT_FAST_STAT\") ?\n> +\t\tcygwin_lstat : lstat;\n> +\treturn (*cygwin_lstat_fn)(file_name, buf);\n> +}\n\nI wonder, should this be controlled by an environment variable?\n\nGiven your description of the feature it seems to be more a property\nof the specific repository, as it is based upon where the repository\nlives within the Cygwin namespace.  Should this be controlled instead\nby say a \"core.cygwinnativestat = true\" configuration property?\n\n-- \nShawn.\n"},{"id":"91407","messageId":"20080923165247.GO21650@dpotapov.dyndns.org","threadId":"15635","inReplyTo":"81b0412b0809230737s7498e214w4c58991e79f76507@mail.gmail.com","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Dmitry Potapov","fromEmail":"dpotapov@gmail.com","sentAt":"2008-09-23T16:52:47Z","receivedAt":"2008-09-23T16:52:47Z","isPatch":true,"sender":{"key":"dpotapov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6568595?v=4"},"body":"On Tue, Sep 23, 2008 at 04:37:14PM +0200, Alex Riesen wrote:\n> 2008/9/23 Dmitry Potapov <dpotapov@gmail.com>:\n> >\n> > This fast mode works only for relative paths. It is assumed that the\n> > whole repository is located inside one directory without using Cygwin\n> > mount to bind external paths inside of the current tree.\n> \n> Why runtime conditional? Why conditional at all?\n\nI thought that in rather unusual circumstances (such as using Cygwin\nmount to connect separately directories in one tree), this fast version\nmay not work. So, I made it conditional. It is runtime conditional,\nbecause most users do not build Git themselves but install a ready\nCygwin package.\n\n> Why not fallback\n> to cygwin's slow stat on absolute pathnames like you do for symlinks?\n\nOf course, I do:\n\n+       if (file_name[0] == '/')\n+               return cygstat (file_name, buf);\n\nSorry, if it was not clear from my above comment.\n\n> \n> > +/*\n> > + * This are startup stubs, which choose what implementation of lstat/stat\n> \n> why do you need two of them? Isn't one not enough?\n\nI did not want to give people reasons to say that I broke lstat :)\nYou can opt for the standard Cygwin version of it if for some reason,\nthis new function does not work. Now, I know only one case -- it is\nwhen you use Cygwin mount inside of Git repo. Yet, I don't know enough\nabout Cygwin to be sure that there is no other cases. So, I just wanted\nto be extra careful and not to break anything.\n\n> \n> > +stat_fn_t cygwin_stat_fn = cygwin_stat_choice;\n> > +stat_fn_t cygwin_lstat_fn = cygwin_lstat_choice;\n> ...\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> \n>     extern int (*cygwin_stat_fn)(const char *, struct stat *);\n> \n> Is shorter, easier to read and easier to understand (for a C person).\n> You don't even use the type anywhere else, it is just for the declaration sake!\n\nI use it in description of a parameter of another function:\n\nstatic int do_stat(const char *file_name, struct stat *buf, stat_fn_t cygstat)\n\nOf course, you can avoid it here too, but the declaration will become\nsomewhat longer:\n\nstatic int do_stat(const char *file_name, struct stat *buf,\n       int (*cygstat)(const char *, struct stat *));\n\nso I am not sure that removing stat_fn_t improves readability, but if\nthere are other people who think so, I will correct that.\n\n\nDmitry\n"},{"id":"91408","messageId":"20080923171209.GP21650@dpotapov.dyndns.org","threadId":"15635","inReplyTo":"20080923153148.GI3669@spearce.org","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Dmitry Potapov","fromEmail":"dpotapov@gmail.com","sentAt":"2008-09-23T17:12:09Z","receivedAt":"2008-09-23T17:12:09Z","isPatch":true,"sender":{"key":"dpotapov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6568595?v=4"},"body":"On Tue, Sep 23, 2008 at 08:31:48AM -0700, Shawn O. Pearce wrote:\n> \n> I wonder, should this be controlled by an environment variable?\n> \n> Given your description of the feature it seems to be more a property\n> of the specific repository, as it is based upon where the repository\n> lives within the Cygwin namespace.  Should this be controlled instead\n> by say a \"core.cygwinnativestat = true\" configuration property?\n\nI am not sure that you will find many people who will want to set this\noption per repository, yet Git has the configuration file, and I agree\nit is better to place it there.\n\nHowever, this option is Cygwin specific, so I am not sure where it\nshould be read. Should I place it in git_default_core_config like\nthis:\n\n#ifdef __CYGWIN__\n\tif (!strcmp(var, \"core.cygwinnativestat\")) {\n\t\tcygwin_native_stat = git_config_bool(var, value);\n\t\treturn 0;\n\t}\n#endif\n\nSo far, we have not had any system specific options here. So, perhaps,\nit is better to leave git_default_core_config alone and just replace\nget_env(GIT_FAST_STAT) with git_config_bool() in the cygwin specific\ncode.\n\n\nDmitry\n"},{"id":"91411","messageId":"gbbaam$hte$1@ger.gmane.org","threadId":"15635","inReplyTo":"20080923165247.GO21650@dpotapov.dyndns.org","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-09-23T17:51:19Z","receivedAt":"2008-09-23T17:51:19Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Dmitry Potapov wrote:\n> On Tue, Sep 23, 2008 at 04:37:14PM +0200, Alex Riesen wrote:\n>> 2008/9/23 Dmitry Potapov <dpotapov@gmail.com>:\n\n>>> +stat_fn_t cygwin_stat_fn = cygwin_stat_choice;\n>>> +stat_fn_t cygwin_lstat_fn = cygwin_lstat_choice;\n>> ...\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>> \n>>     extern int (*cygwin_stat_fn)(const char *, struct stat *);\n>> \n>> Is shorter, easier to read and easier to understand (for a C person).\n>> You don't even use the type anywhere else, it is just for the declaration sake!\n> \n> I use it in description of a parameter of another function:\n> \n> static int do_stat(const char *file_name, struct stat *buf, stat_fn_t cygstat)\n> \n> Of course, you can avoid it here too, but the declaration will become\n> somewhat longer:\n> \n> static int do_stat(const char *file_name, struct stat *buf,\n>        int (*cygstat)(const char *, struct stat *));\n> \n> so I am not sure that removing stat_fn_t improves readability, but if\n> there are other people who think so, I will correct that.\n\nI think that using typedef here definitly improves readibility.\nYou don't have to carefully analyse if you can pass cygwin_stat_fn\nto do_stat function or not.\n\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"91413","messageId":"200809232103.09133.johannes.sixt@telecom.at","threadId":"15635","inReplyTo":"20080923140144.GN21650@dpotapov.dyndns.org","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Johannes Sixt","fromEmail":"johannes.sixt@telecom.at","sentAt":"2008-09-23T19:03:08Z","receivedAt":"2008-09-23T19:03:08Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"On Dienstag, 23. September 2008, Dmitry Potapov wrote:\n> +static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)\n> +{ \n> +\tlong long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;\n> +\twinTime -= 116444736000000000LL; /* Windows to Unix  Epoch conversion */\n> +\tts->tv_sec = (time_t)(winTime/10000000); /* 100-nanosecond interval to seconds */\n> +\tts->tv_nsec = (long)(winTime - ts->tv_sec) * 100; /* nanoseconds */ +}\n\n+\tts->tv_nsec = (long)(winTime - ts->tv_sec*10000000LL) * 100;\n\n> +static int do_stat(const char *file_name, struct stat *buf, stat_fn_t cygstat)\n> +{ \n> +\tWIN32_FILE_ATTRIBUTE_DATA fdata;\n> +\n> +\tif (file_name[0] == '/')\n> +\t\treturn cygstat (file_name, buf);\n\nYou should do this in the caller; it would make this function's\nsemantics much clearer.\n\n> +\n> +\tif (GetFileAttributesExA(file_name, GetFileExInfoStandard, &fdata)) {\n> +\t\tint fMode = S_IREAD;\n> +\t\t/*\n> +\t\t * If the system attribute is set and it is not a directory then\n> +\t\t * it could be a symbol link created in the nowinsymlinks mode.\n> +\t\t * Normally, Cygwin works in the winsymlinks mode, so this situation\n> +\t\t * is very unlikely. For the sake of simplicity of our code, let's\n> +\t\t * Cygwin to handle it.\n> +\t\t */\n> +\t\tif ((fdata.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) &&\n> +\t\t    !(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))\n> +\t\t\treturn cygstat (file_name, buf);\n> +\n> +\t\tif (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)\n> +\t\t\tfMode |= S_IFDIR;\n> +\t\telse\n> +\t\t\tfMode |= S_IFREG;\n> +\t\tif (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))\n> +\t\t\tfMode |= S_IWRITE;\n> +\n> +\t\t/* st_dev, st_rdev are not used by Git */\n> +\t\tbuf->st_dev = buf->st_rdev = 0;\n> +\t\t/* it is difficult to obtain the inode number on Windows,\n> +\t\t * so let's set it to zero as MinGW Git does. */\n> +\t\tbuf->st_ino = 0;\n> +\t\tbuf->st_mode = fMode;\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> +#else\n> +\t\tbuf->st_size = (off_t)fdata.nFileSizeLow;\n> +#endif\n> +\t\tbuf->st_blocks = size_to_blocks(buf->st_size);\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\terrno = 0;\n> +\t\treturn 0;\n> +\t}\n> +\n> +\tswitch (GetLastError()) {\n> +\tcase ERROR_ACCESS_DENIED:\n> +\tcase ERROR_SHARING_VIOLATION:\n> +\tcase ERROR_LOCK_VIOLATION:\n> +\tcase ERROR_SHARING_BUFFER_EXCEEDED:\n> +\t\terrno = EACCES;\n> +\t\tbreak;\n> +\tcase ERROR_BUFFER_OVERFLOW:\n> +\t\terrno = ENAMETOOLONG;\n> +\t\tbreak;\n> +\tcase ERROR_NOT_ENOUGH_MEMORY:\n> +\t\terrno = ENOMEM;\n> +\t\tbreak;\n> +\tdefault:\n> +\t\t/* In the winsymlinks mode (which is the default), Cygwin\n> +\t\t * emulates symbol links using Windows shortcut files. These\n> +\t\t * files are formed by adding .lnk extension. So, if we have\n> +\t\t * not found the specified file name, it could be that it is\n> +\t\t * a symbol link. Let's Cygwin to deal with that.\n> +\t\t */\n> +\t\treturn cygstat (file_name, buf);\n> +\t}\n> +\treturn -1;\n\nYou do duplicate a lot of code here. Any chances to factor out the\ncommon parts? Start with platform specific function\nfiletime_to_stat_time() that is your filetime_to_timespec() on Cygwin,\nbut filetime_to_time_t() (which needs modification) on MinGW.\n\n-- Hannes\n"},{"id":"91414","messageId":"20080923190637.GJ3669@spearce.org","threadId":"15635","inReplyTo":"20080923171209.GP21650@dpotapov.dyndns.org","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-23T19:06:37Z","receivedAt":"2008-09-23T19:06:37Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Dmitry Potapov <dpotapov@gmail.com> wrote:\n> On Tue, Sep 23, 2008 at 08:31:48AM -0700, Shawn O. Pearce wrote:\n> > \n> > I wonder, should this be controlled by an environment variable?\n> > \n> > Given your description of the feature it seems to be more a property\n> > of the specific repository, as it is based upon where the repository\n> > lives within the Cygwin namespace.  Should this be controlled instead\n> > by say a \"core.cygwinnativestat = true\" configuration property?\n> \n> I am not sure that you will find many people who will want to set this\n> option per repository, yet Git has the configuration file, and I agree\n> it is better to place it there.\n\nIf you want it globally you can do:\n\n  git config --global core.cygwinnativestat true\n\nand then disable it on a per-repository basis if you and a specific\nrepository which has this inner mount problem:\n\n  git config core.cygwinnativestat false\n\nWhich is a lot more powerful than an environment variable.\n \n> However, this option is Cygwin specific, so I am not sure where it\n> should be read. Should I place it in git_default_core_config like\n> this:\n> \n> #ifdef __CYGWIN__\n> \tif (!strcmp(var, \"core.cygwinnativestat\")) {\n> \t\tcygwin_native_stat = git_config_bool(var, value);\n> \t\treturn 0;\n> \t}\n> #endif\n\nI would have the two initial stat functions swap themselves out with\nthe default Cygin stat implementations, run a parse over the config\nto load that one bool, then install the proper implementations based\nupon its value.  Hence all Cygwin code is kept inside of the Cygwin\ncompat code, and no #ifdef is necessary\n\nOf course that config file parse can only happen after the repository\nhas been entered, which means you need to somehow rely on the real\nCygwin stat functions until setup_git_directory() has completed,\nand then on the next stat call (re)parse the config and swap the\nimplementation.\n\n-- \nShawn.\n"},{"id":"91416","messageId":"20080923194802.GQ21650@dpotapov.dyndns.org","threadId":"15635","inReplyTo":"200809232103.09133.johannes.sixt@telecom.at","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Dmitry Potapov","fromEmail":"dpotapov@gmail.com","sentAt":"2008-09-23T19:48:02Z","receivedAt":"2008-09-23T19:48:02Z","isPatch":true,"sender":{"key":"dpotapov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6568595?v=4"},"body":"On Tue, Sep 23, 2008 at 09:03:08PM +0200, Johannes Sixt wrote:\n> On Dienstag, 23. September 2008, Dmitry Potapov wrote:\n> > +static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)\n> > +{ \n> > +\tlong long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;\n> > +\twinTime -= 116444736000000000LL; /* Windows to Unix  Epoch conversion */\n> > +\tts->tv_sec = (time_t)(winTime/10000000); /* 100-nanosecond interval to seconds */\n> > +\tts->tv_nsec = (long)(winTime - ts->tv_sec) * 100; /* nanoseconds */ +}\n> \n> +\tts->tv_nsec = (long)(winTime - ts->tv_sec*10000000LL) * 100;\n\nThanks.... What was I thought about when wrote this....\n\n> \n> > +static int do_stat(const char *file_name, struct stat *buf, stat_fn_t cygstat)\n> > +{ \n> > +\tWIN32_FILE_ATTRIBUTE_DATA fdata;\n> > +\n> > +\tif (file_name[0] == '/')\n> > +\t\treturn cygstat (file_name, buf);\n> \n> You should do this in the caller; it would make this function's\n> semantics much clearer.\n\nIMHO, the semantic of this function is clear: do_stat performs stat/lstat\nusing Windows API with falling back on Cygwin implementation in those\nrare cases that it cannot handle correctly. Absolute path is just one of\nthose cases. So, I am not sure what you win by moving this two lines out.\n\n\n> > +\tif (GetFileAttributesExA(file_name, GetFileExInfoStandard, &fdata)) {\n> > +\t\tint fMode = S_IREAD;\n> > +\t\t/*\n> > +\t\t * If the system attribute is set and it is not a directory then\n> > +\t\t * it could be a symbol link created in the nowinsymlinks mode.\n> > +\t\t * Normally, Cygwin works in the winsymlinks mode, so this situation\n> > +\t\t * is very unlikely. For the sake of simplicity of our code, let's\n> > +\t\t * Cygwin to handle it.\n> > +\t\t */\n> > +\t\tif ((fdata.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) &&\n> > +\t\t    !(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))\n> > +\t\t\treturn cygstat (file_name, buf);\n\nThis is specific to cygwin.\n\n> > +\n> > +\t\tif (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)\n> > +\t\t\tfMode |= S_IFDIR;\n> > +\t\telse\n> > +\t\t\tfMode |= S_IFREG;\n> > +\t\tif (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))\n> > +\t\t\tfMode |= S_IWRITE;\n\nThese lines the same as mingw\n\n> > +\n> > +\t\t/* st_dev, st_rdev are not used by Git */\n> > +\t\tbuf->st_dev = buf->st_rdev = 0;\n\nI set this to 0, while MinGW Git uses _getdrive(). I have no idea why\nit does so. Git does not use this field, and if it did, adding the\n_current_ drive number is useless at best when we are trying to\ndetermine whether the file is changed or not.\n\n> > +\t\t/* it is difficult to obtain the inode number on Windows,\n> > +\t\t * so let's set it to zero as MinGW Git does. */\n> > +\t\tbuf->st_ino = 0;\n> > +\t\tbuf->st_mode = fMode;\n> > +\t\tbuf->st_nlink = 1;\n> > +\t\tbuf->st_uid = buf->st_gid = 0;\n\nThis is the same as for MinGW\n\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\tbuf->st_blocks = size_to_blocks(buf->st_size);\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\nThis is different: using 64-bit version for st_size, st_blocks does not\nexist in MinGW, and finally filetime_to_timespec instead of filetime_to_time_t,\nas well as the name of fields is different (st_ctim instead of st_ctime, etc).\n\n> > +\t\terrno = 0;\n> > +\t\treturn 0;\n> > +\t}\n> > +\n> > +\tswitch (GetLastError()) {\n> > +\tcase ERROR_ACCESS_DENIED:\n> > +\tcase ERROR_SHARING_VIOLATION:\n> > +\tcase ERROR_LOCK_VIOLATION:\n> > +\tcase ERROR_SHARING_BUFFER_EXCEEDED:\n> > +\t\terrno = EACCES;\n> > +\t\tbreak;\n> > +\tcase ERROR_BUFFER_OVERFLOW:\n> > +\t\terrno = ENAMETOOLONG;\n> > +\t\tbreak;\n> > +\tcase ERROR_NOT_ENOUGH_MEMORY:\n> > +\t\terrno = ENOMEM;\n> > +\t\tbreak;\n> > +\tdefault:\n> > +\t\t/* In the winsymlinks mode (which is the default), Cygwin\n> > +\t\t * emulates symbol links using Windows shortcut files. These\n> > +\t\t * files are formed by adding .lnk extension. So, if we have\n> > +\t\t * not found the specified file name, it could be that it is\n> > +\t\t * a symbol link. Let's Cygwin to deal with that.\n> > +\t\t */\n> > +\t\treturn cygstat (file_name, buf);\n> > +\t}\n\nThis is the same as in MinGW, except the default case, where MinGW\nreturns error immediately while this version calls the fallback\nfunction.\n\n\n> > +\treturn -1;\n> \n> You do duplicate a lot of code here. Any chances to factor out the\n> common parts?\n\nI don't see much common code here. Initialization of 5 variables where\nfour of them are just constants? Perhaps, the biggest common part here\nis conversion of dwFileAttributes to st_mode, but it is still 5 lines of\ntrivial code.\n\nDmitry\n"},{"id":"91418","messageId":"20080923200456.GR21650@dpotapov.dyndns.org","threadId":"15635","inReplyTo":"20080923190637.GJ3669@spearce.org","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Dmitry Potapov","fromEmail":"dpotapov@gmail.com","sentAt":"2008-09-23T20:04:56Z","receivedAt":"2008-09-23T20:04:56Z","isPatch":true,"sender":{"key":"dpotapov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6568595?v=4"},"body":"On Tue, Sep 23, 2008 at 12:06:37PM -0700, Shawn O. Pearce wrote:\n> \n> and then disable it on a per-repository basis if you and a specific\n> repository which has this inner mount problem:\n> \n>   git config core.cygwinnativestat false\n> \n> Which is a lot more powerful than an environment variable.\n\nI already said that I completely agree that is a good idea even I don't\nknow the real need for having per-repository configuration in practice.\n\n>  \n> > However, this option is Cygwin specific, so I am not sure where it\n> > should be read. Should I place it in git_default_core_config like\n> > this:\n> > \n> > #ifdef __CYGWIN__\n> > \tif (!strcmp(var, \"core.cygwinnativestat\")) {\n> > \t\tcygwin_native_stat = git_config_bool(var, value);\n> > \t\treturn 0;\n> > \t}\n> > #endif\n> \n> I would have the two initial stat functions swap themselves out with\n> the default Cygin stat implementations, run a parse over the config\n> to load that one bool, then install the proper implementations based\n> upon its value.  Hence all Cygwin code is kept inside of the Cygwin\n> compat code, and no #ifdef is necessary\n\nDo I understand you correctly that you propose to add the code like\nthis in compat/cygwin.c:\n\nstatic int native_stat;\n\nstatic int git_cygwin_config(const char *var, const char *value, void\n*cb)\n{\n\tif (!strcmp(var, \"core.cygwinnativestat\"))\n\t\tcygwin_native_stat = git_config_bool(var, value);\n\treturn 0;\n}\n\nstatic void init_stat(void)\n{\n\tgit_config(git_cygwin_config, NULL);\n\tcygwin_stat_fn = native_stat ? cygwin_stat : stat;\n\tcygwin_lstat_fn = native_stat ? cygwin_lstat : lstat;\n}\n\nstatic int cygwin_stat_choice(const char *file_name, struct stat *buf)\n{\n\tinit_stat();\n\treturn (*cygwin_stat_fn)(file_name, buf);\n}\n\nstatic int cygwin_lstat_choice(const char *file_name, struct stat *buf)\n{\n\tinit_stat();\n\treturn (*cygwin_lstat_fn)(file_name, buf);\n}\n\nDmitry\n"},{"id":"91419","messageId":"20080923201739.GK3669@spearce.org","threadId":"15635","inReplyTo":"20080923200456.GR21650@dpotapov.dyndns.org","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-23T20:17:39Z","receivedAt":"2008-09-23T20:17:39Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Dmitry Potapov <dpotapov@gmail.com> wrote:\n> Do I understand you correctly that you propose to add the code like\n> this in compat/cygwin.c:\n\nYes.  But with minor changes (see below):\n \n> static int native_stat;\n\nstatic int native_stat = -1;\n\n> static int git_cygwin_config(const char *var, const char *value, void\n> *cb)\n> {\n> \tif (!strcmp(var, \"core.cygwinnativestat\"))\n> \t\tcygwin_native_stat = git_config_bool(var, value);\n> \treturn 0;\n> }\n> \n> static void init_stat(void)\n> {\n> \tgit_config(git_cygwin_config, NULL);\n> \tcygwin_stat_fn = native_stat ? cygwin_stat : stat;\n> \tcygwin_lstat_fn = native_stat ? cygwin_lstat : lstat;\n\nif (native_stat < 0 && have_git_dir()) {\n\tnative_stat = 0;\n\tgit_config(git_cygwin_config, NULL);\n\tcygwin_stat_fn = native_stat ? cygwin_stat : stat;\n\tcygwin_lstat_fn = native_stat ? cygwin_lstat : lstat;\n}\n\nand then you have to define have_git_dir() inside environment.c as:\n\nint have_git_dir(void)\n{\n\treturn !!git_dir;\n}\n \n> static int cygwin_stat_choice(const char *file_name, struct stat *buf)\n> {\n> \tinit_stat();\n> \treturn (*cygwin_stat_fn)(file_name, buf);\n> }\n> \n> static int cygwin_lstat_choice(const char *file_name, struct stat *buf)\n> {\n> \tinit_stat();\n> \treturn (*cygwin_lstat_fn)(file_name, buf);\n> }\n\n-- \nShawn.\n"},{"id":"91421","messageId":"200809232241.42649.johannes.sixt@telecom.at","threadId":"15635","inReplyTo":"20080923194802.GQ21650@dpotapov.dyndns.org","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Johannes Sixt","fromEmail":"johannes.sixt@telecom.at","sentAt":"2008-09-23T20:41:42Z","receivedAt":"2008-09-23T20:41:42Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"On Dienstag, 23. September 2008, Dmitry Potapov wrote:\n> On Tue, Sep 23, 2008 at 09:03:08PM +0200, Johannes Sixt wrote:\n> > On Dienstag, 23. September 2008, Dmitry Potapov wrote:\n> > > +static int do_stat(const char *file_name, struct stat *buf, stat_fn_t\n> > > cygstat) +{\n> > > +\tWIN32_FILE_ATTRIBUTE_DATA fdata;\n> > > +\n> > > +\tif (file_name[0] == '/')\n> > > +\t\treturn cygstat (file_name, buf);\n> >\n> > You should do this in the caller; it would make this function's\n> > semantics much clearer.\n>\n> IMHO, the semantic of this function is clear: do_stat performs stat/lstat\n> using Windows API with falling back on Cygwin implementation in those\n> rare cases that it cannot handle correctly. Absolute path is just one of\n> those cases. So, I am not sure what you win by moving this two lines out.\n\nYou copied the function from compat/mingw.c. There it has the meaning \"Fill in \nstruct stat using Win32 API\" and nothing else. Here it has the meaning \"Fill \nin struct stat using Win32 API if you can, and using cygstat() in certain \nexceptional cases\". If you stayed with the original meaning, it would be \nslightly easier to factor out common code.\n\n> > > +\t\t/* st_dev, st_rdev are not used by Git */\n> > > +\t\tbuf->st_dev = buf->st_rdev = 0;\n>\n> I set this to 0, while MinGW Git uses _getdrive(). I have no idea why\n> it does so. \n\nIndeed. Calling _getdrive() is absolutely useless.\n\n> > You do duplicate a lot of code here. Any chances to factor out the\n> > common parts?\n>\n> I don't see much common code here. Initialization of 5 variables where\n> four of them are just constants? Perhaps, the biggest common part here\n> is conversion of dwFileAttributes to st_mode, but it is still 5 lines of\n> trivial code.\n\nSigh. I gave a pointer how to unify the two functions (although I missed the \nfact that the member variables are named differently). I'd appreciate if you \ndid not make it more difficult than necessary to factor out common code.\n\n-- Hannes\n"},{"id":"91426","messageId":"20080923211124.GT21650@dpotapov.dyndns.org","threadId":"15635","inReplyTo":"200809232241.42649.johannes.sixt@telecom.at","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Dmitry Potapov","fromEmail":"dpotapov@gmail.com","sentAt":"2008-09-23T21:11:24Z","receivedAt":"2008-09-23T21:11:24Z","isPatch":true,"sender":{"key":"dpotapov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6568595?v=4"},"body":"On Tue, Sep 23, 2008 at 10:41:42PM +0200, Johannes Sixt wrote:\n> \n> You copied the function from compat/mingw.c. There it has the meaning \"Fill in \n> struct stat using Win32 API\" and nothing else. Here it has the meaning \"Fill \n> in struct stat using Win32 API if you can, and using cygstat() in certain \n> exceptional cases\". If you stayed with the original meaning, it would be \n> slightly easier to factor out common code.\n\ndo_stat() always fills in the structure, but it can do that fast using\nWin32 API or fallback on cygstat() in exceptional cases. So, I don't\nthink I change its meaning much, its implementation certainly differs.\n\n> > > You do duplicate a lot of code here. Any chances to factor out the\n> > > common parts?\n> >\n> > I don't see much common code here. Initialization of 5 variables where\n> > four of them are just constants? Perhaps, the biggest common part here\n> > is conversion of dwFileAttributes to st_mode, but it is still 5 lines of\n> > trivial code.\n> \n> Sigh. I gave a pointer how to unify the two functions (although I missed the \n> fact that the member variables are named differently). I'd appreciate if you \n> did not make it more difficult than necessary to factor out common code.\n\nBecause the stat structure is different and handling exceptional\nsituation is different, I don't think we can have a single do_stat\nfunction for Cygwin and MinGW. Yet, perhaps, it is possible to\nmove some code in common functions even if it is just a few lines.\n\nThe first candidate is win_attr_to_st_mode(), which converts\ndwFileAttributes returned by GetFileAttributesExA to st_mode.\nAnother possible function is that obtains and converts Win32 error\ncode to errno value. These function can be placed into some common\nheader (for example, win32.h), which will included by both\nimplementations. Does it make sense?\n\n\nDmitry\n"},{"id":"91434","messageId":"20080923212858.GU21650@dpotapov.dyndns.org","threadId":"15635","inReplyTo":"20080923201739.GK3669@spearce.org","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Dmitry Potapov","fromEmail":"dpotapov@gmail.com","sentAt":"2008-09-23T21:28:58Z","receivedAt":"2008-09-23T21:28:58Z","isPatch":true,"sender":{"key":"dpotapov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6568595?v=4"},"body":"On Tue, Sep 23, 2008 at 01:17:39PM -0700, Shawn O. Pearce wrote:\n> Dmitry Potapov <dpotapov@gmail.com> wrote:\n> > \n> > static void init_stat(void)\n> > {\n> > \tgit_config(git_cygwin_config, NULL);\n> > \tcygwin_stat_fn = native_stat ? cygwin_stat : stat;\n> > \tcygwin_lstat_fn = native_stat ? cygwin_lstat : lstat;\n> \n> if (native_stat < 0 && have_git_dir()) {\n> \tnative_stat = 0;\n> \tgit_config(git_cygwin_config, NULL);\n> \tcygwin_stat_fn = native_stat ? cygwin_stat : stat;\n> \tcygwin_lstat_fn = native_stat ? cygwin_lstat : lstat;\n> }\n\nI am not sure that I understand what you are trying to do here.\n\nFirst, in my implementation, init_stat was supposed to always set\ncygwin_stat_fn() and cygwin_lstat_fn(), otherwise the code is going\nto hit the NULL pointer call.\n\nSecond, the check of native_stat < 0 is absolutely useless, because once\nwe set cygwin_stat_fn and cygwin_lstat_fn, we are never going to call\ninit_stat() again.\n\nDid you mean this:\n\n\tif (have_git_dir())\n\t\tgit_config(git_cygwin_config, NULL);\n\telse\n\t\tnative_stat = 0\n\tcygwin_stat_fn = native_stat ? cygwin_stat : stat;\n\tcygwin_lstat_fn = native_stat ? cygwin_lstat : lstat;\n\nOr:\n\nif (have_git_dir()) {\n\tgit_config(git_cygwin_config, NULL);\n\tcygwin_stat_fn = native_stat ? cygwin_stat : stat;\n\tcygwin_lstat_fn = native_stat ? cygwin_lstat : lstat;\n}\n\nand\n\n> > static int cygwin_stat_choice(const char *file_name, struct stat *buf)\n> > {\n> > \tinit_stat();\n> > \treturn (*cygwin_stat_fn)(file_name, buf);\n\nchange the above line to:\n\treturn (cygwin_stat_fn ? cygwin_stat_fn : stat) (file_name, buf);\n\nso init_stat may be called a few times outside of git directory and then\nuse the default cygwin function, and once we enter to it then load the\nconfiguration option and act accordingly.\n\nDmitry\n"},{"id":"91437","messageId":"20080923215858.GL3669@spearce.org","threadId":"15635","inReplyTo":"20080923212858.GU21650@dpotapov.dyndns.org","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-23T21:58:58Z","receivedAt":"2008-09-23T21:58:58Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Dmitry Potapov <dpotapov@gmail.com> wrote:\n> I am not sure that I understand what you are trying to do here.\n...\n> Did you mean this:\n...\n> if (have_git_dir()) {\n> \tgit_config(git_cygwin_config, NULL);\n> \tcygwin_stat_fn = native_stat ? cygwin_stat : stat;\n> \tcygwin_lstat_fn = native_stat ? cygwin_lstat : lstat;\n> }\n\nErr, yes, something more like that.\n \n> > > static int cygwin_stat_choice(const char *file_name, struct stat *buf)\n> > > {\n> > > \tinit_stat();\n> > > \treturn (*cygwin_stat_fn)(file_name, buf);\n> \n> change the above line to:\n> \treturn (cygwin_stat_fn ? cygwin_stat_fn : stat) (file_name, buf);\n\nRight.\n \n> so init_stat may be called a few times outside of git directory and then\n> use the default cygwin function, and once we enter to it then load the\n> configuration option and act accordingly.\n\nYup, exactly.  Sorry I wasn't being very clear earlier.\n\n-- \nShawn.\n"},{"id":"91460","messageId":"81b0412b0809240425t63a2a28cw1cc0c0d95b3290f7@mail.gmail.com","threadId":"15635","inReplyTo":"20080923165247.GO21650@dpotapov.dyndns.org","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-09-24T11:25:06Z","receivedAt":"2008-09-24T11:25:06Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"2008/9/23 Dmitry Potapov <dpotapov@gmail.com>:\n> On Tue, Sep 23, 2008 at 04:37:14PM +0200, Alex Riesen wrote:\n>> 2008/9/23 Dmitry Potapov <dpotapov@gmail.com>:\n>> >\n>> > This fast mode works only for relative paths. It is assumed that the\n>> > whole repository is located inside one directory without using Cygwin\n>> > mount to bind external paths inside of the current tree.\n>>\n>> Why runtime conditional? Why conditional at all?\n>\n> I thought that in rather unusual circumstances (such as using Cygwin\n> mount to connect separately directories in one tree), this fast version\n> may not work. So, I made it conditional. It is runtime conditional,\n> because most users do not build Git themselves but install a ready\n> Cygwin package.\n\nSo? How about make the fast version _always_ work? We don't seem\nto fallback to copy+unlink everytime the POSIX rename fails.\n\nBesides it will remove your setup code, which looks bigger and provoked\nmore discussion than the real subject itself.\n"},{"id":"91463","messageId":"20080924140358.GX21650@dpotapov.dyndns.org","threadId":"15635","inReplyTo":"81b0412b0809240425t63a2a28cw1cc0c0d95b3290f7@mail.gmail.com","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Dmitry Potapov","fromEmail":"dpotapov@gmail.com","sentAt":"2008-09-24T14:03:58Z","receivedAt":"2008-09-24T14:03:58Z","isPatch":true,"sender":{"key":"dpotapov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6568595?v=4"},"body":"On Wed, Sep 24, 2008 at 01:25:06PM +0200, Alex Riesen wrote:\n> 2008/9/23 Dmitry Potapov <dpotapov@gmail.com>:\n> >\n> > I thought that in rather unusual circumstances (such as using Cygwin\n> > mount to connect separately directories in one tree), this fast version\n> > may not work. So, I made it conditional. It is runtime conditional,\n> > because most users do not build Git themselves but install a ready\n> > Cygwin package.\n> \n> So? How about make the fast version _always_ work? We don't seem\n> to fallback to copy+unlink everytime the POSIX rename fails.\n\nI am not sure that I understand your analogue here. First, rename has\nnever meant to work as copy+unlink. Second, I don't fall back on some\nother code when the implementation provided by Cygwin fails. I replace\nthe Cygwin implementation with a faster but a bit hackish version. Yes,\nit works fine in almost all practical cases I aware of, but I cannot\nguarantee identical behavior in _all_ cases.\n\nFrankly, I don't have strong preference here neither for making this\nfast version always work nor leave it conditional (perhaps, with the\ndefault setting use-fast-version). So, whatever the majority decides\nis fine with me.\n\n> Besides it will remove your setup code, which looks bigger and provoked\n> more discussion than the real subject itself.\n\nI believe Shawn wanted it to be configurable on per-repository basis.\nI have just finished re-writing the code in the way he suggested, so I\nhope all objections with the setup code are resolved now. I will send\nthe new version a bit later, I did not have time to test it yet.\n\n\nDmitry\n"},{"id":"91467","messageId":"81b0412b0809240742g2918b300h9114579c4ebf05b4@mail.gmail.com","threadId":"15635","inReplyTo":"20080924140358.GX21650@dpotapov.dyndns.org","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-09-24T14:42:03Z","receivedAt":"2008-09-24T14:42:03Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"2008/9/24 Dmitry Potapov <dpotapov@gmail.com>:\n> it works fine in almost all practical cases I aware of, but I cannot\n> guarantee identical behavior in _all_ cases.\n\nWell, make it as good as MSys/Cygwin's and no one asks for your guarantee.\n\n> Frankly, I don't have strong preference here neither for making this\n> fast version always work nor leave it conditional (perhaps, with the\n> default setting use-fast-version). So, whatever the majority decides\n> is fine with me.\n\nI'm voting for compile-time configuration then.\n\n>> Besides it will remove your setup code, which looks bigger and provoked\n>> more discussion than the real subject itself.\n>\n> I believe Shawn wanted it to be configurable on per-repository basis.\n\nwhich, I believe, is pointless.\n"},{"id":"91473","messageId":"20080924150231.GO3669@spearce.org","threadId":"15635","inReplyTo":"81b0412b0809240742g2918b300h9114579c4ebf05b4@mail.gmail.com","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-24T15:02:31Z","receivedAt":"2008-09-24T15:02:31Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Alex Riesen <raa.lkml@gmail.com> wrote:\n> 2008/9/24 Dmitry Potapov <dpotapov@gmail.com>:\n> \n> > Frankly, I don't have strong preference here neither for making this\n> > fast version always work nor leave it conditional (perhaps, with the\n> > default setting use-fast-version). So, whatever the majority decides\n> > is fine with me.\n> \n> I'm voting for compile-time configuration then.\n\nTo be consistent with everything else, compile-time sounds like\nwhat we should do, its how just about every other part of Git\nis configured.\n\nHowever Dmitry pointed out that he has cases where this faster\nfunction doesn't work correctly, and it was path specific.  Some\nareas of the filesystem work, others don't, on the same system.\nA current example of a feature more like this is core.filemode.\n\nA compile-time option makes the feature useful only to those users\nwho don't ever have a repository which has a mount contained within\nthe working directory.  My understanding of Dmitry's explanation\nis he has such cases, which is why I was voting for a runtime\nconfiguration.\n\nA compile-time option means that Git will work fine for years, until\nyou put a mount in a working directory and *wham* it suddenly stops\nworking like it should, because of that compile-time optimization\nyou made long ago and forgot about.\n \n> >> Besides it will remove your setup code, which looks bigger and provoked\n> >> more discussion than the real subject itself.\n> >\n> > I believe Shawn wanted it to be configurable on per-repository basis.\n> \n> which, I believe, is pointless.\n\nSee above.  I suggested configurable per-repository because\nDmitry seemed to be saying this feature only works in some of his\nrepositories and not others.  Controlling it by an environment\nvariable isn't very easy to use as you move between repositories\non the same system.\n\nMaybe I should have leaned more towards compile-time earlier in\nthe discussion, but Dmitry lead off the patch though with a remark\nabout users just running the Cygwin package, without building\ntheir own Git.  We can't expect the Cygwin maintainers to enable\na feature in a software package that makes it work on 90% of the\nCygwin installs out there; that's just asking for trouble.\n\nBut we can compile in a user-configurable switch, where the user can\nshoot their own foot off in the name of speed, especially if they\ncan easily disable it on the oddball repositories where it fails.\n\nOf course it might be even better if the code could auto-sense\nwhen its busted and just switch itself off.  E.g. if four or\nmore consecutive \"fast\" stat calls fail but the original Cygwin\ncall succeeds then just always use Cygwin calls for the rest of\nthe process.\n\n-- \nShawn.\n"},{"id":"91475","messageId":"81b0412b0809240809y4daa990cl5494d7b7398353f0@mail.gmail.com","threadId":"15635","inReplyTo":"20080924150231.GO3669@spearce.org","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-09-24T15:09:22Z","receivedAt":"2008-09-24T15:09:22Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"2008/9/24 Shawn O. Pearce <spearce@spearce.org>:\n> Alex Riesen <raa.lkml@gmail.com> wrote:\n>> 2008/9/24 Dmitry Potapov <dpotapov@gmail.com>:\n>>\n>> > Frankly, I don't have strong preference here neither for making this\n>> > fast version always work nor leave it conditional (perhaps, with the\n>> > default setting use-fast-version). So, whatever the majority decides\n>> > is fine with me.\n>>\n>> I'm voting for compile-time configuration then.\n>\n> To be consistent with everything else, compile-time sounds like\n> what we should do, its how just about every other part of Git\n> is configured.\n>\n> However Dmitry pointed out that he has cases where this faster\n> function doesn't work correctly, and it was path specific. Some\n> areas of the filesystem work, others don't, on the same system.\n\nHuh?! What are they? What paths require cygwin's handling\nwhich aren't handled already? (the absolute paths are handled).\n"},{"id":"91477","messageId":"20080924151653.GQ3669@spearce.org","threadId":"15635","inReplyTo":"81b0412b0809240809y4daa990cl5494d7b7398353f0@mail.gmail.com","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-24T15:16:53Z","receivedAt":"2008-09-24T15:16:53Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Alex Riesen <raa.lkml@gmail.com> wrote:\n> 2008/9/24 Shawn O. Pearce <spearce@spearce.org>:\n> >\n> > However Dmitry pointed out that he has cases where this faster\n> > function doesn't work correctly, and it was path specific. Some\n> > areas of the filesystem work, others don't, on the same system.\n> \n> Huh?! What are they? What paths require cygwin's handling\n> which aren't handled already? (the absolute paths are handled).\n\nCygwin lets you mount a filesystem at a different part of the\nfilesystem.  Sort of like Linux's mount -t bind (IIRC).\n\nFor example its possible to remap C:\\foo\\bar\\widget\\srcs into\nC:\\cygwin\\home\\lib, so you see the files under /home/lib in Cygwin,\neven though that folder is empty (or flat out doesn't exist)\nin Windows.\n\nThat filesystem remount stuff is part of the reason why the Cygwin\nstat/lstat routines are so much slower than the native Windows ones.\nThey have to evaluate the path space twice (once in Cygwin, again\nin the Windows kernel).\n\n-- \nShawn.\n"},{"id":"91481","messageId":"81b0412b0809240832g52a2f83cx69125895cc7f88b2@mail.gmail.com","threadId":"15635","inReplyTo":"20080924151653.GQ3669@spearce.org","subject":"Re: [PATCH] add GIT_FAST_STAT mode for Cygwin","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-09-24T15:32:06Z","receivedAt":"2008-09-24T15:32:06Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"2008/9/24 Shawn O. Pearce <spearce@spearce.org>:\n> Alex Riesen <raa.lkml@gmail.com> wrote:\n>> 2008/9/24 Shawn O. Pearce <spearce@spearce.org>:\n>> >\n>> > However Dmitry pointed out that he has cases where this faster\n>> > function doesn't work correctly, and it was path specific. Some\n>> > areas of the filesystem work, others don't, on the same system.\n>>\n>> Huh?! What are they? What paths require cygwin's handling\n>> which aren't handled already? (the absolute paths are handled).\n>\n> Cygwin lets you mount a filesystem at a different part of the\n> filesystem.\n\nEwwww... Yes, you're right. Disgusting feature. Just when I\nthought Cygwin cannot get any worse...\nConfig parameter looks like the only way to workaround that.\n\n> Sort of like Linux's mount -t bind (IIRC).\n\nExcept that in Linux the binding is part of the filesystem namespace,\nnot a special knowledge of some stupid library.\n"},{"id":"91731","messageId":"1222498926-30635-1-git-send-email-marcus@griep.us","threadId":"15635","inReplyTo":"20080923140144.GN21650@dpotapov.dyndns.org","subject":"[PATCH v2] Add a \"fast stat\" mode for Cygwin","fromName":"Marcus Griep","fromEmail":"marcus@griep.us","sentAt":"2008-09-27T07:02:06Z","receivedAt":"2008-09-27T07:02:06Z","isPatch":true,"sender":{"key":"marcus@griep.us","avatar":"https://gravatar.com/avatar/0a841f2aad3f9a38c9bcf87a567c2a1751cb08924bae1bc46ee171395bcf9794?d=mp&s=160"},"body":"This patch introduces core.cygwinnativestat configuration flag. If this\nvariable is not set then Git will work as before. However, if it is set\nthen the Cygwin version of Git will try to use a Win32 API function if\nit is possible to speed up stat/lstat.\n\nThis fast mode works only for relative paths. It is assumed that the\nwhole repository is located inside one directory without using Cygwin\nmount to bind external paths inside of the current tree.\n\nSymbolic links are supported by falling back on the cygwin version of\nthese functions.\n\nA very superficial testing shows 'git status' in the fast mode works more\nthan twice faster than in the normal mode, i.e. with about the same speed\nas the native MinGW version.\n\nAlso, with this patch, Cygwin and MinGW share the same code for doing\nnative filesystem stats.  Also incorporates Shawn Pearce's suggestion\nto use a config flag rather than an environment variable to control\nwhich method (native or cygwin) is used.\n\nOriginally-by: Dmitry Potapov <dpotapov@gmail.com>\nSigned-off-by: Marcus Griep <marcus@griep.us>\n---\n\n This is a substitute patch that takes care of many of the concerns already\n posted to this thread regarding the patch.  Sorry if it steps on your toes,\n Dmitry.  You began scratching my itch, so I wanted to jump in and scratch\n some more.\n\n Overall, the new patch implements many of the ideas from the thread, including\n using a configuration flag to determine which stat (cygwin or native) to use,\n and the code is refactored so that MinGW and Cygwin can both use the same\n base stat code.\n\n If it looks good, I'd appreciate a regression 'Tested-by' from the MinGW\n folks to make sure I didn't break their compile or such.\n\n Also, if you'd prefer that I submit a patch that would be applied on top\n of Dmitry's currently pending patch, I can do that as well.\n\n Finally, here is the output from a little benchmark I ran on my large\n repository at work:\n 115769 files in 17626 directories\n\n Windows native stat: false\n 2.17user 8.92system 0:14.40elapsed 76%CPU (0avgtext+0avgdata 22544384maxresident)k\n 0inputs+0outputs (161427major+0minor)pagefaults 0swaps\n\n Windows native stat: true\n 1.00user 2.85system 0:06.26elapsed 61%CPU (0avgtext+0avgdata 22544384maxresident)k\n 0inputs+0outputs (161427major+0minor)pagefaults 0swaps\n\n Looks like a nice improvement to me.\n\n -Marcus\n\n Makefile          |    7 ++++\n cache.h           |    1 +\n compat/cygwin.c   |   67 ++++++++++++++++++++++++++++++++++++\n compat/cygwin.h   |    7 ++++\n compat/mingw.c    |   64 +---------------------------------\n compat/windows.c  |   98 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n compat/windows.h  |   12 ++++++\n environment.c     |    5 +++\n git-compat-util.h |    1 +\n 9 files changed, 200 insertions(+), 62 deletions(-)\n create mode 100644 compat/cygwin.c\n create mode 100644 compat/cygwin.h\n create mode 100644 compat/windows.c\n create mode 100644 compat/windows.h\n\ndiff --git a/Makefile b/Makefile\nindex e0c03c3..685f038 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -346,6 +346,8 @@ LIB_H += cache.h\n LIB_H += cache-tree.h\n LIB_H += commit.h\n LIB_H += compat/mingw.h\n+LIB_H += compat/cygwin.h\n+LIB_H += compat/windows.h\n LIB_H += csum-file.h\n LIB_H += decorate.h\n LIB_H += delta.h\n@@ -748,6 +750,10 @@ ifeq ($(uname_S),HP-UX)\n \tNO_SYS_SELECT_H = YesPlease\n \tSNPRINTF_RETURNS_BOGUS = YesPlease\n endif\n+ifneq (,$(findstring CYGWIN,$(uname_S)))\n+\tCOMPAT_OBJS += compat/cygwin.o\n+\tCOMPAT_OBJS += compat/windows.o\n+endif\n ifneq (,$(findstring MINGW,$(uname_S)))\n \tNO_MMAP = YesPlease\n \tNO_PREAD = YesPlease\n@@ -774,6 +780,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))\n \tCOMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1\n \tCOMPAT_CFLAGS += -DSTRIP_EXTENSION=\\\".exe\\\"\n \tCOMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o\n+\tCOMPAT_OBJS += compat/windows.o\n \tEXTLIBS += -lws2_32\n \tX = .exe\n \tgitexecdir = ../libexec/git-core\ndiff --git a/cache.h b/cache.h\nindex f4b8ddf..b42ca0f 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -321,6 +321,7 @@ extern int set_git_dir(const char *path);\n extern const char *get_git_work_tree(void);\n extern const char *read_gitfile_gently(const char *path);\n extern void set_git_work_tree(const char *tree);\n+extern int have_git_dir(void);\n \n #define ALTERNATE_DB_ENVIRONMENT \"GIT_ALTERNATE_OBJECT_DIRECTORIES\"\n \ndiff --git a/compat/cygwin.c b/compat/cygwin.c\nnew file mode 100644\nindex 0000000..db44aa8\n--- /dev/null\n+++ b/compat/cygwin.c\n@@ -0,0 +1,67 @@\n+#include \"windows.h\"\n+#include \"../cache.h\"\n+\n+#undef stat\n+#undef lstat\n+\n+/* We provide our own lstat/stat functions, since the provided Cygwin versions\n+ * of these functions are too slow. These stat functions are tailored for Git's\n+ * usage, and therefore they are not meant to be complete and correct emulation\n+ * of lstat/stat functionality.\n+ */\n+static int cygwin_lstat(const char *path, struct stat *buf)\n+{\n+\treturn win_stat(path, buf, lstat);\n+}\n+\n+static int cygwin_stat(const char *path, struct stat *buf)\n+{\n+\treturn win_stat(path, buf, stat);\n+}\n+\n+static int native_stat = -1;\n+static stat_fn_t cygwin_stat_fn = stat;\n+static stat_fn_t cygwin_lstat_fn = lstat;\n+\n+static int git_cygwin_config(const char *var, const char *value, void *cb)\n+{\n+\tif (!strcmp(var, \"core.cygwinnativestat\"))\n+\t\tnative_stat = git_config_bool(var, value);\n+\treturn 0;\n+}\n+\n+static void init_stat(void)\n+{\n+\tif (native_stat < 0 && have_git_dir()) {\n+\t\tnative_stat = 0;\n+\t\tgit_config(git_cygwin_config, NULL);\n+\t\tcygwin_stat_fn = native_stat ? cygwin_stat : stat;\n+\t\tcygwin_lstat_fn = native_stat ? cygwin_lstat : lstat;\n+\t}\n+}\n+\n+/*\n+ * This are startup stubs, which choose what implementation of lstat/stat\n+ * should be used. If core.cygwinnativestat is not set then the standard\n+ * functions included in the cygwin library are used. If it is set then our\n+ * fast and dirty implementation is invoked, which should be 2-3 times\n+ * faster than cygwin functions.\n+ */\n+int cygwin_stat_choice(const char *file_name, struct stat *buf)\n+{\n+\tif (file_name[0] == '/')\n+\t\treturn stat(file_name, buf);\n+\n+\tinit_stat();\n+\treturn (cygwin_stat_fn ? cygwin_stat_fn : stat) (file_name, buf);\n+}\n+\n+int cygwin_lstat_choice(const char *file_name, struct stat *buf)\n+{\n+\tif (file_name[0] == '/')\n+\t\treturn lstat(file_name, buf);\n+\n+\tinit_stat();\n+\treturn (cygwin_lstat_fn ? cygwin_lstat_fn : lstat) (file_name, buf);\n+}\n+\ndiff --git a/compat/cygwin.h b/compat/cygwin.h\nnew file mode 100644\nindex 0000000..14775fd\n--- /dev/null\n+++ b/compat/cygwin.h\n@@ -0,0 +1,7 @@\n+#include \"windows.h\"\n+\n+int cygwin_stat_choice(const char*, struct stat*);\n+int cygwin_lstat_choice(const char*, struct stat*);\n+\n+#define stat(path,buf) cygwin_stat_choice(path,buf)\n+#define lstat cygwin_lstat_choice\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex ccfa2a0..174142c 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -23,66 +23,6 @@ int mingw_open (const char *filename, int oflags, ...)\n \treturn fd;\n }\n \n-static inline time_t filetime_to_time_t(const FILETIME *ft)\n-{\n-\tlong long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;\n-\twinTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */\n-\twinTime /= 10000000;\t\t /* Nano to seconds resolution */\n-\treturn (time_t)winTime;\n-}\n-\n-extern int _getdrive( void );\n-/* We keep the do_lstat code in a separate function to avoid recursion.\n- * When a path ends with a slash, the stat will fail with ENOENT. In\n- * this case, we strip the trailing slashes and stat again.\n- */\n-static int do_lstat(const char *file_name, struct stat *buf)\n-{\n-\tWIN32_FILE_ATTRIBUTE_DATA fdata;\n-\n-\tif (GetFileAttributesExA(file_name, GetFileExInfoStandard, &fdata)) {\n-\t\tint fMode = S_IREAD;\n-\t\tif (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)\n-\t\t\tfMode |= S_IFDIR;\n-\t\telse\n-\t\t\tfMode |= S_IFREG;\n-\t\tif (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))\n-\t\t\tfMode |= S_IWRITE;\n-\n-\t\tbuf->st_ino = 0;\n-\t\tbuf->st_gid = 0;\n-\t\tbuf->st_uid = 0;\n-\t\tbuf->st_nlink = 1;\n-\t\tbuf->st_mode = fMode;\n-\t\tbuf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */\n-\t\tbuf->st_dev = buf->st_rdev = (_getdrive() - 1);\n-\t\tbuf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));\n-\t\tbuf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));\n-\t\tbuf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));\n-\t\terrno = 0;\n-\t\treturn 0;\n-\t}\n-\n-\tswitch (GetLastError()) {\n-\tcase ERROR_ACCESS_DENIED:\n-\tcase ERROR_SHARING_VIOLATION:\n-\tcase ERROR_LOCK_VIOLATION:\n-\tcase ERROR_SHARING_BUFFER_EXCEEDED:\n-\t\terrno = EACCES;\n-\t\tbreak;\n-\tcase ERROR_BUFFER_OVERFLOW:\n-\t\terrno = ENAMETOOLONG;\n-\t\tbreak;\n-\tcase ERROR_NOT_ENOUGH_MEMORY:\n-\t\terrno = ENOMEM;\n-\t\tbreak;\n-\tdefault:\n-\t\terrno = ENOENT;\n-\t\tbreak;\n-\t}\n-\treturn -1;\n-}\n-\n /* We provide our own lstat/fstat functions, since the provided\n  * lstat/fstat functions are so slow. These stat functions are\n  * tailored for Git's usage (read: fast), and are not meant to be\n@@ -94,7 +34,7 @@ int mingw_lstat(const char *file_name, struct stat *buf)\n \tint namelen;\n \tstatic char alt_name[PATH_MAX];\n \n-\tif (!do_lstat(file_name, buf))\n+\tif (!win_stat(file_name, buf, win_stat_fail))\n \t\treturn 0;\n \n \t/* if file_name ended in a '/', Windows returned ENOENT;\n@@ -113,7 +53,7 @@ int mingw_lstat(const char *file_name, struct stat *buf)\n \n \tmemcpy(alt_name, file_name, namelen);\n \talt_name[namelen] = 0;\n-\treturn do_lstat(alt_name, buf);\n+\treturn win_stat(alt_name, buf, win_stat_fail);\n }\n \n #undef fstat\ndiff --git a/compat/windows.c b/compat/windows.c\nnew file mode 100644\nindex 0000000..8c7d976\n--- /dev/null\n+++ b/compat/windows.c\n@@ -0,0 +1,98 @@\n+#define WIN32_LEAN_AND_MEAN\n+#include \"../git-compat-util.h\"\n+#include <windows.h>\n+\n+static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)\n+{\n+\tlong long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;\n+\twinTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */\n+\tts->tv_sec = (time_t)(winTime/10000000); /* 100-nanosecond interval to seconds */\n+\tts->tv_nsec = (long)(winTime - ts->tv_sec*10000000LL) * 100; /* nanoseconds */\n+}\n+\n+#define size_to_blocks(s) (((s)+511)/512)\n+\n+/* do_lstat is a common implementation of a faster stat algorithm for Windows\n+ *\n+ * When the Windows stat fails for an unknown reason, a fallback is called to\n+ * handle the error.\n+ */\n+int win_stat(const char *file_name, struct stat *buf, stat_fn_t fallback)\n+{\n+\tWIN32_FILE_ATTRIBUTE_DATA fdata;\n+\n+\tif (GetFileAttributesExA(file_name, GetFileExInfoStandard, &fdata)) {\n+\t\tint fMode = S_IREAD;\n+\n+#if defined(__CYGWIN__)\n+\t\t/*\n+\t\t * If the system attribute is set and it is not a directory then\n+\t\t * it could be a symbol link created in the nowinsymlinks mode.\n+\t\t * Normally, Cygwin works in the winsymlinks mode, so this situation\n+\t\t * is very unlikely. For the sake of simplicity of our code, let's\n+\t\t * Cygwin to handle it.\n+\t\t */\n+\t\tif ((fdata.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) &&\n+\t\t    !(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))\n+\t\t\treturn fallback (file_name, buf);\n+#endif\n+\n+\t\tif (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)\n+\t\t\tfMode |= S_IFDIR;\n+\t\telse\n+\t\t\tfMode |= S_IFREG;\n+\t\tif (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))\n+\t\t\tfMode |= S_IWRITE;\n+\n+\t\tbuf->st_ino = 0;\n+\t\tbuf->st_gid = buf->st_uid = 0;\n+\t\tbuf->st_nlink = 1;\n+\t\tbuf->st_mode = fMode;\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 = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */\n+#endif\n+\t\tbuf->st_blocks = size_to_blocks(buf->st_size);\n+\t\t/* st_dev, st_rdev are not used by Git */\n+\t\tbuf->st_dev = buf->st_rdev = 0;\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\terrno = 0;\n+\t\treturn 0;\n+\t}\n+\n+\tswitch (GetLastError()) {\n+\tcase ERROR_ACCESS_DENIED:\n+\tcase ERROR_SHARING_VIOLATION:\n+\tcase ERROR_LOCK_VIOLATION:\n+\tcase ERROR_SHARING_BUFFER_EXCEEDED:\n+\t\terrno = EACCES;\n+\t\tbreak;\n+\tcase ERROR_BUFFER_OVERFLOW:\n+\t\terrno = ENAMETOOLONG;\n+\t\tbreak;\n+\tcase ERROR_NOT_ENOUGH_MEMORY:\n+\t\terrno = ENOMEM;\n+\t\tbreak;\n+\tdefault:\n+\t\t/* In the winsymlinks mode (which is the default), Cygwin\n+\t\t * emulates symbol links using Windows shortcut files. These\n+\t\t * files are formed by adding .lnk extension. So, if we have\n+\t\t * not found the specified file name, it could be that it is\n+\t\t * a symbol link. Let's the fallback deal with that.\n+\t\t * In MinGW, this could also happen if the path ends with a\n+\t\t * slash.\n+\t\t */\n+\t\treturn fallback (file_name, buf);\n+\t}\n+\treturn -1;\n+}\n+\n+int win_stat_fail(const char *file_name, struct stat *buf)\n+{\n+\terrno = ENOENT;\n+\treturn -1;\n+}\ndiff --git a/compat/windows.h b/compat/windows.h\nnew file mode 100644\nindex 0000000..8412e42\n--- /dev/null\n+++ b/compat/windows.h\n@@ -0,0 +1,12 @@\n+#ifndef COMPAT_WINDOWS_H\n+#define COMPAT_WINDOWS_H\n+\n+#include <sys/types.h>\n+#include <sys/stat.h>\n+\n+typedef int (*stat_fn_t)(const char*, struct stat*);\n+\n+extern int win_stat(const char*, struct stat*, stat_fn_t);\n+extern int win_stat_fail(const char*, struct stat *);\n+\n+#endif\ndiff --git a/environment.c b/environment.c\nindex 0c6d11f..cbd8074 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -151,3 +151,8 @@ int set_git_dir(const char *path)\n \tsetup_git_env();\n \treturn 0;\n }\n+\n+int have_git_dir(void)\n+{\n+\treturn !!git_dir;\n+}\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex db2836f..cd9752c 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -85,6 +85,7 @@\n #undef _XOPEN_SOURCE\n #include <grp.h>\n #define _XOPEN_SOURCE 600\n+#include \"compat/cygwin.h\"\n #else\n #undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */\n #include <grp.h>\n-- \n1.6.0.2.405.g3cc38\n"},{"id":"91732","messageId":"20080927083507.GA5342@blimp.localhost","threadId":"15635","inReplyTo":"1222498926-30635-1-git-send-email-marcus@griep.us","subject":"Re: [PATCH v2] Add a \"fast stat\" mode for Cygwin","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-09-27T08:35:07Z","receivedAt":"2008-09-27T08:35:07Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"Marcus Griep, Sat, Sep 27, 2008 09:02:06 +0200:\n> This patch introduces core.cygwinnativestat configuration flag. If this\n\n\"cygwin.nativestat\"? If only to shame them\n\n> variable is not set then Git will work as before. However, if it is set\n> then the Cygwin version of Git will try to use a Win32 API function if\n> it is possible to speed up stat/lstat.\n> \n> This fast mode works only for relative paths. It is assumed that the\n> whole repository is located inside one directory without using Cygwin\n> mount to bind external paths inside of the current tree.\n> \n> Symbolic links are supported by falling back on the cygwin version of\n> these functions.\n\nThe cygwins .lnk cannot be supported. The names just don't exist for\nnative GetFileAttributesExA.\n"},{"id":"91739","messageId":"20080927103911.GD21650@dpotapov.dyndns.org","threadId":"15635","inReplyTo":"1222498926-30635-1-git-send-email-marcus@griep.us","subject":"Re: [PATCH v2] Add a \"fast stat\" mode for Cygwin","fromName":"Dmitry Potapov","fromEmail":"dpotapov@gmail.com","sentAt":"2008-09-27T10:39:11Z","receivedAt":"2008-09-27T10:39:11Z","isPatch":true,"sender":{"key":"dpotapov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6568595?v=4"},"body":"Hi Marcus,\n\nOn Sat, Sep 27, 2008 at 03:02:06AM -0400, Marcus Griep wrote:\n> \n>  This is a substitute patch that takes care of many of the concerns already\n>  posted to this thread regarding the patch.  Sorry if it steps on your toes,\n>  Dmitry.  You began scratching my itch, so I wanted to jump in and scratch\n>  some more.\n\nI am sorry I was not able to send my patches earlier. I had them ready\nby the end of the day when we had the discussion, but I have not had an\nopportunity to test it on Windows till today.\n\nI have only skimmed over your patch, but there are a few changes that\nI really dislike about your patch. You changed the semantic of _choice\nfunctions. While I use it as stubs to choose what implementation to use,\nyou make them part of implementation, which is always called. So I do\nnot understand why you left the comment saying that they are only stubs\nand then why you need function pointers at all then.\n\nAlso, you made some changes to MinGW (I don't know if you tested it),\nbut any change like removing _getdrive() from MinGW version is better\nto move into separately patch (or, at least, clearly state them in the\ncommit comment).\n\nAnyway, thanks for your efforts, but if you want to go ahead with some\nother match of mine (especially Windows related), please, let me know,\nso we can avoid stepping on each other toes.\n\nDmitry\n"}]}