summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@microsoft.com>2017-04-03 14:58:24 +0100
committerEdward Thomson <ethomson@microsoft.com>2017-04-03 14:58:24 +0100
commita97699db6e9566912ecf2e5e504700c8bb89353f (patch)
treed71788e0e59cac721c7f22f3d87376676d8f87f6
parentcaf7a7a6b14b3b2f200f88f2f8d7a18ca10fd3ac (diff)
downloadlibgit2-ethomson/win_utimes.tar.gz
-rw-r--r--src/posix.h4
-rw-r--r--src/win32/posix_w32.c34
-rw-r--r--tests/odb/freshen.c25
3 files changed, 58 insertions, 5 deletions
diff --git a/src/posix.h b/src/posix.h
index bd5a98e26..d26371bca 100644
--- a/src/posix.h
+++ b/src/posix.h
@@ -24,6 +24,10 @@
#define _S_IFLNK S_IFLNK
#endif
+#ifndef S_IWUSR
+#define S_IWUSR 00200
+#endif
+
#ifndef S_IXUSR
#define S_IXUSR 00100
#endif
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index 5172627b0..af4f5743a 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -212,16 +212,40 @@ int p_lstat_posixly(const char *filename, struct stat *buf)
return do_lstat(filename, buf, true);
}
-int p_utimes(const char *filename, const struct p_timeval times[2])
+int p_utimes(const char *path, const struct p_timeval times[2])
{
+ git_win32_path wpath;
int fd, error;
+ DWORD attrs_orig, attrs_new = 0;
- if ((fd = p_open(filename, O_RDWR)) < 0)
- return fd;
+ if (git_win32_path_from_utf8(wpath, path) < 0)
+ return -1;
- error = p_futimes(fd, times);
+ attrs_orig = GetFileAttributesW(wpath);
+
+ if (attrs_orig & FILE_ATTRIBUTE_READONLY) {
+ attrs_new = attrs_orig & ~FILE_ATTRIBUTE_READONLY;
+
+ if (!SetFileAttributesW(wpath, attrs_new)) {
+ giterr_set(GITERR_OS, "failed to set attributes");
+ return -1;
+ }
+ }
+ /* TODO: CreateFile */
+ if ((error = fd = p_open(path, O_RDWR)) < 0)
+ goto done;
+
+ error = p_futimes(fd, times);
close(fd);
+
+done:
+ if (attrs_orig != attrs_new) {
+ DWORD os_error = GetLastError();
+ SetFileAttributesW(wpath, attrs_orig);
+ SetLastError(os_error);
+ }
+
return error;
}
@@ -605,7 +629,7 @@ static int ensure_writable(wchar_t *fpath)
return -1;
}
- return 0;
+ return 1;
}
int p_rename(const char *from, const char *to)
diff --git a/tests/odb/freshen.c b/tests/odb/freshen.c
index f41e4361e..9d3cf51dc 100644
--- a/tests/odb/freshen.c
+++ b/tests/odb/freshen.c
@@ -55,6 +55,31 @@ void test_odb_freshen__loose_blob(void)
cl_assert(before.st_mtime < after.st_mtime);
}
+#define UNIQUE_STR "doesnt exist in the odb yet\n"
+#define UNIQUE_BLOB_ID "78a87d0b8878c5953b9a63015ff4e22a3d898826"
+#define UNIQUE_BLOB_FN "78/a87d0b8878c5953b9a63015ff4e22a3d898826"
+
+void test_odb_freshen__readonly_object(void)
+{
+ git_oid expected_id, id;
+ struct stat before, after;
+
+ cl_git_pass(git_oid_fromstr(&expected_id, UNIQUE_BLOB_ID));
+
+ cl_git_pass(git_blob_create_frombuffer(&id, repo, UNIQUE_STR, CONST_STRLEN(UNIQUE_STR)));
+ cl_assert_equal_oid(&expected_id, &id);
+
+ set_time_wayback(&before, UNIQUE_BLOB_FN);
+ cl_assert((before.st_mode & S_IWUSR) == 0);
+
+ cl_git_pass(git_blob_create_frombuffer(&id, repo, UNIQUE_STR, CONST_STRLEN(UNIQUE_STR)));
+ cl_assert_equal_oid(&expected_id, &id);
+ cl_must_pass(p_lstat("testrepo.git/objects/" UNIQUE_BLOB_FN, &after));
+
+ cl_assert(before.st_atime < after.st_atime);
+ cl_assert(before.st_mtime < after.st_mtime);
+}
+
#define LOOSE_TREE_ID "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"
#define LOOSE_TREE_FN "94/4c0f6e4dfa41595e6eb3ceecdb14f50fe18162"