aboutsummaryrefslogtreecommitdiff
path: root/compat/mingw.c
diff options
context:
space:
mode:
authorMarius Storm-Olsen <marius@trolltech.com>2009-05-31 18:15:22 +0200
committerJunio C Hamano <gitster@pobox.com>2009-06-01 00:25:54 -0700
commite16c60d9f98c66fd2c9bba64562b3439970c13f8 (patch)
treeac682110cc4fc94da135be7e5f3033119e3e496e /compat/mingw.c
parent36ad53ffee6ed5b7c277cde660f526fd8ce3d68f (diff)
downloadgit-e16c60d9f98c66fd2c9bba64562b3439970c13f8.tar.gz
git-e16c60d9f98c66fd2c9bba64562b3439970c13f8.tar.xz
MinGW readdir reimplementation to support d_type
The original readdir implementation was fast, but didn't support the d_type. This means that git would do additional lstats for each entry, to figure out if the entry was a directory or not. This unneedingly slowed down many operations, since Windows API provides this information directly when walking the directories. By running this implementation on Moe's repo structure: mkdir bummer && cd bummer; for ((i=0;i<100;i++)); do mkdir $i && pushd $i; for ((j=0;j<1000;j++)); do echo "$j" >$j; done; popd; done We see the following speedups: git add . ------------------- old: 00:00:23(.087) new: 00:00:21(.512) 1.07x git status ------------------- old: 00:00:03(.306) new: 00:00:01(.684) 1.96x git clean -dxf ------------------- old: 00:00:01(.918) new: 00:00:00(.295) 6.50x Signed-off-by: Marius Storm-Olsen <marius@trolltech.com> Signed-off-by: Steffen Prohaska <prohaska@zib.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'compat/mingw.c')
-rw-r--r--compat/mingw.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/compat/mingw.c b/compat/mingw.c
index 12d0c2fd8..bed417875 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1172,3 +1172,62 @@ char *getpass(const char *prompt)
fputs("\n", stderr);
return strbuf_detach(&buf, NULL);
}
+
+#ifndef NO_MINGW_REPLACE_READDIR
+/* MinGW readdir implementation to avoid extra lstats for Git */
+struct mingw_DIR
+{
+ struct _finddata_t dd_dta; /* disk transfer area for this dir */
+ struct mingw_dirent dd_dir; /* Our own implementation, including d_type */
+ long dd_handle; /* _findnext handle */
+ int dd_stat; /* 0 = next entry to read is first entry, -1 = off the end, positive = 0 based index of next entry */
+ char dd_name[1]; /* given path for dir with search pattern (struct is extended) */
+};
+
+struct dirent *mingw_readdir(DIR *dir)
+{
+ WIN32_FIND_DATAA buf;
+ HANDLE handle;
+ struct mingw_DIR *mdir = (struct mingw_DIR*)dir;
+
+ if (!dir->dd_handle) {
+ errno = EBADF; /* No set_errno for mingw */
+ return NULL;
+ }
+
+ if (dir->dd_handle == (long)INVALID_HANDLE_VALUE && dir->dd_stat == 0)
+ {
+ handle = FindFirstFileA(dir->dd_name, &buf);
+ DWORD lasterr = GetLastError();
+ dir->dd_handle = (long)handle;
+ if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
+ errno = err_win_to_posix(lasterr);
+ return NULL;
+ }
+ } else if (dir->dd_handle == (long)INVALID_HANDLE_VALUE) {
+ return NULL;
+ } else if (!FindNextFileA((HANDLE)dir->dd_handle, &buf)) {
+ DWORD lasterr = GetLastError();
+ FindClose((HANDLE)dir->dd_handle);
+ dir->dd_handle = (long)INVALID_HANDLE_VALUE;
+ /* POSIX says you shouldn't set errno when readdir can't
+ find any more files; so, if another error we leave it set. */
+ if (lasterr != ERROR_NO_MORE_FILES)
+ errno = err_win_to_posix(lasterr);
+ return NULL;
+ }
+
+ /* We get here if `buf' contains valid data. */
+ strcpy(dir->dd_dir.d_name, buf.cFileName);
+ ++dir->dd_stat;
+
+ /* Set file type, based on WIN32_FIND_DATA */
+ mdir->dd_dir.d_type = 0;
+ if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ mdir->dd_dir.d_type |= DT_DIR;
+ else
+ mdir->dd_dir.d_type |= DT_REG;
+
+ return (struct dirent*)&dir->dd_dir;
+}
+#endif // !NO_MINGW_REPLACE_READDIR