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 @@ -267,89 +267,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). * @@ -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 #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 +#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 @@ -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 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)