static int inside_git_dir = -1;
static int inside_work_tree = -1;
+static int work_tree_config_is_bogus;
+static struct string_list unknown_extensions = STRING_LIST_INIT_DUP;
/*
* The input parameter must contain an absolute path, and it must already be
return NULL;
}
} else {
- sanitized = xmalloc(len + strlen(path) + 1);
- if (len)
- memcpy(sanitized, prefix, len);
- strcpy(sanitized + len, path);
+ sanitized = xstrfmt("%.*s%s", len, prefix, path);
if (remaining_prefix)
*remaining_prefix = len;
if (normalize_path_copy_len(sanitized, sanitized, remaining_prefix)) {
}
int get_common_dir(struct strbuf *sb, const char *gitdir)
+{
+ const char *git_env_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
+ if (git_env_common_dir) {
+ strbuf_addstr(sb, git_env_common_dir);
+ return 1;
+ } else {
+ return get_common_dir_noenv(sb, gitdir);
+ }
+}
+
+int get_common_dir_noenv(struct strbuf *sb, const char *gitdir)
{
struct strbuf data = STRBUF_INIT;
struct strbuf path = STRBUF_INIT;
- const char *git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
int ret = 0;
- if (git_common_dir) {
- strbuf_addstr(sb, git_common_dir);
- return 1;
- }
+
strbuf_addf(&path, "%s/commondir", gitdir);
if (file_exists(path.buf)) {
if (strbuf_read_file(&data, path.buf, 0) <= 0)
if (initialized)
return;
+
+ if (work_tree_config_is_bogus)
+ die("unable to set up work tree using invalid config");
+
work_tree = get_git_work_tree();
git_dir = get_git_dir();
if (!is_absolute_path(git_dir))
static int check_repo_format(const char *var, const char *value, void *cb)
{
+ const char *ext;
+
if (strcmp(var, "core.repositoryformatversion") == 0)
repository_format_version = git_config_int(var, value);
else if (strcmp(var, "core.sharedrepository") == 0)
shared_repository = git_config_perm(var, value);
+ else if (skip_prefix(var, "extensions.", &ext)) {
+ /*
+ * record any known extensions here; otherwise,
+ * we fall through to recording it as unknown, and
+ * check_repository_format will complain
+ */
+ if (!strcmp(ext, "noop"))
+ ;
+ else if (!strcmp(ext, "preciousobjects"))
+ repository_format_precious_objects = git_config_bool(var, value);
+ else
+ string_list_append(&unknown_extensions, ext);
+ }
return 0;
}
config_fn_t fn;
int ret = 0;
+ string_list_clear(&unknown_extensions, 0);
+
if (get_common_dir(&sb, gitdir))
fn = check_repo_format;
else
* is a good one.
*/
git_config_early(fn, NULL, repo_config);
- if (GIT_REPO_VERSION < repository_format_version) {
+ if (GIT_REPO_VERSION_READ < repository_format_version) {
if (!nongit_ok)
die ("Expected git repo version <= %d, found %d",
- GIT_REPO_VERSION, repository_format_version);
+ GIT_REPO_VERSION_READ, repository_format_version);
warning("Expected git repo version <= %d, found %d",
- GIT_REPO_VERSION, repository_format_version);
+ GIT_REPO_VERSION_READ, repository_format_version);
warning("Please upgrade Git");
*nongit_ok = -1;
ret = -1;
}
+
+ if (repository_format_version >= 1 && unknown_extensions.nr) {
+ int i;
+
+ if (!nongit_ok)
+ die("unknown repository extension: %s",
+ unknown_extensions.items[0].string);
+
+ for (i = 0; i < unknown_extensions.nr; i++)
+ warning("unknown repository extension: %s",
+ unknown_extensions.items[i].string);
+ *nongit_ok = -1;
+ ret = -1;
+ }
+
strbuf_release(&sb);
return ret;
}
struct strbuf path = STRBUF_INIT;
struct stat st;
- strbuf_addf(&path, "%s/gitfile", gitdir);
+ strbuf_addf(&path, "%s/gitdir", gitdir);
if (stat(path.buf, &st) || st.st_mtime + 24 * 3600 < time(NULL))
- write_file(path.buf, 0, "%s\n", gitfile);
+ write_file(path.buf, "%s", gitfile);
strbuf_release(&path);
}
*/
const char *read_gitfile_gently(const char *path, int *return_error_code)
{
+ const int max_file_size = 1 << 20; /* 1MB */
int error_code = 0;
char *buf = NULL;
char *dir = NULL;
error_code = READ_GITFILE_ERR_NOT_A_FILE;
goto cleanup_return;
}
+ if (st.st_size > max_file_size) {
+ error_code = READ_GITFILE_ERR_TOO_LARGE;
+ goto cleanup_return;
+ }
fd = open(path, O_RDONLY);
if (fd < 0) {
error_code = READ_GITFILE_ERR_OPEN_FAILED;
if (!is_absolute_path(dir) && (slash = strrchr(path, '/'))) {
size_t pathlen = slash+1 - path;
- size_t dirlen = pathlen + len - 8;
- dir = xmalloc(dirlen + 1);
- strncpy(dir, path, pathlen);
- strncpy(dir + pathlen, buf + 8, len - 8);
- dir[dirlen] = '\0';
+ dir = xstrfmt("%.*s%.*s", (int)pathlen, path,
+ (int)(len - 8), buf + 8);
free(buf);
buf = dir;
}
path = real_path(dir);
cleanup_return:
- free(buf);
-
if (return_error_code)
*return_error_code = error_code;
-
- if (error_code) {
- if (return_error_code)
- return NULL;
-
+ else if (error_code) {
switch (error_code) {
case READ_GITFILE_ERR_STAT_FAILED:
case READ_GITFILE_ERR_NOT_A_FILE:
- return NULL;
+ /* non-fatal; follow return path */
+ break;
case READ_GITFILE_ERR_OPEN_FAILED:
die_errno("Error opening '%s'", path);
+ case READ_GITFILE_ERR_TOO_LARGE:
+ die("Too large to be a .git file: '%s'", path);
case READ_GITFILE_ERR_READ_FAILED:
die("Error reading %s", path);
case READ_GITFILE_ERR_INVALID_FORMAT:
}
}
- return path;
+ free(buf);
+ return error_code ? NULL : path;
}
static const char *setup_explicit_git_dir(const char *gitdirenv,
if (work_tree_env)
set_git_work_tree(work_tree_env);
else if (is_bare_repository_cfg > 0) {
- if (git_work_tree_cfg) /* #22.2, #30 */
- die("core.bare and core.worktree do not make sense");
+ if (git_work_tree_cfg) {
+ /* #22.2, #30 */
+ warning("core.bare and core.worktree do not make sense");
+ work_tree_config_is_bogus = 1;
+ }
/* #18, #26 */
set_git_dir(gitdirenv);