Skip to content

Commit

Permalink
Merge branch 'nd/fsck-progress'
Browse files Browse the repository at this point in the history
* nd/fsck-progress:
  fsck: print progress
  fsck: avoid reading every object twice
  verify_packfile(): check as many object as possible in a pack
  fsck: return error code when verify_pack() goes wrong
  • Loading branch information
Junio C Hamano committed Dec 5, 2011
2 parents c4c9a63 + 1e49f22 commit d7194d3
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 27 deletions.
11 changes: 10 additions & 1 deletion Documentation/git-fsck.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ SYNOPSIS
--------
[verse]
'git fsck' [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]
[--[no-]full] [--strict] [--verbose] [--lost-found] [<object>*]
[--[no-]full] [--strict] [--verbose] [--lost-found]
[--[no-]progress] [<object>*]

DESCRIPTION
-----------
Expand Down Expand Up @@ -72,6 +73,14 @@ index file, all SHA1 references in .git/refs/*, and all reflogs (unless
a blob, the contents are written into the file, rather than
its object name.

--progress::
--no-progress::
Progress status is reported on the standard error stream by
default when it is attached to a terminal, unless
--no-progress or --verbose is specified. --progress forces
progress status even if the standard error stream is not
directed to a terminal.

It tests SHA1 and general object sanity, and it does full tracking of
the resulting reachability and everything else. It prints out any
corruption it finds (missing or bad objects), and if you use the
Expand Down
78 changes: 62 additions & 16 deletions builtin/fsck.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "fsck.h"
#include "parse-options.h"
#include "dir.h"
#include "progress.h"

#define REACHABLE 0x0001
#define SEEN 0x0002
Expand All @@ -27,8 +28,10 @@ static const char *head_points_at;
static int errors_found;
static int write_lost_and_found;
static int verbose;
static int show_progress = -1;
#define ERROR_OBJECT 01
#define ERROR_REACHABLE 02
#define ERROR_PACK 04

#ifdef NO_D_INO_IN_DIRENT
#define SORT_DIRENT 0
Expand Down Expand Up @@ -137,15 +140,21 @@ static int traverse_one_object(struct object *obj)

static int traverse_reachable(void)
{
struct progress *progress = NULL;
unsigned int nr = 0;
int result = 0;
if (show_progress)
progress = start_progress_delay("Checking connectivity", 0, 0, 2);
while (pending.nr) {
struct object_array_entry *entry;
struct object *obj;

entry = pending.objects + --pending.nr;
obj = entry->item;
result |= traverse_one_object(obj);
display_progress(progress, ++nr);
}
stop_progress(&progress);
return !!result;
}

Expand Down Expand Up @@ -281,14 +290,8 @@ static void check_connectivity(void)
}
}

static int fsck_sha1(const unsigned char *sha1)
static int fsck_obj(struct object *obj)
{
struct object *obj = parse_object(sha1);
if (!obj) {
errors_found |= ERROR_OBJECT;
return error("%s: object corrupt or missing",
sha1_to_hex(sha1));
}
if (obj->flags & SEEN)
return 0;
obj->flags |= SEEN;
Expand Down Expand Up @@ -331,6 +334,29 @@ static int fsck_sha1(const unsigned char *sha1)
return 0;
}

static int fsck_sha1(const unsigned char *sha1)
{
struct object *obj = parse_object(sha1);
if (!obj) {
errors_found |= ERROR_OBJECT;
return error("%s: object corrupt or missing",
sha1_to_hex(sha1));
}
return fsck_obj(obj);
}

static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,
unsigned long size, void *buffer, int *eaten)
{
struct object *obj;
obj = parse_object_buffer(sha1, type, size, buffer, eaten);
if (!obj) {
errors_found |= ERROR_OBJECT;
return error("%s: object corrupt or missing", sha1_to_hex(sha1));
}
return fsck_obj(obj);
}

/*
* This is the sorting chunk size: make it reasonably
* big so that we can sort well..
Expand Down Expand Up @@ -512,15 +538,20 @@ static void get_default_heads(void)
static void fsck_object_dir(const char *path)
{
int i;
struct progress *progress = NULL;

if (verbose)
fprintf(stderr, "Checking object directory\n");

if (show_progress)
progress = start_progress("Checking object directories", 256);
for (i = 0; i < 256; i++) {
static char dir[4096];
sprintf(dir, "%s/%02x", path, i);
fsck_dir(i, dir);
display_progress(progress, i+1);
}
stop_progress(&progress);
fsck_sha1_list();
}

Expand Down Expand Up @@ -591,6 +622,7 @@ static struct option fsck_opts[] = {
OPT_BOOLEAN(0, "strict", &check_strict, "enable more strict checking"),
OPT_BOOLEAN(0, "lost-found", &write_lost_and_found,
"write dangling objects in .git/lost-found"),
OPT_BOOL(0, "progress", &show_progress, "show progress"),
OPT_END(),
};

Expand All @@ -603,6 +635,12 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
read_replace_refs = 0;

argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);

if (show_progress == -1)
show_progress = isatty(2);
if (verbose)
show_progress = 0;

if (write_lost_and_found) {
check_full = 1;
include_reflogs = 0;
Expand All @@ -622,20 +660,28 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)

if (check_full) {
struct packed_git *p;
uint32_t total = 0, count = 0;
struct progress *progress = NULL;

prepare_packed_git();
for (p = packed_git; p; p = p->next)
/* verify gives error messages itself */
verify_pack(p);

if (show_progress) {
for (p = packed_git; p; p = p->next) {
if (open_pack_index(p))
continue;
total += p->num_objects;
}

progress = start_progress("Checking objects", total);
}
for (p = packed_git; p; p = p->next) {
uint32_t j, num;
if (open_pack_index(p))
continue;
num = p->num_objects;
for (j = 0; j < num; j++)
fsck_sha1(nth_packed_object_sha1(p, j));
/* verify gives error messages itself */
if (verify_pack(p, fsck_obj_buffer,
progress, count))
errors_found |= ERROR_PACK;
count += p->num_objects;
}
stop_progress(&progress);
}

heads = 0;
Expand Down
28 changes: 19 additions & 9 deletions pack-check.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "cache.h"
#include "pack.h"
#include "pack-revindex.h"
#include "progress.h"

struct idx_entry {
off_t offset;
Expand Down Expand Up @@ -42,7 +43,10 @@ int check_pack_crc(struct packed_git *p, struct pack_window **w_curs,
}

static int verify_packfile(struct packed_git *p,
struct pack_window **w_curs)
struct pack_window **w_curs,
verify_fn fn,
struct progress *progress, uint32_t base_count)

{
off_t index_size = p->index_size;
const unsigned char *index_base = p->index_data;
Expand Down Expand Up @@ -113,20 +117,25 @@ static int verify_packfile(struct packed_git *p,
p->pack_name, (uintmax_t)offset);
}
data = unpack_entry(p, entries[i].offset, &type, &size);
if (!data) {
if (!data)
err = error("cannot unpack %s from %s at offset %"PRIuMAX"",
sha1_to_hex(entries[i].sha1), p->pack_name,
(uintmax_t)entries[i].offset);
break;
}
if (check_sha1_signature(entries[i].sha1, data, size, typename(type))) {
else if (check_sha1_signature(entries[i].sha1, data, size, typename(type)))
err = error("packed %s from %s is corrupt",
sha1_to_hex(entries[i].sha1), p->pack_name);
free(data);
break;
else if (fn) {
int eaten = 0;
fn(entries[i].sha1, type, size, data, &eaten);
if (eaten)
data = NULL;
}
if (((base_count + i) & 1023) == 0)
display_progress(progress, base_count + i);
free(data);

}
display_progress(progress, base_count + i);
free(entries);

return err;
Expand Down Expand Up @@ -155,7 +164,8 @@ int verify_pack_index(struct packed_git *p)
return err;
}

int verify_pack(struct packed_git *p)
int verify_pack(struct packed_git *p, verify_fn fn,
struct progress *progress, uint32_t base_count)
{
int err = 0;
struct pack_window *w_curs = NULL;
Expand All @@ -164,7 +174,7 @@ int verify_pack(struct packed_git *p)
if (!p->index_data)
return -1;

err |= verify_packfile(p, &w_curs);
err |= verify_packfile(p, &w_curs, fn, progress, base_count);
unuse_pack(&w_curs);

return err;
Expand Down
6 changes: 5 additions & 1 deletion pack.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,14 @@ struct pack_idx_entry {
off_t offset;
};


struct progress;
typedef int (*verify_fn)(const unsigned char*, enum object_type, unsigned long, void*, int*);

extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, const struct pack_idx_option *, unsigned char *sha1);
extern int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr);
extern int verify_pack_index(struct packed_git *);
extern int verify_pack(struct packed_git *);
extern int verify_pack(struct packed_git *, verify_fn fn, struct progress *, uint32_t);
extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t);
extern char *index_pack_lockfile(int fd);
extern int encode_in_pack_object_header(enum object_type, uintmax_t, unsigned char *);
Expand Down

0 comments on commit d7194d3

Please sign in to comment.