git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 08/11] MinGW readdir reimplementation to support d_type

From
Steffen Prohaska <prohaska@zib.de>
Date
May 31, 2009, 16:15 UTC
Message-ID
<1243786525-4493-9-git-send-email-prohaska@zib.de>
In-Reply-To
<1243786525-4493-8-git-send-email-prohaska@zib.de>
From: Marius Storm-Olsen <marius@trolltech.com>

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>
---
 compat/mingw.c |   59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 compat/mingw.h |   29 +++++++++++++++++++++++++++
 2 files changed, 88 insertions(+), 0 deletions(-)
diff --git a/compat/mingw.c b/compat/mingw.c
index e190fdd..d85d680 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1171,3 +1171,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
diff --git a/compat/mingw.h b/compat/mingw.h
index 4c50f5b..4f7ba4c 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -235,3 +235,32 @@ int main(int argc, const char **argv) \
 	return mingw_main(argc, argv); \
 } \
 static int mingw_main(c,v)
+
+#ifndef NO_MINGW_REPLACE_READDIR
+/*
+ * A replacement of readdir, to ensure that it reads the file type at
+ * the same time. This avoid extra unneeded lstats in git on MinGW
+ */
+#undef DT_UNKNOWN
+#undef DT_DIR
+#undef DT_REG
+#undef DT_LNK
+#define DT_UNKNOWN	0
+#define DT_DIR		1
+#define DT_REG		2
+#define DT_LNK		3
+
+struct mingw_dirent
+{
+	long		d_ino;			/* Always zero. */
+	union {
+		unsigned short	d_reclen;	/* Always zero. */
+		unsigned char   d_type;		/* Reimplementation adds this */
+	};
+	unsigned short	d_namlen;		/* Length of name in d_name. */
+	char		d_name[FILENAME_MAX];	/* File name. */
+};
+#define dirent mingw_dirent
+#define readdir(x) mingw_readdir(x)
+struct dirent *mingw_readdir(DIR *dir);
+#endif // !NO_MINGW_REPLACE_READDIR
-- 
1.6.3.1.54.g99dd
Previous: Steffen ProhaskaNext: Johannes Sixt
Message 9 of 37 in “Various msysgit patches”
  1. 00/11 Various msysgit patchesSteffen Prohaska, May 31, 2009
  2. 01/11 MinGW: GCC >= 4 does not need SNPRINTF_SIZE_CORR anymoreSteffen Prohaska, May 31, 2009
  3. 02/11 Quiet make: do not leave Windows behindSteffen Prohaska, May 31, 2009
  4. 03/11 Work around a regression in Windows 7, causing erase_in_line() to crash sometimesSteffen Prohaska, May 31, 2009
  5. 04/11 test-chmtime: work around Windows limitationSteffen Prohaska, May 31, 2009
  6. 05/11 winansi: fix compile warningsSteffen Prohaska, May 31, 2009
  7. 06/11 git: browsing paths with spaces when using the start commandSteffen Prohaska, May 31, 2009
  8. 07/11 connect.c: Support PuTTY plink and TortoisePlink as SSH on WindowsSteffen Prohaska, May 31, 2009
  9. 08/11 MinGW readdir reimplementation to support d_typeSteffen Prohaska, May 31, 2009
  10. Johannes SixtMay 31, 2009
  11. Johannes SixtMay 31, 2009
  12. 05/11 MinGW: fix warning about implicit declaration of _getch()Steffen Prohaska, Jun 1, 2009
  13. 03/11 Work around a regression in Windows 7, causing erase_in_line() to crash sometimesSteffen Prohaska, Jun 1, 2009
  14. Johannes SchindelinJun 1, 2009
  15. Steffen ProhaskaJun 1, 2009
  16. Johannes SchindelinJun 1, 2009
  17. Junio C HamanoJun 1, 2009
  18. Johannes SchindelinJun 1, 2009
  19. Johannes SixtMay 31, 2009
  20. 10/11 Fix warnings in nedmalloc when compiling with GCC 4.4.0Steffen Prohaska, May 31, 2009
  21. 11/11 MinGW: Teach Makefile to detect msysgit and apply specific settingsSteffen Prohaska, May 31, 2009
  22. Junio C HamanoJun 1, 2009
  23. Johannes SchindelinJun 1, 2009
  24. Junio C HamanoJun 1, 2009
  25. GeunSik LimJun 1, 2009
  26. Johannes SchindelinJun 2, 2009
  27. Junio C HamanoJun 2, 2009
  28. Johannes SchindelinJun 3, 2009
  29. Junio C HamanoJun 3, 2009
  30. 10/11 Fix warnings in nedmalloc when compiling with GCC 4.4.0Johannes Schindelin, Jun 8, 2009
  31. Junio C HamanoJun 8, 2009
  32. Johannes SixtJun 8, 2009
  33. Steffen ProhaskaJun 9, 2009
  34. Johannes SixtJun 10, 2009
  35. Fix typo in nedmalloc warning fixJohannes Sixt, Jun 11, 2009
  36. compat/ has subdirectories: do not omit them in 'make clean'Johannes Sixt, Jun 11, 2009
  37. Johannes SchindelinJun 11, 2009

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.