summaryrefslogtreecommitdiff
path: root/setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'setup.c')
-rw-r--r--setup.c52
1 files changed, 44 insertions, 8 deletions
diff --git a/setup.c b/setup.c
index fac34f77a7..7e0460205d 100644
--- a/setup.c
+++ b/setup.c
@@ -18,14 +18,15 @@ const char *prefix_path(const char *prefix, int len, const char *path)
if (normalize_path_copy(sanitized, sanitized))
goto error_out;
if (is_absolute_path(orig)) {
- size_t len, total;
+ size_t root_len, len, total;
const char *work_tree = get_git_work_tree();
if (!work_tree)
goto error_out;
len = strlen(work_tree);
+ root_len = offset_1st_component(work_tree);
total = strlen(sanitized) + 1;
if (strncmp(sanitized, work_tree, len) ||
- (sanitized[len] != '\0' && sanitized[len] != '/')) {
+ (len > root_len && sanitized[len] != '\0' && sanitized[len] != '/')) {
error_out:
die("'%s' is outside repository", orig);
}
@@ -321,7 +322,9 @@ const char *setup_git_directory_gently(int *nongit_ok)
static char cwd[PATH_MAX+1];
const char *gitdirenv;
const char *gitfile_dir;
- int len, offset, ceil_offset;
+ int len, offset, ceil_offset, root_len;
+ int current_device = 0, one_filesystem = 1;
+ struct stat buf;
/*
* Let's assume that we are in a git repository.
@@ -389,6 +392,12 @@ const char *setup_git_directory_gently(int *nongit_ok)
* etc.
*/
offset = len = strlen(cwd);
+ one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0);
+ if (one_filesystem) {
+ if (stat(".", &buf))
+ die_errno("failed to stat '.'");
+ current_device = buf.st_dev;
+ }
for (;;) {
gitfile_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
if (gitfile_dir) {
@@ -403,10 +412,11 @@ const char *setup_git_directory_gently(int *nongit_ok)
if (!work_tree_env)
inside_work_tree = 0;
if (offset != len) {
- cwd[offset] = '\0';
- setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
+ root_len = offset_1st_component(cwd);
+ cwd[offset > root_len ? offset : root_len] = '\0';
+ set_git_dir(cwd);
} else
- setenv(GIT_DIR_ENVIRONMENT, ".", 1);
+ set_git_dir(".");
check_repository_format_gently(nongit_ok);
return NULL;
}
@@ -420,14 +430,34 @@ const char *setup_git_directory_gently(int *nongit_ok)
}
die("Not a git repository (or any of the parent directories): %s", DEFAULT_GIT_DIR_ENVIRONMENT);
}
- if (chdir(".."))
+ if (one_filesystem) {
+ if (stat("..", &buf)) {
+ cwd[offset] = '\0';
+ die_errno("failed to stat '%s/..'", cwd);
+ }
+ if (buf.st_dev != current_device) {
+ if (nongit_ok) {
+ if (chdir(cwd))
+ die_errno("Cannot come back to cwd");
+ *nongit_ok = 1;
+ return NULL;
+ }
+ cwd[offset] = '\0';
+ die("Not a git repository (or any parent up to mount parent %s)\n"
+ "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).", cwd);
+ }
+ }
+ if (chdir("..")) {
+ cwd[offset] = '\0';
die_errno("Cannot change to '%s/..'", cwd);
+ }
}
inside_git_dir = 0;
if (!work_tree_env)
inside_work_tree = 1;
- git_work_tree_cfg = xstrndup(cwd, offset);
+ root_len = offset_1st_component(cwd);
+ git_work_tree_cfg = xstrndup(cwd, offset > root_len ? offset : root_len);
if (check_repository_format_gently(nongit_ok))
return NULL;
if (offset == len)
@@ -516,6 +546,12 @@ int check_repository_format(void)
return check_repository_format_gently(NULL);
}
+/*
+ * Returns the "prefix", a path to the current working directory
+ * relative to the work tree root, or NULL, if the current working
+ * directory is not a strict subdirectory of the work tree root. The
+ * prefix always ends with a '/' character.
+ */
const char *setup_git_directory(void)
{
const char *retval = setup_git_directory_gently(NULL);