summaryrefslogtreecommitdiff
path: root/src/fileops.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fileops.c')
-rw-r--r--src/fileops.c161
1 files changed, 111 insertions, 50 deletions
diff --git a/src/fileops.c b/src/fileops.c
index c1824e812..4ed46ce85 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -558,75 +558,136 @@ clean_up:
return error;
}
-int git_futils_find_system_file(git_buf *path, const char *filename)
+
+static int git_futils_guess_system_dirs(git_strarray *out)
{
#ifdef GIT_WIN32
- // try to find git.exe/git.cmd on path
- if (!win32_find_system_file_using_path(path, filename))
- return 0;
+ return win32_find_system_dirs(out);
+#else
+ return git_strarray_set(out, 1, "/etc");
+#endif
+}
- // try to find msysgit installation path using registry
- if (!win32_find_system_file_using_registry(path, filename))
- return 0;
+static int git_futils_guess_global_dirs(git_strarray *out)
+{
+#ifdef GIT_WIN32
+ return win32_find_global_dirs(out);
#else
- if (git_buf_joinpath(path, "/etc", filename) < 0)
- return -1;
+ return git_strarray_set(out, 1, getenv("HOME"));
+#endif
+}
- if (git_path_exists(path->ptr) == true)
- return 0;
+static int git_futils_guess_xdg_dirs(git_strarray *out)
+{
+#ifdef GIT_WIN32
+ return win32_find_xdg_dirs(out);
+#else
+ int error = 0;
+ git_buf xdg = GIT_BUF_INIT;
+ const char *env = NULL;
+
+ if ((env = getenv("XDG_CONFIG_HOME")) != NULL)
+ git_buf_joinpath(&xdg, env, "git");
+ else if ((env = getenv("HOME")) != NULL)
+ git_buf_joinpath(&xdg, env, ".config/git");
+
+ error = git_strarray_set(out, 1, xdg.ptr);
+ git_buf_free(&xdg);
+
+ return error;
#endif
+}
- git_buf_clear(path);
- giterr_set(GITERR_OS, "The system file '%s' doesn't exist", filename);
- return GIT_ENOTFOUND;
+typedef int (*git_futils_dirs_guess_cb)(git_strarray *out);
+
+static git_strarray git_futils__dirs[GIT_FUTILS_DIR__MAX];
+static git_futils_dirs_guess_cb git_futils__dir_guess[GIT_FUTILS_DIR__MAX] = {
+ git_futils_guess_system_dirs,
+ git_futils_guess_global_dirs,
+ git_futils_guess_xdg_dirs,
+};
+
+static int git_futils_check_selector(git_futils_dir_t which)
+{
+ if (which < GIT_FUTILS_DIR__MAX)
+ return 0;
+ giterr_set(GITERR_INVALID, "config directory selector out of range");
+ return -1;
}
-int git_futils_find_global_file(git_buf *path, const char *filename)
+int git_futils_dirs_get(const git_strarray **out, git_futils_dir_t which)
{
-#ifdef GIT_WIN32
- struct win32_path root;
- static const wchar_t *tmpls[4] = {
- L"%HOME%\\",
- L"%HOMEDRIVE%%HOMEPATH%\\",
- L"%USERPROFILE%\\",
- NULL,
- };
- const wchar_t **tmpl;
-
- for (tmpl = tmpls; *tmpl != NULL; tmpl++) {
- /* try to expand environment variable, skipping if not set */
- if (win32_expand_path(&root, *tmpl) != 0 || root.path[0] == L'%')
- continue;
-
- /* try to look up file under path */
- if (!win32_find_file(path, &root, filename))
- return 0;
+ if (!out) {
+ giterr_set(GITERR_INVALID, "Output git_strarray not provided");
+ return -1;
}
- giterr_set(GITERR_OS, "The global file '%s' doesn't exist", filename);
- git_buf_clear(path);
+ *out = NULL;
- return GIT_ENOTFOUND;
-#else
- const char *home = getenv("HOME");
+ GITERR_CHECK_ERROR(git_futils_check_selector(which));
- if (home == NULL) {
- giterr_set(GITERR_OS, "Global file lookup failed. "
- "Cannot locate the user's home directory");
- return GIT_ENOTFOUND;
+ if (!git_futils__dirs[which].count) {
+ int error = git_futils__dir_guess[which](&git_futils__dirs[which]);
+ if (error < 0)
+ return error;
}
- if (git_buf_joinpath(path, home, filename) < 0)
- return -1;
+ *out = &git_futils__dirs[which];
+ return 0;
+}
- if (git_path_exists(path->ptr) == false) {
- giterr_set(GITERR_OS, "The global file '%s' doesn't exist", filename);
- git_buf_clear(path);
- return GIT_ENOTFOUND;
+int git_futils_dirs_set(
+ git_futils_dir_t which, const git_strarray *dirs, bool replace)
+{
+ GITERR_CHECK_ERROR(git_futils_check_selector(which));
+
+ if (replace)
+ git_strarray_free(&git_futils__dirs[which]);
+
+ /* init with defaults if it hasn't been done yet, but ignore error */
+ else if (!git_futils__dirs[which].count)
+ git_futils__dir_guess[which](&git_futils__dirs[which]);
+
+ return git_strarray_prepend(&git_futils__dirs[which], dirs);
+}
+
+static int git_futils_find_in_dirlist(
+ git_buf *path, const char *name, git_futils_dir_t which, const char *label)
+{
+ size_t i;
+ const git_strarray *syspaths;
+
+ GITERR_CHECK_ERROR(git_futils_dirs_get(&syspaths, which));
+
+ for (i = 0; i < syspaths->count; ++i) {
+ GITERR_CHECK_ERROR(
+ git_buf_joinpath(path, syspaths->strings[i], name));
+
+ if (git_path_exists(path->ptr))
+ return 0;
}
- return 0;
-#endif
+ git_buf_clear(path);
+ giterr_set(GITERR_OS, "The %s file '%s' doesn't exist", label, name);
+ return GIT_ENOTFOUND;
+}
+
+int git_futils_find_system_file(git_buf *path, const char *filename)
+{
+ return git_futils_find_in_dirlist(
+ path, filename, GIT_FUTILS_DIR_SYSTEM, "system");
+}
+
+int git_futils_find_global_file(git_buf *path, const char *filename)
+{
+ return git_futils_find_in_dirlist(
+ path, filename, GIT_FUTILS_DIR_GLOBAL, "global");
+}
+
+int git_futils_find_xdg_file(git_buf *path, const char *filename)
+{
+ return git_futils_find_in_dirlist(
+ path, filename, GIT_FUTILS_DIR_XDG, "global/xdg");
}
int git_futils_fake_symlink(const char *old, const char *new)