This gives us a significant speedup when adding, committing and stat'ing files. (Also, since Windows doesn't really handle symlinks, it's fine that stat just uses lstat) Signed-off-by: Marius Storm-Olsen <mstormo_git@xxxxxxxxxxxxxxx> --- Revision #2 of the patch. For this one I change the filetime_to_time_t function to do the timestamp conversion inline in the FILETIME struct. That way we also avoid one assignment, bitshifting and addition. Sneaky, huh? ;-) New stats: ------------------------- Command: git init ------------------------- real 0m0.047s user 0m0.031s sys 0m0.000s ------------------------- Command: git add . ------------------------- real 0m12.016s user 0m0.015s sys 0m0.000s ------------------------- Command: git commit -a... ------------------------- real 0m17.031s user 0m0.015s sys 0m0.030s ------------------------- 3x Command: git-status ------------------------- real 0m5.265s user 0m0.015s sys 0m0.015s real 0m5.297s user 0m0.015s sys 0m0.000s real 0m5.250s user 0m0.015s sys 0m0.016s ------------------------- Command: git commit... (single file) ------------------------- real 0m7.859s user 0m0.015s sys 0m0.015s compat/mingw.c | 41 +++++++++++++++++++++++++++++++++-------- git-compat-util.h | 4 ++++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 7711a3f..86a1419 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -23,19 +23,44 @@ int fchmod(int fildes, mode_t mode) return -1; } -int lstat(const char *file_name, struct stat *buf) +static inline time_t filetime_to_time_t(const FILETIME *ft) +{ + long long *winTime = (long long*)ft; + *winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */ + *winTime /= 10000000; /* Nano to seconds resolution */ + return (time_t)ft->dwLowDateTime; +} + +extern int _getdrive( void ); +int git_lstat(const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - - if (!stat(file_name, buf)) + WIN32_FILE_ATTRIBUTE_DATA fdata; + + if (GetFileAttributesExA(file_name, GetFileExInfoStandard, &fdata)) { + int fMode = S_IREAD; + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + fMode |= S_IFDIR; + else + fMode |= S_IFREG; + if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + fMode |= S_IWRITE; + + buf->st_ino = 0; + buf->st_gid = 0; + buf->st_uid = 0; + buf->st_nlink = 1; + buf->st_mode = fMode; + buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ + buf->st_dev = buf->st_rdev = (_getdrive() - 1); + buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); + buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); + buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); return 0; + } + errno = ENOENT; - /* if file_name ended in a '/', Windows returned ENOENT; - * try again without trailing slashes - */ - if (errno != ENOENT) - return -1; namelen = strlen(file_name); if (namelen && file_name[namelen-1] != '/') return -1; diff --git a/git-compat-util.h b/git-compat-util.h index 1ba499f..4122465 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -488,6 +488,10 @@ int mingw_rename(const char*, const char*); extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); +/* Make git on Windows use git_lstat instead of lstat and stat */ +int git_lstat(const char *file_name, struct stat *buf); +#define lstat(x,y) git_lstat(x,y) +#define stat(x,y) git_lstat(x,y) #endif /* __MINGW32__ */ #endif -- 1.5.3.GIT-dirty - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html