@matheusbsbs / matheus-bagliano / commits / 9b9784cab9
Fork 0

MinGW: fix stat() and lstat() implementations for handling symlinks

In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Includes squashed fix st_mode for symlink dirs Signed-off-by: Pat Thoyts <patthoyts@users.sourceforge.net> Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>

Pat Thoyts committed Mar 17, 2010 at 15:17 UTC 9b9784cab9bba925ab35c7aa8d4e5967a4268093
2 files changed +37 -5
compat/mingw.c
+35 -4
@@ -192,8 +192,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft)
192 /* We keep the do_lstat code in a separate function to avoid recursion.
193 * When a path ends with a slash, the stat will fail with ENOENT. In
194 * this case, we strip the trailing slashes and stat again.
195 + *
196 + * If follow is true then act like stat() and report on the link
197 + * target. Otherwise report on the link itself.
198 */
196 -static int do_lstat(const char *file_name, struct stat *buf)
199 +static int do_lstat(int follow, const char *file_name, struct stat *buf)
200 {
201 WIN32_FILE_ATTRIBUTE_DATA fdata;
202
@@ -209,6 +212,25 @@ static int do_lstat(const char *file_name, struct stat *buf)
212 buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
213 buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
214 buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
215 + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
216 + WIN32_FIND_DATAA findbuf;
217 + HANDLE handle = FindFirstFileA(file_name, &findbuf);
218 + if (handle != INVALID_HANDLE_VALUE) {
219 + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
220 + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
221 + if (follow) {
222 + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
223 + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
224 + } else {
225 + buf->st_mode = S_IFLNK;
226 + }
227 + buf->st_mode |= S_IREAD;
228 + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
229 + buf->st_mode |= S_IWRITE;
230 + }
231 + FindClose(handle);
232 + }
233 + }
234 return 0;
235 }
236 return -1;
@@ -220,12 +242,12 @@ static int do_lstat(const char *file_name, struct stat *buf)
242 * complete. Note that Git stat()s are redirected to mingw_lstat()
243 * too, since Windows doesn't really handle symlinks that well.
244 */
223 -int mingw_lstat(const char *file_name, struct stat *buf)
245 +static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
246 {
247 int namelen;
248 static char alt_name[PATH_MAX];
249
228 - if (!do_lstat(file_name, buf))
250 + if (!do_lstat(follow, file_name, buf))
251 return 0;
252
253 /* if file_name ended in a '/', Windows returned ENOENT;
@@ -244,7 +266,16 @@ int mingw_lstat(const char *file_name, struct stat *buf)
266
267 memcpy(alt_name, file_name, namelen);
268 alt_name[namelen] = 0;
247 - return do_lstat(alt_name, buf);
269 + return do_lstat(follow, alt_name, buf);
270 +}
271 +
272 +int mingw_lstat(const char *file_name, struct stat *buf)
273 +{
274 + return do_stat_internal(0, file_name, buf);
275 +}
276 +int mingw_stat(const char *file_name, struct stat *buf)
277 +{
278 + return do_stat_internal(1, file_name, buf);
279 }
280
281 #undef fstat
compat/mingw.h
+2 -1
@@ -235,10 +235,11 @@ int mingw_getpagesize(void);
235 #ifndef ALREADY_DECLARED_STAT_FUNCS
236 #define stat _stati64
237 int mingw_lstat(const char *file_name, struct stat *buf);
238 +int mingw_stat(const char *file_name, struct stat *buf);
239 int mingw_fstat(int fd, struct stat *buf);
240 #define fstat mingw_fstat
241 #define lstat mingw_lstat
241 -#define _stati64(x,y) mingw_lstat(x,y)
242 +#define _stati64(x,y) mingw_stat(x,y)
243 #endif
244
245 int mingw_utime(const char *file_name, const struct utimbuf *times);