Merge branch 'jc/pack'
* jc/pack: more lightweight revalidation while reusing deflated stream in packing pack-objects: fix thinko in revalidate code pack-objects: re-validate data we copy from elsewhere.
This commit is contained in:
commit
8f5d6b469f
@ -65,6 +65,7 @@ static unsigned char pack_file_sha1[20];
|
|||||||
static int progress = 1;
|
static int progress = 1;
|
||||||
static volatile sig_atomic_t progress_update;
|
static volatile sig_atomic_t progress_update;
|
||||||
static int window = 10;
|
static int window = 10;
|
||||||
|
static int pack_to_stdout;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The object names in objects array are hashed with this hashtable,
|
* The object names in objects array are hashed with this hashtable,
|
||||||
@ -242,6 +243,82 @@ static int encode_header(enum object_type type, unsigned long size, unsigned cha
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int check_inflate(unsigned char *data, unsigned long len, unsigned long expect)
|
||||||
|
{
|
||||||
|
z_stream stream;
|
||||||
|
unsigned char fakebuf[4096];
|
||||||
|
int st;
|
||||||
|
|
||||||
|
memset(&stream, 0, sizeof(stream));
|
||||||
|
stream.next_in = data;
|
||||||
|
stream.avail_in = len;
|
||||||
|
stream.next_out = fakebuf;
|
||||||
|
stream.avail_out = sizeof(fakebuf);
|
||||||
|
inflateInit(&stream);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
st = inflate(&stream, Z_FINISH);
|
||||||
|
if (st == Z_STREAM_END || st == Z_OK) {
|
||||||
|
st = (stream.total_out == expect &&
|
||||||
|
stream.total_in == len) ? 0 : -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (st != Z_BUF_ERROR) {
|
||||||
|
st = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
stream.next_out = fakebuf;
|
||||||
|
stream.avail_out = sizeof(fakebuf);
|
||||||
|
}
|
||||||
|
inflateEnd(&stream);
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we are going to reuse the existing pack entry data. make
|
||||||
|
* sure it is not corrupt.
|
||||||
|
*/
|
||||||
|
static int revalidate_pack_entry(struct object_entry *entry, unsigned char *data, unsigned long len)
|
||||||
|
{
|
||||||
|
enum object_type type;
|
||||||
|
unsigned long size, used;
|
||||||
|
|
||||||
|
if (pack_to_stdout)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* the caller has already called use_packed_git() for us,
|
||||||
|
* so it is safe to access the pack data from mmapped location.
|
||||||
|
* make sure the entry inflates correctly.
|
||||||
|
*/
|
||||||
|
used = unpack_object_header_gently(data, len, &type, &size);
|
||||||
|
if (!used)
|
||||||
|
return -1;
|
||||||
|
if (type == OBJ_DELTA)
|
||||||
|
used += 20; /* skip base object name */
|
||||||
|
data += used;
|
||||||
|
len -= used;
|
||||||
|
return check_inflate(data, len, entry->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int revalidate_loose_object(struct object_entry *entry,
|
||||||
|
unsigned char *map,
|
||||||
|
unsigned long mapsize)
|
||||||
|
{
|
||||||
|
/* we already know this is a loose object with new type header. */
|
||||||
|
enum object_type type;
|
||||||
|
unsigned long size, used;
|
||||||
|
|
||||||
|
if (pack_to_stdout)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
used = unpack_object_header_gently(map, mapsize, &type, &size);
|
||||||
|
if (!used)
|
||||||
|
return -1;
|
||||||
|
map += used;
|
||||||
|
mapsize -= used;
|
||||||
|
return check_inflate(map, mapsize, size);
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned long write_object(struct sha1file *f,
|
static unsigned long write_object(struct sha1file *f,
|
||||||
struct object_entry *entry)
|
struct object_entry *entry)
|
||||||
{
|
{
|
||||||
@ -276,6 +353,9 @@ static unsigned long write_object(struct sha1file *f,
|
|||||||
map = map_sha1_file(entry->sha1, &mapsize);
|
map = map_sha1_file(entry->sha1, &mapsize);
|
||||||
if (map && !legacy_loose_object(map)) {
|
if (map && !legacy_loose_object(map)) {
|
||||||
/* We can copy straight into the pack file */
|
/* We can copy straight into the pack file */
|
||||||
|
if (revalidate_loose_object(entry, map, mapsize))
|
||||||
|
die("corrupt loose object %s",
|
||||||
|
sha1_to_hex(entry->sha1));
|
||||||
sha1write(f, map, mapsize);
|
sha1write(f, map, mapsize);
|
||||||
munmap(map, mapsize);
|
munmap(map, mapsize);
|
||||||
written++;
|
written++;
|
||||||
@ -286,7 +366,7 @@ static unsigned long write_object(struct sha1file *f,
|
|||||||
munmap(map, mapsize);
|
munmap(map, mapsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! to_reuse) {
|
if (!to_reuse) {
|
||||||
buf = read_sha1_file(entry->sha1, type, &size);
|
buf = read_sha1_file(entry->sha1, type, &size);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
die("unable to read %s", sha1_to_hex(entry->sha1));
|
die("unable to read %s", sha1_to_hex(entry->sha1));
|
||||||
@ -319,6 +399,9 @@ static unsigned long write_object(struct sha1file *f,
|
|||||||
|
|
||||||
datalen = find_packed_object_size(p, entry->in_pack_offset);
|
datalen = find_packed_object_size(p, entry->in_pack_offset);
|
||||||
buf = (char *) p->pack_base + entry->in_pack_offset;
|
buf = (char *) p->pack_base + entry->in_pack_offset;
|
||||||
|
|
||||||
|
if (revalidate_pack_entry(entry, buf, datalen))
|
||||||
|
die("corrupt delta in pack %s", sha1_to_hex(entry->sha1));
|
||||||
sha1write(f, buf, datalen);
|
sha1write(f, buf, datalen);
|
||||||
unuse_packed_git(p);
|
unuse_packed_git(p);
|
||||||
hdrlen = 0; /* not really */
|
hdrlen = 0; /* not really */
|
||||||
@ -1163,7 +1246,7 @@ static void prepare_pack(int window, int depth)
|
|||||||
find_deltas(sorted_by_type, window+1, depth);
|
find_deltas(sorted_by_type, window+1, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int reuse_cached_pack(unsigned char *sha1, int pack_to_stdout)
|
static int reuse_cached_pack(unsigned char *sha1)
|
||||||
{
|
{
|
||||||
static const char cache[] = "pack-cache/pack-%s.%s";
|
static const char cache[] = "pack-cache/pack-%s.%s";
|
||||||
char *cached_pack, *cached_idx;
|
char *cached_pack, *cached_idx;
|
||||||
@ -1247,7 +1330,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
|||||||
{
|
{
|
||||||
SHA_CTX ctx;
|
SHA_CTX ctx;
|
||||||
char line[40 + 1 + PATH_MAX + 2];
|
char line[40 + 1 + PATH_MAX + 2];
|
||||||
int depth = 10, pack_to_stdout = 0;
|
int depth = 10;
|
||||||
struct object_entry **list;
|
struct object_entry **list;
|
||||||
int num_preferred_base = 0;
|
int num_preferred_base = 0;
|
||||||
int i;
|
int i;
|
||||||
@ -1367,7 +1450,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
|||||||
if (progress && (nr_objects != nr_result))
|
if (progress && (nr_objects != nr_result))
|
||||||
fprintf(stderr, "Result has %d objects.\n", nr_result);
|
fprintf(stderr, "Result has %d objects.\n", nr_result);
|
||||||
|
|
||||||
if (reuse_cached_pack(object_list_sha1, pack_to_stdout))
|
if (reuse_cached_pack(object_list_sha1))
|
||||||
;
|
;
|
||||||
else {
|
else {
|
||||||
if (nr_result)
|
if (nr_result)
|
||||||
|
12
cache.h
12
cache.h
@ -267,6 +267,17 @@ extern int legacy_loose_object(unsigned char *);
|
|||||||
extern int has_pack_file(const unsigned char *sha1);
|
extern int has_pack_file(const unsigned char *sha1);
|
||||||
extern int has_pack_index(const unsigned char *sha1);
|
extern int has_pack_index(const unsigned char *sha1);
|
||||||
|
|
||||||
|
enum object_type {
|
||||||
|
OBJ_NONE = 0,
|
||||||
|
OBJ_COMMIT = 1,
|
||||||
|
OBJ_TREE = 2,
|
||||||
|
OBJ_BLOB = 3,
|
||||||
|
OBJ_TAG = 4,
|
||||||
|
/* 5/6 for future expansion */
|
||||||
|
OBJ_DELTA = 7,
|
||||||
|
OBJ_BAD,
|
||||||
|
};
|
||||||
|
|
||||||
/* Convert to/from hex/sha1 representation */
|
/* Convert to/from hex/sha1 representation */
|
||||||
#define MINIMUM_ABBREV 4
|
#define MINIMUM_ABBREV 4
|
||||||
#define DEFAULT_ABBREV 7
|
#define DEFAULT_ABBREV 7
|
||||||
@ -374,6 +385,7 @@ extern int num_packed_objects(const struct packed_git *p);
|
|||||||
extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*);
|
extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*);
|
||||||
extern int find_pack_entry_one(const unsigned char *, struct pack_entry *, struct packed_git *);
|
extern int find_pack_entry_one(const unsigned char *, struct pack_entry *, struct packed_git *);
|
||||||
extern void *unpack_entry_gently(struct pack_entry *, char *, unsigned long *);
|
extern void *unpack_entry_gently(struct pack_entry *, char *, unsigned long *);
|
||||||
|
extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
|
||||||
extern void packed_object_info_detail(struct pack_entry *, char *, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
|
extern void packed_object_info_detail(struct pack_entry *, char *, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
|
||||||
|
|
||||||
/* Dumb servers support */
|
/* Dumb servers support */
|
||||||
|
11
object.h
11
object.h
@ -27,17 +27,6 @@ struct object_array {
|
|||||||
/*
|
/*
|
||||||
* The object type is stored in 3 bits.
|
* The object type is stored in 3 bits.
|
||||||
*/
|
*/
|
||||||
enum object_type {
|
|
||||||
OBJ_NONE = 0,
|
|
||||||
OBJ_COMMIT = 1,
|
|
||||||
OBJ_TREE = 2,
|
|
||||||
OBJ_BLOB = 3,
|
|
||||||
OBJ_TAG = 4,
|
|
||||||
/* 5/6 for future expansion */
|
|
||||||
OBJ_DELTA = 7,
|
|
||||||
OBJ_BAD,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct object {
|
struct object {
|
||||||
unsigned parsed : 1;
|
unsigned parsed : 1;
|
||||||
unsigned used : 1;
|
unsigned used : 1;
|
||||||
|
@ -711,7 +711,7 @@ int legacy_loose_object(unsigned char *map)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep)
|
unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep)
|
||||||
{
|
{
|
||||||
unsigned shift;
|
unsigned shift;
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
|
Loading…
Reference in New Issue
Block a user