[PATCH] Add a new lstat implementation based on Win32 API, and make stat use that implementation too.
From: Marius Storm-Olsen <hidden>
Date: 2016-06-15 22:43:32
Subsystem:
the rest · Maintainer:
Linus Torvalds
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 <redacted>
---
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