Merge branch 'jk/check-repository-format' into maint

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:
Junio C Hamano 2016-05-02 14:24:04 -07:00
commit 8591654998
7 changed files with 167 additions and 114 deletions

View File

@ -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. Specify whether include directives should be followed in parsed files.
Regular `git_config` defaults to `1`. 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 Reading Specific Files
---------------------- ----------------------

View File

@ -95,6 +95,8 @@ static void copy_templates(const char *template_dir)
struct strbuf path = STRBUF_INIT; struct strbuf path = STRBUF_INIT;
struct strbuf template_path = STRBUF_INIT; struct strbuf template_path = STRBUF_INIT;
size_t template_len; size_t template_len;
struct repository_format template_format;
struct strbuf err = STRBUF_INIT;
DIR *dir; DIR *dir;
char *to_free = NULL; 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 */ /* Make sure that template is from the correct vintage */
strbuf_addstr(&template_path, "config"); strbuf_addstr(&template_path, "config");
repository_format_version = 0; read_repository_format(&template_format, template_path.buf);
git_config_from_file(check_repository_format_version,
template_path.buf, NULL);
strbuf_setlen(&template_path, template_len); strbuf_setlen(&template_path, template_len);
if (repository_format_version && /*
repository_format_version != GIT_REPO_VERSION) { * No mention of version at all is OK, but anything else should be
warning(_("not copying templates of " * verified.
"a wrong format version %d from '%s'"), */
repository_format_version, if (template_format.version >= 0 &&
template_dir); 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; goto close_free_return;
} }
@ -199,13 +202,13 @@ static int create_default_files(const char *template_path)
/* reading existing config may have overwrote it */ /* reading existing config may have overwrote it */
if (init_shared_repository != -1) 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 * We would have created the above under user's umask -- under
* shared-repository settings, we would need to fix them up. * 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(get_git_dir());
adjust_shared_perm(git_path_buf(&buf, "refs")); adjust_shared_perm(git_path_buf(&buf, "refs"));
adjust_shared_perm(git_path_buf(&buf, "refs/heads")); 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(); create_object_directory();
if (shared_repository) { if (get_shared_repository()) {
char buf[10]; char buf[10];
/* We do not spell "group" and such, so that /* We do not spell "group" and such, so that
* the configuration can be read by older version * 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 * and compatibility values for PERM_GROUP and
* PERM_EVERYBODY. * PERM_EVERYBODY.
*/ */
if (shared_repository < 0) if (get_shared_repository() < 0)
/* force to the mode value */ /* force to the mode value */
xsnprintf(buf, sizeof(buf), "0%o", -shared_repository); xsnprintf(buf, sizeof(buf), "0%o", -get_shared_repository());
else if (shared_repository == PERM_GROUP) else if (get_shared_repository() == PERM_GROUP)
xsnprintf(buf, sizeof(buf), "%d", OLD_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); xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY);
else else
die("BUG: invalid value for shared_repository"); 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. */ "", and the last '%s%s' is the verbatim directory name. */
printf(_("%s%s Git repository in %s%s\n"), printf(_("%s%s Git repository in %s%s\n"),
reinit ? _("Reinitialized existing") : _("Initialized empty"), reinit ? _("Reinitialized existing") : _("Initialized empty"),
shared_repository ? _(" shared") : "", get_shared_repository() ? _(" shared") : "",
git_dir, len && git_dir[len-1] != '/' ? "/" : ""); 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; * and we know shared_repository should always be 0;
* but just in case we play safe. * but just in case we play safe.
*/ */
saved = shared_repository; saved = get_shared_repository();
shared_repository = 0; set_shared_repository(0);
switch (safe_create_leading_directories_const(argv[0])) { switch (safe_create_leading_directories_const(argv[0])) {
case SCLD_OK: case SCLD_OK:
case SCLD_PERMS: 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]); die_errno(_("cannot mkdir %s"), argv[0]);
break; break;
} }
shared_repository = saved; set_shared_repository(saved);
if (mkdir(argv[0], 0777) < 0) if (mkdir(argv[0], 0777) < 0)
die_errno(_("cannot mkdir %s"), argv[0]); die_errno(_("cannot mkdir %s"), argv[0]);
mkdir_tried = 1; mkdir_tried = 1;
@ -525,7 +528,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
} }
if (init_shared_repository != -1) 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 * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR

40
cache.h
View File

@ -651,7 +651,6 @@ extern int prefer_symlink_refs;
extern int log_all_ref_updates; extern int log_all_ref_updates;
extern int warn_ambiguous_refs; extern int warn_ambiguous_refs;
extern int warn_on_object_refname_ambiguity; extern int warn_on_object_refname_ambiguity;
extern int shared_repository;
extern const char *apply_default_whitespace; extern const char *apply_default_whitespace;
extern const char *apply_default_ignorewhitespace; extern const char *apply_default_ignorewhitespace;
extern const char *git_attributes_file; 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 big_file_threshold;
extern unsigned long pack_size_limit_cfg; 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 * Do replace refs need to be checked this run? This variable is
* initialized to true unless --no-replace-object is used or * 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 0
#define GIT_REPO_VERSION_READ 1 #define GIT_REPO_VERSION_READ 1
extern int repository_format_version;
extern int repository_format_precious_objects; 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 MTIME_CHANGED 0x0001
#define CTIME_CHANGED 0x0002 #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 *, extern int git_config_with_options(config_fn_t fn, void *,
struct git_config_source *config_source, struct git_config_source *config_source,
int respect_includes); 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_ulong(const char *, unsigned long *);
extern int git_parse_maybe_bool(const char *); extern int git_parse_maybe_bool(const char *);
extern int git_config_int(const char *, 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(const char *, const char *);
extern int git_config_rename_section_in_file(const char *, 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 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 int git_env_bool(const char *, int);
extern unsigned long git_env_ulong(const char *, unsigned long); extern unsigned long git_env_ulong(const char *, unsigned long);
extern int git_config_system(void); extern int git_config_system(void);

View File

@ -1188,11 +1188,12 @@ int git_config_system(void)
return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0); 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; int ret = 0, found = 0;
char *xdg_config = xdg_config_home("config"); char *xdg_config = xdg_config_home("config");
char *user_config = expand_user_path("~/.gitconfig"); 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)) { if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0)) {
ret += git_config_from_file(fn, git_etc_gitconfig(), 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(xdg_config);
free(user_config); free(user_config);
free(repo_config);
return ret == 0 ? found : ret; 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, struct git_config_source *config_source,
int respect_includes) int respect_includes)
{ {
char *repo_config = NULL;
int ret;
struct config_include_data inc = CONFIG_INCLUDE_INIT; struct config_include_data inc = CONFIG_INCLUDE_INIT;
if (respect_includes) { 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) else if (config_source && config_source->blob)
return git_config_from_blob_ref(fn, config_source->blob, data); return git_config_from_blob_ref(fn, config_source->blob, data);
repo_config = git_pathdup("config"); return do_git_config_sequence(fn, data);
ret = git_config_early(fn, data, repo_config);
if (repo_config)
free(repo_config);
return ret;
} }
static void git_config_raw(config_fn_t fn, void *data) static void git_config_raw(config_fn_t fn, void *data)

View File

@ -25,11 +25,9 @@ int log_all_ref_updates = -1; /* unspecified */
int warn_ambiguous_refs = 1; int warn_ambiguous_refs = 1;
int warn_on_object_refname_ambiguity = 1; int warn_on_object_refname_ambiguity = 1;
int ref_paranoia = -1; int ref_paranoia = -1;
int repository_format_version;
int repository_format_precious_objects; int repository_format_precious_objects;
const char *git_commit_encoding; const char *git_commit_encoding;
const char *git_log_output_encoding; const char *git_log_output_encoding;
int shared_repository = PERM_UMASK;
const char *apply_default_whitespace; const char *apply_default_whitespace;
const char *apply_default_ignorewhitespace; const char *apply_default_ignorewhitespace;
const char *git_attributes_file; 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"; 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
View File

@ -702,17 +702,17 @@ static int calc_shared_perm(int mode)
{ {
int tweak; int tweak;
if (shared_repository < 0) if (get_shared_repository() < 0)
tweak = -shared_repository; tweak = -get_shared_repository();
else else
tweak = shared_repository; tweak = get_shared_repository();
if (!(mode & S_IWUSR)) if (!(mode & S_IWUSR))
tweak &= ~0222; tweak &= ~0222;
if (mode & S_IXUSR) if (mode & S_IXUSR)
/* Copy read bits to execute bits */ /* Copy read bits to execute bits */
tweak |= (tweak & 0444) >> 2; tweak |= (tweak & 0444) >> 2;
if (shared_repository < 0) if (get_shared_repository() < 0)
mode = (mode & ~0777) | tweak; mode = (mode & ~0777) | tweak;
else else
mode |= tweak; mode |= tweak;
@ -725,7 +725,7 @@ int adjust_shared_perm(const char *path)
{ {
int old_mode, new_mode; int old_mode, new_mode;
if (!shared_repository) if (!get_shared_repository())
return 0; return 0;
if (get_st_mode_bits(path, &old_mode) < 0) if (get_st_mode_bits(path, &old_mode) < 0)
return -1; return -1;

144
setup.c
View File

@ -5,7 +5,6 @@
static int inside_git_dir = -1; static int inside_git_dir = -1;
static int inside_work_tree = -1; static int inside_work_tree = -1;
static int work_tree_config_is_bogus; static int work_tree_config_is_bogus;
static struct string_list unknown_extensions = STRING_LIST_INIT_DUP;
static struct startup_info the_startup_info; static struct startup_info the_startup_info;
struct startup_info *startup_info = &the_startup_info; struct startup_info *startup_info = &the_startup_info;
@ -373,14 +372,13 @@ void setup_work_tree(void)
initialized = 1; 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; const char *ext;
if (strcmp(var, "core.repositoryformatversion") == 0) if (strcmp(var, "core.repositoryformatversion") == 0)
repository_format_version = git_config_int(var, value); data->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)) { else if (skip_prefix(var, "extensions.", &ext)) {
/* /*
* record any known extensions here; otherwise, * 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")) if (!strcmp(ext, "noop"))
; ;
else if (!strcmp(ext, "preciousobjects")) else if (!strcmp(ext, "preciousobjects"))
repository_format_precious_objects = git_config_bool(var, value); data->precious_objects = git_config_bool(var, value);
else 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; 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) static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
{ {
struct strbuf sb = STRBUF_INIT; struct strbuf sb = STRBUF_INIT;
const char *repo_config; struct strbuf err = STRBUF_INIT;
config_fn_t fn; struct repository_format candidate;
int ret = 0; int has_common;
string_list_clear(&unknown_extensions, 0); has_common = get_common_dir(&sb, gitdir);
if (get_common_dir(&sb, gitdir))
fn = check_repo_format;
else
fn = check_repository_format_version;
strbuf_addstr(&sb, "/config"); 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() * For historical use of check_repository_format() in git-init,
* to get $GIT_CONFIG/config. That call will make setup_git_env() * we treat a missing config as a silent "ok", even when nongit_ok
* set git_dir to ".git". * is unset.
*
* 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.
*/ */
git_config_early(fn, NULL, repo_config); if (candidate.version < 0)
if (GIT_REPO_VERSION_READ < repository_format_version) { return 0;
if (!nongit_ok)
die ("Expected git repo version <= %d, found %d", if (verify_repository_format(&candidate, &err) < 0) {
GIT_REPO_VERSION_READ, repository_format_version); if (nongit_ok) {
warning("Expected git repo version <= %d, found %d", warning("%s", err.buf);
GIT_REPO_VERSION_READ, repository_format_version); strbuf_release(&err);
warning("Please upgrade Git"); *nongit_ok = -1;
*nongit_ok = -1; return -1;
ret = -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; int i;
if (!nongit_ok) strbuf_addstr(err, _("unknown repository extensions found:"));
die("unknown repository extension: %s",
unknown_extensions.items[0].string);
for (i = 0; i < unknown_extensions.nr; i++) for (i = 0; i < format->unknown_extensions.nr; i++)
warning("unknown repository extension: %s", strbuf_addf(err, "\n\t%s",
unknown_extensions.items[i].string); format->unknown_extensions.items[i].string);
*nongit_ok = -1; return -1;
ret = -1;
} }
strbuf_release(&sb); return 0;
return ret;
} }
/* /*
@ -965,30 +997,10 @@ int git_config_perm(const char *var, const char *value)
return -(i & 0666); return -(i & 0666);
} }
int check_repository_format_version(const char *var, const char *value, void *cb) void check_repository_format(void)
{
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)
{ {
check_repository_format_gently(get_git_dir(), NULL); check_repository_format_gently(get_git_dir(), NULL);
startup_info->have_repository = 1; startup_info->have_repository = 1;
return 0;
} }
/* /*