aboutsummaryrefslogtreecommitdiffstats
path: root/setup.c
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2025-11-19 08:50:49 +0100
committerJunio C Hamano <gitster@pobox.com>2025-11-19 17:41:03 -0800
commit831e02340b9de46c9ea0a1bbce3894f390f5a45e (patch)
tree2277541bc28b371ed41ef8538b6ea60f85aa33f8 /setup.c
parentc6def6a05504575dc92f8be785f18e326ea5f23c (diff)
downloadgit-831e02340b9de46c9ea0a1bbce3894f390f5a45e.tar.gz
path: move `enter_repo()` into "setup.c"
The function `enter_repo()` is used to enter a repository at a given path. As such it sits way closer to setting up a repository than it does with handling paths, but regardless of that it's located in "path.c" instead of in "setup.c". Move the function into "setup.c". Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'setup.c')
-rw-r--r--setup.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/setup.c b/setup.c
index 7086741e6c..98c6fd8ee4 100644
--- a/setup.c
+++ b/setup.c
@@ -1703,6 +1703,87 @@ void set_git_dir(const char *path, int make_realpath)
strbuf_release(&realpath);
}
+const char *enter_repo(const char *path, unsigned flags)
+{
+ static struct strbuf validated_path = STRBUF_INIT;
+ static struct strbuf used_path = STRBUF_INIT;
+
+ if (!path)
+ return NULL;
+
+ if (!(flags & ENTER_REPO_STRICT)) {
+ static const char *suffix[] = {
+ "/.git", "", ".git/.git", ".git", NULL,
+ };
+ const char *gitfile;
+ int len = strlen(path);
+ int i;
+ while ((1 < len) && (path[len-1] == '/'))
+ len--;
+
+ /*
+ * We can handle arbitrary-sized buffers, but this remains as a
+ * sanity check on untrusted input.
+ */
+ if (PATH_MAX <= len)
+ return NULL;
+
+ strbuf_reset(&used_path);
+ strbuf_reset(&validated_path);
+ strbuf_add(&used_path, path, len);
+ strbuf_add(&validated_path, path, len);
+
+ if (used_path.buf[0] == '~') {
+ char *newpath = interpolate_path(used_path.buf, 0);
+ if (!newpath)
+ return NULL;
+ strbuf_attach(&used_path, newpath, strlen(newpath),
+ strlen(newpath));
+ }
+ for (i = 0; suffix[i]; i++) {
+ struct stat st;
+ size_t baselen = used_path.len;
+ strbuf_addstr(&used_path, suffix[i]);
+ if (!stat(used_path.buf, &st) &&
+ (S_ISREG(st.st_mode) ||
+ (S_ISDIR(st.st_mode) && is_git_directory(used_path.buf)))) {
+ strbuf_addstr(&validated_path, suffix[i]);
+ break;
+ }
+ strbuf_setlen(&used_path, baselen);
+ }
+ if (!suffix[i])
+ return NULL;
+ gitfile = read_gitfile(used_path.buf);
+ if (!(flags & ENTER_REPO_ANY_OWNER_OK))
+ die_upon_dubious_ownership(gitfile, NULL, used_path.buf);
+ if (gitfile) {
+ strbuf_reset(&used_path);
+ strbuf_addstr(&used_path, gitfile);
+ }
+ if (chdir(used_path.buf))
+ return NULL;
+ path = validated_path.buf;
+ }
+ else {
+ const char *gitfile = read_gitfile(path);
+ if (!(flags & ENTER_REPO_ANY_OWNER_OK))
+ die_upon_dubious_ownership(gitfile, NULL, path);
+ if (gitfile)
+ path = gitfile;
+ if (chdir(path))
+ return NULL;
+ }
+
+ if (is_git_directory(".")) {
+ set_git_dir(".", 0);
+ check_repository_format(NULL);
+ return path;
+ }
+
+ return NULL;
+}
+
static int git_work_tree_initialized;
/*