Merge branch 'ps/fsck-wo-the-repository'

Internals of "git fsck" have been refactored to not depend on the
global `the_repository` variable.

* ps/fsck-wo-the-repository:
  builtin/fsck: stop using `the_repository` in error reporting
  builtin/fsck: stop using `the_repository` when marking objects
  builtin/fsck: stop using `the_repository` when checking packed objects
  builtin/fsck: stop using `the_repository` with loose objects
  builtin/fsck: stop using `the_repository` when checking reflogs
  builtin/fsck: stop using `the_repository` when checking refs
  builtin/fsck: stop using `the_repository` when snapshotting refs
  builtin/fsck: fix trivial dependence on `the_repository`
  fsck: drop USE_THE_REPOSITORY
  fsck: store repository in fsck options
  fsck: initialize fsck options via a function
  fetch-pack: move fsck options into function scope
This commit is contained in:
Junio C Hamano
2026-04-07 14:59:26 -07:00
11 changed files with 259 additions and 181 deletions

View File

@@ -1,4 +1,3 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "gettext.h"
#include "hex.h"
@@ -42,8 +41,8 @@ static int check_full = 1;
static int connectivity_only;
static int check_strict;
static int keep_cache_objects;
static struct fsck_options fsck_walk_options = FSCK_OPTIONS_DEFAULT;
static struct fsck_options fsck_obj_options = FSCK_OPTIONS_DEFAULT;
static struct fsck_options fsck_walk_options;
static struct fsck_options fsck_obj_options;
static int errors_found;
static int write_lost_and_found;
static int verbose;
@@ -66,14 +65,14 @@ static const char *describe_object(const struct object_id *oid)
return fsck_describe_object(&fsck_walk_options, oid);
}
static const char *printable_type(const struct object_id *oid,
static const char *printable_type(struct repository *repo,
const struct object_id *oid,
enum object_type type)
{
const char *ret;
if (type == OBJ_NONE)
type = odb_read_object_info(the_repository->objects,
oid, NULL);
type = odb_read_object_info(repo->objects, oid, NULL);
ret = type_name(type);
if (!ret)
@@ -82,17 +81,17 @@ static const char *printable_type(const struct object_id *oid,
return ret;
}
static int objerror(struct object *obj, const char *err)
static int objerror(struct repository *repo, struct object *obj, const char *err)
{
errors_found |= ERROR_OBJECT;
/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */
fprintf_ln(stderr, _("error in %s %s: %s"),
printable_type(&obj->oid, obj->type),
printable_type(repo, &obj->oid, obj->type),
describe_object(&obj->oid), err);
return -1;
}
static int fsck_objects_error_func(struct fsck_options *o UNUSED,
static int fsck_objects_error_func(struct fsck_options *o,
void *fsck_report,
enum fsck_msg_type msg_type,
enum fsck_msg_id msg_id UNUSED,
@@ -106,13 +105,13 @@ static int fsck_objects_error_func(struct fsck_options *o UNUSED,
case FSCK_WARN:
/* TRANSLATORS: e.g. warning in tree 01bfda: <more explanation> */
fprintf_ln(stderr, _("warning in %s %s: %s"),
printable_type(oid, object_type),
printable_type(o->repo, oid, object_type),
describe_object(oid), message);
return 0;
case FSCK_ERROR:
/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */
fprintf_ln(stderr, _("error in %s %s: %s"),
printable_type(oid, object_type),
printable_type(o->repo, oid, object_type),
describe_object(oid), message);
return 1;
default:
@@ -124,7 +123,7 @@ static int fsck_objects_error_func(struct fsck_options *o UNUSED,
static struct object_array pending;
static int mark_object(struct object *obj, enum object_type type,
void *data, struct fsck_options *options UNUSED)
void *data, struct fsck_options *options)
{
struct object *parent = data;
@@ -136,7 +135,7 @@ static int mark_object(struct object *obj, enum object_type type,
if (!obj) {
/* ... these references to parent->fld are safe here */
printf_ln(_("broken link from %7s %s"),
printable_type(&parent->oid, parent->type),
printable_type(options->repo, &parent->oid, parent->type),
describe_object(&parent->oid));
printf_ln(_("broken link from %7s %s"),
(type == OBJ_ANY ? _("unknown") : type_name(type)),
@@ -147,13 +146,13 @@ static int mark_object(struct object *obj, enum object_type type,
if (type != OBJ_ANY && obj->type != type)
/* ... and the reference to parent is safe here */
objerror(parent, _("wrong object type in link"));
objerror(options->repo, parent, _("wrong object type in link"));
if (obj->flags & REACHABLE)
return 0;
obj->flags |= REACHABLE;
if (is_promisor_object(the_repository, &obj->oid))
if (is_promisor_object(options->repo, &obj->oid))
/*
* Further recursion does not need to be performed on this
* object since it is a promisor object (so it does not need to
@@ -162,13 +161,13 @@ static int mark_object(struct object *obj, enum object_type type,
return 0;
if (!(obj->flags & HAS_OBJ)) {
if (parent && !odb_has_object(the_repository->objects, &obj->oid,
if (parent && !odb_has_object(options->repo->objects, &obj->oid,
HAS_OBJECT_RECHECK_PACKED)) {
printf_ln(_("broken link from %7s %s\n"
" to %7s %s"),
printable_type(&parent->oid, parent->type),
printable_type(options->repo, &parent->oid, parent->type),
describe_object(&parent->oid),
printable_type(&obj->oid, obj->type),
printable_type(options->repo, &obj->oid, obj->type),
describe_object(&obj->oid));
errors_found |= ERROR_REACHABLE;
}
@@ -181,7 +180,7 @@ static int mark_object(struct object *obj, enum object_type type,
static void mark_object_reachable(struct object *obj)
{
mark_object(obj, OBJ_ANY, NULL, NULL);
mark_object(obj, OBJ_ANY, NULL, &fsck_walk_options);
}
static int traverse_one_object(struct object *obj)
@@ -195,13 +194,13 @@ static int traverse_one_object(struct object *obj)
return result;
}
static int traverse_reachable(void)
static int traverse_reachable(struct repository *repo)
{
struct progress *progress = NULL;
unsigned int nr = 0;
int result = 0;
if (show_progress)
progress = start_delayed_progress(the_repository,
progress = start_delayed_progress(repo,
_("Checking connectivity"), 0);
while (pending.nr) {
result |= traverse_one_object(object_array_pop(&pending));
@@ -222,10 +221,11 @@ static int mark_used(struct object *obj, enum object_type type UNUSED,
static int mark_unreachable_referents(const struct object_id *oid,
struct object_info *oi UNUSED,
void *data UNUSED)
void *data)
{
struct fsck_options options = FSCK_OPTIONS_DEFAULT;
struct object *obj = lookup_object(the_repository, oid);
struct repository *repo = data;
struct fsck_options options;
struct object *obj = lookup_object(data, oid);
if (!obj || !(obj->flags & HAS_OBJ))
return 0; /* not part of our original set */
@@ -237,12 +237,13 @@ static int mark_unreachable_referents(const struct object_id *oid,
* (and we want to avoid parsing blobs).
*/
if (obj->type == OBJ_NONE) {
enum object_type type = odb_read_object_info(the_repository->objects,
enum object_type type = odb_read_object_info(repo->objects,
&obj->oid, NULL);
if (type > 0)
object_as_type(obj, type, 0);
}
fsck_options_init(&options, repo, FSCK_OPTIONS_DEFAULT);
options.walk = mark_used;
fsck_walk(obj, NULL, &options);
if (obj->type == OBJ_TREE)
@@ -254,7 +255,7 @@ static int mark_unreachable_referents(const struct object_id *oid,
/*
* Check a single reachable object
*/
static void check_reachable_object(struct object *obj)
static void check_reachable_object(struct repository *repo, struct object *obj)
{
/*
* We obviously want the object to be parsed,
@@ -262,12 +263,12 @@ static void check_reachable_object(struct object *obj)
* do a full fsck
*/
if (!(obj->flags & HAS_OBJ)) {
if (is_promisor_object(the_repository, &obj->oid))
if (is_promisor_object(repo, &obj->oid))
return;
if (has_object_pack(the_repository, &obj->oid))
if (has_object_pack(repo, &obj->oid))
return; /* it is in pack - forget about it */
printf_ln(_("missing %s %s"),
printable_type(&obj->oid, obj->type),
printable_type(repo, &obj->oid, obj->type),
describe_object(&obj->oid));
errors_found |= ERROR_REACHABLE;
return;
@@ -277,7 +278,7 @@ static void check_reachable_object(struct object *obj)
/*
* Check a single unreachable object
*/
static void check_unreachable_object(struct object *obj)
static void check_unreachable_object(struct repository *repo, struct object *obj)
{
/*
* Missing unreachable object? Ignore it. It's not like
@@ -294,7 +295,7 @@ static void check_unreachable_object(struct object *obj)
*/
if (show_unreachable) {
printf_ln(_("unreachable %s %s"),
printable_type(&obj->oid, obj->type),
printable_type(repo, &obj->oid, obj->type),
describe_object(&obj->oid));
return;
}
@@ -314,22 +315,22 @@ static void check_unreachable_object(struct object *obj)
if (!(obj->flags & USED)) {
if (show_dangling)
printf_ln(_("dangling %s %s"),
printable_type(&obj->oid, obj->type),
printable_type(repo, &obj->oid, obj->type),
describe_object(&obj->oid));
if (write_lost_and_found) {
char *filename = repo_git_path(the_repository, "lost-found/%s/%s",
char *filename = repo_git_path(repo, "lost-found/%s/%s",
obj->type == OBJ_COMMIT ? "commit" : "other",
describe_object(&obj->oid));
FILE *f;
if (safe_create_leading_directories_const(the_repository, filename)) {
if (safe_create_leading_directories_const(repo, filename)) {
error(_("could not create lost-found"));
free(filename);
return;
}
f = xfopen(filename, "w");
if (obj->type == OBJ_BLOB) {
if (odb_stream_blob_to_fd(the_repository->objects, fileno(f),
if (odb_stream_blob_to_fd(repo->objects, fileno(f),
&obj->oid, NULL, 1))
die_errno(_("could not write '%s'"), filename);
} else
@@ -349,23 +350,23 @@ static void check_unreachable_object(struct object *obj)
*/
}
static void check_object(struct object *obj)
static void check_object(struct repository *repo, struct object *obj)
{
if (verbose)
fprintf_ln(stderr, _("Checking %s"), describe_object(&obj->oid));
if (obj->flags & REACHABLE)
check_reachable_object(obj);
check_reachable_object(repo, obj);
else
check_unreachable_object(obj);
check_unreachable_object(repo, obj);
}
static void check_connectivity(void)
static void check_connectivity(struct repository *repo)
{
int i, max;
/* Traverse the pending reachable objects */
traverse_reachable();
traverse_reachable(repo);
/*
* With --connectivity-only, we won't have actually opened and marked
@@ -383,24 +384,25 @@ static void check_connectivity(void)
* and ignore any that weren't present in our earlier
* traversal.
*/
odb_for_each_object(the_repository->objects, NULL,
mark_unreachable_referents, NULL, 0);
odb_for_each_object(repo->objects, NULL,
mark_unreachable_referents, repo, 0);
}
/* Look up all the requirements, warn about missing objects.. */
max = get_max_object_index(the_repository);
max = get_max_object_index(repo);
if (verbose)
fprintf_ln(stderr, _("Checking connectivity (%d objects)"), max);
for (i = 0; i < max; i++) {
struct object *obj = get_indexed_object(the_repository, i);
struct object *obj = get_indexed_object(repo, i);
if (obj)
check_object(obj);
check_object(repo, obj);
}
}
static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
static int fsck_obj(struct repository *repo,
struct object *obj, void *buffer, unsigned long size)
{
int err;
@@ -410,11 +412,11 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
if (verbose)
fprintf_ln(stderr, _("Checking %s %s"),
printable_type(&obj->oid, obj->type),
printable_type(repo, &obj->oid, obj->type),
describe_object(&obj->oid));
if (fsck_walk(obj, NULL, &fsck_obj_options))
objerror(obj, _("broken links"));
objerror(repo, obj, _("broken links"));
err = fsck_object(obj, buffer, size, &fsck_obj_options);
if (err)
goto out;
@@ -432,7 +434,7 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
if (show_tags && tag->tagged) {
printf_ln(_("tagged %s %s (%s) in %s"),
printable_type(&tag->tagged->oid, tag->tagged->type),
printable_type(repo, &tag->tagged->oid, tag->tagged->type),
describe_object(&tag->tagged->oid),
tag->tag,
describe_object(&tag->object.oid));
@@ -446,15 +448,16 @@ out:
}
static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,
unsigned long size, void *buffer, int *eaten)
unsigned long size, void *buffer, int *eaten, void *cb_data)
{
struct repository *repo = cb_data;
struct object *obj;
/*
* Note, buffer may be NULL if type is OBJ_BLOB. See
* verify_packfile(), data_valid variable for details.
*/
struct object *obj;
obj = parse_object_buffer(the_repository, oid, type, size, buffer,
eaten);
obj = parse_object_buffer(repo, oid, type, size, buffer, eaten);
if (!obj) {
errors_found |= ERROR_OBJECT;
return error(_("%s: object corrupt or missing"),
@@ -462,18 +465,19 @@ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,
}
obj->flags &= ~(REACHABLE | SEEN);
obj->flags |= HAS_OBJ;
return fsck_obj(obj, buffer, size);
return fsck_obj(repo, obj, buffer, size);
}
static int default_refs;
static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
timestamp_t timestamp)
static void fsck_handle_reflog_oid(struct repository *repo,
const char *refname, struct object_id *oid,
timestamp_t timestamp)
{
struct object *obj;
if (!is_null_oid(oid)) {
obj = lookup_object(the_repository, oid);
obj = lookup_object(repo, oid);
if (obj && (obj->flags & HAS_OBJ)) {
if (timestamp)
fsck_put_object_name(&fsck_walk_options, oid,
@@ -481,7 +485,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
refname, timestamp);
obj->flags |= USED;
mark_object_reachable(obj);
} else if (!is_promisor_object(the_repository, oid)) {
} else if (!is_promisor_object(repo, oid)) {
error(_("%s: invalid reflog entry %s"),
refname, oid_to_hex(oid));
errors_found |= ERROR_REACHABLE;
@@ -493,8 +497,10 @@ static int fsck_handle_reflog_ent(const char *refname,
struct object_id *ooid, struct object_id *noid,
const char *email UNUSED,
timestamp_t timestamp, int tz UNUSED,
const char *message UNUSED, void *cb_data UNUSED)
const char *message UNUSED, void *cb_data)
{
struct repository *repo = cb_data;
if (now && timestamp > now)
return 0;
@@ -502,19 +508,20 @@ static int fsck_handle_reflog_ent(const char *refname,
fprintf_ln(stderr, _("Checking reflog %s->%s"),
oid_to_hex(ooid), oid_to_hex(noid));
fsck_handle_reflog_oid(refname, ooid, 0);
fsck_handle_reflog_oid(refname, noid, timestamp);
fsck_handle_reflog_oid(repo, refname, ooid, 0);
fsck_handle_reflog_oid(repo, refname, noid, timestamp);
return 0;
}
static int fsck_handle_reflog(const char *logname, void *cb_data)
{
struct strbuf refname = STRBUF_INIT;
struct worktree *wt = cb_data;
strbuf_worktree_ref(cb_data, &refname, logname);
refs_for_each_reflog_ent(get_main_ref_store(the_repository),
strbuf_worktree_ref(wt, &refname, logname);
refs_for_each_reflog_ent(get_main_ref_store(wt->repo),
refname.buf, fsck_handle_reflog_ent,
NULL);
wt->repo);
strbuf_release(&refname);
return 0;
}
@@ -532,14 +539,20 @@ struct snapshot {
/* TODO: Consider also snapshotting the index of each worktree. */
};
struct snapshot_ref_data {
struct repository *repo;
struct snapshot *snap;
};
static int snapshot_ref(const struct reference *ref, void *cb_data)
{
struct snapshot *snap = cb_data;
struct snapshot_ref_data *data = cb_data;
struct snapshot *snap = data->snap;
struct object *obj;
obj = parse_object(the_repository, ref->oid);
obj = parse_object(data->repo, ref->oid);
if (!obj) {
if (is_promisor_object(the_repository, ref->oid)) {
if (is_promisor_object(data->repo, ref->oid)) {
/*
* Increment default_refs anyway, because this is a
* valid ref.
@@ -567,11 +580,12 @@ static int snapshot_ref(const struct reference *ref, void *cb_data)
return 0;
}
static int fsck_handle_ref(const struct reference *ref, void *cb_data UNUSED)
static int fsck_handle_ref(const struct reference *ref, void *cb_data)
{
struct repository *repo = cb_data;
struct object *obj;
obj = parse_object(the_repository, ref->oid);
obj = parse_object(repo, ref->oid);
obj->flags |= USED;
fsck_put_object_name(&fsck_walk_options,
ref->oid, "%s", ref->name);
@@ -580,11 +594,16 @@ static int fsck_handle_ref(const struct reference *ref, void *cb_data UNUSED)
return 0;
}
static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)
static void snapshot_refs(struct repository *repo,
struct snapshot *snap, int argc, const char **argv)
{
struct refs_for_each_ref_options opts = {
.flags = REFS_FOR_EACH_INCLUDE_BROKEN,
};
struct snapshot_ref_data data = {
.repo = repo,
.snap = snap,
};
struct worktree **worktrees, **p;
const char *head_points_at;
struct object_id head_oid;
@@ -592,13 +611,13 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)
for (int i = 0; i < argc; i++) {
const char *arg = argv[i];
struct object_id oid;
if (!repo_get_oid(the_repository, arg, &oid)) {
if (!repo_get_oid(repo, arg, &oid)) {
struct reference ref = {
.name = arg,
.oid = &oid,
};
snapshot_ref(&ref, snap);
snapshot_ref(&ref, &data);
continue;
}
error(_("invalid parameter: expected sha1, got '%s'"), arg);
@@ -610,8 +629,8 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)
return;
}
refs_for_each_ref_ext(get_main_ref_store(the_repository),
snapshot_ref, snap, &opts);
refs_for_each_ref_ext(get_main_ref_store(repo),
snapshot_ref, &data, &opts);
worktrees = get_worktrees();
for (p = worktrees; *p; p++) {
@@ -620,7 +639,7 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)
strbuf_worktree_ref(wt, &refname, "HEAD");
head_points_at = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
head_points_at = refs_resolve_ref_unsafe(get_main_ref_store(repo),
refname.buf, 0, &head_oid, NULL);
if (head_points_at && !is_null_oid(&head_oid)) {
@@ -629,7 +648,7 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)
.oid = &head_oid,
};
snapshot_ref(&ref, snap);
snapshot_ref(&ref, &data);
}
strbuf_release(&refname);
@@ -653,7 +672,7 @@ static void free_snapshot_refs(struct snapshot *snap)
free(snap->ref);
}
static void process_refs(struct snapshot *snap)
static void process_refs(struct repository *repo, struct snapshot *snap)
{
struct worktree **worktrees, **p;
@@ -662,7 +681,7 @@ static void process_refs(struct snapshot *snap)
.name = snap->ref[i].refname,
.oid = &snap->ref[i].oid,
};
fsck_handle_ref(&ref, NULL);
fsck_handle_ref(&ref, repo);
}
if (include_reflogs) {
@@ -694,27 +713,28 @@ static void process_refs(struct snapshot *snap)
}
}
struct for_each_loose_cb
{
struct for_each_loose_cb {
struct repository *repo;
struct progress *progress;
};
static int fsck_loose(const struct object_id *oid, const char *path,
void *data UNUSED)
void *cb_data)
{
struct for_each_loose_cb *data = cb_data;
struct object *obj;
enum object_type type = OBJ_NONE;
unsigned long size;
void *contents = NULL;
int eaten;
struct object_info oi = OBJECT_INFO_INIT;
struct object_id real_oid = *null_oid(the_hash_algo);
struct object_id real_oid = *null_oid(data->repo->hash_algo);
int err = 0;
oi.sizep = &size;
oi.typep = &type;
if (read_loose_object(the_repository, path, oid, &real_oid, &contents, &oi) < 0) {
if (read_loose_object(data->repo, path, oid, &real_oid, &contents, &oi) < 0) {
if (contents && !oideq(&real_oid, oid))
err = error(_("%s: hash-path mismatch, found at: %s"),
oid_to_hex(&real_oid), path);
@@ -731,7 +751,7 @@ static int fsck_loose(const struct object_id *oid, const char *path,
if (!contents && type != OBJ_BLOB)
BUG("read_loose_object streamed a non-blob");
obj = parse_object_buffer(the_repository, oid, type, size,
obj = parse_object_buffer(data->repo, oid, type, size,
contents, &eaten);
if (!obj) {
@@ -745,7 +765,7 @@ static int fsck_loose(const struct object_id *oid, const char *path,
obj->flags &= ~(REACHABLE | SEEN);
obj->flags |= HAS_OBJ;
if (fsck_obj(obj, contents, size))
if (fsck_obj(data->repo, obj, contents, size))
errors_found |= ERROR_OBJECT;
if (!eaten)
@@ -769,10 +789,11 @@ static int fsck_subdir(unsigned int nr, const char *path UNUSED, void *data)
return 0;
}
static void fsck_source(struct odb_source *source)
static void fsck_source(struct repository *repo, struct odb_source *source)
{
struct progress *progress = NULL;
struct for_each_loose_cb cb_data = {
.repo = source->odb->repo,
.progress = progress,
};
@@ -780,7 +801,7 @@ static void fsck_source(struct odb_source *source)
fprintf_ln(stderr, _("Checking object directory"));
if (show_progress)
progress = start_progress(the_repository,
progress = start_progress(repo,
_("Checking object directories"), 256);
for_each_loose_file_in_source(source, fsck_loose,
@@ -789,7 +810,7 @@ static void fsck_source(struct odb_source *source)
stop_progress(&progress);
}
static int fsck_cache_tree(struct cache_tree *it, const char *index_path)
static int fsck_cache_tree(struct repository *repo, struct cache_tree *it, const char *index_path)
{
int i;
int err = 0;
@@ -798,7 +819,7 @@ static int fsck_cache_tree(struct cache_tree *it, const char *index_path)
fprintf_ln(stderr, _("Checking cache tree of %s"), index_path);
if (0 <= it->entry_count) {
struct object *obj = parse_object(the_repository, &it->oid);
struct object *obj = parse_object(repo, &it->oid);
if (!obj) {
error(_("%s: invalid sha1 pointer in cache-tree of %s"),
oid_to_hex(&it->oid), index_path);
@@ -809,10 +830,10 @@ static int fsck_cache_tree(struct cache_tree *it, const char *index_path)
fsck_put_object_name(&fsck_walk_options, &it->oid, ":");
mark_object_reachable(obj);
if (obj->type != OBJ_TREE)
err |= objerror(obj, _("non-tree in cache-tree"));
err |= objerror(repo, obj, _("non-tree in cache-tree"));
}
for (i = 0; i < it->subtree_nr; i++)
err |= fsck_cache_tree(it->down[i]->cache_tree, index_path);
err |= fsck_cache_tree(repo, it->down[i]->cache_tree, index_path);
return err;
}
@@ -838,7 +859,7 @@ static int fsck_resolve_undo(struct index_state *istate,
if (!ru->mode[i] || !S_ISREG(ru->mode[i]))
continue;
obj = parse_object(the_repository, &ru->oid[i]);
obj = parse_object(istate->repo, &ru->oid[i]);
if (!obj) {
error(_("%s: invalid sha1 pointer in resolve-undo of %s"),
oid_to_hex(&ru->oid[i]),
@@ -870,7 +891,7 @@ static void fsck_index(struct index_state *istate, const char *index_path,
mode = istate->cache[i]->ce_mode;
if (S_ISGITLINK(mode))
continue;
blob = lookup_blob(the_repository,
blob = lookup_blob(istate->repo,
&istate->cache[i]->oid);
if (!blob)
continue;
@@ -883,15 +904,16 @@ static void fsck_index(struct index_state *istate, const char *index_path,
mark_object_reachable(obj);
}
if (istate->cache_tree)
fsck_cache_tree(istate->cache_tree, index_path);
fsck_cache_tree(istate->repo, istate->cache_tree, index_path);
fsck_resolve_undo(istate, index_path);
}
static int mark_object_for_connectivity(const struct object_id *oid,
struct object_info *oi UNUSED,
void *cb_data UNUSED)
void *cb_data)
{
struct object *obj = lookup_unknown_object(the_repository, oid);
struct repository *repo = cb_data;
struct object *obj = lookup_unknown_object(repo, oid);
obj->flags |= HAS_OBJ;
return 0;
}
@@ -906,7 +928,7 @@ static int check_pack_rev_indexes(struct repository *r, int show_progress)
if (show_progress) {
repo_for_each_pack(r, p)
pack_count++;
progress = start_delayed_progress(the_repository,
progress = start_delayed_progress(r,
"Verifying reverse pack-indexes", pack_count);
pack_count = 0;
}
@@ -986,7 +1008,7 @@ static struct option fsck_opts[] = {
int cmd_fsck(int argc,
const char **argv,
const char *prefix,
struct repository *repo UNUSED)
struct repository *repo)
{
struct odb_source *source;
struct snapshot snap = {
@@ -1004,7 +1026,10 @@ int cmd_fsck(int argc,
argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);
fsck_options_init(&fsck_walk_options, repo, FSCK_OPTIONS_DEFAULT);
fsck_walk_options.walk = mark_object;
fsck_options_init(&fsck_obj_options, repo, FSCK_OPTIONS_DEFAULT);
fsck_obj_options.walk = mark_used;
fsck_obj_options.error_func = fsck_objects_error_func;
if (check_strict)
@@ -1023,11 +1048,11 @@ int cmd_fsck(int argc,
if (name_objects)
fsck_enable_object_names(&fsck_walk_options);
repo_config(the_repository, git_fsck_config, &fsck_obj_options);
prepare_repo_settings(the_repository);
repo_config(repo, git_fsck_config, &fsck_obj_options);
prepare_repo_settings(repo);
if (check_references)
fsck_refs(the_repository);
fsck_refs(repo);
/*
* Take a snapshot of the refs before walking objects to avoid looking
@@ -1035,18 +1060,18 @@ int cmd_fsck(int argc,
* objects. We can still walk over new objects that are added during the
* execution of fsck but won't miss any objects that were reachable.
*/
snapshot_refs(&snap, argc, argv);
snapshot_refs(repo, &snap, argc, argv);
/* Ensure we get a "fresh" view of the odb */
odb_reprepare(the_repository->objects);
odb_reprepare(repo->objects);
if (connectivity_only) {
odb_for_each_object(the_repository->objects, NULL,
mark_object_for_connectivity, NULL, 0);
odb_for_each_object(repo->objects, NULL,
mark_object_for_connectivity, repo, 0);
} else {
odb_prepare_alternates(the_repository->objects);
for (source = the_repository->objects->sources; source; source = source->next)
fsck_source(source);
odb_prepare_alternates(repo->objects);
for (source = repo->objects->sources; source; source = source->next)
fsck_source(repo, source);
if (check_full) {
struct packed_git *p;
@@ -1054,20 +1079,20 @@ int cmd_fsck(int argc,
struct progress *progress = NULL;
if (show_progress) {
repo_for_each_pack(the_repository, p) {
repo_for_each_pack(repo, p) {
if (open_pack_index(p))
continue;
total += p->num_objects;
}
progress = start_progress(the_repository,
progress = start_progress(repo,
_("Checking objects"), total);
}
repo_for_each_pack(the_repository, p) {
repo_for_each_pack(repo, p) {
/* verify gives error messages itself */
if (verify_pack(the_repository,
p, fsck_obj_buffer,
if (verify_pack(repo,
p, fsck_obj_buffer, repo,
progress, count))
errors_found |= ERROR_PACK;
count += p->num_objects;
@@ -1080,7 +1105,7 @@ int cmd_fsck(int argc,
}
/* Process the snapshotted refs and the reflogs. */
process_refs(&snap);
process_refs(repo, &snap);
/* If not given any explicit objects, process index files too. */
if (!argc)
@@ -1100,7 +1125,7 @@ int cmd_fsck(int argc,
for (p = worktrees; *p; p++) {
struct worktree *wt = *p;
struct index_state istate =
INDEX_STATE_INIT(the_repository);
INDEX_STATE_INIT(repo);
char *path, *wt_gitdir;
/*
@@ -1121,17 +1146,17 @@ int cmd_fsck(int argc,
free_worktrees(worktrees);
}
errors_found |= check_pack_rev_indexes(the_repository, show_progress);
if (verify_bitmap_files(the_repository))
errors_found |= check_pack_rev_indexes(repo, show_progress);
if (verify_bitmap_files(repo))
errors_found |= ERROR_BITMAP;
check_connectivity();
check_connectivity(repo);
if (the_repository->settings.core_commit_graph) {
if (repo->settings.core_commit_graph) {
struct child_process commit_graph_verify = CHILD_PROCESS_INIT;
odb_prepare_alternates(the_repository->objects);
for (source = the_repository->objects->sources; source; source = source->next) {
odb_prepare_alternates(repo->objects);
for (source = repo->objects->sources; source; source = source->next) {
child_process_init(&commit_graph_verify);
commit_graph_verify.git_cmd = 1;
strvec_pushl(&commit_graph_verify.args, "commit-graph",
@@ -1145,11 +1170,11 @@ int cmd_fsck(int argc,
}
}
if (the_repository->settings.core_multi_pack_index) {
if (repo->settings.core_multi_pack_index) {
struct child_process midx_verify = CHILD_PROCESS_INIT;
odb_prepare_alternates(the_repository->objects);
for (source = the_repository->objects->sources; source; source = source->next) {
odb_prepare_alternates(repo->objects);
for (source = repo->objects->sources; source; source = source->next) {
child_process_init(&midx_verify);
midx_verify.git_cmd = 1;
strvec_pushl(&midx_verify.args, "multi-pack-index",

View File

@@ -136,7 +136,7 @@ static int nr_threads;
static int from_stdin;
static int strict;
static int do_fsck_object;
static struct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES;
static struct fsck_options fsck_options;
static int verbose;
static const char *progress_title;
static int show_resolving_progress;
@@ -1908,6 +1908,8 @@ int cmd_index_pack(int argc,
show_usage_if_asked(argc, argv, index_pack_usage);
disable_replace_refs();
fsck_options_init(&fsck_options, the_repository, FSCK_OPTIONS_MISSING_GITMODULES);
fsck_options.walk = mark_link;
reset_pack_idx_option(&opts);

View File

@@ -16,7 +16,7 @@ static char const * const builtin_mktag_usage[] = {
};
static int option_strict = 1;
static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
static struct fsck_options fsck_options;
static int mktag_fsck_error_func(struct fsck_options *o UNUSED,
void *fsck_report UNUSED,
@@ -75,7 +75,7 @@ static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)
int cmd_mktag(int argc,
const char **argv,
const char *prefix,
struct repository *repo UNUSED)
struct repository *repo)
{
static struct option builtin_mktag_options[] = {
OPT_BOOL(0, "strict", &option_strict,
@@ -94,6 +94,7 @@ int cmd_mktag(int argc,
if (strbuf_read(&buf, 0, 0) < 0)
die_errno(_("could not read from stdin"));
fsck_options_init(&fsck_options, repo, FSCK_OPTIONS_STRICT);
fsck_options.error_func = mktag_fsck_error_func;
fsck_set_msg_type_from_ids(&fsck_options, FSCK_MSG_EXTRA_HEADER_ENTRY,
FSCK_WARN);

View File

@@ -78,9 +78,9 @@ out:
}
static int cmd_refs_verify(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
struct repository *repo)
{
struct fsck_options fsck_refs_options = FSCK_REFS_OPTIONS_DEFAULT;
struct fsck_options fsck_refs_options;
struct worktree **worktrees;
const char * const verify_usage[] = {
REFS_VERIFY_USAGE,
@@ -93,6 +93,8 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix,
};
int ret = 0;
fsck_options_init(&fsck_refs_options, repo, FSCK_OPTIONS_REFS);
argc = parse_options(argc, argv, prefix, options, verify_usage, 0);
if (argc)
usage(_("'git refs verify' takes no arguments"));

View File

@@ -29,7 +29,7 @@ static unsigned int offset, len;
static off_t consumed_bytes;
static off_t max_input_size;
static struct git_hash_ctx ctx;
static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
static struct fsck_options fsck_options;
static struct progress *progress;
/*
@@ -613,7 +613,7 @@ static void unpack_all(void)
int cmd_unpack_objects(int argc,
const char **argv,
const char *prefix UNUSED,
struct repository *repo UNUSED)
struct repository *repo)
{
int i;
struct object_id oid;
@@ -627,6 +627,8 @@ int cmd_unpack_objects(int argc,
show_usage_if_asked(argc, argv, unpack_usage);
fsck_options_init(&fsck_options, repo, FSCK_OPTIONS_STRICT);
for (i = 1 ; i < argc; i++) {
const char *arg = argv[i];

View File

@@ -51,7 +51,6 @@ static int server_supports_filtering;
static int advertise_sid;
static struct shallow_lock shallow_lock;
static const char *alternate_shallow_file;
static struct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES;
static struct strbuf fsck_msg_types = STRBUF_INIT;
static struct string_list uri_protocols = STRING_LIST_INIT_DUP;
@@ -1096,6 +1095,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
struct shallow_info *si,
struct string_list *pack_lockfiles)
{
struct fsck_options fsck_options = { 0 };
struct repository *r = the_repository;
struct ref *ref = copy_ref_list(orig_ref);
struct object_id oid;
@@ -1224,6 +1224,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
alternate_shallow_file = setup_temporary_shallow(si->shallow);
} else
alternate_shallow_file = NULL;
fsck_options_init(&fsck_options, the_repository, FSCK_OPTIONS_MISSING_GITMODULES);
if (get_pack(args, fd, pack_lockfiles, NULL, sought, nr_sought,
&fsck_options.gitmodules_found))
die(_("git fetch-pack: fetch failed."));
@@ -1231,6 +1233,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
die("fsck failed");
all_done:
fsck_options_clear(&fsck_options);
if (negotiator)
negotiator->release(negotiator);
return ref;
@@ -1650,6 +1653,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
struct string_list *pack_lockfiles)
{
struct repository *r = the_repository;
struct fsck_options fsck_options;
struct ref *ref = copy_ref_list(orig_ref);
enum fetch_state state = FETCH_CHECK_LOCAL;
struct oidset common = OIDSET_INIT;
@@ -1667,6 +1671,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
struct strvec index_pack_args = STRVEC_INIT;
const char *promisor_remote_config;
fsck_options_init(&fsck_options, the_repository, FSCK_OPTIONS_MISSING_GITMODULES);
if (server_feature_v2("promisor-remote", &promisor_remote_config))
promisor_remote_reply(promisor_remote_config, NULL);
@@ -1878,6 +1884,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
if (negotiator)
negotiator->release(negotiator);
fsck_options_clear(&fsck_options);
oidset_clear(&common);
return ref;
}

76
fsck.c
View File

@@ -1,5 +1,3 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "git-compat-util.h"
#include "date.h"
#include "dir.h"
@@ -207,7 +205,7 @@ void fsck_set_msg_types(struct fsck_options *options, const char *values)
if (equal == len)
die("skiplist requires a path");
oidset_parse_file(&options->skip_oids, buf + equal + 1,
the_repository->hash_algo);
options->repo->hash_algo);
buf += len + 1;
continue;
}
@@ -360,7 +358,7 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
int res = 0;
const char *name;
if (repo_parse_tree(the_repository, tree))
if (repo_parse_tree(options->repo, tree))
return -1;
name = fsck_get_object_name(options, &tree->object.oid);
@@ -375,14 +373,14 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
continue;
if (S_ISDIR(entry.mode)) {
obj = (struct object *)lookup_tree(the_repository, &entry.oid);
obj = (struct object *)lookup_tree(options->repo, &entry.oid);
if (name && obj)
fsck_put_object_name(options, &entry.oid, "%s%s/",
name, entry.path);
result = options->walk(obj, OBJ_TREE, data, options);
}
else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
obj = (struct object *)lookup_blob(the_repository, &entry.oid);
obj = (struct object *)lookup_blob(options->repo, &entry.oid);
if (name && obj)
fsck_put_object_name(options, &entry.oid, "%s%s",
name, entry.path);
@@ -409,7 +407,7 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
int result;
const char *name;
if (repo_parse_commit(the_repository, commit))
if (repo_parse_commit(options->repo, commit))
return -1;
name = fsck_get_object_name(options, &commit->object.oid);
@@ -417,7 +415,7 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
fsck_put_object_name(options, get_commit_tree_oid(commit),
"%s:", name);
result = options->walk((struct object *) repo_get_commit_tree(the_repository, commit),
result = options->walk((struct object *) repo_get_commit_tree(options->repo, commit),
OBJ_TREE, data, options);
if (result < 0)
return result;
@@ -474,7 +472,7 @@ static int fsck_walk_tag(struct tag *tag, void *data, struct fsck_options *optio
{
const char *name = fsck_get_object_name(options, &tag->object.oid);
if (parse_tag(the_repository, tag))
if (parse_tag(options->repo, tag))
return -1;
if (name)
fsck_put_object_name(options, &tag->tagged->oid, "%s", name);
@@ -487,7 +485,7 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options)
return -1;
if (obj->type == OBJ_NONE)
parse_object(the_repository, &obj->oid);
parse_object(options->repo, &obj->oid);
switch (obj->type) {
case OBJ_BLOB:
@@ -970,14 +968,14 @@ static int fsck_commit(const struct object_id *oid,
if (buffer >= buffer_end || !skip_prefix(buffer, "tree ", &buffer))
return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line");
if (parse_oid_hex(buffer, &tree_oid, &p) || *p != '\n') {
if (parse_oid_hex_algop(buffer, &tree_oid, &p, options->repo->hash_algo) || *p != '\n') {
err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1");
if (err)
return err;
}
buffer = p + 1;
while (buffer < buffer_end && skip_prefix(buffer, "parent ", &buffer)) {
if (parse_oid_hex(buffer, &parent_oid, &p) || *p != '\n') {
if (parse_oid_hex_algop(buffer, &parent_oid, &p, options->repo->hash_algo) || *p != '\n') {
err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1");
if (err)
return err;
@@ -1044,7 +1042,7 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line");
goto done;
}
if (parse_oid_hex(buffer, tagged_oid, &p) || *p != '\n') {
if (parse_oid_hex_algop(buffer, tagged_oid, &p, options->repo->hash_algo) || *p != '\n') {
ret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_OBJECT_SHA1, "invalid 'object' line format - bad sha1");
if (ret)
goto done;
@@ -1336,9 +1334,9 @@ static int fsck_blobs(struct oidset *blobs_found, struct oidset *blobs_done,
if (oidset_contains(blobs_done, oid))
continue;
buf = odb_read_object(the_repository->objects, oid, &type, &size);
buf = odb_read_object(options->repo->objects, oid, &type, &size);
if (!buf) {
if (is_promisor_object(the_repository, oid))
if (is_promisor_object(options->repo, oid))
continue;
ret |= report(options,
oid, OBJ_BLOB, msg_missing,
@@ -1380,6 +1378,54 @@ bool fsck_has_queued_checks(struct fsck_options *options)
!oidset_equal(&options->gitattributes_found, &options->gitattributes_done);
}
void fsck_options_init(struct fsck_options *options,
struct repository *repo,
enum fsck_options_type type)
{
static const struct fsck_options defaults[] = {
[FSCK_OPTIONS_DEFAULT] = {
.skip_oids = OIDSET_INIT,
.gitmodules_found = OIDSET_INIT,
.gitmodules_done = OIDSET_INIT,
.gitattributes_found = OIDSET_INIT,
.gitattributes_done = OIDSET_INIT,
.error_func = fsck_objects_error_function
},
[FSCK_OPTIONS_STRICT] = {
.strict = 1,
.gitmodules_found = OIDSET_INIT,
.gitmodules_done = OIDSET_INIT,
.gitattributes_found = OIDSET_INIT,
.gitattributes_done = OIDSET_INIT,
.error_func = fsck_objects_error_function,
},
[FSCK_OPTIONS_MISSING_GITMODULES] = {
.strict = 1,
.gitmodules_found = OIDSET_INIT,
.gitmodules_done = OIDSET_INIT,
.gitattributes_found = OIDSET_INIT,
.gitattributes_done = OIDSET_INIT,
.error_func = fsck_objects_error_cb_print_missing_gitmodules,
},
[FSCK_OPTIONS_REFS] = {
.error_func = fsck_refs_error_function,
},
};
switch (type) {
case FSCK_OPTIONS_DEFAULT:
case FSCK_OPTIONS_STRICT:
case FSCK_OPTIONS_MISSING_GITMODULES:
case FSCK_OPTIONS_REFS:
memcpy(options, &defaults[type], sizeof(*options));
break;
default:
BUG("unknown fsck options type %d", type);
}
options->repo = repo;
}
void fsck_options_clear(struct fsck_options *options)
{
free(options->msg_type);

42
fsck.h
View File

@@ -166,7 +166,10 @@ struct fsck_ref_report {
const char *path;
};
struct repository;
struct fsck_options {
struct repository *repo;
fsck_walk_func walk;
fsck_error error_func;
unsigned strict;
@@ -180,34 +183,6 @@ struct fsck_options {
kh_oid_map_t *object_names;
};
#define FSCK_OPTIONS_DEFAULT { \
.skip_oids = OIDSET_INIT, \
.gitmodules_found = OIDSET_INIT, \
.gitmodules_done = OIDSET_INIT, \
.gitattributes_found = OIDSET_INIT, \
.gitattributes_done = OIDSET_INIT, \
.error_func = fsck_objects_error_function \
}
#define FSCK_OPTIONS_STRICT { \
.strict = 1, \
.gitmodules_found = OIDSET_INIT, \
.gitmodules_done = OIDSET_INIT, \
.gitattributes_found = OIDSET_INIT, \
.gitattributes_done = OIDSET_INIT, \
.error_func = fsck_objects_error_function, \
}
#define FSCK_OPTIONS_MISSING_GITMODULES { \
.strict = 1, \
.gitmodules_found = OIDSET_INIT, \
.gitmodules_done = OIDSET_INIT, \
.gitattributes_found = OIDSET_INIT, \
.gitattributes_done = OIDSET_INIT, \
.error_func = fsck_objects_error_cb_print_missing_gitmodules, \
}
#define FSCK_REFS_OPTIONS_DEFAULT { \
.error_func = fsck_refs_error_function, \
}
/* descend in all linked child objects
* the return value is:
* -1 error in processing the object
@@ -255,6 +230,17 @@ int fsck_finish(struct fsck_options *options);
*/
bool fsck_has_queued_checks(struct fsck_options *options);
enum fsck_options_type {
FSCK_OPTIONS_DEFAULT,
FSCK_OPTIONS_STRICT,
FSCK_OPTIONS_MISSING_GITMODULES,
FSCK_OPTIONS_REFS,
};
void fsck_options_init(struct fsck_options *options,
struct repository *repo,
enum fsck_options_type type);
/*
* Clear the fsck_options struct, freeing any allocated memory.
*/

View File

@@ -1282,8 +1282,9 @@ static int index_mem(struct index_state *istate,
}
}
if (flags & INDEX_FORMAT_CHECK) {
struct fsck_options opts = FSCK_OPTIONS_DEFAULT;
struct fsck_options opts;
fsck_options_init(&opts, the_repository, FSCK_OPTIONS_DEFAULT);
opts.strict = 1;
opts.error_func = hash_format_check_report;
if (fsck_buffer(null_oid(istate->repo->hash_algo), type, buf, size, &opts))

View File

@@ -53,6 +53,7 @@ static int verify_packfile(struct repository *r,
struct packed_git *p,
struct pack_window **w_curs,
verify_fn fn,
void *fn_data,
struct progress *progress, uint32_t base_count)
{
@@ -161,7 +162,7 @@ static int verify_packfile(struct repository *r,
oid_to_hex(&oid), p->pack_name);
else if (fn) {
int eaten = 0;
err |= fn(&oid, type, size, data, &eaten);
err |= fn(&oid, type, size, data, &eaten, fn_data);
if (eaten)
data = NULL;
}
@@ -192,7 +193,7 @@ int verify_pack_index(struct packed_git *p)
return err;
}
int verify_pack(struct repository *r, struct packed_git *p, verify_fn fn,
int verify_pack(struct repository *r, struct packed_git *p, verify_fn fn, void *fn_data,
struct progress *progress, uint32_t base_count)
{
int err = 0;
@@ -202,7 +203,7 @@ int verify_pack(struct repository *r, struct packed_git *p, verify_fn fn,
if (!p->index_data)
return -1;
err |= verify_packfile(r, p, &w_curs, fn, progress, base_count);
err |= verify_packfile(r, p, &w_curs, fn, fn_data, progress, base_count);
unuse_pack(&w_curs);
return err;

9
pack.h
View File

@@ -85,7 +85,11 @@ struct pack_idx_entry {
struct progress;
/* Note, the data argument could be NULL if object type is blob */
typedef int (*verify_fn)(const struct object_id *, enum object_type, unsigned long, void*, int*);
typedef int (*verify_fn)(const struct object_id *oid,
enum object_type type,
unsigned long size,
void *buffer, int *eaten,
void *fn_data);
const char *write_idx_file(struct repository *repo,
const char *index_name,
@@ -95,7 +99,8 @@ const char *write_idx_file(struct repository *repo,
const unsigned char *sha1);
int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr);
int verify_pack_index(struct packed_git *);
int verify_pack(struct repository *, struct packed_git *, verify_fn fn, struct progress *, uint32_t);
int verify_pack(struct repository *, struct packed_git *, verify_fn fn, void *fn_data,
struct progress *, uint32_t);
off_t write_pack_header(struct hashfile *f, uint32_t);
void fixup_pack_header_footer(const struct git_hash_algo *, int,
unsigned char *, const char *, uint32_t,