summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicent Marti <vicent@github.com>2014-02-25 10:46:41 +0100
committerVicent Marti <vicent@github.com>2014-02-25 10:46:41 +0100
commitcb81c3a764447ceb2cd693935bf970138ea60ccc (patch)
treeaaccb862502fff37d3c5d71a191e20e5a16469b2
parent1c8b339d3483bb5262174908b376dc1152787021 (diff)
parent83634d38be2d0a1ac006d912216cd6787c2b1542 (diff)
downloadlibgit2-cb81c3a764447ceb2cd693935bf970138ea60ccc.tar.gz
Merge pull request #2138 from ethomson/sysdir
Move system directory cache out of utils
-rw-r--r--src/attr.c8
-rw-r--r--src/config.c10
-rw-r--r--src/config_file.c4
-rw-r--r--src/fileops.c220
-rw-r--r--src/fileops.h88
-rw-r--r--src/global.c6
-rw-r--r--src/repository.c3
-rw-r--r--src/settings.c22
-rw-r--r--src/sysdir.c244
-rw-r--r--src/sysdir.h101
-rw-r--r--tests/core/env.c33
-rw-r--r--tests/repo/config.c9
-rw-r--r--tests/repo/open.c3
13 files changed, 396 insertions, 355 deletions
diff --git a/src/attr.c b/src/attr.c
index 15ed5c9e0..d8a171d0f 100644
--- a/src/attr.c
+++ b/src/attr.c
@@ -1,6 +1,6 @@
#include "common.h"
#include "repository.h"
-#include "fileops.h"
+#include "sysdir.h"
#include "config.h"
#include "attr.h"
#include "ignore.h"
@@ -589,7 +589,7 @@ static int collect_attr_files(
}
if ((flags & GIT_ATTR_CHECK_NO_SYSTEM) == 0) {
- error = git_futils_find_system_file(&dir, GIT_ATTR_FILE_SYSTEM);
+ error = git_sysdir_find_system_file(&dir, GIT_ATTR_FILE_SYSTEM);
if (!error)
error = push_attr_file(repo, files, NULL, dir.ptr);
else if (error == GIT_ENOTFOUND) {
@@ -623,13 +623,13 @@ static int attr_cache__lookup_path(
/* expand leading ~/ as needed */
if (cfgval && cfgval[0] == '~' && cfgval[1] == '/' &&
- !git_futils_find_global_file(&buf, &cfgval[2]))
+ !git_sysdir_find_global_file(&buf, &cfgval[2]))
*out = git_buf_detach(&buf);
else if (cfgval)
*out = git__strdup(cfgval);
}
- else if (!git_futils_find_xdg_file(&buf, fallback))
+ else if (!git_sysdir_find_xdg_file(&buf, fallback))
*out = git_buf_detach(&buf);
git_buf_free(&buf);
diff --git a/src/config.c b/src/config.c
index 6aa71468a..ae093ed64 100644
--- a/src/config.c
+++ b/src/config.c
@@ -6,7 +6,7 @@
*/
#include "common.h"
-#include "fileops.h"
+#include "sysdir.h"
#include "config.h"
#include "git2/config.h"
#include "git2/sys/config.h"
@@ -937,17 +937,17 @@ void git_config_iterator_free(git_config_iterator *iter)
int git_config_find_global(git_buf *path)
{
- return git_futils_find_global_file(path, GIT_CONFIG_FILENAME_GLOBAL);
+ return git_sysdir_find_global_file(path, GIT_CONFIG_FILENAME_GLOBAL);
}
int git_config_find_xdg(git_buf *path)
{
- return git_futils_find_xdg_file(path, GIT_CONFIG_FILENAME_XDG);
+ return git_sysdir_find_xdg_file(path, GIT_CONFIG_FILENAME_XDG);
}
int git_config_find_system(git_buf *path)
{
- return git_futils_find_system_file(path, GIT_CONFIG_FILENAME_SYSTEM);
+ return git_sysdir_find_system_file(path, GIT_CONFIG_FILENAME_SYSTEM);
}
int git_config__global_location(git_buf *buf)
@@ -956,7 +956,7 @@ int git_config__global_location(git_buf *buf)
const char *sep, *start;
size_t len;
- if (git_futils_dirs_get(&paths, GIT_FUTILS_DIR_GLOBAL) < 0)
+ if (git_sysdir_get(&paths, GIT_SYSDIR_GLOBAL) < 0)
return -1;
/* no paths, so give up */
diff --git a/src/config_file.c b/src/config_file.c
index c7727c029..aedf2cb12 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -7,8 +7,8 @@
#include "common.h"
#include "config.h"
-#include "fileops.h"
#include "filebuf.h"
+#include "sysdir.h"
#include "buffer.h"
#include "buf_text.h"
#include "git2/config.h"
@@ -1003,7 +1003,7 @@ static int included_path(git_buf *out, const char *dir, const char *path)
{
/* From the user's home */
if (path[0] == '~' && path[1] == '/')
- return git_futils_find_global_file(out, &path[1]);
+ return git_sysdir_find_global_file(out, &path[1]);
return git_path_join_unrooted(out, path, dir, NULL);
}
diff --git a/src/fileops.c b/src/fileops.c
index a60689f3f..5709499b0 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -558,226 +558,6 @@ int git_futils_rmdir_r(
return error;
}
-
-static int git_futils_guess_system_dirs(git_buf *out)
-{
-#ifdef GIT_WIN32
- return git_win32__find_system_dirs(out, L"etc\\");
-#else
- return git_buf_sets(out, "/etc");
-#endif
-}
-
-static int git_futils_guess_global_dirs(git_buf *out)
-{
-#ifdef GIT_WIN32
- return git_win32__find_global_dirs(out);
-#else
- return git_buf_sets(out, getenv("HOME"));
-#endif
-}
-
-static int git_futils_guess_xdg_dirs(git_buf *out)
-{
-#ifdef GIT_WIN32
- return git_win32__find_xdg_dirs(out);
-#else
- const char *env = NULL;
-
- if ((env = getenv("XDG_CONFIG_HOME")) != NULL)
- return git_buf_joinpath(out, env, "git");
- else if ((env = getenv("HOME")) != NULL)
- return git_buf_joinpath(out, env, ".config/git");
-
- git_buf_clear(out);
- return 0;
-#endif
-}
-
-static int git_futils_guess_template_dirs(git_buf *out)
-{
-#ifdef GIT_WIN32
- return git_win32__find_system_dirs(out, L"share\\git-core\\templates");
-#else
- return git_buf_sets(out, "/usr/share/git-core/templates");
-#endif
-}
-
-typedef int (*git_futils_dirs_guess_cb)(git_buf *out);
-
-static git_buf git_futils__dirs[GIT_FUTILS_DIR__MAX] =
- { GIT_BUF_INIT, GIT_BUF_INIT, GIT_BUF_INIT, GIT_BUF_INIT };
-
-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,
- git_futils_guess_template_dirs,
-};
-
-static int git_futils__dirs_shutdown_set = 0;
-
-void git_futils_dirs_global_shutdown(void)
-{
- int i;
- for (i = 0; i < GIT_FUTILS_DIR__MAX; ++i)
- git_buf_free(&git_futils__dirs[i]);
-}
-
-int git_futils_dirs_global_init(void)
-{
- git_futils_dir_t i;
- const git_buf *path;
- int error = 0;
-
- for (i = 0; !error && i < GIT_FUTILS_DIR__MAX; i++)
- error = git_futils_dirs_get(&path, i);
-
- return error;
-}
-
-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_dirs_get(const git_buf **out, git_futils_dir_t which)
-{
- assert(out);
-
- *out = NULL;
-
- GITERR_CHECK_ERROR(git_futils_check_selector(which));
-
- if (!git_buf_len(&git_futils__dirs[which])) {
- /* prepare shutdown if we're going to need it */
- if (!git_futils__dirs_shutdown_set) {
- git__on_shutdown(git_futils_dirs_global_shutdown);
- git_futils__dirs_shutdown_set = 1;
- }
-
- GITERR_CHECK_ERROR(
- git_futils__dir_guess[which](&git_futils__dirs[which]));
- }
-
- *out = &git_futils__dirs[which];
- return 0;
-}
-
-int git_futils_dirs_get_str(char *out, size_t outlen, git_futils_dir_t which)
-{
- const git_buf *path = NULL;
-
- GITERR_CHECK_ERROR(git_futils_check_selector(which));
- GITERR_CHECK_ERROR(git_futils_dirs_get(&path, which));
-
- if (!out || path->size >= outlen) {
- giterr_set(GITERR_NOMEMORY, "Buffer is too short for the path");
- return GIT_EBUFS;
- }
-
- git_buf_copy_cstr(out, outlen, path);
- return 0;
-}
-
-#define PATH_MAGIC "$PATH"
-
-int git_futils_dirs_set(git_futils_dir_t which, const char *search_path)
-{
- const char *expand_path = NULL;
- git_buf merge = GIT_BUF_INIT;
-
- GITERR_CHECK_ERROR(git_futils_check_selector(which));
-
- if (search_path != NULL)
- expand_path = strstr(search_path, PATH_MAGIC);
-
- /* init with default if not yet done and needed (ignoring error) */
- if ((!search_path || expand_path) &&
- !git_buf_len(&git_futils__dirs[which]))
- git_futils__dir_guess[which](&git_futils__dirs[which]);
-
- /* if $PATH is not referenced, then just set the path */
- if (!expand_path)
- return git_buf_sets(&git_futils__dirs[which], search_path);
-
- /* otherwise set to join(before $PATH, old value, after $PATH) */
- if (expand_path > search_path)
- git_buf_set(&merge, search_path, expand_path - search_path);
-
- if (git_buf_len(&git_futils__dirs[which]))
- git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR,
- merge.ptr, git_futils__dirs[which].ptr);
-
- expand_path += strlen(PATH_MAGIC);
- if (*expand_path)
- git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR, merge.ptr, expand_path);
-
- git_buf_swap(&git_futils__dirs[which], &merge);
- git_buf_free(&merge);
-
- return git_buf_oom(&git_futils__dirs[which]) ? -1 : 0;
-}
-
-static int git_futils_find_in_dirlist(
- git_buf *path, const char *name, git_futils_dir_t which, const char *label)
-{
- size_t len;
- const char *scan, *next = NULL;
- const git_buf *syspath;
-
- GITERR_CHECK_ERROR(git_futils_dirs_get(&syspath, which));
-
- for (scan = git_buf_cstr(syspath); scan; scan = next) {
- for (next = strchr(scan, GIT_PATH_LIST_SEPARATOR);
- next && next > scan && next[-1] == '\\';
- next = strchr(next + 1, GIT_PATH_LIST_SEPARATOR))
- /* find unescaped separator or end of string */;
-
- len = next ? (size_t)(next++ - scan) : strlen(scan);
- if (!len)
- continue;
-
- GITERR_CHECK_ERROR(git_buf_set(path, scan, len));
- if (name)
- GITERR_CHECK_ERROR(git_buf_joinpath(path, path->ptr, name));
-
- if (git_path_exists(path->ptr))
- return 0;
- }
-
- 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_find_template_dir(git_buf *path)
-{
- return git_futils_find_in_dirlist(
- path, NULL, GIT_FUTILS_DIR_TEMPLATE, "template");
-}
-
int git_futils_fake_symlink(const char *old, const char *new)
{
int retcode = GIT_ERROR;
diff --git a/src/fileops.h b/src/fileops.h
index 636c9b67d..6a65235de 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -268,89 +268,6 @@ extern int git_futils_mmap_ro_file(
extern void git_futils_mmap_free(git_map *map);
/**
- * Find a "global" file (i.e. one in a user's home directory).
- *
- * @param path buffer to write the full path into
- * @param filename name of file to find in the home directory
- * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error
- */
-extern int git_futils_find_global_file(git_buf *path, const char *filename);
-
-/**
- * Find an "XDG" file (i.e. one in user's XDG config path).
- *
- * @param path buffer to write the full path into
- * @param filename name of file to find in the home directory
- * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error
- */
-extern int git_futils_find_xdg_file(git_buf *path, const char *filename);
-
-/**
- * Find a "system" file (i.e. one shared for all users of the system).
- *
- * @param path buffer to write the full path into
- * @param filename name of file to find in the home directory
- * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error
- */
-extern int git_futils_find_system_file(git_buf *path, const char *filename);
-
-/**
- * Find template directory.
- *
- * @param path buffer to write the full path into
- * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error
- */
-extern int git_futils_find_template_dir(git_buf *path);
-
-typedef enum {
- GIT_FUTILS_DIR_SYSTEM = 0,
- GIT_FUTILS_DIR_GLOBAL = 1,
- GIT_FUTILS_DIR_XDG = 2,
- GIT_FUTILS_DIR_TEMPLATE = 3,
- GIT_FUTILS_DIR__MAX = 4,
-} git_futils_dir_t;
-
-/**
- * Configures global data for configuration file search paths.
- *
- * @return 0 on success, <0 on failure
- */
-extern int git_futils_dirs_global_init(void);
-
-/**
- * Get the search path for global/system/xdg files
- *
- * @param out pointer to git_buf containing search path
- * @param which which list of paths to return
- * @return 0 on success, <0 on failure
- */
-extern int git_futils_dirs_get(const git_buf **out, git_futils_dir_t which);
-
-/**
- * Get search path into a preallocated buffer
- *
- * @param out String buffer to write into
- * @param outlen Size of string buffer
- * @param which Which search path to return
- * @return 0 on success, GIT_EBUFS if out is too small, <0 on other failure
- */
-
-extern int git_futils_dirs_get_str(
- char *out, size_t outlen, git_futils_dir_t which);
-
-/**
- * Set search paths for global/system/xdg files
- *
- * The first occurrence of the magic string "$PATH" in the new value will
- * be replaced with the old value of the search path.
- *
- * @param which Which search path to modify
- * @param paths New search path (separated by GIT_PATH_LIST_SEPARATOR)
- * @return 0 on success, <0 on failure (allocation error)
- */
-extern int git_futils_dirs_set(git_futils_dir_t which, const char *paths);
-
-/**
* Create a "fake" symlink (text file containing the target path).
*
* @param new symlink file to be created
@@ -399,9 +316,4 @@ extern int git_futils_filestamp_check(
extern void git_futils_filestamp_set(
git_futils_filestamp *tgt, const git_futils_filestamp *src);
-/**
- * Free the configuration file search paths.
- */
-extern void git_futils_dirs_global_shutdown(void);
-
#endif /* INCLUDE_fileops_h__ */
diff --git a/src/global.c b/src/global.c
index 7d39c6fa8..8c8f55a90 100644
--- a/src/global.c
+++ b/src/global.c
@@ -7,7 +7,7 @@
#include "common.h"
#include "global.h"
#include "hash.h"
-#include "fileops.h"
+#include "sysdir.h"
#include "git2/threads.h"
#include "thread-utils.h"
@@ -86,7 +86,7 @@ static int synchronized_threads_init()
/* Initialize any other subsystems that have global state */
if ((error = git_hash_global_init()) >= 0)
- error = git_futils_dirs_global_init();
+ error = git_sysdir_global_init();
win32_pthread_initialize();
@@ -169,7 +169,7 @@ static void init_once(void)
/* Initialize any other subsystems that have global state */
if ((init_error = git_hash_global_init()) >= 0)
- init_error = git_futils_dirs_global_init();
+ init_error = git_sysdir_global_init();
GIT_MEMORY_BARRIER;
}
diff --git a/src/repository.c b/src/repository.c
index 8b336c215..b94973c74 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -16,6 +16,7 @@
#include "tag.h"
#include "blob.h"
#include "fileops.h"
+#include "sysdir.h"
#include "filebuf.h"
#include "index.h"
#include "config.h"
@@ -1264,7 +1265,7 @@ static int repo_init_structure(
}
if (!tdir) {
- if (!(error = git_futils_find_template_dir(&template_buf)))
+ if (!(error = git_sysdir_find_template_dir(&template_buf)))
tdir = template_buf.ptr;
default_template = true;
}
diff --git a/src/settings.c b/src/settings.c
index 7c2a30377..3856735f7 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -7,7 +7,7 @@
#include <git2.h>
#include "common.h"
-#include "fileops.h"
+#include "sysdir.h"
#include "cache.h"
void git_libgit2_version(int *major, int *minor, int *rev)
@@ -36,14 +36,14 @@ int git_libgit2_capabilities()
extern size_t git_mwindow__window_size;
extern size_t git_mwindow__mapped_limit;
-static int config_level_to_futils_dir(int config_level)
+static int config_level_to_sysdir(int config_level)
{
int val = -1;
switch (config_level) {
- case GIT_CONFIG_LEVEL_SYSTEM: val = GIT_FUTILS_DIR_SYSTEM; break;
- case GIT_CONFIG_LEVEL_XDG: val = GIT_FUTILS_DIR_XDG; break;
- case GIT_CONFIG_LEVEL_GLOBAL: val = GIT_FUTILS_DIR_GLOBAL; break;
+ case GIT_CONFIG_LEVEL_SYSTEM: val = GIT_SYSDIR_SYSTEM; break;
+ case GIT_CONFIG_LEVEL_XDG: val = GIT_SYSDIR_XDG; break;
+ case GIT_CONFIG_LEVEL_GLOBAL: val = GIT_SYSDIR_GLOBAL; break;
default:
giterr_set(
GITERR_INVALID, "Invalid config path selector %d", config_level);
@@ -77,17 +77,17 @@ int git_libgit2_opts(int key, ...)
break;
case GIT_OPT_GET_SEARCH_PATH:
- if ((error = config_level_to_futils_dir(va_arg(ap, int))) >= 0) {
+ if ((error = config_level_to_sysdir(va_arg(ap, int))) >= 0) {
char *out = va_arg(ap, char *);
size_t outlen = va_arg(ap, size_t);
- error = git_futils_dirs_get_str(out, outlen, error);
+ error = git_sysdir_get_str(out, outlen, error);
}
break;
case GIT_OPT_SET_SEARCH_PATH:
- if ((error = config_level_to_futils_dir(va_arg(ap, int))) >= 0)
- error = git_futils_dirs_set(error, va_arg(ap, const char *));
+ if ((error = config_level_to_sysdir(va_arg(ap, int))) >= 0)
+ error = git_sysdir_set(error, va_arg(ap, const char *));
break;
case GIT_OPT_SET_CACHE_OBJECT_LIMIT:
@@ -116,12 +116,12 @@ int git_libgit2_opts(int key, ...)
char *out = va_arg(ap, char *);
size_t outlen = va_arg(ap, size_t);
- error = git_futils_dirs_get_str(out, outlen, GIT_FUTILS_DIR_TEMPLATE);
+ error = git_sysdir_get_str(out, outlen, GIT_SYSDIR_TEMPLATE);
}
break;
case GIT_OPT_SET_TEMPLATE_PATH:
- error = git_futils_dirs_set(GIT_FUTILS_DIR_TEMPLATE, va_arg(ap, const char *));
+ error = git_sysdir_set(GIT_SYSDIR_TEMPLATE, va_arg(ap, const char *));
break;
}
diff --git a/src/sysdir.c b/src/sysdir.c
new file mode 100644
index 000000000..2e6304e35
--- /dev/null
+++ b/src/sysdir.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "common.h"
+#include "sysdir.h"
+#include "global.h"
+#include "buffer.h"
+#include "path.h"
+#include <ctype.h>
+#if GIT_WIN32
+#include "win32/findfile.h"
+#endif
+
+static int git_sysdir_guess_system_dirs(git_buf *out)
+{
+#ifdef GIT_WIN32
+ return git_win32__find_system_dirs(out, L"etc\\");
+#else
+ return git_buf_sets(out, "/etc");
+#endif
+}
+
+static int git_sysdir_guess_global_dirs(git_buf *out)
+{
+#ifdef GIT_WIN32
+ return git_win32__find_global_dirs(out);
+#else
+ return git_buf_sets(out, getenv("HOME"));
+#endif
+}
+
+static int git_sysdir_guess_xdg_dirs(git_buf *out)
+{
+#ifdef GIT_WIN32
+ return git_win32__find_xdg_dirs(out);
+#else
+ const char *env = NULL;
+
+ if ((env = getenv("XDG_CONFIG_HOME")) != NULL)
+ return git_buf_joinpath(out, env, "git");
+ else if ((env = getenv("HOME")) != NULL)
+ return git_buf_joinpath(out, env, ".config/git");
+
+ git_buf_clear(out);
+ return 0;
+#endif
+}
+
+static int git_sysdir_guess_template_dirs(git_buf *out)
+{
+#ifdef GIT_WIN32
+ return git_win32__find_system_dirs(out, L"share\\git-core\\templates");
+#else
+ return git_buf_sets(out, "/usr/share/git-core/templates");
+#endif
+}
+
+typedef int (*git_sysdir_guess_cb)(git_buf *out);
+
+static git_buf git_sysdir__dirs[GIT_SYSDIR__MAX] =
+ { GIT_BUF_INIT, GIT_BUF_INIT, GIT_BUF_INIT, GIT_BUF_INIT };
+
+static git_sysdir_guess_cb git_sysdir__dir_guess[GIT_SYSDIR__MAX] = {
+ git_sysdir_guess_system_dirs,
+ git_sysdir_guess_global_dirs,
+ git_sysdir_guess_xdg_dirs,
+ git_sysdir_guess_template_dirs,
+};
+
+static int git_sysdir__dirs_shutdown_set = 0;
+
+int git_sysdir_global_init(void)
+{
+ git_sysdir_t i;
+ const git_buf *path;
+ int error = 0;
+
+ for (i = 0; !error && i < GIT_SYSDIR__MAX; i++)
+ error = git_sysdir_get(&path, i);
+
+ return error;
+}
+
+void git_sysdir_global_shutdown(void)
+{
+ int i;
+ for (i = 0; i < GIT_SYSDIR__MAX; ++i)
+ git_buf_free(&git_sysdir__dirs[i]);
+}
+
+static int git_sysdir_check_selector(git_sysdir_t which)
+{
+ if (which < GIT_SYSDIR__MAX)
+ return 0;
+
+ giterr_set(GITERR_INVALID, "config directory selector out of range");
+ return -1;
+}
+
+
+int git_sysdir_get(const git_buf **out, git_sysdir_t which)
+{
+ assert(out);
+
+ *out = NULL;
+
+ GITERR_CHECK_ERROR(git_sysdir_check_selector(which));
+
+ if (!git_buf_len(&git_sysdir__dirs[which])) {
+ /* prepare shutdown if we're going to need it */
+ if (!git_sysdir__dirs_shutdown_set) {
+ git__on_shutdown(git_sysdir_global_shutdown);
+ git_sysdir__dirs_shutdown_set = 1;
+ }
+
+ GITERR_CHECK_ERROR(
+ git_sysdir__dir_guess[which](&git_sysdir__dirs[which]));
+ }
+
+ *out = &git_sysdir__dirs[which];
+ return 0;
+}
+
+int git_sysdir_get_str(
+ char *out,
+ size_t outlen,
+ git_sysdir_t which)
+{
+ const git_buf *path = NULL;
+
+ GITERR_CHECK_ERROR(git_sysdir_check_selector(which));
+ GITERR_CHECK_ERROR(git_sysdir_get(&path, which));
+
+ if (!out || path->size >= outlen) {
+ giterr_set(GITERR_NOMEMORY, "Buffer is too short for the path");
+ return GIT_EBUFS;
+ }
+
+ git_buf_copy_cstr(out, outlen, path);
+ return 0;
+}
+
+#define PATH_MAGIC "$PATH"
+
+int git_sysdir_set(git_sysdir_t which, const char *search_path)
+{
+ const char *expand_path = NULL;
+ git_buf merge = GIT_BUF_INIT;
+
+ GITERR_CHECK_ERROR(git_sysdir_check_selector(which));
+
+ if (search_path != NULL)
+ expand_path = strstr(search_path, PATH_MAGIC);
+
+ /* init with default if not yet done and needed (ignoring error) */
+ if ((!search_path || expand_path) &&
+ !git_buf_len(&git_sysdir__dirs[which]))
+ git_sysdir__dir_guess[which](&git_sysdir__dirs[which]);
+
+ /* if $PATH is not referenced, then just set the path */
+ if (!expand_path)
+ return git_buf_sets(&git_sysdir__dirs[which], search_path);
+
+ /* otherwise set to join(before $PATH, old value, after $PATH) */
+ if (expand_path > search_path)
+ git_buf_set(&merge, search_path, expand_path - search_path);
+
+ if (git_buf_len(&git_sysdir__dirs[which]))
+ git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR,
+ merge.ptr, git_sysdir__dirs[which].ptr);
+
+ expand_path += strlen(PATH_MAGIC);
+ if (*expand_path)
+ git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR, merge.ptr, expand_path);
+
+ git_buf_swap(&git_sysdir__dirs[which], &merge);
+ git_buf_free(&merge);
+
+ return git_buf_oom(&git_sysdir__dirs[which]) ? -1 : 0;
+}
+
+static int git_sysdir_find_in_dirlist(
+ git_buf *path,
+ const char *name,
+ git_sysdir_t which,
+ const char *label)
+{
+ size_t len;
+ const char *scan, *next = NULL;
+ const git_buf *syspath;
+
+ GITERR_CHECK_ERROR(git_sysdir_get(&syspath, which));
+
+ for (scan = git_buf_cstr(syspath); scan; scan = next) {
+ for (next = strchr(scan, GIT_PATH_LIST_SEPARATOR);
+ next && next > scan && next[-1] == '\\';
+ next = strchr(next + 1, GIT_PATH_LIST_SEPARATOR))
+ /* find unescaped separator or end of string */;
+
+ len = next ? (size_t)(next++ - scan) : strlen(scan);
+ if (!len)
+ continue;
+
+ GITERR_CHECK_ERROR(git_buf_set(path, scan, len));
+ if (name)
+ GITERR_CHECK_ERROR(git_buf_joinpath(path, path->ptr, name));
+
+ if (git_path_exists(path->ptr))
+ return 0;
+ }
+
+ git_buf_clear(path);
+ giterr_set(GITERR_OS, "The %s file '%s' doesn't exist", label, name);
+ return GIT_ENOTFOUND;
+}
+
+int git_sysdir_find_system_file(git_buf *path, const char *filename)
+{
+ return git_sysdir_find_in_dirlist(
+ path, filename, GIT_SYSDIR_SYSTEM, "system");
+}
+
+int git_sysdir_find_global_file(git_buf *path, const char *filename)
+{
+ return git_sysdir_find_in_dirlist(
+ path, filename, GIT_SYSDIR_GLOBAL, "global");
+}
+
+int git_sysdir_find_xdg_file(git_buf *path, const char *filename)
+{
+ return git_sysdir_find_in_dirlist(
+ path, filename, GIT_SYSDIR_XDG, "global/xdg");
+}
+
+int git_sysdir_find_template_dir(git_buf *path)
+{
+ return git_sysdir_find_in_dirlist(
+ path, NULL, GIT_SYSDIR_TEMPLATE, "template");
+}
+
diff --git a/src/sysdir.h b/src/sysdir.h
new file mode 100644
index 000000000..f1bbf0bae
--- /dev/null
+++ b/src/sysdir.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_sysdir_h__
+#define INCLUDE_sysdir_h__
+
+#include "common.h"
+#include "posix.h"
+#include "buffer.h"
+
+/**
+ * Find a "global" file (i.e. one in a user's home directory).
+ *
+ * @param path buffer to write the full path into
+ * @param filename name of file to find in the home directory
+ * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error
+ */
+extern int git_sysdir_find_global_file(git_buf *path, const char *filename);
+
+/**
+ * Find an "XDG" file (i.e. one in user's XDG config path).
+ *
+ * @param path buffer to write the full path into
+ * @param filename name of file to find in the home directory
+ * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error
+ */
+extern int git_sysdir_find_xdg_file(git_buf *path, const char *filename);
+
+/**
+ * Find a "system" file (i.e. one shared for all users of the system).
+ *
+ * @param path buffer to write the full path into
+ * @param filename name of file to find in the home directory
+ * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error
+ */
+extern int git_sysdir_find_system_file(git_buf *path, const char *filename);
+
+/**
+ * Find template directory.
+ *
+ * @param path buffer to write the full path into
+ * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error
+ */
+extern int git_sysdir_find_template_dir(git_buf *path);
+
+typedef enum {
+ GIT_SYSDIR_SYSTEM = 0,
+ GIT_SYSDIR_GLOBAL = 1,
+ GIT_SYSDIR_XDG = 2,
+ GIT_SYSDIR_TEMPLATE = 3,
+ GIT_SYSDIR__MAX = 4,
+} git_sysdir_t;
+
+/**
+ * Configures global data for configuration file search paths.
+ *
+ * @return 0 on success, <0 on failure
+ */
+extern int git_sysdir_global_init(void);
+
+/**
+ * Get the search path for global/system/xdg files
+ *
+ * @param out pointer to git_buf containing search path
+ * @param which which list of paths to return
+ * @return 0 on success, <0 on failure
+ */
+extern int git_sysdir_get(const git_buf **out, git_sysdir_t which);
+
+/**
+ * Get search path into a preallocated buffer
+ *
+ * @param out String buffer to write into
+ * @param outlen Size of string buffer
+ * @param which Which search path to return
+ * @return 0 on success, GIT_EBUFS if out is too small, <0 on other failure
+ */
+
+extern int git_sysdir_get_str(char *out, size_t outlen, git_sysdir_t which);
+
+/**
+ * Set search paths for global/system/xdg files
+ *
+ * The first occurrence of the magic string "$PATH" in the new value will
+ * be replaced with the old value of the search path.
+ *
+ * @param which Which search path to modify
+ * @param paths New search path (separated by GIT_PATH_LIST_SEPARATOR)
+ * @return 0 on success, <0 on failure (allocation error)
+ */
+extern int git_sysdir_set(git_sysdir_t which, const char *paths);
+
+/**
+ * Free the configuration file search paths.
+ */
+extern void git_sysdir_global_shutdown(void);
+
+#endif /* INCLUDE_sysdir_h__ */
diff --git a/tests/core/env.c b/tests/core/env.c
index 0fa6472d7..a32f5ed3e 100644
--- a/tests/core/env.c
+++ b/tests/core/env.c
@@ -1,5 +1,6 @@
#include "clar_libgit2.h"
#include "fileops.h"
+#include "sysdir.h"
#include "path.h"
#ifdef GIT_WIN32
@@ -41,12 +42,12 @@ void test_core_env__initialize(void)
static void reset_global_search_path(void)
{
- cl_git_pass(git_futils_dirs_set(GIT_FUTILS_DIR_GLOBAL, NULL));
+ cl_git_pass(git_sysdir_set(GIT_SYSDIR_GLOBAL, NULL));
}
static void reset_system_search_path(void)
{
- cl_git_pass(git_futils_dirs_set(GIT_FUTILS_DIR_SYSTEM, NULL));
+ cl_git_pass(git_sysdir_set(GIT_SYSDIR_SYSTEM, NULL));
}
void test_core_env__cleanup(void)
@@ -120,18 +121,18 @@ void test_core_env__0(void)
git_buf_rtruncate_at_char(&path, '/');
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_global_file(&found, testfile));
+ GIT_ENOTFOUND, git_sysdir_find_global_file(&found, testfile));
setenv_and_check("HOME", path.ptr);
reset_global_search_path();
- cl_git_pass(git_futils_find_global_file(&found, testfile));
+ cl_git_pass(git_sysdir_find_global_file(&found, testfile));
cl_setenv("HOME", env_save[0]);
reset_global_search_path();
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_global_file(&found, testfile));
+ GIT_ENOTFOUND, git_sysdir_find_global_file(&found, testfile));
#ifdef GIT_WIN32
setenv_and_check("HOMEDRIVE", NULL);
@@ -139,7 +140,7 @@ void test_core_env__0(void)
setenv_and_check("USERPROFILE", path.ptr);
reset_global_search_path();
- cl_git_pass(git_futils_find_global_file(&found, testfile));
+ cl_git_pass(git_sysdir_find_global_file(&found, testfile));
{
int root = git_path_root(path.ptr);
@@ -150,7 +151,7 @@ void test_core_env__0(void)
reset_global_search_path();
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_global_file(&found, testfile));
+ GIT_ENOTFOUND, git_sysdir_find_global_file(&found, testfile));
old = path.ptr[root];
path.ptr[root] = '\0';
@@ -159,7 +160,7 @@ void test_core_env__0(void)
setenv_and_check("HOMEPATH", &path.ptr[root]);
reset_global_search_path();
- cl_git_pass(git_futils_find_global_file(&found, testfile));
+ cl_git_pass(git_sysdir_find_global_file(&found, testfile));
}
}
#endif
@@ -177,7 +178,7 @@ void test_core_env__1(void)
git_buf path = GIT_BUF_INIT;
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_global_file(&path, "nonexistentfile"));
+ GIT_ENOTFOUND, git_sysdir_find_global_file(&path, "nonexistentfile"));
cl_git_pass(cl_setenv("HOME", "doesnotexist"));
#ifdef GIT_WIN32
@@ -187,7 +188,7 @@ void test_core_env__1(void)
reset_global_search_path();
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_global_file(&path, "nonexistentfile"));
+ GIT_ENOTFOUND, git_sysdir_find_global_file(&path, "nonexistentfile"));
cl_git_pass(cl_setenv("HOME", NULL));
#ifdef GIT_WIN32
@@ -198,17 +199,17 @@ void test_core_env__1(void)
reset_system_search_path();
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_global_file(&path, "nonexistentfile"));
+ GIT_ENOTFOUND, git_sysdir_find_global_file(&path, "nonexistentfile"));
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_system_file(&path, "nonexistentfile"));
+ GIT_ENOTFOUND, git_sysdir_find_system_file(&path, "nonexistentfile"));
#ifdef GIT_WIN32
cl_git_pass(cl_setenv("PROGRAMFILES", NULL));
reset_system_search_path();
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_system_file(&path, "nonexistentfile"));
+ GIT_ENOTFOUND, git_sysdir_find_system_file(&path, "nonexistentfile"));
#endif
git_buf_free(&path);
@@ -242,13 +243,13 @@ static void check_global_searchpath(
cl_assert_equal_s(out, path);
/* find file using new path */
- cl_git_pass(git_futils_find_global_file(temp, file));
+ cl_git_pass(git_sysdir_find_global_file(temp, file));
/* reset path and confirm file not found */
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, NULL));
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_global_file(temp, file));
+ GIT_ENOTFOUND, git_sysdir_find_global_file(temp, file));
}
void test_core_env__2(void)
@@ -285,7 +286,7 @@ void test_core_env__2(void)
/* default should be NOTFOUND */
cl_assert_equal_i(
- GIT_ENOTFOUND, git_futils_find_global_file(&found, testfile));
+ GIT_ENOTFOUND, git_sysdir_find_global_file(&found, testfile));
/* try plain, append $PATH, and prepend $PATH */
check_global_searchpath(path.ptr, 0, testfile, &found);
diff --git a/tests/repo/config.c b/tests/repo/config.c
index e77acc8c5..2e7be37aa 100644
--- a/tests/repo/config.c
+++ b/tests/repo/config.c
@@ -1,4 +1,5 @@
#include "clar_libgit2.h"
+#include "sysdir.h"
#include "fileops.h"
#include <ctype.h>
@@ -47,7 +48,7 @@ void test_repo_config__open_missing_global(void)
git_config_free(config);
git_repository_free(repo);
- git_futils_dirs_global_shutdown();
+ git_sysdir_global_shutdown();
}
void test_repo_config__open_missing_global_with_separators(void)
@@ -76,7 +77,7 @@ void test_repo_config__open_missing_global_with_separators(void)
git_config_free(config);
git_repository_free(repo);
- git_futils_dirs_global_shutdown();
+ git_sysdir_global_shutdown();
}
#include "repository.h"
@@ -105,7 +106,7 @@ void test_repo_config__read_no_configs(void)
cl_assert_equal_i(GIT_ABBREV_DEFAULT, val);
git_repository_free(repo);
- git_futils_dirs_global_shutdown();
+ git_sysdir_global_shutdown();
/* with just system */
@@ -204,5 +205,5 @@ void test_repo_config__read_no_configs(void)
cl_assert(!git_path_exists("empty_standard_repo/.git/config"));
cl_assert(!git_path_exists("alternate/3/.gitconfig"));
- git_futils_dirs_global_shutdown();
+ git_sysdir_global_shutdown();
}
diff --git a/tests/repo/open.c b/tests/repo/open.c
index 7cfe041c2..f7420bd3a 100644
--- a/tests/repo/open.c
+++ b/tests/repo/open.c
@@ -1,5 +1,6 @@
#include "clar_libgit2.h"
#include "fileops.h"
+#include "sysdir.h"
#include <ctype.h>
void test_repo_open__cleanup(void)
@@ -323,7 +324,7 @@ void test_repo_open__no_config(void)
git_repository_free(repo);
cl_fixture_cleanup("empty_standard_repo");
- git_futils_dirs_global_shutdown();
+ git_sysdir_global_shutdown();
}
void test_repo_open__force_bare(void)