--- /dev/null
+safe.directory::
+ These config entries specify Git-tracked directories that are
+ considered safe even if they are owned by someone other than the
+ current user. By default, Git will refuse to even parse a Git
+ config of a repository owned by someone else, let alone run its
+ hooks, and this config setting allows users to specify exceptions,
+ e.g. for intentionally shared repositories (see the `--shared`
+ option in linkgit:git-init[1]).
++
+This is a multi-valued setting, i.e. you can add more than one directory
+via `git config --add`. To reset the list of safe directories (e.g. to
+override any such directories specified in the system config), add a
+`safe.directory` entry with an empty value.
++
+This config setting is only respected when specified in a system or global
+config, not when it is specified in a repository config or via the command
+line option `-c safe.directory=<path>`.
++
+The value of this setting is interpolated, i.e. `~/<path>` expands to a
+path relative to the home directory and `%(prefix)/<path>` expands to a
+path relative to Git's (runtime) prefix.
#include "string-list.h"
#include "chdir-notify.h"
#include "promisor-remote.h"
+#include "quote.h"
static int inside_git_dir = -1;
static int inside_work_tree = -1;
}
}
+struct safe_directory_data {
+ const char *path;
+ int is_safe;
+};
+
+static int safe_directory_cb(const char *key, const char *value, void *d)
+{
+ struct safe_directory_data *data = d;
+
+ if (!value || !*value)
+ data->is_safe = 0;
+ else {
+ const char *interpolated = NULL;
+
+ if (!git_config_pathname(&interpolated, key, value) &&
+ !fspathcmp(data->path, interpolated ? interpolated : value))
+ data->is_safe = 1;
+
+ free((char *)interpolated);
+ }
+
+ return 0;
+}
+
+static int ensure_valid_ownership(const char *path)
+{
+ struct safe_directory_data data = { .path = path };
+
+ if (is_path_owned_by_current_user(path))
+ return 1;
+
+ read_very_early_config(safe_directory_cb, &data);
+
+ return data.is_safe;
+}
+
enum discovery_result {
GIT_DIR_NONE = 0,
GIT_DIR_EXPLICIT,
/* these are errors */
GIT_DIR_HIT_CEILING = -1,
GIT_DIR_HIT_MOUNT_POINT = -2,
- GIT_DIR_INVALID_GITFILE = -3
+ GIT_DIR_INVALID_GITFILE = -3,
+ GIT_DIR_INVALID_OWNERSHIP = -4
};
/*
}
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;
}
if (is_git_directory(dir->buf)) {
+ if (!ensure_valid_ownership(dir->buf))
+ return GIT_DIR_INVALID_OWNERSHIP;
strbuf_addstr(gitdir, ".");
return GIT_DIR_BARE;
}
dir.buf);
*nongit_ok = 1;
break;
+ case GIT_DIR_INVALID_OWNERSHIP:
+ if (!nongit_ok) {
+ struct strbuf quoted = STRBUF_INIT;
+
+ sq_quote_buf_pretty("ed, dir.buf);
+ die(_("unsafe repository ('%s' is owned by someone else)\n"
+ "To add an exception for this directory, call:\n"
+ "\n"
+ "\tgit config --global --add safe.directory %s"),
+ dir.buf, quoted.buf);
+ }
+ *nongit_ok = 1;
+ break;
case GIT_DIR_NONE:
/*
* As a safeguard against setup_git_directory_gently_1 returning