Merge branch 'jc/fsck'

* jc/fsck:
  fsck: exit with non-zero status upon errors
  unpack_sha1_file(): detect corrupt loose object files.
  fsck: fix broken loose object check.
This commit is contained in:
Junio C Hamano 2007-03-10 23:10:26 -08:00
commit 8509fed75d
3 changed files with 41 additions and 15 deletions

View File

@ -18,6 +18,9 @@ static int check_full;
static int check_strict; static int check_strict;
static int keep_cache_objects; static int keep_cache_objects;
static unsigned char head_sha1[20]; static unsigned char head_sha1[20];
static int errors_found;
#define ERROR_OBJECT 01
#define ERROR_REACHABLE 02
#ifdef NO_D_INO_IN_DIRENT #ifdef NO_D_INO_IN_DIRENT
#define SORT_DIRENT 0 #define SORT_DIRENT 0
@ -40,6 +43,7 @@ static int objerror(struct object *obj, const char *err, ...)
{ {
va_list params; va_list params;
va_start(params, err); va_start(params, err);
errors_found |= ERROR_OBJECT;
objreport(obj, "error", err, params); objreport(obj, "error", err, params);
va_end(params); va_end(params);
return -1; return -1;
@ -67,9 +71,10 @@ static void check_reachable_object(struct object *obj)
* do a full fsck * do a full fsck
*/ */
if (!obj->parsed) { if (!obj->parsed) {
if (has_sha1_file(obj->sha1)) if (has_sha1_pack(obj->sha1, NULL))
return; /* it is in pack - forget about it */ return; /* it is in pack - forget about it */
printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1)); printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
errors_found |= ERROR_REACHABLE;
return; return;
} }
@ -88,6 +93,7 @@ static void check_reachable_object(struct object *obj)
typename(obj->type), sha1_to_hex(obj->sha1)); typename(obj->type), sha1_to_hex(obj->sha1));
printf(" to %7s %s\n", printf(" to %7s %s\n",
typename(ref->type), sha1_to_hex(ref->sha1)); typename(ref->type), sha1_to_hex(ref->sha1));
errors_found |= ERROR_REACHABLE;
} }
} }
} }
@ -346,8 +352,11 @@ static int fsck_tag(struct tag *tag)
static int fsck_sha1(unsigned char *sha1) static int fsck_sha1(unsigned char *sha1)
{ {
struct object *obj = parse_object(sha1); struct object *obj = parse_object(sha1);
if (!obj) if (!obj) {
return error("%s: object corrupt or missing", sha1_to_hex(sha1)); 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;
@ -359,8 +368,10 @@ static int fsck_sha1(unsigned char *sha1)
return fsck_commit((struct commit *) obj); return fsck_commit((struct commit *) obj);
if (obj->type == OBJ_TAG) if (obj->type == OBJ_TAG)
return fsck_tag((struct tag *) obj); return fsck_tag((struct tag *) obj);
/* By now, parse_object() would've returned NULL instead. */ /* By now, parse_object() would've returned NULL instead. */
return objerror(obj, "unknown type '%d' (internal fsck error)", obj->type); return objerror(obj, "unknown type '%d' (internal fsck error)",
obj->type);
} }
/* /*
@ -576,11 +587,16 @@ static int fsck_cache_tree(struct cache_tree *it)
return err; return err;
} }
static const char fsck_usage[] =
"git-fsck [--tags] [--root] [[--unreachable] [--cache] [--full] "
"[--strict] <head-sha1>*]";
int cmd_fsck(int argc, char **argv, const char *prefix) int cmd_fsck(int argc, char **argv, const char *prefix)
{ {
int i, heads; int i, heads;
track_object_refs = 1; track_object_refs = 1;
errors_found = 0;
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
const char *arg = argv[i]; const char *arg = argv[i];
@ -610,7 +626,7 @@ int cmd_fsck(int argc, char **argv, const char *prefix)
continue; continue;
} }
if (*arg == '-') if (*arg == '-')
usage("git-fsck [--tags] [--root] [[--unreachable] [--cache] [--full] [--strict] <head-sha1>*]"); usage(fsck_usage);
} }
fsck_head_link(); fsck_head_link();
@ -690,5 +706,5 @@ int cmd_fsck(int argc, char **argv, const char *prefix)
} }
check_connectivity(); check_connectivity();
return 0; return errors_found;
} }

View File

@ -281,7 +281,6 @@ char *enter_repo(char *path, int strict);
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */ /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
extern int sha1_object_info(const unsigned char *, unsigned long *); extern int sha1_object_info(const unsigned char *, unsigned long *);
extern void * unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size);
extern void * read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size); extern void * read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size);
extern int hash_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *sha1); extern int hash_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *sha1);
extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1); extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);

View File

@ -967,11 +967,12 @@ static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned lon
return 0; return 0;
} }
static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size) static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size, const unsigned char *sha1)
{ {
int bytes = strlen(buffer) + 1; int bytes = strlen(buffer) + 1;
unsigned char *buf = xmalloc(1+size); unsigned char *buf = xmalloc(1+size);
unsigned long n; unsigned long n;
int status = Z_OK;
n = stream->total_out - bytes; n = stream->total_out - bytes;
if (n > size) if (n > size)
@ -981,12 +982,22 @@ static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size
if (bytes < size) { if (bytes < size) {
stream->next_out = buf + bytes; stream->next_out = buf + bytes;
stream->avail_out = size - bytes; stream->avail_out = size - bytes;
while (inflate(stream, Z_FINISH) == Z_OK) while (status == Z_OK)
/* nothing */; status = inflate(stream, Z_FINISH);
} }
buf[size] = 0; buf[size] = 0;
if ((status == Z_OK || status == Z_STREAM_END) && !stream->avail_in) {
inflateEnd(stream); inflateEnd(stream);
return buf; return buf;
}
if (status < 0)
error("corrupt loose object '%s'", sha1_to_hex(sha1));
else if (stream->avail_in)
error("garbage at end of loose object '%s'",
sha1_to_hex(sha1));
free(buf);
return NULL;
} }
/* /*
@ -1040,7 +1051,7 @@ static int parse_sha1_header(const char *hdr, unsigned long *sizep)
return *hdr ? -1 : type_from_string(type); return *hdr ? -1 : type_from_string(type);
} }
void * unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size) static void *unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size, const unsigned char *sha1)
{ {
int ret; int ret;
z_stream stream; z_stream stream;
@ -1050,7 +1061,7 @@ void * unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type
if (ret < Z_OK || (*type = parse_sha1_header(hdr, size)) < 0) if (ret < Z_OK || (*type = parse_sha1_header(hdr, size)) < 0)
return NULL; return NULL;
return unpack_sha1_rest(&stream, hdr, *size); return unpack_sha1_rest(&stream, hdr, *size, sha1);
} }
static off_t get_delta_base(struct packed_git *p, static off_t get_delta_base(struct packed_git *p,
@ -1571,7 +1582,7 @@ void *read_sha1_file(const unsigned char *sha1, enum object_type *type,
return buf; return buf;
map = map_sha1_file(sha1, &mapsize); map = map_sha1_file(sha1, &mapsize);
if (map) { if (map) {
buf = unpack_sha1_file(map, mapsize, type, size); buf = unpack_sha1_file(map, mapsize, type, size, sha1);
munmap(map, mapsize); munmap(map, mapsize);
return buf; return buf;
} }