Skip to content

Commit 7b35efd

Browse files
dschogitster
authored andcommitted
fsck_walk(): optionally name objects on the go
If fsck_options->name_objects is initialized, and if it already has name(s) for the object(s) that are to be the starting point(s) for fsck_walk(), then that function will now add names for the objects that were walked. This will be highly useful for teaching git-fsck to identify root causes for broken links, which is the task for the next patch in this series. Note that this patch opts for decorating the objects with plain strings instead of full-blown structs (à la `struct rev_name` in the code of the `git name-rev` command), for several reasons: - the code is much simpler than if it had to work with structs that describe arbitrarily long names such as "master~14^2~5:builtin/am.c", - the string processing is actually quite light-weight compared to the rest of fsck's operation, - the caller of fsck_walk() is expected to provide names for the starting points, and using plain and simple strings is just the easiest way to do that. Signed-off-by: Johannes Schindelin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 993a21b commit 7b35efd

File tree

2 files changed

+84
-4
lines changed

2 files changed

+84
-4
lines changed

fsck.c

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "refs.h"
1010
#include "utf8.h"
1111
#include "sha1-array.h"
12+
#include "decorate.h"
1213

1314
#define FSCK_FATAL -1
1415
#define FSCK_INFO -2
@@ -297,25 +298,64 @@ static int report(struct fsck_options *options, struct object *object,
297298
return result;
298299
}
299300

301+
static char *get_object_name(struct fsck_options *options, struct object *obj)
302+
{
303+
if (!options->object_names)
304+
return NULL;
305+
return lookup_decoration(options->object_names, obj);
306+
}
307+
308+
static void put_object_name(struct fsck_options *options, struct object *obj,
309+
const char *fmt, ...)
310+
{
311+
va_list ap;
312+
struct strbuf buf = STRBUF_INIT;
313+
char *existing;
314+
315+
if (!options->object_names)
316+
return;
317+
existing = lookup_decoration(options->object_names, obj);
318+
if (existing)
319+
return;
320+
va_start(ap, fmt);
321+
strbuf_vaddf(&buf, fmt, ap);
322+
add_decoration(options->object_names, obj, strbuf_detach(&buf, NULL));
323+
va_end(ap);
324+
}
325+
300326
static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *options)
301327
{
302328
struct tree_desc desc;
303329
struct name_entry entry;
304330
int res = 0;
331+
const char *name;
305332

306333
if (parse_tree(tree))
307334
return -1;
308335

336+
name = get_object_name(options, &tree->object);
309337
init_tree_desc(&desc, tree->buffer, tree->size);
310338
while (tree_entry(&desc, &entry)) {
339+
struct object *obj;
311340
int result;
312341

313342
if (S_ISGITLINK(entry.mode))
314343
continue;
315-
if (S_ISDIR(entry.mode))
316-
result = options->walk(&lookup_tree(entry.oid->hash)->object, OBJ_TREE, data, options);
317-
else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode))
318-
result = options->walk(&lookup_blob(entry.oid->hash)->object, OBJ_BLOB, data, options);
344+
345+
if (S_ISDIR(entry.mode)) {
346+
obj = &lookup_tree(entry.oid->hash)->object;
347+
if (name)
348+
put_object_name(options, obj, "%s%s/", name,
349+
entry.path);
350+
result = options->walk(obj, OBJ_TREE, data, options);
351+
}
352+
else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
353+
obj = &lookup_blob(entry.oid->hash)->object;
354+
if (name)
355+
put_object_name(options, obj, "%s%s", name,
356+
entry.path);
357+
result = options->walk(obj, OBJ_BLOB, data, options);
358+
}
319359
else {
320360
result = error("in tree %s: entry %s has bad mode %.6o",
321361
oid_to_hex(&tree->object.oid), entry.path, entry.mode);
@@ -330,20 +370,55 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
330370

331371
static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_options *options)
332372
{
373+
int counter = 0, generation = 0, name_prefix_len = 0;
333374
struct commit_list *parents;
334375
int res;
335376
int result;
377+
const char *name;
336378

337379
if (parse_commit(commit))
338380
return -1;
339381

382+
name = get_object_name(options, &commit->object);
383+
if (name)
384+
put_object_name(options, &commit->tree->object, "%s:", name);
385+
340386
result = options->walk((struct object *)commit->tree, OBJ_TREE, data, options);
341387
if (result < 0)
342388
return result;
343389
res = result;
344390

345391
parents = commit->parents;
392+
if (name && parents) {
393+
int len = strlen(name), power;
394+
395+
if (len && name[len - 1] == '^') {
396+
generation = 1;
397+
name_prefix_len = len - 1;
398+
}
399+
else { /* parse ~<generation> suffix */
400+
for (generation = 0, power = 1;
401+
len && isdigit(name[len - 1]);
402+
power *= 10)
403+
generation += power * (name[--len] - '0');
404+
if (power > 1 && len && name[len - 1] == '~')
405+
name_prefix_len = len - 1;
406+
}
407+
}
408+
346409
while (parents) {
410+
if (name) {
411+
struct object *obj = &parents->item->object;
412+
413+
if (++counter > 1)
414+
put_object_name(options, obj, "%s^%d",
415+
name, counter);
416+
else if (generation > 0)
417+
put_object_name(options, obj, "%.*s~%d",
418+
name_prefix_len, name, generation + 1);
419+
else
420+
put_object_name(options, obj, "%s^", name);
421+
}
347422
result = options->walk((struct object *)parents->item, OBJ_COMMIT, data, options);
348423
if (result < 0)
349424
return result;
@@ -356,8 +431,12 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
356431

357432
static int fsck_walk_tag(struct tag *tag, void *data, struct fsck_options *options)
358433
{
434+
char *name = get_object_name(options, &tag->object);
435+
359436
if (parse_tag(tag))
360437
return -1;
438+
if (name)
439+
put_object_name(options, tag->tagged, "%s", name);
361440
return options->walk(tag->tagged, OBJ_ANY, data, options);
362441
}
363442

fsck.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ struct fsck_options {
3333
unsigned strict:1;
3434
int *msg_type;
3535
struct sha1_array *skiplist;
36+
struct decoration *object_names;
3637
};
3738

3839
#define FSCK_OPTIONS_DEFAULT { NULL, fsck_error_function, 0, NULL }

0 commit comments

Comments
 (0)