mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-05 17:12:51 +00:00
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.
This commit is contained in:
parent
146b4d1c5f
commit
6b7991e264
@ -843,10 +843,6 @@ fail:
|
|||||||
static bool is_chmod_supported(const char *file_path)
|
static bool is_chmod_supported(const char *file_path)
|
||||||
{
|
{
|
||||||
struct stat st1, st2;
|
struct stat st1, st2;
|
||||||
static int _is_supported = -1;
|
|
||||||
|
|
||||||
if (_is_supported > -1)
|
|
||||||
return _is_supported;
|
|
||||||
|
|
||||||
if (p_stat(file_path, &st1) < 0)
|
if (p_stat(file_path, &st1) < 0)
|
||||||
return false;
|
return false;
|
||||||
@ -857,27 +853,19 @@ static bool is_chmod_supported(const char *file_path)
|
|||||||
if (p_stat(file_path, &st2) < 0)
|
if (p_stat(file_path, &st2) < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_is_supported = (st1.st_mode != st2.st_mode);
|
return (st1.st_mode != st2.st_mode);
|
||||||
|
|
||||||
return _is_supported;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_filesystem_case_insensitive(const char *gitdir_path)
|
static bool is_filesystem_case_insensitive(const char *gitdir_path)
|
||||||
{
|
{
|
||||||
git_buf path = GIT_BUF_INIT;
|
git_buf path = GIT_BUF_INIT;
|
||||||
static int _is_insensitive = -1;
|
int is_insensitive = -1;
|
||||||
|
|
||||||
if (_is_insensitive > -1)
|
if (!git_buf_joinpath(&path, gitdir_path, "CoNfIg"))
|
||||||
return _is_insensitive;
|
is_insensitive = git_path_exists(git_buf_cstr(&path));
|
||||||
|
|
||||||
if (git_buf_joinpath(&path, gitdir_path, "CoNfIg") < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
_is_insensitive = git_path_exists(git_buf_cstr(&path));
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
git_buf_free(&path);
|
git_buf_free(&path);
|
||||||
return _is_insensitive;
|
return is_insensitive;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool are_symlinks_supported(const char *wd_path)
|
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;
|
git_buf path = GIT_BUF_INIT;
|
||||||
int fd;
|
int fd;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
static int _symlinks_supported = -1;
|
int symlinks_supported = -1;
|
||||||
|
|
||||||
if (_symlinks_supported > -1)
|
|
||||||
return _symlinks_supported;
|
|
||||||
|
|
||||||
if ((fd = git_futils_mktmp(&path, wd_path)) < 0 ||
|
if ((fd = git_futils_mktmp(&path, wd_path)) < 0 ||
|
||||||
p_close(fd) < 0 ||
|
p_close(fd) < 0 ||
|
||||||
p_unlink(path.ptr) < 0 ||
|
p_unlink(path.ptr) < 0 ||
|
||||||
p_symlink("testing", path.ptr) < 0 ||
|
p_symlink("testing", path.ptr) < 0 ||
|
||||||
p_lstat(path.ptr, &st) < 0)
|
p_lstat(path.ptr, &st) < 0)
|
||||||
_symlinks_supported = false;
|
symlinks_supported = false;
|
||||||
else
|
else
|
||||||
_symlinks_supported = (S_ISLNK(st.st_mode) != 0);
|
symlinks_supported = (S_ISLNK(st.st_mode) != 0);
|
||||||
|
|
||||||
(void)p_unlink(path.ptr);
|
(void)p_unlink(path.ptr);
|
||||||
git_buf_free(&path);
|
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)
|
static int create_empty_file(const char *path, mode_t mode)
|
||||||
@ -930,6 +963,7 @@ static int repo_init_config(
|
|||||||
int error = 0;
|
int error = 0;
|
||||||
git_buf cfg_path = GIT_BUF_INIT;
|
git_buf cfg_path = GIT_BUF_INIT;
|
||||||
git_config *config = NULL;
|
git_config *config = NULL;
|
||||||
|
bool is_bare = ((opts->flags & GIT_REPOSITORY_INIT_BARE) != 0);
|
||||||
|
|
||||||
#define SET_REPO_CONFIG(TYPE, NAME, VAL) do {\
|
#define SET_REPO_CONFIG(TYPE, NAME, VAL) do {\
|
||||||
if ((error = git_config_set_##TYPE(config, NAME, VAL)) < 0) \
|
if ((error = git_config_set_##TYPE(config, NAME, VAL)) < 0) \
|
||||||
@ -954,18 +988,24 @@ static int repo_init_config(
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
SET_REPO_CONFIG(
|
SET_REPO_CONFIG(
|
||||||
bool, "core.bare", (opts->flags & GIT_REPOSITORY_INIT_BARE) != 0);
|
bool, "core.bare", is_bare);
|
||||||
SET_REPO_CONFIG(
|
SET_REPO_CONFIG(
|
||||||
int32, "core.repositoryformatversion", GIT_REPO_VERSION);
|
int32, "core.repositoryformatversion", GIT_REPO_VERSION);
|
||||||
SET_REPO_CONFIG(
|
SET_REPO_CONFIG(
|
||||||
bool, "core.filemode", is_chmod_supported(git_buf_cstr(&cfg_path)));
|
bool, "core.filemode", is_chmod_supported(git_buf_cstr(&cfg_path)));
|
||||||
|
|
||||||
if (!(opts->flags & GIT_REPOSITORY_INIT_BARE)) {
|
#if __APPLE__
|
||||||
SET_REPO_CONFIG(bool, "core.logallrefupdates", true);
|
SET_REPO_CONFIG(
|
||||||
|
bool, "core.precomposeunicode",
|
||||||
|
should_precompose_unicode_paths(is_bare ? repo_dir : work_dir));
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!are_symlinks_supported(work_dir))
|
if (!are_symlinks_supported(is_bare ? repo_dir : work_dir))
|
||||||
SET_REPO_CONFIG(bool, "core.symlinks", false);
|
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)) {
|
if (!(opts->flags & GIT_REPOSITORY_INIT__NATURAL_WD)) {
|
||||||
SET_REPO_CONFIG(string, "core.worktree", work_dir);
|
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)
|
if (git_config_delete_entry(config, "core.worktree") < 0)
|
||||||
giterr_clear();
|
giterr_clear();
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (!are_symlinks_supported(repo_dir))
|
|
||||||
SET_REPO_CONFIG(bool, "core.symlinks", false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(opts->flags & GIT_REPOSITORY_INIT__IS_REINIT) &&
|
if (!(opts->flags & GIT_REPOSITORY_INIT__IS_REINIT) &&
|
||||||
|
@ -241,6 +241,16 @@ void test_repo_init__detect_ignorecase(void)
|
|||||||
#endif
|
#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)
|
void test_repo_init__reinit_doesnot_overwrite_ignorecase(void)
|
||||||
{
|
{
|
||||||
git_config *config;
|
git_config *config;
|
||||||
|
Loading…
Reference in New Issue
Block a user