Commit ded77bb1 by Patrick Steinhardt

path: extract function to check whether a path supports symlinks

When initializing a repository, we need to check whether its working
directory supports symlinks to correctly set the initial value of the
"core.symlinks" config variable. The code to check the filesystem is
reusable in other parts of our codebase, like for example in our tests
to determine whether certain tests can be expected to succeed or not.

Extract the code into a new function `git_path_supports_symlinks` to
avoid duplicate implementations. Remove a duplicate implementation in
the repo test helper code.
parent e54343a4
...@@ -1924,3 +1924,25 @@ extern int git_path_is_gitfile(const char *path, size_t pathlen, git_path_gitfil ...@@ -1924,3 +1924,25 @@ extern int git_path_is_gitfile(const char *path, size_t pathlen, git_path_gitfil
return -1; return -1;
} }
} }
bool git_path_supports_symlinks(const char *dir)
{
git_buf path = GIT_BUF_INIT;
bool supported = false;
struct stat st;
int fd;
if ((fd = git_futils_mktmp(&path, dir, 0666)) < 0 ||
p_close(fd) < 0 ||
p_unlink(path.ptr) < 0 ||
p_symlink("testing", path.ptr) < 0 ||
p_lstat(path.ptr, &st) < 0)
goto done;
supported = (S_ISLNK(st.st_mode) != 0);
done:
if (path.size)
(void)p_unlink(path.ptr);
git_buf_dispose(&path);
return supported;
}
...@@ -647,4 +647,6 @@ extern bool git_path_isvalid( ...@@ -647,4 +647,6 @@ extern bool git_path_isvalid(
*/ */
int git_path_normalize_slashes(git_buf *out, const char *path); int git_path_normalize_slashes(git_buf *out, const char *path);
bool git_path_supports_symlinks(const char *dir);
#endif #endif
...@@ -1419,9 +1419,6 @@ static bool are_symlinks_supported(const char *wd_path) ...@@ -1419,9 +1419,6 @@ static bool are_symlinks_supported(const char *wd_path)
git_buf xdg_buf = GIT_BUF_INIT; git_buf xdg_buf = GIT_BUF_INIT;
git_buf system_buf = GIT_BUF_INIT; git_buf system_buf = GIT_BUF_INIT;
git_buf programdata_buf = GIT_BUF_INIT; git_buf programdata_buf = GIT_BUF_INIT;
git_buf path = GIT_BUF_INIT;
int fd;
struct stat st;
int symlinks = 0; int symlinks = 0;
/* /*
...@@ -1448,23 +1445,14 @@ static bool are_symlinks_supported(const char *wd_path) ...@@ -1448,23 +1445,14 @@ static bool are_symlinks_supported(const char *wd_path)
goto done; goto done;
#endif #endif
if ((fd = git_futils_mktmp(&path, wd_path, 0666)) < 0 || if (!(symlinks = git_path_supports_symlinks(wd_path)))
p_close(fd) < 0 ||
p_unlink(path.ptr) < 0 ||
p_symlink("testing", path.ptr) < 0 ||
p_lstat(path.ptr, &st) < 0)
goto done; goto done;
symlinks = (S_ISLNK(st.st_mode) != 0);
(void)p_unlink(path.ptr);
done: done:
git_buf_dispose(&global_buf); git_buf_dispose(&global_buf);
git_buf_dispose(&xdg_buf); git_buf_dispose(&xdg_buf);
git_buf_dispose(&system_buf); git_buf_dispose(&system_buf);
git_buf_dispose(&programdata_buf); git_buf_dispose(&programdata_buf);
git_buf_dispose(&path);
git_config_free(config); git_config_free(config);
return symlinks != 0; return symlinks != 0;
} }
......
...@@ -181,7 +181,7 @@ void test_checkout_index__honor_coresymlinks_default_true(void) ...@@ -181,7 +181,7 @@ void test_checkout_index__honor_coresymlinks_default_true(void)
cl_must_pass(p_mkdir("symlink", 0777)); cl_must_pass(p_mkdir("symlink", 0777));
if (!filesystem_supports_symlinks("symlink/test")) if (!git_path_supports_symlinks("symlink/test"))
cl_skip(); cl_skip();
#ifdef GIT_WIN32 #ifdef GIT_WIN32
...@@ -214,7 +214,7 @@ void test_checkout_index__honor_coresymlinks_default_false(void) ...@@ -214,7 +214,7 @@ void test_checkout_index__honor_coresymlinks_default_false(void)
* supports symlinks. Bail entirely on POSIX platforms that * supports symlinks. Bail entirely on POSIX platforms that
* do support symlinks. * do support symlinks.
*/ */
if (filesystem_supports_symlinks("symlink/test")) if (git_path_supports_symlinks("symlink/test"))
cl_skip(); cl_skip();
#endif #endif
...@@ -226,7 +226,7 @@ void test_checkout_index__coresymlinks_set_to_true_fails_when_unsupported(void) ...@@ -226,7 +226,7 @@ void test_checkout_index__coresymlinks_set_to_true_fails_when_unsupported(void)
{ {
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
if (filesystem_supports_symlinks("testrepo/test")) { if (git_path_supports_symlinks("testrepo/test")) {
cl_skip(); cl_skip();
} }
...@@ -242,7 +242,7 @@ void test_checkout_index__honor_coresymlinks_setting_set_to_true(void) ...@@ -242,7 +242,7 @@ void test_checkout_index__honor_coresymlinks_setting_set_to_true(void)
char link_data[GIT_PATH_MAX]; char link_data[GIT_PATH_MAX];
size_t link_size = GIT_PATH_MAX; size_t link_size = GIT_PATH_MAX;
if (!filesystem_supports_symlinks("testrepo/test")) { if (!git_path_supports_symlinks("testrepo/test")) {
cl_skip(); cl_skip();
} }
......
...@@ -253,7 +253,7 @@ void test_repo_init__symlinks_win32_enabled_by_global_config(void) ...@@ -253,7 +253,7 @@ void test_repo_init__symlinks_win32_enabled_by_global_config(void)
git_config *config, *repo_config; git_config *config, *repo_config;
int val; int val;
if (!filesystem_supports_symlinks("link")) if (!git_path_supports_symlinks("link"))
cl_skip(); cl_skip();
create_tmp_global_config("tmp_global_config", "core.symlinks", "true"); create_tmp_global_config("tmp_global_config", "core.symlinks", "true");
...@@ -296,7 +296,7 @@ void test_repo_init__symlinks_posix_detected(void) ...@@ -296,7 +296,7 @@ void test_repo_init__symlinks_posix_detected(void)
cl_skip(); cl_skip();
#else #else
assert_config_entry_on_init( assert_config_entry_on_init(
"core.symlinks", filesystem_supports_symlinks("link") ? GIT_ENOTFOUND : false); "core.symlinks", git_path_supports_symlinks("link") ? GIT_ENOTFOUND : false);
#endif #endif
} }
......
...@@ -21,21 +21,6 @@ void delete_head(git_repository* repo) ...@@ -21,21 +21,6 @@ void delete_head(git_repository* repo)
git_buf_dispose(&head_path); git_buf_dispose(&head_path);
} }
int filesystem_supports_symlinks(const char *path)
{
struct stat st;
bool support = 0;
if (p_symlink("target", path) == 0) {
if (p_lstat(path, &st) == 0 && S_ISLNK(st.st_mode))
support = 1;
p_unlink(path);
}
return support;
}
void create_tmp_global_config(const char *dirname, const char *key, const char *val) void create_tmp_global_config(const char *dirname, const char *key, const char *val)
{ {
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
......
...@@ -4,5 +4,4 @@ ...@@ -4,5 +4,4 @@
extern void make_head_unborn(git_repository* repo, const char *target); extern void make_head_unborn(git_repository* repo, const char *target);
extern void delete_head(git_repository* repo); extern void delete_head(git_repository* repo);
extern int filesystem_supports_symlinks(const char *path);
extern void create_tmp_global_config(const char *path, const char *key, const char *val); extern void create_tmp_global_config(const char *path, const char *key, const char *val);
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