Commit 290f240ee006fef9d65cf987ad5e0d99e956b936

Russell Belfer 2012-02-23T11:16:47

Fix readdir usage across platforms This fixes the missing readdir_r from win32 and fixes other platforms to always use the reentrant readdir_r form for reading directory contents.

diff --git a/src/path.c b/src/path.c
index 88ea95a..ec40f4b 100644
--- a/src/path.c
+++ b/src/path.c
@@ -491,7 +491,7 @@ int git_path_direach(
 {
 	ssize_t wd_len;
 	DIR *dir;
-	struct dirent *de;
+	struct dirent de_buf, *de;
 
 	if (git_path_to_dir(path) < GIT_SUCCESS)
 		return git_buf_lasterror(path);
@@ -501,7 +501,7 @@ int git_path_direach(
 	if (!dir)
 		return git__throw(GIT_EOSERR, "Failed to process `%s` tree structure. An error occured while opening the directory", path->ptr);
 
-	while ((de = readdir(dir)) != NULL) {
+	while (p_readdir_r(dir, &de_buf, &de) == 0 && de != NULL) {
 		int result;
 
 		if (is_dot_or_dotdot(de->d_name))
@@ -547,7 +547,7 @@ int git_path_dirload(
 	path_len -= prefix_len;
 	need_slash = (path_len > 0 && path[path_len-1] != '/') ? 1 : 0;
 
-	while ((error = readdir_r(dir, &de_buf, &de)) == 0 && de != NULL) {
+	while ((error = p_readdir_r(dir, &de_buf, &de)) == 0 && de != NULL) {
 		char *entry_path;
 		size_t entry_len;
 
diff --git a/src/unix/posix.h b/src/unix/posix.h
index 9973acf..2b0d85b 100644
--- a/src/unix/posix.h
+++ b/src/unix/posix.h
@@ -21,5 +21,6 @@
 #define p_snprintf(b, c, f, ...) snprintf(b, c, f, __VA_ARGS__)
 #define p_mkstemp(p) mkstemp(p)
 #define p_setenv(n,v,o) setenv(n,v,o)
+#define p_readdir_r(d,e,r) readdir_r(d,e,r)
 
 #endif
diff --git a/src/win32/dir.c b/src/win32/dir.c
index 0a634f0..23bc555 100644
--- a/src/win32/dir.c
+++ b/src/win32/dir.c
@@ -58,25 +58,37 @@ git__DIR *git__opendir(const char *dir)
 	return new;
 }
 
-struct git__dirent *git__readdir(git__DIR *d)
+int git__readdir_r(
+	git__DIR *d, struct git__dirent *entry, struct git__dirent **result)
 {
-	if (!d || d->h == INVALID_HANDLE_VALUE)
-		return NULL;
+	if (!d || !entry || !result || d->h == INVALID_HANDLE_VALUE)
+		return -1;
 
 	if (d->first)
 		d->first = 0;
-	else {
-		if (!FindNextFileW(d->h, &d->f))
-			return NULL;
+	else if (!FindNextFileW(d->h, &d->f)) {
+		*result = NULL;
+		return 0;
 	}
 
-	if (wcslen(d->f.cFileName) >= sizeof(d->entry.d_name))
-		return NULL;
+	if (wcslen(d->f.cFileName) >= sizeof(entry->d_name))
+		return -1;
+
+	entry->d_ino = 0;
+	WideCharToMultiByte(
+		gitwin_get_codepage(), 0, d->f.cFileName, -1,
+		entry->d_name, GIT_PATH_MAX, NULL, NULL);
 
-	d->entry.d_ino = 0;
-	WideCharToMultiByte(gitwin_get_codepage(), 0, d->f.cFileName, -1, d->entry.d_name, GIT_PATH_MAX, NULL, NULL);
+	*result = entry;
+	return 0;
+}
 
-	return &d->entry;
+struct git__dirent *git__readdir(git__DIR *d)
+{
+	struct git__dirent *result;
+	if (git__readdir_r(d, &d->entry, &result) < 0)
+		return NULL;
+	return result;
 }
 
 void git__rewinddir(git__DIR *d)
diff --git a/src/win32/dir.h b/src/win32/dir.h
index c16e136..fc54e29 100644
--- a/src/win32/dir.h
+++ b/src/win32/dir.h
@@ -24,6 +24,7 @@ typedef struct {
 
 extern git__DIR *git__opendir(const char *);
 extern struct git__dirent *git__readdir(git__DIR *);
+extern int git__readdir_r(git__DIR*, struct git__dirent*, struct git__dirent**);
 extern void git__rewinddir(git__DIR *);
 extern int git__closedir(git__DIR *);
 
@@ -36,4 +37,6 @@ extern int git__closedir(git__DIR *);
 #	define closedir git__closedir
 # endif
 
+#define p_readdir_r(d,e,r) git__readdir_r(d,e,r)
+
 #endif /* INCLUDE_dir_h__ */