diff options
-rw-r--r-- | builtin-fsck.c | 28 | ||||
-rw-r--r-- | cache.h | 1 | ||||
-rw-r--r-- | sha1_file.c | 27 |
3 files changed, 41 insertions, 15 deletions
diff --git a/builtin-fsck.c b/builtin-fsck.c index 39cfc32818..b8e71b640b 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -18,6 +18,9 @@ static int check_full; static int check_strict; static int keep_cache_objects; static unsigned char head_sha1[20]; +static int errors_found; +#define ERROR_OBJECT 01 +#define ERROR_REACHABLE 02 #ifdef NO_D_INO_IN_DIRENT #define SORT_DIRENT 0 @@ -40,6 +43,7 @@ static int objerror(struct object *obj, const char *err, ...) { va_list params; va_start(params, err); + errors_found |= ERROR_OBJECT; objreport(obj, "error", err, params); va_end(params); return -1; @@ -67,9 +71,10 @@ static void check_reachable_object(struct object *obj) * do a full fsck */ if (!obj->parsed) { - if (has_sha1_file(obj->sha1)) + if (has_sha1_pack(obj->sha1, NULL)) return; /* it is in pack - forget about it */ printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1)); + errors_found |= ERROR_REACHABLE; return; } @@ -88,6 +93,7 @@ static void check_reachable_object(struct object *obj) typename(obj->type), sha1_to_hex(obj->sha1)); printf(" to %7s %s\n", 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) { struct object *obj = parse_object(sha1); - if (!obj) - return error("%s: object corrupt or missing", sha1_to_hex(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; @@ -359,8 +368,10 @@ static int fsck_sha1(unsigned char *sha1) return fsck_commit((struct commit *) obj); if (obj->type == OBJ_TAG) return fsck_tag((struct tag *) obj); + /* 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; } +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 i, heads; track_object_refs = 1; + errors_found = 0; for (i = 1; i < argc; i++) { const char *arg = argv[i]; @@ -610,7 +626,7 @@ int cmd_fsck(int argc, char **argv, const char *prefix) continue; } if (*arg == '-') - usage("git-fsck [--tags] [--root] [[--unreachable] [--cache] [--full] [--strict] <head-sha1>*]"); + usage(fsck_usage); } fsck_head_link(); @@ -690,5 +706,5 @@ int cmd_fsck(int argc, char **argv, const char *prefix) } check_connectivity(); - return 0; + return errors_found; } @@ -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 */ 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 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); diff --git a/sha1_file.c b/sha1_file.c index 219a10f403..7faa8bcd50 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -967,11 +967,12 @@ static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned lon 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; unsigned char *buf = xmalloc(1+size); unsigned long n; + int status = Z_OK; n = stream->total_out - bytes; if (n > size) @@ -981,12 +982,22 @@ static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size if (bytes < size) { stream->next_out = buf + bytes; stream->avail_out = size - bytes; - while (inflate(stream, Z_FINISH) == Z_OK) - /* nothing */; + while (status == Z_OK) + status = inflate(stream, Z_FINISH); } buf[size] = 0; - inflateEnd(stream); - return buf; + if ((status == Z_OK || status == Z_STREAM_END) && !stream->avail_in) { + inflateEnd(stream); + 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); } -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; 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) 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, @@ -1571,7 +1582,7 @@ void *read_sha1_file(const unsigned char *sha1, enum object_type *type, return buf; map = map_sha1_file(sha1, &mapsize); if (map) { - buf = unpack_sha1_file(map, mapsize, type, size); + buf = unpack_sha1_file(map, mapsize, type, size, sha1); munmap(map, mapsize); return buf; } |