Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2013-10-01 03:13:53 +0400
committerRussell Belfer <rb@github.com>2013-10-03 21:44:13 +0400
commit6b7991e264b2fb0448e3dc47f972bafabf38c1fa (patch)
treedce9bd0d6076339f73c3cd74bd6abc8f7aeac5b2 /src/repository.c
parent146b4d1c5f98aa14df086503f996d131d40b92f8 (diff)
Add check if we need to precompose unicode on Mac
This adds initialization of core.precomposeunicode to repo init on Mac. This is necessary because when a Mac accesses a repo on a VFAT or SAMBA file system, it will return directory entries in decomposed unicode even if the filesystem entry is precomposed. This also removes caching of a number of repo properties from the repo init pipeline because these are properties of the specific filesystem on which the repo is created, not of the system as a whole.
Diffstat (limited to 'src/repository.c')
-rw-r--r--src/repository.c101
1 files changed, 69 insertions, 32 deletions
diff --git a/src/repository.c b/src/repository.c
index 0d7c09484..64f13978d 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -843,10 +843,6 @@ fail:
static bool is_chmod_supported(const char *file_path)
{
struct stat st1, st2;
- static int _is_supported = -1;
-
- if (_is_supported > -1)
- return _is_supported;
if (p_stat(file_path, &st1) < 0)
return false;
@@ -857,27 +853,19 @@ static bool is_chmod_supported(const char *file_path)
if (p_stat(file_path, &st2) < 0)
return false;
- _is_supported = (st1.st_mode != st2.st_mode);
-
- return _is_supported;
+ return (st1.st_mode != st2.st_mode);
}
static bool is_filesystem_case_insensitive(const char *gitdir_path)
{
git_buf path = GIT_BUF_INIT;
- static int _is_insensitive = -1;
-
- if (_is_insensitive > -1)
- return _is_insensitive;
-
- if (git_buf_joinpath(&path, gitdir_path, "CoNfIg") < 0)
- goto cleanup;
+ int is_insensitive = -1;
- _is_insensitive = git_path_exists(git_buf_cstr(&path));
+ if (!git_buf_joinpath(&path, gitdir_path, "CoNfIg"))
+ is_insensitive = git_path_exists(git_buf_cstr(&path));
-cleanup:
git_buf_free(&path);
- return _is_insensitive;
+ return is_insensitive;
}
static bool are_symlinks_supported(const char *wd_path)
@@ -885,24 +873,69 @@ static bool are_symlinks_supported(const char *wd_path)
git_buf path = GIT_BUF_INIT;
int fd;
struct stat st;
- static int _symlinks_supported = -1;
-
- if (_symlinks_supported > -1)
- return _symlinks_supported;
+ int symlinks_supported = -1;
if ((fd = git_futils_mktmp(&path, wd_path)) < 0 ||
p_close(fd) < 0 ||
p_unlink(path.ptr) < 0 ||
p_symlink("testing", path.ptr) < 0 ||
p_lstat(path.ptr, &st) < 0)
- _symlinks_supported = false;
+ symlinks_supported = false;
else
- _symlinks_supported = (S_ISLNK(st.st_mode) != 0);
+ symlinks_supported = (S_ISLNK(st.st_mode) != 0);
(void)p_unlink(path.ptr);
git_buf_free(&path);
- return _symlinks_supported;
+ return symlinks_supported;
+}
+
+static const char *nfc_file = "\xC3\x85\x73\x74\x72\xC3\xB6\x6D.XXXXXX";
+static const char *nfd_file = "\x41\xCC\x8A\x73\x74\x72\x6F\xCC\x88\x6D.XXXXXX";
+
+/* On Mac, HDFS always stores files using decomposed unicode, but when
+ * writing to VFAT or SAMBA file systems, filenames may be kept as
+ * precomposed unicode, but will be converted to decomposed form when
+ * reading the directory entries. This can cause file name mismatches.
+ * The solution is to convert directory entries to precomposed form if we
+ * cannot look up the file from the decomposed path.
+ */
+static bool should_precompose_unicode_paths(const char *wd_path)
+{
+ git_buf path = GIT_BUF_INIT;
+ int fd;
+ bool need_precompose = false;
+ char tmp[6];
+
+ /* Create a file using a precomposed path and then try to find it
+ * using the decomposed name. If the lookup fails, then we will mark
+ * that we should precompose unicode for this repository.
+ */
+ if (git_buf_joinpath(&path, wd_path, nfc_file) < 0 ||
+ (fd = p_mkstemp(path.ptr)) < 0)
+ goto fail;
+ p_close(fd);
+
+ /* record trailing digits generated by mkstemp */
+ memcpy(tmp, path.ptr + path.size - sizeof(tmp), sizeof(tmp));
+
+ /* try to look up as NFD path */
+ if (git_buf_joinpath(&path, wd_path, nfd_file) < 0)
+ goto fail;
+ memcpy(path.ptr + path.size - sizeof(tmp), tmp, sizeof(tmp));
+
+ need_precompose = !git_path_exists(path.ptr);
+
+ /* remove temporary file */
+ if (git_buf_joinpath(&path, wd_path, nfc_file) < 0)
+ goto fail;
+ memcpy(path.ptr + path.size - sizeof(tmp), tmp, sizeof(tmp));
+
+ (void)p_unlink(path.ptr);
+
+fail:
+ git_buf_free(&path);
+ return need_precompose;
}
static int create_empty_file(const char *path, mode_t mode)
@@ -930,6 +963,7 @@ static int repo_init_config(
int error = 0;
git_buf cfg_path = GIT_BUF_INIT;
git_config *config = NULL;
+ bool is_bare = ((opts->flags & GIT_REPOSITORY_INIT_BARE) != 0);
#define SET_REPO_CONFIG(TYPE, NAME, VAL) do {\
if ((error = git_config_set_##TYPE(config, NAME, VAL)) < 0) \
@@ -954,17 +988,23 @@ static int repo_init_config(
goto cleanup;
SET_REPO_CONFIG(
- bool, "core.bare", (opts->flags & GIT_REPOSITORY_INIT_BARE) != 0);
+ bool, "core.bare", is_bare);
SET_REPO_CONFIG(
int32, "core.repositoryformatversion", GIT_REPO_VERSION);
SET_REPO_CONFIG(
bool, "core.filemode", is_chmod_supported(git_buf_cstr(&cfg_path)));
- if (!(opts->flags & GIT_REPOSITORY_INIT_BARE)) {
- SET_REPO_CONFIG(bool, "core.logallrefupdates", true);
+#if __APPLE__
+ SET_REPO_CONFIG(
+ bool, "core.precomposeunicode",
+ should_precompose_unicode_paths(is_bare ? repo_dir : work_dir));
+#endif
- if (!are_symlinks_supported(work_dir))
- SET_REPO_CONFIG(bool, "core.symlinks", false);
+ if (!are_symlinks_supported(is_bare ? repo_dir : work_dir))
+ SET_REPO_CONFIG(bool, "core.symlinks", false);
+
+ if (!is_bare) {
+ SET_REPO_CONFIG(bool, "core.logallrefupdates", true);
if (!(opts->flags & GIT_REPOSITORY_INIT__NATURAL_WD)) {
SET_REPO_CONFIG(string, "core.worktree", work_dir);
@@ -973,9 +1013,6 @@ static int repo_init_config(
if (git_config_delete_entry(config, "core.worktree") < 0)
giterr_clear();
}
- } else {
- if (!are_symlinks_supported(repo_dir))
- SET_REPO_CONFIG(bool, "core.symlinks", false);
}
if (!(opts->flags & GIT_REPOSITORY_INIT__IS_REINIT) &&