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);
}
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;
+ dev_t current_device = 0;
+ int one_filesystem = 1;
+ struct stat buf;
/*
* Let's assume that we are in a git repository.
* 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) {
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;
}
}
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)
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);