]> git.ipfire.org Git - thirdparty/git.git/blobdiff - setup.c
Sync with 2.34.4
[thirdparty/git.git] / setup.c
diff --git a/setup.c b/setup.c
index 7e5af7178c045a7362f7dfc63821868e576fbd6f..8686ffed341cd98af41585f326f9b4ad52b915cd 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -1119,14 +1119,32 @@ static int safe_directory_cb(const char *key, const char *value, void *d)
        return 0;
 }
 
-static int ensure_valid_ownership(const char *path)
+/*
+ * Check if a repository is safe, by verifying the ownership of the
+ * worktree (if any), the git directory, and the gitfile (if any).
+ *
+ * Exemptions for known-safe repositories can be added via `safe.directory`
+ * config settings; for non-bare repositories, their worktree needs to be
+ * added, for bare ones their git directory.
+ */
+static int ensure_valid_ownership(const char *gitfile,
+                               const char *worktree, const char *gitdir)
 {
-       struct safe_directory_data data = { .path = path };
+       struct safe_directory_data data = {
+               .path = worktree ? worktree : gitdir
+       };
 
        if (!git_env_bool("GIT_TEST_ASSUME_DIFFERENT_OWNER", 0) &&
-           is_path_owned_by_current_user(path))
+          (!gitfile || is_path_owned_by_current_user(gitfile)) &&
+          (!worktree || is_path_owned_by_current_user(worktree)) &&
+          (!gitdir || is_path_owned_by_current_user(gitdir)))
                return 1;
 
+       /*
+        * data.path is the "path" that identifies the repository and it is
+        * constant regardless of what failed above. data.is_safe should be
+        * initialized to false, and might be changed by the callback.
+        */
        read_very_early_config(safe_directory_cb, &data);
 
        return data.is_safe;
@@ -1214,6 +1232,8 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
                current_device = get_device_or_die(dir->buf, NULL, 0);
        for (;;) {
                int offset = dir->len, error_code = 0;
+               char *gitdir_path = NULL;
+               char *gitfile = NULL;
 
                if (offset > min_offset)
                        strbuf_addch(dir, '/');
@@ -1224,21 +1244,50 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
                        if (die_on_error ||
                            error_code == READ_GITFILE_ERR_NOT_A_FILE) {
                                /* NEEDSWORK: fail if .git is not file nor dir */
-                               if (is_git_directory(dir->buf))
+                               if (is_git_directory(dir->buf)) {
                                        gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT;
+                                       gitdir_path = xstrdup(dir->buf);
+                               }
                        } else if (error_code != READ_GITFILE_ERR_STAT_FAILED)
                                return GIT_DIR_INVALID_GITFILE;
-               }
+               } else
+                       gitfile = xstrdup(dir->buf);
+               /*
+                * Earlier, we tentatively added DEFAULT_GIT_DIR_ENVIRONMENT
+                * to check that directory for a repository.
+                * Now trim that tentative addition away, because we want to
+                * focus on the real directory we are in.
+                */
                strbuf_setlen(dir, offset);
                if (gitdirenv) {
-                       if (!ensure_valid_ownership(dir->buf))
-                               return GIT_DIR_INVALID_OWNERSHIP;
-                       strbuf_addstr(gitdir, gitdirenv);
-                       return GIT_DIR_DISCOVERED;
+                       enum discovery_result ret;
+
+                       if (ensure_valid_ownership(gitfile,
+                                                dir->buf,
+                                (gitdir_path ? gitdir_path : gitdirenv))) {
+                               strbuf_addstr(gitdir, gitdirenv);
+                               ret = GIT_DIR_DISCOVERED;
+                       } else
+                               ret = GIT_DIR_INVALID_OWNERSHIP;
+
+                       /*
+                        * Earlier, during discovery, we might have allocated
+                        * string copies for gitdir_path or gitfile so make
+                        * sure we don't leak by freeing them now, before
+                        * leaving the loop and function.
+                        *
+                        * Note: gitdirenv will be non-NULL whenever these are
+                        * allocated, therefore we need not take care of releasing
+                        * them outside of this conditional block.
+                        */
+                       free(gitdir_path);
+                       free(gitfile);
+
+                       return ret;
                }
 
                if (is_git_directory(dir->buf)) {
-                       if (!ensure_valid_ownership(dir->buf))
+                       if (!ensure_valid_ownership(NULL, NULL, dir->buf))
                                return GIT_DIR_INVALID_OWNERSHIP;
                        strbuf_addstr(gitdir, ".");
                        return GIT_DIR_BARE;
@@ -1376,7 +1425,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
                        struct strbuf quoted = STRBUF_INIT;
 
                        sq_quote_buf_pretty(&quoted, dir.buf);
-                       die(_("unsafe repository ('%s' is owned by someone else)\n"
+                       die(_("detected dubious ownership in repository at '%s'\n"
                              "To add an exception for this directory, call:\n"
                              "\n"
                              "\tgit config --global --add safe.directory %s"),