diff options
Diffstat (limited to 'setup.c')
-rw-r--r-- | setup.c | 74 |
1 files changed, 71 insertions, 3 deletions
@@ -1,5 +1,6 @@ #include "cache.h" #include "dir.h" +#include "string-list.h" static int inside_git_dir = -1; static int inside_work_tree = -1; @@ -65,7 +66,14 @@ int check_filename(const char *prefix, const char *arg) const char *name; struct stat st; - name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg; + if (!prefixcmp(arg, ":/")) { + if (arg[2] == '\0') /* ":/" is root dir, always exists */ + return 1; + name = arg + 2; + } else if (prefix) + name = prefix_filename(prefix, strlen(prefix), arg); + else + name = arg; if (!lstat(name, &st)) return 1; /* file exists */ if (errno == ENOENT || errno == ENOTDIR) @@ -247,6 +255,25 @@ static const char *prefix_pathspec(const char *prefix, int prefixlen, const char return prefix_path(prefix, prefixlen, copyfrom); } +/* + * N.B. get_pathspec() is deprecated in favor of the "struct pathspec" + * based interface - see pathspec_magic above. + * + * Arguments: + * - prefix - a path relative to the root of the working tree + * - pathspec - a list of paths underneath the prefix path + * + * Iterates over pathspec, prepending each path with prefix, + * and return the resulting list. + * + * If pathspec is empty, return a singleton list containing prefix. + * + * If pathspec and prefix are both empty, return an empty list. + * + * This is typically used by built-in commands such as add.c, in order + * to normalize argv arguments provided to the built-in into a list of + * paths to process, all relative to the root of the working tree. + */ const char **get_pathspec(const char *prefix, const char **pathspec) { const char *entry = *pathspec; @@ -623,16 +650,48 @@ static dev_t get_device_or_die(const char *path, const char *prefix, int prefix_ } /* + * A "string_list_each_func_t" function that canonicalizes an entry + * from GIT_CEILING_DIRECTORIES using real_path_if_valid(), or + * discards it if unusable. The presence of an empty entry in + * GIT_CEILING_DIRECTORIES turns off canonicalization for all + * subsequent entries. + */ +static int canonicalize_ceiling_entry(struct string_list_item *item, + void *cb_data) +{ + int *empty_entry_found = cb_data; + char *ceil = item->string; + + if (!*ceil) { + *empty_entry_found = 1; + return 0; + } else if (!is_absolute_path(ceil)) { + return 0; + } else if (*empty_entry_found) { + /* Keep entry but do not canonicalize it */ + return 1; + } else { + const char *real_path = real_path_if_valid(ceil); + if (!real_path) + return 0; + free(item->string); + item->string = xstrdup(real_path); + return 1; + } +} + +/* * We cannot decide in this function whether we are in the work tree or * not, since the config can only be read _after_ this function was called. */ static const char *setup_git_directory_gently_1(int *nongit_ok) { const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT); + struct string_list ceiling_dirs = STRING_LIST_INIT_DUP; static char cwd[PATH_MAX+1]; const char *gitdirenv, *ret; char *gitfile; - int len, offset, offset_parent, ceil_offset; + int len, offset, offset_parent, ceil_offset = -1; dev_t current_device = 0; int one_filesystem = 1; @@ -657,7 +716,16 @@ static const char *setup_git_directory_gently_1(int *nongit_ok) if (gitdirenv) return setup_explicit_git_dir(gitdirenv, cwd, len, nongit_ok); - ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs); + if (env_ceiling_dirs) { + int empty_entry_found = 0; + + string_list_split(&ceiling_dirs, env_ceiling_dirs, PATH_SEP, -1); + filter_string_list(&ceiling_dirs, 0, + canonicalize_ceiling_entry, &empty_entry_found); + ceil_offset = longest_ancestor_length(cwd, &ceiling_dirs); + string_list_clear(&ceiling_dirs, 0); + } + if (ceil_offset < 0 && has_dos_drive_prefix(cwd)) ceil_offset = 1; |