Commit b0b2dd5ecc2d309875e8dcd744fa5ff0a55b8fe5

Vicent Martí 2011-11-07T12:04:13

Merge pull request #475 from carlosmn/perms Fix Windows permissions problems

diff --git a/src/filebuf.c b/src/filebuf.c
index 1a3fe6d..1994180 100644
--- a/src/filebuf.c
+++ b/src/filebuf.c
@@ -278,7 +278,7 @@ int git_filebuf_commit(git_filebuf *file, mode_t mode)
 		goto cleanup;
 	}
 
-	error = git_futils_mv_atomic(file->path_lock, file->path_original);
+	error = p_rename(file->path_lock, file->path_original);
 
 cleanup:
 	git_filebuf_cleanup(file);
diff --git a/src/fileops.c b/src/fileops.c
index 2030c78..955bb1b 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -8,29 +8,6 @@
 #include "fileops.h"
 #include <ctype.h>
 
-int git_futils_mv_atomic(const char *from, const char *to)
-{
-#ifdef GIT_WIN32
-	/*
-	 * Win32 POSIX compilance my ass. If the destination
-	 * file exists, the `rename` call fails. This is as
-	 * close as it gets with the Win32 API.
-	 */
-	return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? GIT_SUCCESS : GIT_EOSERR;
-#else
-	/* Don't even try this on Win32 */
-	if (!link(from, to)) {
-		p_unlink(from);
-		return GIT_SUCCESS;
-	}
-
-	if (!rename(from, to))
-		return GIT_SUCCESS;
-
-	return GIT_ERROR;
-#endif
-}
-
 int git_futils_mkpath2file(const char *file_path, const mode_t mode)
 {
 	int error = GIT_SUCCESS;
@@ -216,7 +193,7 @@ int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmod
 	if (git_futils_mkpath2file(to, dirmode) < GIT_SUCCESS)
 		return GIT_EOSERR;	/* The callee already takes care of setting the correct error message. */
 
-	return git_futils_mv_atomic(from, to);	/* The callee already takes care of setting the correct error message. */
+	return p_rename(from, to); /* The callee already takes care of setting the correct error message. */
 }
 
 int git_futils_mmap_ro(git_map *out, git_file fd, git_off_t begin, size_t len)
diff --git a/src/posix.c b/src/posix.c
index 7cd0749..8c19588 100644
--- a/src/posix.c
+++ b/src/posix.c
@@ -39,6 +39,20 @@ int p_getcwd(char *buffer_out, size_t size)
 	return GIT_SUCCESS;
 }
 
+int p_rename(const char *from, const char *to)
+{
+	if (!link(from, to)) {
+		p_unlink(from);
+		return GIT_SUCCESS;
+	}
+
+	if (!rename(from, to))
+		return GIT_SUCCESS;
+
+	return GIT_ERROR;
+
+}
+
 #endif
 
 int p_read(git_file fd, void *buf, size_t cnt)
diff --git a/src/posix.h b/src/posix.h
index 55cd35a..c12b413 100644
--- a/src/posix.h
+++ b/src/posix.h
@@ -45,6 +45,7 @@ extern int p_write(git_file fd, const void *buf, size_t cnt);
 extern int p_open(const char *path, int flags);
 extern int p_creat(const char *path, mode_t mode);
 extern int p_getcwd(char *buffer_out, size_t size);
+extern int p_rename(const char *from, const char *to);
 
 #ifndef GIT_WIN32
 
diff --git a/src/refs.c b/src/refs.c
index 5634066..05f9357 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -16,6 +16,8 @@
 
 #define MAX_NESTING_LEVEL 5
 
+#define GIT_PACKED_REFS_FILE_MODE 0644
+
 enum {
 	GIT_PACKREF_HAS_PEEL = 1,
 	GIT_PACKREF_WAS_LOOSE = 2
@@ -757,7 +759,7 @@ static int packed_write(git_repository *repo)
 	total_refs = repo->references.packfile->key_count;
 	if ((error =
 		git_vector_init(&packing_list, total_refs, packed_sort)) < GIT_SUCCESS)
-		return git__rethrow(error, "Failed to write packed reference");
+		return git__rethrow(error, "Failed to init packed refernces list");
 
 	/* Load all the packfile into a vector */
 	{
@@ -776,14 +778,14 @@ static int packed_write(git_repository *repo)
 	/* Now we can open the file! */
 	git_path_join(pack_file_path, repo->path_repository, GIT_PACKEDREFS_FILE);
 	if ((error = git_filebuf_open(&pack_file, pack_file_path, 0)) < GIT_SUCCESS)
-		return git__rethrow(error, "Failed to write packed reference");
+		return git__rethrow(error, "Failed to write open packed references file");
 
 	/* Packfiles have a header... apparently
 	 * This is in fact not required, but we might as well print it
 	 * just for kicks */
 	if ((error =
 		git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < GIT_SUCCESS)
-		return git__rethrow(error, "Failed to write packed reference");
+		return git__rethrow(error, "Failed to write packed references file header");
 
 	for (i = 0; i < packing_list.length; ++i) {
 		struct packref *ref = (struct packref *)git_vector_get(&packing_list, i);
@@ -802,7 +804,7 @@ cleanup:
 	/* if we've written all the references properly, we can commit
 	 * the packfile to make the changes effective */
 	if (error == GIT_SUCCESS) {
-		error = git_filebuf_commit(&pack_file, GIT_PACK_FILE_MODE);
+		error = git_filebuf_commit(&pack_file, GIT_PACKED_REFS_FILE_MODE);
 
 		/* when and only when the packfile has been properly written,
 		 * we can go ahead and remove the loose refs */
@@ -821,7 +823,7 @@ cleanup:
 
 	return error == GIT_SUCCESS ?
 		GIT_SUCCESS :
-		git__rethrow(error, "Failed to write packed reference");
+		git__rethrow(error, "Failed to write packed references file");
 }
 
 static int _reference_available_cb(const char *ref, void *data)
diff --git a/src/win32/posix.h b/src/win32/posix.h
index 7b55530..ae63236 100644
--- a/src/win32/posix.h
+++ b/src/win32/posix.h
@@ -48,5 +48,6 @@ extern int p_fsync(int fd);
 extern int p_open(const char *path, int flags);
 extern int p_creat(const char *path, mode_t mode);
 extern int p_getcwd(char *buffer_out, size_t size);
+extern int p_rename(const char *from, const char *to);
 
 #endif
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index 4b1b007..6f72258 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -388,3 +388,17 @@ int p_access(const char* path, mode_t mode)
 
 	return ret;
 }
+
+extern int p_rename(const char *from, const char *to)
+{
+	wchar_t *wfrom = gitwin_to_utf16(from);
+	wchar_t *wto = gitwin_to_utf16(to);
+	int ret;
+
+	ret = MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? GIT_SUCCESS : GIT_EOSERR;
+
+	git__free(wfrom);
+	git__free(wto);
+
+	return ret;
+}
diff --git a/tests-clay/status/worktree.c b/tests-clay/status/worktree.c
index 7449c6d..1e8a5dd 100644
--- a/tests-clay/status/worktree.c
+++ b/tests-clay/status/worktree.c
@@ -71,7 +71,7 @@ void test_status_worktree__initialize(void)
 	 * inside the fixtures folder in our libgit2 repo.
 	 */
 	cl_git_pass(
-		git_futils_mv_atomic("status/.gitted", "status/.git")
+		p_rename("status/.gitted", "status/.git")
 	);
 
 	/*
diff --git a/tests/t18-status.c b/tests/t18-status.c
index d836fb9..73e328c 100644
--- a/tests/t18-status.c
+++ b/tests/t18-status.c
@@ -136,7 +136,7 @@ BEGIN_TEST(statuscb0, "test retrieving status for worktree of repository")
 	struct status_entry_counts counts;
 
 	must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
-	must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
+	must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
 	must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
 
 	memset(&counts, 0x0, sizeof(struct status_entry_counts));
@@ -223,7 +223,7 @@ BEGIN_TEST(statuscb2, "test retrieving status for a purged worktree of an valid 
 	struct status_entry_counts counts;
 
 	must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
-	must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
+	must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
 	must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
 
 	/* Purging the working */
@@ -309,12 +309,12 @@ BEGIN_TEST(statuscb3, "test retrieving status for a worktree where a file and a 
 	struct status_entry_counts counts;
 
 	must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
-	must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
+	must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
 	must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
 
-	must_pass(git_futils_mv_atomic(TEMP_REPO_FOLDER "current_file", TEMP_REPO_FOLDER "swap"));
-	must_pass(git_futils_mv_atomic(TEMP_REPO_FOLDER "subdir", TEMP_REPO_FOLDER "current_file"));
-	must_pass(git_futils_mv_atomic(TEMP_REPO_FOLDER "swap", TEMP_REPO_FOLDER "subdir"));
+	must_pass(p_rename(TEMP_REPO_FOLDER "current_file", TEMP_REPO_FOLDER "swap"));
+	must_pass(p_rename(TEMP_REPO_FOLDER "subdir", TEMP_REPO_FOLDER "current_file"));
+	must_pass(p_rename(TEMP_REPO_FOLDER "swap", TEMP_REPO_FOLDER "subdir"));
 
 	must_pass(file_create(TEMP_REPO_FOLDER ".HEADER", "dummy"));
 	must_pass(file_create(TEMP_REPO_FOLDER "42-is-not-prime.sigh", "dummy"));
@@ -341,7 +341,7 @@ BEGIN_TEST(singlestatus0, "test retrieving status for single file")
 	int i;
 
 	must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
-	must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
+	must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
 	must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
 
 	for (i = 0; i < ENTRY_COUNT0; ++i) {
@@ -360,7 +360,7 @@ BEGIN_TEST(singlestatus1, "test retrieving status for nonexistent file")
 	int error;
 
 	must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
-	must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
+	must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
 	must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
 
 	// "nonexistent" does not exist in HEAD, Index or the worktree
@@ -421,7 +421,7 @@ BEGIN_TEST(singlestatus4, "can't determine the status for a folder")
 	int error;
 
 	must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
-	must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
+	must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
 	must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
 
 	error = git_status_file(&status_flags, repo, "subdir");