char path[PATH_MAX];
size_t len = strlen(suspect);
+ if (PATH_MAX <= len + strlen("/objects"))
+ die("Too long path: %.*s", 60, suspect);
strcpy(path, suspect);
if (getenv(DB_ENVIRONMENT)) {
if (access(getenv(DB_ENVIRONMENT), X_OK))
return path;
}
+static const char *setup_explicit_git_dir(const char *gitdirenv,
+ const char *work_tree_env, int *nongit_ok)
+{
+ static char buffer[1024 + 1];
+ const char *retval;
+
+ if (PATH_MAX - 40 < strlen(gitdirenv))
+ die("'$%s' too big", GIT_DIR_ENVIRONMENT);
+ if (!is_git_directory(gitdirenv)) {
+ if (nongit_ok) {
+ *nongit_ok = 1;
+ return NULL;
+ }
+ die("Not a git repository: '%s'", gitdirenv);
+ }
+ if (!work_tree_env) {
+ retval = set_work_tree(gitdirenv);
+ /* config may override worktree */
+ if (check_repository_format_gently(nongit_ok))
+ return NULL;
+ return retval;
+ }
+ if (check_repository_format_gently(nongit_ok))
+ return NULL;
+ retval = get_relative_cwd(buffer, sizeof(buffer) - 1,
+ get_git_work_tree());
+ if (!retval || !*retval)
+ return NULL;
+ set_git_dir(make_absolute_path(gitdirenv));
+ if (chdir(work_tree_env) < 0)
+ die_errno ("Could not chdir to '%s'", work_tree_env);
+ strcat(buffer, "/");
+ return retval;
+}
+
+static int cwd_contains_git_dir(const char **gitfile_dirp)
+{
+ const char *gitfile_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
+ *gitfile_dirp = gitfile_dir;
+ if (gitfile_dir) {
+ if (set_git_dir(gitfile_dir))
+ die("Repository setup failed");
+ return 1;
+ }
+ return is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT);
+}
+
/*
* 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.
const char *gitdirenv;
const char *gitfile_dir;
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.
* validation.
*/
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
- if (gitdirenv) {
- if (PATH_MAX - 40 < strlen(gitdirenv))
- die("'$%s' too big", GIT_DIR_ENVIRONMENT);
- if (is_git_directory(gitdirenv)) {
- static char buffer[1024 + 1];
- const char *retval;
-
- if (!work_tree_env) {
- retval = set_work_tree(gitdirenv);
- /* config may override worktree */
- if (check_repository_format_gently(nongit_ok))
- return NULL;
- return retval;
- }
- if (check_repository_format_gently(nongit_ok))
- return NULL;
- retval = get_relative_cwd(buffer, sizeof(buffer) - 1,
- get_git_work_tree());
- if (!retval || !*retval)
- return NULL;
- set_git_dir(make_absolute_path(gitdirenv));
- if (chdir(work_tree_env) < 0)
- die_errno ("Could not chdir to '%s'", work_tree_env);
- strcat(buffer, "/");
- return retval;
- }
- if (nongit_ok) {
- *nongit_ok = 1;
- return NULL;
- }
- die("Not a git repository: '%s'", gitdirenv);
- }
+ if (gitdirenv)
+ return setup_explicit_git_dir(gitdirenv, work_tree_env, nongit_ok);
if (!getcwd(cwd, sizeof(cwd)-1))
die_errno("Unable to read current working directory");
* 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 (set_git_dir(gitfile_dir))
- die("Repository setup failed");
- break;
- }
- if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT))
+ if (cwd_contains_git_dir(&gitfile_dir))
break;
if (is_git_directory(".")) {
inside_git_dir = 1;
}
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;