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:
commit
8509fed75d
@ -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;
|
||||||
}
|
}
|
||||||
|
1
cache.h
1
cache.h
@ -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);
|
||||||
|
23
sha1_file.c
23
sha1_file.c
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user