зеркало из https://github.com/microsoft/git.git
Merge branch 'nd/fsck-progress'
* 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
This commit is contained in:
Коммит
d7194d318b
|
@ -10,7 +10,8 @@ SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git fsck' [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]
|
'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
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
@ -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
|
a blob, the contents are written into the file, rather than
|
||||||
its object name.
|
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
|
It tests SHA1 and general object sanity, and it does full tracking of
|
||||||
the resulting reachability and everything else. It prints out any
|
the resulting reachability and everything else. It prints out any
|
||||||
corruption it finds (missing or bad objects), and if you use the
|
corruption it finds (missing or bad objects), and if you use the
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "fsck.h"
|
#include "fsck.h"
|
||||||
#include "parse-options.h"
|
#include "parse-options.h"
|
||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
|
#include "progress.h"
|
||||||
|
|
||||||
#define REACHABLE 0x0001
|
#define REACHABLE 0x0001
|
||||||
#define SEEN 0x0002
|
#define SEEN 0x0002
|
||||||
|
@ -27,8 +28,10 @@ static const char *head_points_at;
|
||||||
static int errors_found;
|
static int errors_found;
|
||||||
static int write_lost_and_found;
|
static int write_lost_and_found;
|
||||||
static int verbose;
|
static int verbose;
|
||||||
|
static int show_progress = -1;
|
||||||
#define ERROR_OBJECT 01
|
#define ERROR_OBJECT 01
|
||||||
#define ERROR_REACHABLE 02
|
#define ERROR_REACHABLE 02
|
||||||
|
#define ERROR_PACK 04
|
||||||
|
|
||||||
#ifdef NO_D_INO_IN_DIRENT
|
#ifdef NO_D_INO_IN_DIRENT
|
||||||
#define SORT_DIRENT 0
|
#define SORT_DIRENT 0
|
||||||
|
@ -137,7 +140,11 @@ static int traverse_one_object(struct object *obj)
|
||||||
|
|
||||||
static int traverse_reachable(void)
|
static int traverse_reachable(void)
|
||||||
{
|
{
|
||||||
|
struct progress *progress = NULL;
|
||||||
|
unsigned int nr = 0;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
if (show_progress)
|
||||||
|
progress = start_progress_delay("Checking connectivity", 0, 0, 2);
|
||||||
while (pending.nr) {
|
while (pending.nr) {
|
||||||
struct object_array_entry *entry;
|
struct object_array_entry *entry;
|
||||||
struct object *obj;
|
struct object *obj;
|
||||||
|
@ -145,7 +152,9 @@ static int traverse_reachable(void)
|
||||||
entry = pending.objects + --pending.nr;
|
entry = pending.objects + --pending.nr;
|
||||||
obj = entry->item;
|
obj = entry->item;
|
||||||
result |= traverse_one_object(obj);
|
result |= traverse_one_object(obj);
|
||||||
|
display_progress(progress, ++nr);
|
||||||
}
|
}
|
||||||
|
stop_progress(&progress);
|
||||||
return !!result;
|
return !!result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
if (obj->flags & SEEN)
|
||||||
return 0;
|
return 0;
|
||||||
obj->flags |= SEEN;
|
obj->flags |= SEEN;
|
||||||
|
@ -331,6 +334,29 @@ static int fsck_sha1(const unsigned char *sha1)
|
||||||
return 0;
|
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
|
* This is the sorting chunk size: make it reasonably
|
||||||
* big so that we can sort well..
|
* big so that we can sort well..
|
||||||
|
@ -512,15 +538,20 @@ static void get_default_heads(void)
|
||||||
static void fsck_object_dir(const char *path)
|
static void fsck_object_dir(const char *path)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
struct progress *progress = NULL;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
fprintf(stderr, "Checking object directory\n");
|
fprintf(stderr, "Checking object directory\n");
|
||||||
|
|
||||||
|
if (show_progress)
|
||||||
|
progress = start_progress("Checking object directories", 256);
|
||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++) {
|
||||||
static char dir[4096];
|
static char dir[4096];
|
||||||
sprintf(dir, "%s/%02x", path, i);
|
sprintf(dir, "%s/%02x", path, i);
|
||||||
fsck_dir(i, dir);
|
fsck_dir(i, dir);
|
||||||
|
display_progress(progress, i+1);
|
||||||
}
|
}
|
||||||
|
stop_progress(&progress);
|
||||||
fsck_sha1_list();
|
fsck_sha1_list();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,6 +622,7 @@ static struct option fsck_opts[] = {
|
||||||
OPT_BOOLEAN(0, "strict", &check_strict, "enable more strict checking"),
|
OPT_BOOLEAN(0, "strict", &check_strict, "enable more strict checking"),
|
||||||
OPT_BOOLEAN(0, "lost-found", &write_lost_and_found,
|
OPT_BOOLEAN(0, "lost-found", &write_lost_and_found,
|
||||||
"write dangling objects in .git/lost-found"),
|
"write dangling objects in .git/lost-found"),
|
||||||
|
OPT_BOOL(0, "progress", &show_progress, "show progress"),
|
||||||
OPT_END(),
|
OPT_END(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -603,6 +635,12 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
|
||||||
read_replace_refs = 0;
|
read_replace_refs = 0;
|
||||||
|
|
||||||
argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 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) {
|
if (write_lost_and_found) {
|
||||||
check_full = 1;
|
check_full = 1;
|
||||||
include_reflogs = 0;
|
include_reflogs = 0;
|
||||||
|
@ -622,20 +660,28 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
|
||||||
|
|
||||||
if (check_full) {
|
if (check_full) {
|
||||||
struct packed_git *p;
|
struct packed_git *p;
|
||||||
|
uint32_t total = 0, count = 0;
|
||||||
|
struct progress *progress = NULL;
|
||||||
|
|
||||||
prepare_packed_git();
|
prepare_packed_git();
|
||||||
for (p = packed_git; p; p = p->next)
|
|
||||||
/* verify gives error messages itself */
|
|
||||||
verify_pack(p);
|
|
||||||
|
|
||||||
for (p = packed_git; p; p = p->next) {
|
if (show_progress) {
|
||||||
uint32_t j, num;
|
for (p = packed_git; p; p = p->next) {
|
||||||
if (open_pack_index(p))
|
if (open_pack_index(p))
|
||||||
continue;
|
continue;
|
||||||
num = p->num_objects;
|
total += p->num_objects;
|
||||||
for (j = 0; j < num; j++)
|
}
|
||||||
fsck_sha1(nth_packed_object_sha1(p, j));
|
|
||||||
|
progress = start_progress("Checking objects", total);
|
||||||
}
|
}
|
||||||
|
for (p = packed_git; p; p = p->next) {
|
||||||
|
/* 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;
|
heads = 0;
|
||||||
|
|
28
pack-check.c
28
pack-check.c
|
@ -1,6 +1,7 @@
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "pack.h"
|
#include "pack.h"
|
||||||
#include "pack-revindex.h"
|
#include "pack-revindex.h"
|
||||||
|
#include "progress.h"
|
||||||
|
|
||||||
struct idx_entry {
|
struct idx_entry {
|
||||||
off_t offset;
|
off_t offset;
|
||||||
|
@ -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,
|
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;
|
off_t index_size = p->index_size;
|
||||||
const unsigned char *index_base = p->index_data;
|
const unsigned char *index_base = p->index_data;
|
||||||
|
@ -113,20 +117,25 @@ static int verify_packfile(struct packed_git *p,
|
||||||
p->pack_name, (uintmax_t)offset);
|
p->pack_name, (uintmax_t)offset);
|
||||||
}
|
}
|
||||||
data = unpack_entry(p, entries[i].offset, &type, &size);
|
data = unpack_entry(p, entries[i].offset, &type, &size);
|
||||||
if (!data) {
|
if (!data)
|
||||||
err = error("cannot unpack %s from %s at offset %"PRIuMAX"",
|
err = error("cannot unpack %s from %s at offset %"PRIuMAX"",
|
||||||
sha1_to_hex(entries[i].sha1), p->pack_name,
|
sha1_to_hex(entries[i].sha1), p->pack_name,
|
||||||
(uintmax_t)entries[i].offset);
|
(uintmax_t)entries[i].offset);
|
||||||
break;
|
else if (check_sha1_signature(entries[i].sha1, data, size, typename(type)))
|
||||||
}
|
|
||||||
if (check_sha1_signature(entries[i].sha1, data, size, typename(type))) {
|
|
||||||
err = error("packed %s from %s is corrupt",
|
err = error("packed %s from %s is corrupt",
|
||||||
sha1_to_hex(entries[i].sha1), p->pack_name);
|
sha1_to_hex(entries[i].sha1), p->pack_name);
|
||||||
free(data);
|
else if (fn) {
|
||||||
break;
|
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);
|
free(data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
display_progress(progress, base_count + i);
|
||||||
free(entries);
|
free(entries);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -155,7 +164,8 @@ int verify_pack_index(struct packed_git *p)
|
||||||
return err;
|
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;
|
int err = 0;
|
||||||
struct pack_window *w_curs = NULL;
|
struct pack_window *w_curs = NULL;
|
||||||
|
@ -164,7 +174,7 @@ int verify_pack(struct packed_git *p)
|
||||||
if (!p->index_data)
|
if (!p->index_data)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
err |= verify_packfile(p, &w_curs);
|
err |= verify_packfile(p, &w_curs, fn, progress, base_count);
|
||||||
unuse_pack(&w_curs);
|
unuse_pack(&w_curs);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
6
pack.h
6
pack.h
|
@ -70,10 +70,14 @@ struct pack_idx_entry {
|
||||||
off_t offset;
|
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 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 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_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 void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t);
|
||||||
extern char *index_pack_lockfile(int fd);
|
extern char *index_pack_lockfile(int fd);
|
||||||
extern int encode_in_pack_object_header(enum object_type, uintmax_t, unsigned char *);
|
extern int encode_in_pack_object_header(enum object_type, uintmax_t, unsigned char *);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче