summaryrefslogtreecommitdiff
path: root/setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'setup.c')
-rw-r--r--setup.c74
1 files changed, 71 insertions, 3 deletions
diff --git a/setup.c b/setup.c
index da0d8c80ba..a2be9690ad 100644
--- a/setup.c
+++ b/setup.c
@@ -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;