From: Junio C Hamano Date: Sun, 11 Mar 2007 07:10:26 +0000 (-0800) Subject: Merge branch 'jc/fsck' X-Git-Tag: v1.5.1-rc1~63 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/8509fed75d576023f5f2db8542fad102fcc62d4d?ds=inline;hp=-c 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. --- 8509fed75d576023f5f2db8542fad102fcc62d4d diff --combined builtin-fsck.c index 39cfc32818,4d03378c1b..b8e71b640b --- a/builtin-fsck.c +++ b/builtin-fsck.c @@@ -18,6 -18,9 +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 +43,7 @@@ static int objerror(struct object *obj { 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 +71,10 @@@ static void check_reachable_object(stru * 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 +93,7 @@@ 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 +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 +368,10 @@@ 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 +587,16 @@@ static int fsck_cache_tree(struct cache return err; } + static const char fsck_usage[] = + "git-fsck [--tags] [--root] [[--unreachable] [--cache] [--full] " + "[--strict] *]"; + 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 +626,7 @@@ continue; } if (*arg == '-') - usage("git-fsck [--tags] [--root] [[--unreachable] [--cache] [--full] [--strict] *]"); + usage(fsck_usage); } fsck_head_link(); @@@ -632,7 -648,7 +648,7 @@@ verify_pack(p, 0); for (p = packed_git; p; p = p->next) { - int num = num_packed_objects(p); + uint32_t i, num = num_packed_objects(p); for (i = 0; i < num; i++) { unsigned char sha1[20]; nth_packed_object_sha1(p, i, sha1); @@@ -690,5 -706,5 +706,5 @@@ } check_connectivity(); - return 0; + return errors_found; } diff --combined cache.h index ae25759c43,4b5a7541a8..f172d02a65 --- a/cache.h +++ b/cache.h @@@ -281,7 -281,6 +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); @@@ -383,7 -382,7 +382,7 @@@ extern struct packed_git } *packed_git; struct pack_entry { - unsigned int offset; + off_t offset; unsigned char sha1[20]; struct packed_git *p; }; @@@ -422,15 -421,15 +421,15 @@@ extern struct packed_git *find_sha1_pac struct packed_git *packs); extern void pack_report(void); -extern unsigned char* use_pack(struct packed_git *, struct pack_window **, unsigned long, unsigned int *); +extern unsigned char* use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *); extern void unuse_pack(struct pack_window **); extern struct packed_git *add_packed_git(char *, int, int); -extern int num_packed_objects(const struct packed_git *p); -extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*); -extern unsigned long find_pack_entry_one(const unsigned char *, struct packed_git *); -extern void *unpack_entry(struct packed_git *, unsigned long, enum object_type *, unsigned long *); +extern uint32_t num_packed_objects(const struct packed_git *p); +extern int nth_packed_object_sha1(const struct packed_git *, uint32_t, unsigned char*); +extern off_t find_pack_entry_one(const unsigned char *, struct packed_git *); +extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsigned long *); extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep); -extern const char *packed_object_info_detail(struct packed_git *, unsigned long, unsigned long *, unsigned long *, unsigned int *, unsigned char *); +extern const char *packed_object_info_detail(struct packed_git *, off_t, unsigned long *, unsigned long *, unsigned int *, unsigned char *); /* Dumb servers support */ extern int update_server_info(int); @@@ -451,7 -450,7 +450,7 @@@ extern char git_default_email[MAX_GITNA extern char git_default_name[MAX_GITNAME]; extern char *git_commit_encoding; -extern char *git_log_output_encoding; +extern const char *git_log_output_encoding; extern int copy_fd(int ifd, int ofd); extern int read_in_full(int fd, void *buf, size_t count); diff --combined sha1_file.c index 219a10f403,ac6b5e00b6..7faa8bcd50 --- a/sha1_file.c +++ b/sha1_file.c @@@ -349,7 -349,6 +349,7 @@@ static void link_alt_odb_entries(const static void read_info_alternates(const char * relative_base, int depth) { char *map; + size_t mapsz; struct stat st; char path[PATH_MAX]; int fd; @@@ -362,13 -361,12 +362,13 @@@ close(fd); return; } - map = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + mapsz = xsize_t(st.st_size); + map = xmmap(NULL, mapsz, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); - link_alt_odb_entries(map, map + st.st_size, '\n', relative_base, depth); + link_alt_odb_entries(map, map + mapsz, '\n', relative_base, depth); - munmap(map, st.st_size); + munmap(map, mapsz); } void prepare_alt_odb(void) @@@ -432,14 -430,13 +432,14 @@@ void pack_report( pack_mapped, peak_pack_mapped); } -static int check_packed_git_idx(const char *path, unsigned long *idx_size_, - void **idx_map_) +static int check_packed_git_idx(const char *path, + unsigned long *idx_size_, + void **idx_map_) { void *idx_map; uint32_t *index; - unsigned long idx_size; - int nr, i; + size_t idx_size; + uint32_t nr, i; int fd = open(path, O_RDONLY); struct stat st; if (fd < 0) @@@ -448,11 -445,7 +448,11 @@@ close(fd); return -1; } - idx_size = st.st_size; + idx_size = xsize_t(st.st_size); + if (idx_size < 4 * 256 + 20 + 20) { + close(fd); + return error("index file %s is too small", path); + } idx_map = xmmap(NULL, idx_size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); @@@ -460,25 -453,25 +460,25 @@@ *idx_map_ = idx_map; *idx_size_ = idx_size; - /* check index map */ - if (idx_size < 4*256 + 20 + 20) - return error("index file %s is too small", path); - /* a future index format would start with this, as older git * binaries would fail the non-monotonic index check below. * give a nicer warning to the user if we can. */ - if (index[0] == htonl(PACK_IDX_SIGNATURE)) + if (index[0] == htonl(PACK_IDX_SIGNATURE)) { + munmap(idx_map, idx_size); return error("index file %s is a newer version" " and is not supported by this binary" " (try upgrading GIT to a newer version)", path); + } nr = 0; for (i = 0; i < 256; i++) { - unsigned int n = ntohl(index[i]); - if (n < nr) + uint32_t n = ntohl(index[i]); + if (n < nr) { + munmap(idx_map, idx_size); return error("non-monotonic index %s", path); + } nr = n; } @@@ -489,10 -482,8 +489,10 @@@ * - 20-byte SHA1 of the packfile * - 20-byte SHA1 file checksum */ - if (idx_size != 4*256 + nr * 24 + 20 + 20) + if (idx_size != 4*256 + nr * 24 + 20 + 20) { + munmap(idx_map, idx_size); return error("wrong index file size in %s", path); + } return 0; } @@@ -631,7 -622,7 +631,7 @@@ static int open_packed_git(struct packe return -1; } -static int in_window(struct pack_window *win, unsigned long offset) +static int in_window(struct pack_window *win, off_t offset) { /* We must promise at least 20 bytes (one hash) after the * offset is available from this window, otherwise the offset @@@ -646,7 -637,7 +646,7 @@@ unsigned char* use_pack(struct packed_git *p, struct pack_window **w_cursor, - unsigned long offset, + off_t offset, unsigned int *left) { struct pack_window *win = *w_cursor; @@@ -671,13 -662,11 +671,13 @@@ } if (!win) { size_t window_align = packed_git_window_size / 2; + off_t len; win = xcalloc(1, sizeof(*win)); win->offset = (offset / window_align) * window_align; - win->len = p->pack_size - win->offset; - if (win->len > packed_git_window_size) - win->len = packed_git_window_size; + len = p->pack_size - win->offset; + if (len > packed_git_window_size) + len = packed_git_window_size; + win->len = (size_t)len; pack_mapped += win->len; while (packed_git_limit < pack_mapped && unuse_one_window(p)) @@@ -706,7 -695,7 +706,7 @@@ } offset -= win->offset; if (left) - *left = win->len - offset; + *left = win->len - xsize_t(offset); return win->base + offset; } @@@ -882,9 -871,9 +882,9 @@@ void *map_sha1_file(const unsigned cha */ sha1_file_open_flag = 0; } - map = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + *size = xsize_t(st.st_size); + map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); - *size = st.st_size; return map; } @@@ -967,11 -956,12 +967,12 @@@ static int unpack_sha1_header(z_stream 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 -971,22 +982,22 @@@ 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 -1040,7 +1051,7 @@@ static int parse_sha1_header(const cha 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,17 -1050,17 +1061,17 @@@ 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 unsigned long get_delta_base(struct packed_git *p, +static off_t get_delta_base(struct packed_git *p, struct pack_window **w_curs, - unsigned long *curpos, + off_t *curpos, enum object_type type, - unsigned long delta_obj_offset) + off_t delta_obj_offset) { unsigned char *base_info = use_pack(p, w_curs, *curpos, NULL); - unsigned long base_offset; + off_t base_offset; /* use_pack() assured us we have [base_info, base_info + 20) * as a range that we can look at without walking off the @@@ -1096,17 -1096,17 +1107,17 @@@ } /* forward declaration for a mutually recursive function */ -static int packed_object_info(struct packed_git *p, unsigned long offset, +static int packed_object_info(struct packed_git *p, off_t offset, unsigned long *sizep); static int packed_delta_info(struct packed_git *p, struct pack_window **w_curs, - unsigned long curpos, + off_t curpos, enum object_type type, - unsigned long obj_offset, + off_t obj_offset, unsigned long *sizep) { - unsigned long base_offset; + off_t base_offset; base_offset = get_delta_base(p, w_curs, &curpos, type, obj_offset); type = packed_object_info(p, base_offset, NULL); @@@ -1156,7 -1156,7 +1167,7 @@@ static int unpack_object_header(struct packed_git *p, struct pack_window **w_curs, - unsigned long *curpos, + off_t *curpos, unsigned long *sizep) { unsigned char *base; @@@ -1180,15 -1180,14 +1191,15 @@@ } const char *packed_object_info_detail(struct packed_git *p, - unsigned long obj_offset, + off_t obj_offset, unsigned long *size, unsigned long *store_size, unsigned int *delta_chain_length, unsigned char *base_sha1) { struct pack_window *w_curs = NULL; - unsigned long curpos, dummy; + off_t curpos; + unsigned long dummy; unsigned char *next_sha1; enum object_type type; @@@ -1212,7 -1211,6 +1223,7 @@@ obj_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset); if (*delta_chain_length == 0) { /* TODO: find base_sha1 as pointed by curpos */ + hashclr(base_sha1); } break; case OBJ_REF_DELTA: @@@ -1228,12 -1226,11 +1239,12 @@@ } } -static int packed_object_info(struct packed_git *p, unsigned long obj_offset, +static int packed_object_info(struct packed_git *p, off_t obj_offset, unsigned long *sizep) { struct pack_window *w_curs = NULL; - unsigned long size, curpos = obj_offset; + unsigned long size; + off_t curpos = obj_offset; enum object_type type; type = unpack_object_header(p, &w_curs, &curpos, &size); @@@ -1261,7 -1258,7 +1272,7 @@@ static void *unpack_compressed_entry(struct packed_git *p, struct pack_window **w_curs, - unsigned long curpos, + off_t curpos, unsigned long size) { int st; @@@ -1292,22 -1289,20 +1303,22 @@@ static void *unpack_delta_entry(struct packed_git *p, struct pack_window **w_curs, - unsigned long curpos, + off_t curpos, unsigned long delta_size, - unsigned long obj_offset, + off_t obj_offset, enum object_type *type, unsigned long *sizep) { void *delta_data, *result, *base; - unsigned long base_size, base_offset; + unsigned long base_size; + off_t base_offset; base_offset = get_delta_base(p, w_curs, &curpos, *type, obj_offset); base = unpack_entry(p, base_offset, type, &base_size); if (!base) - die("failed to read delta base object at %lu from %s", - base_offset, p->pack_name); + die("failed to read delta base object" + " at %"PRIuMAX" from %s", + (uintmax_t)base_offset, p->pack_name); delta_data = unpack_compressed_entry(p, w_curs, curpos, delta_size); result = patch_delta(base, base_size, @@@ -1320,11 -1315,11 +1331,11 @@@ return result; } -void *unpack_entry(struct packed_git *p, unsigned long obj_offset, +void *unpack_entry(struct packed_git *p, off_t obj_offset, enum object_type *type, unsigned long *sizep) { struct pack_window *w_curs = NULL; - unsigned long curpos = obj_offset; + off_t curpos = obj_offset; void *data; *type = unpack_object_header(p, &w_curs, &curpos, sizep); @@@ -1347,23 -1342,23 +1358,23 @@@ return data; } -int num_packed_objects(const struct packed_git *p) +uint32_t num_packed_objects(const struct packed_git *p) { /* See check_packed_git_idx() */ - return (p->index_size - 20 - 20 - 4*256) / 24; + return (uint32_t)((p->index_size - 20 - 20 - 4*256) / 24); } -int nth_packed_object_sha1(const struct packed_git *p, int n, +int nth_packed_object_sha1(const struct packed_git *p, uint32_t n, unsigned char* sha1) { void *index = p->index_base + 256; - if (n < 0 || num_packed_objects(p) <= n) + if (num_packed_objects(p) <= n) return -1; hashcpy(sha1, (unsigned char *) index + (24 * n) + 4); return 0; } -unsigned long find_pack_entry_one(const unsigned char *sha1, +off_t find_pack_entry_one(const unsigned char *sha1, struct packed_git *p) { uint32_t *level1_ofs = p->index_base; @@@ -1405,7 -1400,7 +1416,7 @@@ static int matches_pack_name(struct pac static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, const char **ignore_packed) { struct packed_git *p; - unsigned long offset; + off_t offset; prepare_packed_git(); @@@ -1571,7 -1566,7 +1582,7 @@@ void *read_sha1_file(const unsigned cha 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; } @@@ -2072,10 -2067,11 +2083,10 @@@ int index_pipe(unsigned char *sha1, in int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path) { - unsigned long size = st->st_size; - void *buf; + size_t size = xsize_t(st->st_size); + void *buf = NULL; int ret, re_allocated = 0; - buf = ""; if (size) buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); @@@ -2115,7 -2111,6 +2126,7 @@@ int index_path(unsigned char *sha1, con { int fd; char *target; + size_t len; switch (st->st_mode & S_IFMT) { case S_IFREG: @@@ -2128,17 -2123,16 +2139,17 @@@ path); break; case S_IFLNK: - target = xmalloc(st->st_size+1); - if (readlink(path, target, st->st_size+1) != st->st_size) { + len = xsize_t(st->st_size); + target = xmalloc(len + 1); + if (readlink(path, target, len + 1) != st->st_size) { char *errstr = strerror(errno); free(target); return error("readlink(\"%s\"): %s", path, errstr); } if (!write_object) - hash_sha1_file(target, st->st_size, blob_type, sha1); - else if (write_sha1_file(target, st->st_size, blob_type, sha1)) + hash_sha1_file(target, len, blob_type, sha1); + else if (write_sha1_file(target, len, blob_type, sha1)) return error("%s: failed to insert into database", path); free(target);