Merge branch 'jk/check-repository-format'
The repository set-up sequence has been streamlined (the biggest change is that there is no longer git_config_early()), so that we do not attempt to look into refs/* when we know we do not have a Git repository. * jk/check-repository-format: verify_repository_format: mark messages for translation setup: drop repository_format_version global setup: unify repository version callbacks init: use setup.c's repo version verification setup: refactor repo format reading and verification config: drop git_config_early check_repository_format_gently: stop using git_config_early lazily load core.sharedrepository wrap shared_repository global in get/set accessors setup: document check_repository_format()
This commit is contained in:
commit
907c416534
@ -63,13 +63,6 @@ parse for configuration, rather than looking in the usual files. Regular
|
||||
Specify whether include directives should be followed in parsed files.
|
||||
Regular `git_config` defaults to `1`.
|
||||
|
||||
There is a special version of `git_config` called `git_config_early`.
|
||||
This version takes an additional parameter to specify the repository
|
||||
config, instead of having it looked up via `git_path`. This is useful
|
||||
early in a Git program before the repository has been found. Unless
|
||||
you're working with early setup code, you probably don't want to use
|
||||
this.
|
||||
|
||||
Reading Specific Files
|
||||
----------------------
|
||||
|
||||
|
@ -95,6 +95,8 @@ static void copy_templates(const char *template_dir)
|
||||
struct strbuf path = STRBUF_INIT;
|
||||
struct strbuf template_path = STRBUF_INIT;
|
||||
size_t template_len;
|
||||
struct repository_format template_format;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
DIR *dir;
|
||||
char *to_free = NULL;
|
||||
|
||||
@ -121,17 +123,18 @@ static void copy_templates(const char *template_dir)
|
||||
|
||||
/* Make sure that template is from the correct vintage */
|
||||
strbuf_addstr(&template_path, "config");
|
||||
repository_format_version = 0;
|
||||
git_config_from_file(check_repository_format_version,
|
||||
template_path.buf, NULL);
|
||||
read_repository_format(&template_format, template_path.buf);
|
||||
strbuf_setlen(&template_path, template_len);
|
||||
|
||||
if (repository_format_version &&
|
||||
repository_format_version != GIT_REPO_VERSION) {
|
||||
warning(_("not copying templates of "
|
||||
"a wrong format version %d from '%s'"),
|
||||
repository_format_version,
|
||||
template_dir);
|
||||
/*
|
||||
* No mention of version at all is OK, but anything else should be
|
||||
* verified.
|
||||
*/
|
||||
if (template_format.version >= 0 &&
|
||||
verify_repository_format(&template_format, &err) < 0) {
|
||||
warning(_("not copying templates from '%s': %s"),
|
||||
template_dir, err.buf);
|
||||
strbuf_release(&err);
|
||||
goto close_free_return;
|
||||
}
|
||||
|
||||
@ -199,13 +202,13 @@ static int create_default_files(const char *template_path)
|
||||
|
||||
/* reading existing config may have overwrote it */
|
||||
if (init_shared_repository != -1)
|
||||
shared_repository = init_shared_repository;
|
||||
set_shared_repository(init_shared_repository);
|
||||
|
||||
/*
|
||||
* We would have created the above under user's umask -- under
|
||||
* shared-repository settings, we would need to fix them up.
|
||||
*/
|
||||
if (shared_repository) {
|
||||
if (get_shared_repository()) {
|
||||
adjust_shared_perm(get_git_dir());
|
||||
adjust_shared_perm(git_path_buf(&buf, "refs"));
|
||||
adjust_shared_perm(git_path_buf(&buf, "refs/heads"));
|
||||
@ -370,7 +373,7 @@ int init_db(const char *template_dir, unsigned int flags)
|
||||
|
||||
create_object_directory();
|
||||
|
||||
if (shared_repository) {
|
||||
if (get_shared_repository()) {
|
||||
char buf[10];
|
||||
/* We do not spell "group" and such, so that
|
||||
* the configuration can be read by older version
|
||||
@ -378,12 +381,12 @@ int init_db(const char *template_dir, unsigned int flags)
|
||||
* and compatibility values for PERM_GROUP and
|
||||
* PERM_EVERYBODY.
|
||||
*/
|
||||
if (shared_repository < 0)
|
||||
if (get_shared_repository() < 0)
|
||||
/* force to the mode value */
|
||||
xsnprintf(buf, sizeof(buf), "0%o", -shared_repository);
|
||||
else if (shared_repository == PERM_GROUP)
|
||||
xsnprintf(buf, sizeof(buf), "0%o", -get_shared_repository());
|
||||
else if (get_shared_repository() == PERM_GROUP)
|
||||
xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_GROUP);
|
||||
else if (shared_repository == PERM_EVERYBODY)
|
||||
else if (get_shared_repository() == PERM_EVERYBODY)
|
||||
xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY);
|
||||
else
|
||||
die("BUG: invalid value for shared_repository");
|
||||
@ -399,7 +402,7 @@ int init_db(const char *template_dir, unsigned int flags)
|
||||
"", and the last '%s%s' is the verbatim directory name. */
|
||||
printf(_("%s%s Git repository in %s%s\n"),
|
||||
reinit ? _("Reinitialized existing") : _("Initialized empty"),
|
||||
shared_repository ? _(" shared") : "",
|
||||
get_shared_repository() ? _(" shared") : "",
|
||||
git_dir, len && git_dir[len-1] != '/' ? "/" : "");
|
||||
}
|
||||
|
||||
@ -494,8 +497,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
* and we know shared_repository should always be 0;
|
||||
* but just in case we play safe.
|
||||
*/
|
||||
saved = shared_repository;
|
||||
shared_repository = 0;
|
||||
saved = get_shared_repository();
|
||||
set_shared_repository(0);
|
||||
switch (safe_create_leading_directories_const(argv[0])) {
|
||||
case SCLD_OK:
|
||||
case SCLD_PERMS:
|
||||
@ -507,7 +510,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
die_errno(_("cannot mkdir %s"), argv[0]);
|
||||
break;
|
||||
}
|
||||
shared_repository = saved;
|
||||
set_shared_repository(saved);
|
||||
if (mkdir(argv[0], 0777) < 0)
|
||||
die_errno(_("cannot mkdir %s"), argv[0]);
|
||||
mkdir_tried = 1;
|
||||
@ -525,7 +528,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
if (init_shared_repository != -1)
|
||||
shared_repository = init_shared_repository;
|
||||
set_shared_repository(init_shared_repository);
|
||||
|
||||
/*
|
||||
* GIT_WORK_TREE makes sense only in conjunction with GIT_DIR
|
||||
|
40
cache.h
40
cache.h
@ -651,7 +651,6 @@ extern int prefer_symlink_refs;
|
||||
extern int log_all_ref_updates;
|
||||
extern int warn_ambiguous_refs;
|
||||
extern int warn_on_object_refname_ambiguity;
|
||||
extern int shared_repository;
|
||||
extern const char *apply_default_whitespace;
|
||||
extern const char *apply_default_ignorewhitespace;
|
||||
extern const char *git_attributes_file;
|
||||
@ -664,6 +663,9 @@ extern size_t delta_base_cache_limit;
|
||||
extern unsigned long big_file_threshold;
|
||||
extern unsigned long pack_size_limit_cfg;
|
||||
|
||||
void set_shared_repository(int value);
|
||||
int get_shared_repository(void);
|
||||
|
||||
/*
|
||||
* Do replace refs need to be checked this run? This variable is
|
||||
* initialized to true unless --no-replace-object is used or
|
||||
@ -745,9 +747,39 @@ extern int grafts_replace_parents;
|
||||
*/
|
||||
#define GIT_REPO_VERSION 0
|
||||
#define GIT_REPO_VERSION_READ 1
|
||||
extern int repository_format_version;
|
||||
extern int repository_format_precious_objects;
|
||||
extern int check_repository_format(void);
|
||||
|
||||
struct repository_format {
|
||||
int version;
|
||||
int precious_objects;
|
||||
int is_bare;
|
||||
char *work_tree;
|
||||
struct string_list unknown_extensions;
|
||||
};
|
||||
|
||||
/*
|
||||
* Read the repository format characteristics from the config file "path" into
|
||||
* "format" struct. Returns the numeric version. On error, -1 is returned,
|
||||
* format->version is set to -1, and all other fields in the struct are
|
||||
* undefined.
|
||||
*/
|
||||
int read_repository_format(struct repository_format *format, const char *path);
|
||||
|
||||
/*
|
||||
* Verify that the repository described by repository_format is something we
|
||||
* can read. If it is, return 0. Otherwise, return -1, and "err" will describe
|
||||
* any errors encountered.
|
||||
*/
|
||||
int verify_repository_format(const struct repository_format *format,
|
||||
struct strbuf *err);
|
||||
|
||||
/*
|
||||
* Check the repository format version in the path found in get_git_dir(),
|
||||
* and die if it is a version we don't understand. Generally one would
|
||||
* set_git_dir() before calling this, and use it only for "are we in a valid
|
||||
* repo?".
|
||||
*/
|
||||
extern void check_repository_format(void);
|
||||
|
||||
#define MTIME_CHANGED 0x0001
|
||||
#define CTIME_CHANGED 0x0002
|
||||
@ -1526,7 +1558,6 @@ extern void git_config(config_fn_t fn, void *);
|
||||
extern int git_config_with_options(config_fn_t fn, void *,
|
||||
struct git_config_source *config_source,
|
||||
int respect_includes);
|
||||
extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
|
||||
extern int git_parse_ulong(const char *, unsigned long *);
|
||||
extern int git_parse_maybe_bool(const char *);
|
||||
extern int git_config_int(const char *, const char *);
|
||||
@ -1550,7 +1581,6 @@ extern void git_config_set_multivar_in_file(const char *, const char *, const ch
|
||||
extern int git_config_rename_section(const char *, const char *);
|
||||
extern int git_config_rename_section_in_file(const char *, const char *, const char *);
|
||||
extern const char *git_etc_gitconfig(void);
|
||||
extern int check_repository_format_version(const char *var, const char *value, void *cb);
|
||||
extern int git_env_bool(const char *, int);
|
||||
extern unsigned long git_env_ulong(const char *, unsigned long);
|
||||
extern int git_config_system(void);
|
||||
|
12
config.c
12
config.c
@ -1188,11 +1188,12 @@ int git_config_system(void)
|
||||
return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
|
||||
}
|
||||
|
||||
int git_config_early(config_fn_t fn, void *data, const char *repo_config)
|
||||
static int do_git_config_sequence(config_fn_t fn, void *data)
|
||||
{
|
||||
int ret = 0, found = 0;
|
||||
char *xdg_config = xdg_config_home("config");
|
||||
char *user_config = expand_user_path("~/.gitconfig");
|
||||
char *repo_config = git_pathdup("config");
|
||||
|
||||
if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0)) {
|
||||
ret += git_config_from_file(fn, git_etc_gitconfig(),
|
||||
@ -1228,6 +1229,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
|
||||
|
||||
free(xdg_config);
|
||||
free(user_config);
|
||||
free(repo_config);
|
||||
return ret == 0 ? found : ret;
|
||||
}
|
||||
|
||||
@ -1235,8 +1237,6 @@ int git_config_with_options(config_fn_t fn, void *data,
|
||||
struct git_config_source *config_source,
|
||||
int respect_includes)
|
||||
{
|
||||
char *repo_config = NULL;
|
||||
int ret;
|
||||
struct config_include_data inc = CONFIG_INCLUDE_INIT;
|
||||
|
||||
if (respect_includes) {
|
||||
@ -1257,11 +1257,7 @@ int git_config_with_options(config_fn_t fn, void *data,
|
||||
else if (config_source && config_source->blob)
|
||||
return git_config_from_blob_ref(fn, config_source->blob, data);
|
||||
|
||||
repo_config = git_pathdup("config");
|
||||
ret = git_config_early(fn, data, repo_config);
|
||||
if (repo_config)
|
||||
free(repo_config);
|
||||
return ret;
|
||||
return do_git_config_sequence(fn, data);
|
||||
}
|
||||
|
||||
static void git_config_raw(config_fn_t fn, void *data)
|
||||
|
@ -25,11 +25,9 @@ int log_all_ref_updates = -1; /* unspecified */
|
||||
int warn_ambiguous_refs = 1;
|
||||
int warn_on_object_refname_ambiguity = 1;
|
||||
int ref_paranoia = -1;
|
||||
int repository_format_version;
|
||||
int repository_format_precious_objects;
|
||||
const char *git_commit_encoding;
|
||||
const char *git_log_output_encoding;
|
||||
int shared_repository = PERM_UMASK;
|
||||
const char *apply_default_whitespace;
|
||||
const char *apply_default_ignorewhitespace;
|
||||
const char *git_attributes_file;
|
||||
@ -324,3 +322,24 @@ const char *get_commit_output_encoding(void)
|
||||
{
|
||||
return git_commit_encoding ? git_commit_encoding : "UTF-8";
|
||||
}
|
||||
|
||||
static int the_shared_repository = PERM_UMASK;
|
||||
static int need_shared_repository_from_config = 1;
|
||||
|
||||
void set_shared_repository(int value)
|
||||
{
|
||||
the_shared_repository = value;
|
||||
need_shared_repository_from_config = 0;
|
||||
}
|
||||
|
||||
int get_shared_repository(void)
|
||||
{
|
||||
if (need_shared_repository_from_config) {
|
||||
const char *var = "core.sharedrepository";
|
||||
const char *value;
|
||||
if (!git_config_get_value(var, &value))
|
||||
the_shared_repository = git_config_perm(var, value);
|
||||
need_shared_repository_from_config = 0;
|
||||
}
|
||||
return the_shared_repository;
|
||||
}
|
||||
|
10
path.c
10
path.c
@ -702,17 +702,17 @@ static int calc_shared_perm(int mode)
|
||||
{
|
||||
int tweak;
|
||||
|
||||
if (shared_repository < 0)
|
||||
tweak = -shared_repository;
|
||||
if (get_shared_repository() < 0)
|
||||
tweak = -get_shared_repository();
|
||||
else
|
||||
tweak = shared_repository;
|
||||
tweak = get_shared_repository();
|
||||
|
||||
if (!(mode & S_IWUSR))
|
||||
tweak &= ~0222;
|
||||
if (mode & S_IXUSR)
|
||||
/* Copy read bits to execute bits */
|
||||
tweak |= (tweak & 0444) >> 2;
|
||||
if (shared_repository < 0)
|
||||
if (get_shared_repository() < 0)
|
||||
mode = (mode & ~0777) | tweak;
|
||||
else
|
||||
mode |= tweak;
|
||||
@ -725,7 +725,7 @@ int adjust_shared_perm(const char *path)
|
||||
{
|
||||
int old_mode, new_mode;
|
||||
|
||||
if (!shared_repository)
|
||||
if (!get_shared_repository())
|
||||
return 0;
|
||||
if (get_st_mode_bits(path, &old_mode) < 0)
|
||||
return -1;
|
||||
|
144
setup.c
144
setup.c
@ -5,7 +5,6 @@
|
||||
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;
|
||||
|
||||
static struct startup_info the_startup_info;
|
||||
struct startup_info *startup_info = &the_startup_info;
|
||||
@ -373,14 +372,13 @@ void setup_work_tree(void)
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
static int check_repo_format(const char *var, const char *value, void *cb)
|
||||
static int check_repo_format(const char *var, const char *value, void *vdata)
|
||||
{
|
||||
struct repository_format *data = vdata;
|
||||
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);
|
||||
data->version = git_config_int(var, value);
|
||||
else if (skip_prefix(var, "extensions.", &ext)) {
|
||||
/*
|
||||
* record any known extensions here; otherwise,
|
||||
@ -390,9 +388,15 @@ static int check_repo_format(const char *var, const char *value, void *cb)
|
||||
if (!strcmp(ext, "noop"))
|
||||
;
|
||||
else if (!strcmp(ext, "preciousobjects"))
|
||||
repository_format_precious_objects = git_config_bool(var, value);
|
||||
data->precious_objects = git_config_bool(var, value);
|
||||
else
|
||||
string_list_append(&unknown_extensions, ext);
|
||||
string_list_append(&data->unknown_extensions, ext);
|
||||
} else if (strcmp(var, "core.bare") == 0) {
|
||||
data->is_bare = git_config_bool(var, value);
|
||||
} else if (strcmp(var, "core.worktree") == 0) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
data->work_tree = xstrdup(value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -400,56 +404,84 @@ static int check_repo_format(const char *var, const char *value, void *cb)
|
||||
static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
|
||||
{
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
const char *repo_config;
|
||||
config_fn_t fn;
|
||||
int ret = 0;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
struct repository_format candidate;
|
||||
int has_common;
|
||||
|
||||
string_list_clear(&unknown_extensions, 0);
|
||||
|
||||
if (get_common_dir(&sb, gitdir))
|
||||
fn = check_repo_format;
|
||||
else
|
||||
fn = check_repository_format_version;
|
||||
has_common = get_common_dir(&sb, gitdir);
|
||||
strbuf_addstr(&sb, "/config");
|
||||
repo_config = sb.buf;
|
||||
read_repository_format(&candidate, sb.buf);
|
||||
strbuf_release(&sb);
|
||||
|
||||
/*
|
||||
* git_config() can't be used here because it calls git_pathdup()
|
||||
* to get $GIT_CONFIG/config. That call will make setup_git_env()
|
||||
* set git_dir to ".git".
|
||||
*
|
||||
* We are in gitdir setup, no git dir has been found useable yet.
|
||||
* Use a gentler version of git_config() to check if this repo
|
||||
* is a good one.
|
||||
* For historical use of check_repository_format() in git-init,
|
||||
* we treat a missing config as a silent "ok", even when nongit_ok
|
||||
* is unset.
|
||||
*/
|
||||
git_config_early(fn, NULL, repo_config);
|
||||
if (GIT_REPO_VERSION_READ < repository_format_version) {
|
||||
if (!nongit_ok)
|
||||
die ("Expected git repo version <= %d, found %d",
|
||||
GIT_REPO_VERSION_READ, repository_format_version);
|
||||
warning("Expected git repo version <= %d, found %d",
|
||||
GIT_REPO_VERSION_READ, repository_format_version);
|
||||
warning("Please upgrade Git");
|
||||
*nongit_ok = -1;
|
||||
ret = -1;
|
||||
if (candidate.version < 0)
|
||||
return 0;
|
||||
|
||||
if (verify_repository_format(&candidate, &err) < 0) {
|
||||
if (nongit_ok) {
|
||||
warning("%s", err.buf);
|
||||
strbuf_release(&err);
|
||||
*nongit_ok = -1;
|
||||
return -1;
|
||||
}
|
||||
die("%s", err.buf);
|
||||
}
|
||||
|
||||
if (repository_format_version >= 1 && unknown_extensions.nr) {
|
||||
repository_format_precious_objects = candidate.precious_objects;
|
||||
string_list_clear(&candidate.unknown_extensions, 0);
|
||||
if (!has_common) {
|
||||
if (candidate.is_bare != -1) {
|
||||
is_bare_repository_cfg = candidate.is_bare;
|
||||
if (is_bare_repository_cfg == 1)
|
||||
inside_work_tree = -1;
|
||||
}
|
||||
if (candidate.work_tree) {
|
||||
free(git_work_tree_cfg);
|
||||
git_work_tree_cfg = candidate.work_tree;
|
||||
inside_work_tree = -1;
|
||||
}
|
||||
} else {
|
||||
free(candidate.work_tree);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_repository_format(struct repository_format *format, const char *path)
|
||||
{
|
||||
memset(format, 0, sizeof(*format));
|
||||
format->version = -1;
|
||||
format->is_bare = -1;
|
||||
string_list_init(&format->unknown_extensions, 1);
|
||||
git_config_from_file(check_repo_format, path, format);
|
||||
return format->version;
|
||||
}
|
||||
|
||||
int verify_repository_format(const struct repository_format *format,
|
||||
struct strbuf *err)
|
||||
{
|
||||
if (GIT_REPO_VERSION_READ < format->version) {
|
||||
strbuf_addf(err, _("Expected git repo version <= %d, found %d"),
|
||||
GIT_REPO_VERSION_READ, format->version);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (format->version >= 1 && format->unknown_extensions.nr) {
|
||||
int i;
|
||||
|
||||
if (!nongit_ok)
|
||||
die("unknown repository extension: %s",
|
||||
unknown_extensions.items[0].string);
|
||||
strbuf_addstr(err, _("unknown repository extensions found:"));
|
||||
|
||||
for (i = 0; i < unknown_extensions.nr; i++)
|
||||
warning("unknown repository extension: %s",
|
||||
unknown_extensions.items[i].string);
|
||||
*nongit_ok = -1;
|
||||
ret = -1;
|
||||
for (i = 0; i < format->unknown_extensions.nr; i++)
|
||||
strbuf_addf(err, "\n\t%s",
|
||||
format->unknown_extensions.items[i].string);
|
||||
return -1;
|
||||
}
|
||||
|
||||
strbuf_release(&sb);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -965,30 +997,10 @@ int git_config_perm(const char *var, const char *value)
|
||||
return -(i & 0666);
|
||||
}
|
||||
|
||||
int check_repository_format_version(const char *var, const char *value, void *cb)
|
||||
{
|
||||
int ret = check_repo_format(var, value, cb);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (strcmp(var, "core.bare") == 0) {
|
||||
is_bare_repository_cfg = git_config_bool(var, value);
|
||||
if (is_bare_repository_cfg == 1)
|
||||
inside_work_tree = -1;
|
||||
} else if (strcmp(var, "core.worktree") == 0) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
free(git_work_tree_cfg);
|
||||
git_work_tree_cfg = xstrdup(value);
|
||||
inside_work_tree = -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int check_repository_format(void)
|
||||
void check_repository_format(void)
|
||||
{
|
||||
check_repository_format_gently(get_git_dir(), NULL);
|
||||
startup_info->have_repository = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user