Commit 6b7991e2 by Russell Belfer

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.
parent 146b4d1c
......@@ -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) &&
......
......@@ -241,6 +241,16 @@ void test_repo_init__detect_ignorecase(void)
#endif
}
void test_repo_init__detect_precompose_unicode_required(void)
{
#ifdef __APPLE__
/* hard to test "true" case without SAMBA or VFAT file system available */
assert_config_entry_on_init("core.precomposeunicode", false);
#else
assert_config_entry_on_init("core.precomposeunicode", GIT_ENOTFOUND);
#endif
}
void test_repo_init__reinit_doesnot_overwrite_ignorecase(void)
{
git_config *config;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment