{"thread":{"id":"23051","subject":"[PATCH 1/2] fix mingw stat() and lstat() implementations for handling symlinks","startedAt":"2010-03-17T15:17:34Z","lastAt":"2010-03-17T15:17:34Z","messageCount":1,"participants":["Pat Thoyts"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"137022","messageId":"87eijjdkqj.fsf@fox.patthoyts.tk","threadId":"23051","inReplyTo":null,"subject":"[PATCH 1/2] fix mingw stat() and lstat() implementations for handling symlinks","fromName":"Pat Thoyts","fromEmail":"patthoyts@users.sourceforge.net","sentAt":"2010-03-17T15:17:34Z","receivedAt":"2010-03-17T15:17:34Z","isPatch":true,"sender":{"key":"patthoyts@users.sourceforge.net","avatar":"https://avatars.githubusercontent.com/u/30739?v=4"},"body":"In msysGit the stat() function has been implemented using mingw_lstat\nwhich sets the st_mode member to S_IFLNK when a symbolic links is found.\nThis causes the is_executable function to return when git attempts to\nbuild a list of available commands in the help code and we end up missing\nmost git commands. (msysGit issue #445)\n\nThis patch modifies the implementation so that lstat() will return the link\nflag but if we are called as stat() we read the size of the target and set\nthe mode to that of a regular file.\n\nSigned-off-by: Pat Thoyts <patthoyts@users.sourceforge.net>\n---\n compat/mingw.c |   31 ++++++++++++++++++++++++-------\n compat/mingw.h |    3 ++-\n 2 files changed, 26 insertions(+), 8 deletions(-)\n\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex 0df1a3d..9c10a4c 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -334,8 +334,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft)\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+ * If follow is true then act like stat() and report on the link\n+ * target. Otherwise report on the link itself.\n  */\n-static int do_lstat(const char *file_name, struct stat *buf)\n+static int do_lstat(int follow, const char *file_name, struct stat *buf)\n {\n \tWIN32_FILE_ATTRIBUTE_DATA fdata;\n \n@@ -357,11 +360,16 @@ static int do_lstat(const char *file_name, struct stat *buf)\n \t\t\tif (handle != INVALID_HANDLE_VALUE) {\n \t\t\t\tif ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&\n \t\t\t\t\t\t(findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {\n-\t\t\t\t\tchar buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];\n-\t\t\t\t\tbuf->st_mode = S_IREAD | S_IFLNK;\n+\t\t\t\t\tif (follow) {\n+\t\t\t\t\t\tchar buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];\n+\t\t\t\t\t\tbuf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);\n+\t\t\t\t\t\tbuf->st_mode = S_IFREG;\n+\t\t\t\t\t} else {\n+\t\t\t\t\t\tbuf->st_mode = S_IFLNK;\n+\t\t\t\t\t}\n+\t\t\t\t\tbuf->st_mode |= S_IREAD;\n \t\t\t\t\tif (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY))\n \t\t\t\t\t\tbuf->st_mode |= S_IWRITE;\n-\t\t\t\t\tbuf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);\n \t\t\t\t}\n \t\t\t\tFindClose(handle);\n \t\t\t}\n@@ -378,12 +386,12 @@ static int do_lstat(const char *file_name, struct stat *buf)\n  * complete. Note that Git stat()s are redirected to mingw_lstat()\n  * too, since Windows doesn't really handle symlinks that well.\n  */\n-int mingw_lstat(const char *file_name, struct stat *buf)\n+static int do_stat_internal(int follow, const char *file_name, struct stat *buf)\n {\n \tint namelen;\n \tstatic char alt_name[PATH_MAX];\n \n-\tif (!do_lstat(file_name, buf))\n+\tif (!do_lstat(follow, file_name, buf))\n \t\treturn 0;\n \n \t/*\n@@ -403,7 +411,16 @@ 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 do_lstat(follow, alt_name, buf);\n+}\n+\n+int mingw_lstat(const char *file_name, struct stat *buf)\n+{\n+\treturn do_stat_internal(0, file_name, buf);\n+}\n+int mingw_stat(const char *file_name, struct stat *buf)\n+{\n+\treturn do_stat_internal(1, file_name, buf);\n }\n \n #undef fstat\ndiff --git a/compat/mingw.h b/compat/mingw.h\nindex 4650d8a..ff5477b 100644\n--- a/compat/mingw.h\n+++ b/compat/mingw.h\n@@ -222,10 +222,11 @@ int mingw_getpagesize(void);\n #ifndef ALREADY_DECLARED_STAT_FUNCS\n #define stat _stati64\n int mingw_lstat(const char *file_name, struct stat *buf);\n+int mingw_stat(const char *file_name, struct stat *buf);\n int mingw_fstat(int fd, struct stat *buf);\n #define fstat mingw_fstat\n #define lstat mingw_lstat\n-#define _stati64(x,y) mingw_lstat(x,y)\n+#define _stati64(x,y) mingw_stat(x,y)\n #endif\n \n int mingw_utime(const char *file_name, const struct utimbuf *times);\n-- \n1.7.0.2.msysgit.0.3.g3c992.dirty\n"}]}