Commit 19ac1ed702b043790f4a6f0d095dd81f078b6c4c

Vicent Marti 2011-07-04T21:33:26

fileops: Fix stat() on directories for W32 The `stat` methods were having issues when called with a trailing slash in Windows platforms. We now use GetFileAttributes() where possible, which doesn't have this restriction.

diff --git a/src/fileops.c b/src/fileops.c
index 275934c..fa45fde 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -93,31 +93,20 @@ int git_futils_creat_locked_withpath(const char *path, int mode)
 
 int git_futils_isdir(const char *path)
 {
-	struct stat st;
-	int len, stat_error;
-
-	assert(path);
-
-	len = strlen(path);
-
-	/* win32: stat path for folders cannot end in a slash */
-	if (path[len - 1] == '/') {
-		char *path_fixed = NULL;
-		path_fixed = git__strdup(path);
-		path_fixed[len - 1] = 0;
-		stat_error = p_stat(path_fixed, &st);
-		free(path_fixed);
-	} else {
-		stat_error = p_stat(path, &st);
-	}
-
-	if (stat_error < GIT_SUCCESS)
+#ifdef GIT_WIN32
+	DWORD attr = GetFileAttributes(path);
+	if (attr == INVALID_FILE_ATTRIBUTES)
 		return GIT_ERROR;
 
-	if (!S_ISDIR(st.st_mode))
+	return (attr & FILE_ATTRIBUTE_DIRECTORY) ? GIT_SUCCESS : GIT_ERROR;
+
+#else
+	struct stat st;
+	if (p_stat(path, &st) < GIT_SUCCESS)
 		return GIT_ERROR;
 
-	return GIT_SUCCESS;
+	return S_ISDIR(st.st_mode) ? GIT_SUCCESS : GIT_ERROR;
+#endif
 }
 
 int git_futils_isfile(const char *path)
diff --git a/src/repository.c b/src/repository.c
index 48c8e2b..c820608 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -377,7 +377,7 @@ static int retrieve_device(dev_t *device_out, const char *path)
 
 	assert(device_out);
 
-	if (p_stat(path, &path_info))
+	if (p_lstat(path, &path_info))
 		return git__throw(GIT_EOSERR, "Failed to get file informations: %s", path);
 
 	*device_out = path_info.st_dev;
diff --git a/src/win32/posix.c b/src/win32/posix.c
index 610a416..dfa4e1a 100644
--- a/src/win32/posix.c
+++ b/src/win32/posix.c
@@ -190,13 +190,22 @@ int p_hide_directory__w32(const char *path)
 	return error;
 }
 
-int p_realpath(const char *orig_path, char *buffer)
+char *p_realpath(const char *orig_path, char *buffer)
 {
-	int ret = GetFullPathName(orig_path, GIT_PATH_MAX, buffer, NULL);
-	if (!ret || ret > GIT_PATH_MAX)
-		return GIT_EOSERR;
+	int ret, alloc = 0;
+	
+	if (buffer == NULL) {
+		buffer = (char *)git__malloc(GIT_PATH_MAX);
+		alloc = 1;
+	}
+
+	ret = GetFullPathName(orig_path, GIT_PATH_MAX, buffer, NULL);
+	if (!ret || ret > GIT_PATH_MAX) {
+		if (alloc) free(buffer);
+		return NULL;
+	}
 
 	git_path_mkposix(buffer);
-	return GIT_SUCCESS;
+	return buffer;
 }
 
diff --git a/src/win32/posix.h b/src/win32/posix.h
index 3b5bff8..90571ae 100644
--- a/src/win32/posix.h
+++ b/src/win32/posix.h
@@ -21,6 +21,6 @@ extern int p_unlink(const char *path);
 extern int p_lstat(const char *file_name, struct stat *buf);
 extern int p_readlink(const char *link, char *target, size_t target_len);
 extern int p_hide_directory__w32(const char *path);
-extern int p_realpath(const char *orig_path, char *buffer);
+extern char *p_realpath(const char *orig_path, char *buffer);
 
 #endif