Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
fedc7d5458 | |||
3339e9f686 | |||
852f96b816 | |||
3205364fc4 | |||
c86a54b714 |
@ -110,7 +110,7 @@ int cmd_count_objects(int ac, const char **av, const char *prefix)
|
|||||||
for (p = packed_git; p; p = p->next) {
|
for (p = packed_git; p; p = p->next) {
|
||||||
if (!p->pack_local)
|
if (!p->pack_local)
|
||||||
continue;
|
continue;
|
||||||
packed += num_packed_objects(p);
|
packed += p->num_objects;
|
||||||
}
|
}
|
||||||
printf("count: %lu\n", loose);
|
printf("count: %lu\n", loose);
|
||||||
printf("size: %lu\n", loose_size / 2);
|
printf("size: %lu\n", loose_size / 2);
|
||||||
|
@ -168,16 +168,37 @@ static int cmp_offset(const void *a_, const void *b_)
|
|||||||
static void prepare_pack_revindex(struct pack_revindex *rix)
|
static void prepare_pack_revindex(struct pack_revindex *rix)
|
||||||
{
|
{
|
||||||
struct packed_git *p = rix->p;
|
struct packed_git *p = rix->p;
|
||||||
int num_ent = num_packed_objects(p);
|
int num_ent = p->num_objects;
|
||||||
int i;
|
int i;
|
||||||
void *index = p->index_base + 256;
|
const char *index = p->index_data;
|
||||||
|
|
||||||
rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1));
|
rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1));
|
||||||
for (i = 0; i < num_ent; i++) {
|
index += 4 * 256;
|
||||||
unsigned int hl = *((unsigned int *)((char *) index + 24*i));
|
|
||||||
rix->revindex[i].offset = ntohl(hl);
|
if (p->index_version > 1) {
|
||||||
rix->revindex[i].nr = i;
|
const uint32_t *off_32 =
|
||||||
|
(uint32_t *)(index + 8 + p->num_objects * (20 + 4));
|
||||||
|
const uint32_t *off_64 = off_32 + p->num_objects;
|
||||||
|
for (i = 0; i < num_ent; i++) {
|
||||||
|
uint32_t off = ntohl(*off_32++);
|
||||||
|
if (!(off & 0x80000000)) {
|
||||||
|
rix->revindex[i].offset = off;
|
||||||
|
} else {
|
||||||
|
rix->revindex[i].offset =
|
||||||
|
((uint64_t)ntohl(*off_64++)) << 32;
|
||||||
|
rix->revindex[i].offset |=
|
||||||
|
ntohl(*off_64++);
|
||||||
|
}
|
||||||
|
rix->revindex[i].nr = i;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < num_ent; i++) {
|
||||||
|
uint32_t hl = *((uint32_t *)(index + 24 * i));
|
||||||
|
rix->revindex[i].offset = ntohl(hl);
|
||||||
|
rix->revindex[i].nr = i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This knows the pack format -- the 20-byte trailer
|
/* This knows the pack format -- the 20-byte trailer
|
||||||
* follows immediately after the last object data.
|
* follows immediately after the last object data.
|
||||||
*/
|
*/
|
||||||
@ -201,7 +222,7 @@ static struct revindex_entry * find_packed_object(struct packed_git *p,
|
|||||||
prepare_pack_revindex(rix);
|
prepare_pack_revindex(rix);
|
||||||
revindex = rix->revindex;
|
revindex = rix->revindex;
|
||||||
lo = 0;
|
lo = 0;
|
||||||
hi = num_packed_objects(p) + 1;
|
hi = p->num_objects + 1;
|
||||||
do {
|
do {
|
||||||
int mi = (lo + hi) / 2;
|
int mi = (lo + hi) / 2;
|
||||||
if (revindex[mi].offset == ofs) {
|
if (revindex[mi].offset == ofs) {
|
||||||
@ -222,11 +243,11 @@ static unsigned long find_packed_object_size(struct packed_git *p,
|
|||||||
return entry[1].offset - ofs;
|
return entry[1].offset - ofs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char *find_packed_object_name(struct packed_git *p,
|
static const unsigned char *find_packed_object_name(struct packed_git *p,
|
||||||
unsigned long ofs)
|
unsigned long ofs)
|
||||||
{
|
{
|
||||||
struct revindex_entry *entry = find_packed_object(p, ofs);
|
struct revindex_entry *entry = find_packed_object(p, ofs);
|
||||||
return (unsigned char *)(p->index_base + 256) + 24 * entry->nr + 4;
|
return nth_packed_object_sha1(p, entry->nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *delta_against(void *buf, unsigned long size, struct object_entry *entry)
|
static void *delta_against(void *buf, unsigned long size, struct object_entry *entry)
|
||||||
@ -959,7 +980,8 @@ static void check_object(struct object_entry *entry)
|
|||||||
* delta.
|
* delta.
|
||||||
*/
|
*/
|
||||||
if (!no_reuse_delta) {
|
if (!no_reuse_delta) {
|
||||||
unsigned char c, *base_name;
|
unsigned char c;
|
||||||
|
const unsigned char *base_name;
|
||||||
unsigned long ofs;
|
unsigned long ofs;
|
||||||
/* there is at least 20 bytes left in the pack */
|
/* there is at least 20 bytes left in the pack */
|
||||||
switch (entry->in_pack_type) {
|
switch (entry->in_pack_type) {
|
||||||
|
9
cache.h
9
cache.h
@ -334,8 +334,10 @@ extern struct packed_git {
|
|||||||
struct packed_git *next;
|
struct packed_git *next;
|
||||||
unsigned long index_size;
|
unsigned long index_size;
|
||||||
unsigned long pack_size;
|
unsigned long pack_size;
|
||||||
unsigned int *index_base;
|
const void *index_data;
|
||||||
void *pack_base;
|
void *pack_base;
|
||||||
|
unsigned int num_objects;
|
||||||
|
int index_version;
|
||||||
unsigned int pack_last_used;
|
unsigned int pack_last_used;
|
||||||
unsigned int pack_use_cnt;
|
unsigned int pack_use_cnt;
|
||||||
int pack_local;
|
int pack_local;
|
||||||
@ -374,7 +376,7 @@ extern int server_supports(const char *feature);
|
|||||||
|
|
||||||
extern struct packed_git *parse_pack_index(unsigned char *sha1);
|
extern struct packed_git *parse_pack_index(unsigned char *sha1);
|
||||||
extern struct packed_git *parse_pack_index_file(const unsigned char *sha1,
|
extern struct packed_git *parse_pack_index_file(const unsigned char *sha1,
|
||||||
char *idx_path);
|
const char *idx_path);
|
||||||
|
|
||||||
extern void prepare_packed_git(void);
|
extern void prepare_packed_git(void);
|
||||||
extern void reprepare_packed_git(void);
|
extern void reprepare_packed_git(void);
|
||||||
@ -386,8 +388,7 @@ extern struct packed_git *find_sha1_pack(const unsigned char *sha1,
|
|||||||
extern int use_packed_git(struct packed_git *);
|
extern int use_packed_git(struct packed_git *);
|
||||||
extern void unuse_packed_git(struct packed_git *);
|
extern void unuse_packed_git(struct packed_git *);
|
||||||
extern struct packed_git *add_packed_git(char *, int, int);
|
extern struct packed_git *add_packed_git(char *, int, int);
|
||||||
extern int num_packed_objects(const struct packed_git *p);
|
extern const unsigned char *nth_packed_object_sha1(const struct packed_git *, unsigned int);
|
||||||
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 unsigned long find_pack_entry_one(const unsigned char *, struct packed_git *);
|
||||||
extern void *unpack_entry_gently(struct packed_git *, unsigned long, char *, unsigned long *);
|
extern void *unpack_entry_gently(struct packed_git *, unsigned long, 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 unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
|
||||||
|
@ -289,7 +289,7 @@ static int fsck_tag(struct tag *tag)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fsck_sha1(unsigned char *sha1)
|
static int fsck_sha1(const unsigned char *sha1)
|
||||||
{
|
{
|
||||||
struct object *obj = parse_object(sha1);
|
struct object *obj = parse_object(sha1);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
@ -550,12 +550,9 @@ int main(int argc, char **argv)
|
|||||||
verify_pack(p, 0);
|
verify_pack(p, 0);
|
||||||
|
|
||||||
for (p = packed_git; p; p = p->next) {
|
for (p = packed_git; p; p = p->next) {
|
||||||
int num = num_packed_objects(p);
|
int num = p->num_objects;
|
||||||
for (i = 0; i < num; i++) {
|
for (i = 0; i < num; i++)
|
||||||
unsigned char sha1[20];
|
fsck_sha1(nth_packed_object_sha1(p, i));
|
||||||
nth_packed_object_sha1(p, i, sha1);
|
|
||||||
fsck_sha1(sha1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
23
pack-check.c
23
pack-check.c
@ -6,7 +6,7 @@
|
|||||||
static int verify_packfile(struct packed_git *p)
|
static int verify_packfile(struct packed_git *p)
|
||||||
{
|
{
|
||||||
unsigned long index_size = p->index_size;
|
unsigned long index_size = p->index_size;
|
||||||
void *index_base = p->index_base;
|
const unsigned char *index_base = p->index_data;
|
||||||
SHA_CTX ctx;
|
SHA_CTX ctx;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
struct pack_header *hdr;
|
struct pack_header *hdr;
|
||||||
@ -22,10 +22,10 @@ static int verify_packfile(struct packed_git *p)
|
|||||||
return error("Packfile version %d unsupported",
|
return error("Packfile version %d unsupported",
|
||||||
ntohl(hdr->hdr_version));
|
ntohl(hdr->hdr_version));
|
||||||
nr_objects = ntohl(hdr->hdr_entries);
|
nr_objects = ntohl(hdr->hdr_entries);
|
||||||
if (num_packed_objects(p) != nr_objects)
|
if (p->num_objects != nr_objects)
|
||||||
return error("Packfile claims to have %d objects, "
|
return error("Packfile claims to have %d objects, "
|
||||||
"while idx size expects %d", nr_objects,
|
"while idx size expects %d", nr_objects,
|
||||||
num_packed_objects(p));
|
p->num_objects);
|
||||||
|
|
||||||
/* Check integrity of pack data with its SHA-1 checksum */
|
/* Check integrity of pack data with its SHA-1 checksum */
|
||||||
SHA1_Init(&ctx);
|
SHA1_Init(&ctx);
|
||||||
@ -42,7 +42,7 @@ static int verify_packfile(struct packed_git *p)
|
|||||||
if (hashcmp(sha1, (unsigned char *)(p->pack_base) + p->pack_size - 20))
|
if (hashcmp(sha1, (unsigned char *)(p->pack_base) + p->pack_size - 20))
|
||||||
return error("Packfile %s SHA1 mismatch with itself",
|
return error("Packfile %s SHA1 mismatch with itself",
|
||||||
p->pack_name);
|
p->pack_name);
|
||||||
if (hashcmp(sha1, (unsigned char *)index_base + index_size - 40))
|
if (hashcmp(sha1, index_base + index_size - 40))
|
||||||
return error("Packfile %s SHA1 mismatch with idx",
|
return error("Packfile %s SHA1 mismatch with idx",
|
||||||
p->pack_name);
|
p->pack_name);
|
||||||
|
|
||||||
@ -51,12 +51,13 @@ static int verify_packfile(struct packed_git *p)
|
|||||||
* we do not do scan-streaming check on the pack file.
|
* we do not do scan-streaming check on the pack file.
|
||||||
*/
|
*/
|
||||||
for (i = err = 0; i < nr_objects; i++) {
|
for (i = err = 0; i < nr_objects; i++) {
|
||||||
unsigned char sha1[20];
|
const unsigned char *sha1;
|
||||||
void *data;
|
void *data;
|
||||||
char type[20];
|
char type[20];
|
||||||
unsigned long size, offset;
|
unsigned long size, offset;
|
||||||
|
|
||||||
if (nth_packed_object_sha1(p, i, sha1))
|
sha1 = nth_packed_object_sha1(p, i);
|
||||||
|
if (!sha1)
|
||||||
die("internal error pack-check nth-packed-object");
|
die("internal error pack-check nth-packed-object");
|
||||||
offset = find_pack_entry_one(sha1, p);
|
offset = find_pack_entry_one(sha1, p);
|
||||||
if (!offset)
|
if (!offset)
|
||||||
@ -93,14 +94,16 @@ static void show_pack_info(struct packed_git *p)
|
|||||||
memset(chain_histogram, 0, sizeof(chain_histogram));
|
memset(chain_histogram, 0, sizeof(chain_histogram));
|
||||||
|
|
||||||
for (i = 0; i < nr_objects; i++) {
|
for (i = 0; i < nr_objects; i++) {
|
||||||
unsigned char sha1[20], base_sha1[20];
|
const unsigned char *sha1;
|
||||||
|
unsigned char base_sha1[20];
|
||||||
char type[20];
|
char type[20];
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
unsigned long store_size;
|
unsigned long store_size;
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
unsigned int delta_chain_length;
|
unsigned int delta_chain_length;
|
||||||
|
|
||||||
if (nth_packed_object_sha1(p, i, sha1))
|
sha1 = nth_packed_object_sha1(p, i);
|
||||||
|
if (!sha1)
|
||||||
die("internal error pack-check nth-packed-object");
|
die("internal error pack-check nth-packed-object");
|
||||||
offset = find_pack_entry_one(sha1, p);
|
offset = find_pack_entry_one(sha1, p);
|
||||||
if (!offset)
|
if (!offset)
|
||||||
@ -136,7 +139,7 @@ static void show_pack_info(struct packed_git *p)
|
|||||||
int verify_pack(struct packed_git *p, int verbose)
|
int verify_pack(struct packed_git *p, int verbose)
|
||||||
{
|
{
|
||||||
unsigned long index_size = p->index_size;
|
unsigned long index_size = p->index_size;
|
||||||
void *index_base = p->index_base;
|
const unsigned char *index_base = p->index_data;
|
||||||
SHA_CTX ctx;
|
SHA_CTX ctx;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
int ret;
|
int ret;
|
||||||
@ -146,7 +149,7 @@ int verify_pack(struct packed_git *p, int verbose)
|
|||||||
SHA1_Init(&ctx);
|
SHA1_Init(&ctx);
|
||||||
SHA1_Update(&ctx, index_base, index_size - 20);
|
SHA1_Update(&ctx, index_base, index_size - 20);
|
||||||
SHA1_Final(sha1, &ctx);
|
SHA1_Final(sha1, &ctx);
|
||||||
if (hashcmp(sha1, (unsigned char *)index_base + index_size - 20))
|
if (hashcmp(sha1, index_base + index_size - 20))
|
||||||
ret = error("Packfile index for %s SHA1 mismatch",
|
ret = error("Packfile index for %s SHA1 mismatch",
|
||||||
p->pack_name);
|
p->pack_name);
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ static int load_all_packs, verbose, alt_odb;
|
|||||||
|
|
||||||
struct llist_item {
|
struct llist_item {
|
||||||
struct llist_item *next;
|
struct llist_item *next;
|
||||||
unsigned char *sha1;
|
const unsigned char *sha1;
|
||||||
};
|
};
|
||||||
static struct llist {
|
static struct llist {
|
||||||
struct llist_item *front;
|
struct llist_item *front;
|
||||||
@ -104,9 +104,9 @@ static struct llist * llist_copy(struct llist *list)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct llist_item * llist_insert(struct llist *list,
|
static inline struct llist_item *llist_insert(struct llist *list,
|
||||||
struct llist_item *after,
|
struct llist_item *after,
|
||||||
unsigned char *sha1)
|
const unsigned char *sha1)
|
||||||
{
|
{
|
||||||
struct llist_item *new = llist_item_get();
|
struct llist_item *new = llist_item_get();
|
||||||
new->sha1 = sha1;
|
new->sha1 = sha1;
|
||||||
@ -128,12 +128,14 @@ static inline struct llist_item * llist_insert(struct llist *list,
|
|||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct llist_item *llist_insert_back(struct llist *list, unsigned char *sha1)
|
static inline struct llist_item *llist_insert_back(struct llist *list,
|
||||||
|
const unsigned char *sha1)
|
||||||
{
|
{
|
||||||
return llist_insert(list, list->back, sha1);
|
return llist_insert(list, list->back, sha1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct llist_item *llist_insert_sorted_unique(struct llist *list, unsigned char *sha1, struct llist_item *hint)
|
static inline struct llist_item *llist_insert_sorted_unique(struct llist *list,
|
||||||
|
const unsigned char *sha1, struct llist_item *hint)
|
||||||
{
|
{
|
||||||
struct llist_item *prev = NULL, *l;
|
struct llist_item *prev = NULL, *l;
|
||||||
|
|
||||||
@ -246,12 +248,12 @@ static struct pack_list * pack_list_difference(const struct pack_list *A,
|
|||||||
static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
|
static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
|
||||||
{
|
{
|
||||||
int p1_off, p2_off;
|
int p1_off, p2_off;
|
||||||
unsigned char *p1_base, *p2_base;
|
const unsigned char *p1_base, *p2_base;
|
||||||
struct llist_item *p1_hint = NULL, *p2_hint = NULL;
|
struct llist_item *p1_hint = NULL, *p2_hint = NULL;
|
||||||
|
|
||||||
p1_off = p2_off = 256 * 4 + 4;
|
p1_off = p2_off = 256 * 4 + 4;
|
||||||
p1_base = (unsigned char *) p1->pack->index_base;
|
p1_base = p1->pack->index_data;
|
||||||
p2_base = (unsigned char *) p2->pack->index_base;
|
p2_base = p2->pack->index_data;
|
||||||
|
|
||||||
while (p1_off <= p1->pack->index_size - 3 * 20 &&
|
while (p1_off <= p1->pack->index_size - 3 * 20 &&
|
||||||
p2_off <= p2->pack->index_size - 3 * 20)
|
p2_off <= p2->pack->index_size - 3 * 20)
|
||||||
@ -351,11 +353,11 @@ static size_t sizeof_union(struct packed_git *p1, struct packed_git *p2)
|
|||||||
{
|
{
|
||||||
size_t ret = 0;
|
size_t ret = 0;
|
||||||
int p1_off, p2_off;
|
int p1_off, p2_off;
|
||||||
unsigned char *p1_base, *p2_base;
|
const unsigned char *p1_base, *p2_base;
|
||||||
|
|
||||||
p1_off = p2_off = 256 * 4 + 4;
|
p1_off = p2_off = 256 * 4 + 4;
|
||||||
p1_base = (unsigned char *)p1->index_base;
|
p1_base = p1->index_data;
|
||||||
p2_base = (unsigned char *)p2->index_base;
|
p2_base = p2->index_data;
|
||||||
|
|
||||||
while (p1_off <= p1->index_size - 3 * 20 &&
|
while (p1_off <= p1->index_size - 3 * 20 &&
|
||||||
p2_off <= p2->index_size - 3 * 20)
|
p2_off <= p2->index_size - 3 * 20)
|
||||||
@ -534,7 +536,7 @@ static struct pack_list * add_pack(struct packed_git *p)
|
|||||||
{
|
{
|
||||||
struct pack_list l;
|
struct pack_list l;
|
||||||
size_t off;
|
size_t off;
|
||||||
unsigned char *base;
|
const unsigned char *base;
|
||||||
|
|
||||||
if (!p->pack_local && !(alt_odb || verbose))
|
if (!p->pack_local && !(alt_odb || verbose))
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -543,7 +545,7 @@ static struct pack_list * add_pack(struct packed_git *p)
|
|||||||
llist_init(&l.all_objects);
|
llist_init(&l.all_objects);
|
||||||
|
|
||||||
off = 256 * 4 + 4;
|
off = 256 * 4 + 4;
|
||||||
base = (unsigned char *)p->index_base;
|
base = p->index_data;
|
||||||
while (off <= p->index_size - 3 * 20) {
|
while (off <= p->index_size - 3 * 20) {
|
||||||
llist_insert_back(l.all_objects, base + off);
|
llist_insert_back(l.all_objects, base + off);
|
||||||
off += 24;
|
off += 24;
|
||||||
|
28
pack.h
28
pack.h
@ -15,5 +15,33 @@ struct pack_header {
|
|||||||
unsigned int hdr_entries;
|
unsigned int hdr_entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The first four bytes of index formats later than version 1 should
|
||||||
|
* start with this signature, as all older git binaries would find this
|
||||||
|
* value illegal and abort reading the file.
|
||||||
|
*
|
||||||
|
* This is the case because the number of objects in a packfile
|
||||||
|
* cannot exceed 1,431,660,000 as every object would need at least
|
||||||
|
* 3 bytes of data and the overall packfile cannot exceed 4 GiB with
|
||||||
|
* version 1 of the index file due to the offsets limited to 32 bits.
|
||||||
|
* Clearly the signature exceeds this maximum.
|
||||||
|
*
|
||||||
|
* Very old git binaries will also compare the first 4 bytes to the
|
||||||
|
* next 4 bytes in the index and abort with a "non-monotonic index"
|
||||||
|
* error if the second 4 byte word is smaller than the first 4
|
||||||
|
* byte word. This would be true in the proposed future index
|
||||||
|
* format as idx_signature would be greater than idx_version.
|
||||||
|
*/
|
||||||
|
#define PACK_IDX_SIGNATURE 0xff744f63 /* "\377tOc" */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Packed object index header
|
||||||
|
*/
|
||||||
|
struct pack_idx_header {
|
||||||
|
uint32_t idx_signature;
|
||||||
|
uint32_t idx_version;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
extern int verify_pack(struct packed_git *, int);
|
extern int verify_pack(struct packed_git *, int);
|
||||||
#endif
|
#endif
|
||||||
|
191
sha1_file.c
191
sha1_file.c
@ -402,15 +402,15 @@ static int pack_used_ctr;
|
|||||||
static unsigned long pack_mapped;
|
static unsigned long pack_mapped;
|
||||||
struct packed_git *packed_git;
|
struct packed_git *packed_git;
|
||||||
|
|
||||||
static int check_packed_git_idx(const char *path, unsigned long *idx_size_,
|
static int check_packed_git_idx(const char *path, struct packed_git *p)
|
||||||
void **idx_map_)
|
|
||||||
{
|
{
|
||||||
void *idx_map;
|
void *idx_map;
|
||||||
unsigned int *index;
|
struct pack_idx_header *hdr;
|
||||||
unsigned long idx_size;
|
unsigned long idx_size;
|
||||||
int nr, i;
|
unsigned int version, nr, i, *index;
|
||||||
int fd = open(path, O_RDONLY);
|
int fd = open(path, O_RDONLY);
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (fstat(fd, &st)) {
|
if (fstat(fd, &st)) {
|
||||||
@ -423,14 +423,23 @@ static int check_packed_git_idx(const char *path, unsigned long *idx_size_,
|
|||||||
if (idx_map == MAP_FAILED)
|
if (idx_map == MAP_FAILED)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
index = idx_map;
|
hdr = idx_map;
|
||||||
*idx_map_ = idx_map;
|
if (hdr->idx_signature == htonl(PACK_IDX_SIGNATURE)) {
|
||||||
*idx_size_ = idx_size;
|
version = ntohl(hdr->idx_version);
|
||||||
|
if (version < 2 || version > 2) {
|
||||||
|
munmap(idx_map, idx_size);
|
||||||
|
return error("index file %s is version %d"
|
||||||
|
" and is not supported by this binary"
|
||||||
|
" (try upgrading GIT to a newer version)",
|
||||||
|
path, version);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
version = 1;
|
||||||
|
|
||||||
/* check index map */
|
|
||||||
if (idx_size < 4*256 + 20 + 20)
|
|
||||||
return error("index file too small");
|
|
||||||
nr = 0;
|
nr = 0;
|
||||||
|
index = idx_map;
|
||||||
|
if (version > 1)
|
||||||
|
index += 2; /* skip index header */
|
||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++) {
|
||||||
unsigned int n = ntohl(index[i]);
|
unsigned int n = ntohl(index[i]);
|
||||||
if (n < nr)
|
if (n < nr)
|
||||||
@ -438,16 +447,50 @@ static int check_packed_git_idx(const char *path, unsigned long *idx_size_,
|
|||||||
nr = n;
|
nr = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (version == 1) {
|
||||||
* Total size:
|
/*
|
||||||
* - 256 index entries 4 bytes each
|
* Total size:
|
||||||
* - 24-byte entries * nr (20-byte sha1 + 4-byte offset)
|
* - 256 index entries 4 bytes each
|
||||||
* - 20-byte SHA1 of the packfile
|
* - 24-byte entries * nr (20-byte sha1 + 4-byte offset)
|
||||||
* - 20-byte SHA1 file checksum
|
* - 20-byte SHA1 of the packfile
|
||||||
*/
|
* - 20-byte SHA1 file checksum
|
||||||
if (idx_size != 4*256 + nr * 24 + 20 + 20)
|
*/
|
||||||
return error("wrong index file size");
|
if (idx_size != 4*256 + nr * 24 + 20 + 20) {
|
||||||
|
munmap(idx_map, idx_size);
|
||||||
|
return error("wrong index file size in %s", path);
|
||||||
|
}
|
||||||
|
} else if (version == 2) {
|
||||||
|
/*
|
||||||
|
* Minimum size:
|
||||||
|
* - 8 bytes of header
|
||||||
|
* - 256 index entries 4 bytes each
|
||||||
|
* - 20-byte sha1 entry * nr
|
||||||
|
* - 4-byte crc entry * nr
|
||||||
|
* - 4-byte offset entry * nr
|
||||||
|
* - 20-byte SHA1 of the packfile
|
||||||
|
* - 20-byte SHA1 file checksum
|
||||||
|
* And after the 4-byte offset table might be a
|
||||||
|
* variable sized table containing 8-byte entries
|
||||||
|
* for offsets larger than 2^31.
|
||||||
|
*/
|
||||||
|
unsigned long min_size = 8 + 4*256 + nr*(20 + 4 + 4) + 20 + 20;
|
||||||
|
if (idx_size < min_size || idx_size > min_size + (nr - 1)*8) {
|
||||||
|
munmap(idx_map, idx_size);
|
||||||
|
return error("wrong index file size in %s", path);
|
||||||
|
}
|
||||||
|
if (idx_size != min_size) {
|
||||||
|
/* make sure we can deal with large pack offsets */
|
||||||
|
if (sizeof(unsigned long) <= 4) {
|
||||||
|
munmap(idx_map, idx_size);
|
||||||
|
return error("pack %s too large -- please upgrade your git version", path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p->index_version = version;
|
||||||
|
p->index_data = idx_map;
|
||||||
|
p->index_size = idx_size;
|
||||||
|
p->num_objects = nr;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,7 +564,7 @@ int use_packed_git(struct packed_git *p)
|
|||||||
/* Check if the pack file matches with the index file.
|
/* Check if the pack file matches with the index file.
|
||||||
* this is cheap.
|
* this is cheap.
|
||||||
*/
|
*/
|
||||||
if (hashcmp((unsigned char *)(p->index_base) +
|
if (hashcmp((unsigned char *)(p->index_data) +
|
||||||
p->index_size - 40,
|
p->index_size - 40,
|
||||||
(unsigned char *)p->pack_base +
|
(unsigned char *)p->pack_base +
|
||||||
p->pack_size - 20)) {
|
p->pack_size - 20)) {
|
||||||
@ -536,35 +579,34 @@ int use_packed_git(struct packed_git *p)
|
|||||||
struct packed_git *add_packed_git(char *path, int path_len, int local)
|
struct packed_git *add_packed_git(char *path, int path_len, int local)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
struct packed_git *p;
|
struct packed_git *p = xmalloc(sizeof(*p) + path_len + 2);
|
||||||
unsigned long idx_size;
|
|
||||||
void *idx_map;
|
|
||||||
unsigned char sha1[20];
|
|
||||||
|
|
||||||
if (check_packed_git_idx(path, &idx_size, &idx_map))
|
/*
|
||||||
|
* Make sure a corresponding .pack file exists and that
|
||||||
|
* the index looks sane.
|
||||||
|
*/
|
||||||
|
path_len -= strlen(".idx");
|
||||||
|
if (path_len < 1)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
memcpy(p->pack_name, path, path_len);
|
||||||
/* do we have a corresponding .pack file? */
|
strcpy(p->pack_name + path_len, ".pack");
|
||||||
strcpy(path + path_len - 4, ".pack");
|
if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode) ||
|
||||||
if (stat(path, &st) || !S_ISREG(st.st_mode)) {
|
check_packed_git_idx(path, p)) {
|
||||||
munmap(idx_map, idx_size);
|
free(p);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ok, it looks sane as far as we can check without
|
/* ok, it looks sane as far as we can check without
|
||||||
* actually mapping the pack file.
|
* actually mapping the pack file.
|
||||||
*/
|
*/
|
||||||
p = xmalloc(sizeof(*p) + path_len + 2);
|
|
||||||
strcpy(p->pack_name, path);
|
|
||||||
p->index_size = idx_size;
|
|
||||||
p->pack_size = st.st_size;
|
p->pack_size = st.st_size;
|
||||||
p->index_base = idx_map;
|
|
||||||
p->next = NULL;
|
p->next = NULL;
|
||||||
p->pack_base = NULL;
|
p->pack_base = NULL;
|
||||||
p->pack_last_used = 0;
|
p->pack_last_used = 0;
|
||||||
p->pack_use_cnt = 0;
|
p->pack_use_cnt = 0;
|
||||||
p->pack_local = local;
|
p->pack_local = local;
|
||||||
if ((path_len > 44) && !get_sha1_hex(path + path_len - 44, sha1))
|
if (path_len < 40 || get_sha1_hex(path + path_len - 40, p->sha1))
|
||||||
hashcpy(p->sha1, sha1);
|
hashclr(p->sha1);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,23 +616,19 @@ struct packed_git *parse_pack_index(unsigned char *sha1)
|
|||||||
return parse_pack_index_file(sha1, path);
|
return parse_pack_index_file(sha1, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct packed_git *parse_pack_index_file(const unsigned char *sha1, char *idx_path)
|
struct packed_git *parse_pack_index_file(const unsigned char *sha1,
|
||||||
|
const char *idx_path)
|
||||||
{
|
{
|
||||||
struct packed_git *p;
|
const char *path = sha1_pack_name(sha1);
|
||||||
unsigned long idx_size;
|
struct packed_git *p = xmalloc(sizeof(*p) + strlen(path) + 2);
|
||||||
void *idx_map;
|
|
||||||
char *path;
|
|
||||||
|
|
||||||
if (check_packed_git_idx(idx_path, &idx_size, &idx_map))
|
if (check_packed_git_idx(idx_path, p)) {
|
||||||
|
free(p);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
path = sha1_pack_name(sha1);
|
|
||||||
|
|
||||||
p = xmalloc(sizeof(*p) + strlen(path) + 2);
|
|
||||||
strcpy(p->pack_name, path);
|
strcpy(p->pack_name, path);
|
||||||
p->index_size = idx_size;
|
|
||||||
p->pack_size = 0;
|
p->pack_size = 0;
|
||||||
p->index_base = idx_map;
|
|
||||||
p->next = NULL;
|
p->next = NULL;
|
||||||
p->pack_base = NULL;
|
p->pack_base = NULL;
|
||||||
p->pack_last_used = 0;
|
p->pack_last_used = 0;
|
||||||
@ -1166,35 +1204,60 @@ void *unpack_entry_gently(struct packed_git *p, unsigned long offset,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int num_packed_objects(const struct packed_git *p)
|
const unsigned char *nth_packed_object_sha1(const struct packed_git *p,
|
||||||
|
unsigned int n)
|
||||||
{
|
{
|
||||||
/* See check_packed_git_idx() */
|
const unsigned char *index = p->index_data;
|
||||||
return (p->index_size - 20 - 20 - 4*256) / 24;
|
if (n >= p->num_objects)
|
||||||
|
return NULL;
|
||||||
|
index += 4 * 256;
|
||||||
|
if (p->index_version == 1) {
|
||||||
|
return index + 24 * n + 4;
|
||||||
|
} else {
|
||||||
|
index += 8;
|
||||||
|
return index + 20 * n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int nth_packed_object_sha1(const struct packed_git *p, int n,
|
static off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n)
|
||||||
unsigned char* sha1)
|
|
||||||
{
|
{
|
||||||
void *index = p->index_base + 256;
|
const unsigned char *index = p->index_data;
|
||||||
if (n < 0 || num_packed_objects(p) <= n)
|
index += 4 * 256;
|
||||||
return -1;
|
if (p->index_version == 1) {
|
||||||
hashcpy(sha1, (unsigned char *) index + (24 * n) + 4);
|
return ntohl(*((uint32_t *)(index + 24 * n)));
|
||||||
return 0;
|
} else {
|
||||||
|
uint32_t off;
|
||||||
|
index += 8 + p->num_objects * (20 + 4);
|
||||||
|
off = ntohl(*((uint32_t *)(index + 4 * n)));
|
||||||
|
if (!(off & 0x80000000))
|
||||||
|
return off;
|
||||||
|
index += p->num_objects * 4 + (off & 0x7fffffff) * 8;
|
||||||
|
return (((uint64_t)ntohl(*((uint32_t *)(index + 0)))) << 32) |
|
||||||
|
ntohl(*((uint32_t *)(index + 4)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long find_pack_entry_one(const unsigned char *sha1,
|
unsigned long find_pack_entry_one(const unsigned char *sha1,
|
||||||
struct packed_git *p)
|
struct packed_git *p)
|
||||||
{
|
{
|
||||||
unsigned int *level1_ofs = p->index_base;
|
const unsigned int *level1_ofs = p->index_data;
|
||||||
int hi = ntohl(level1_ofs[*sha1]);
|
const unsigned char *index = p->index_data;
|
||||||
int lo = ((*sha1 == 0x0) ? 0 : ntohl(level1_ofs[*sha1 - 1]));
|
unsigned hi, lo;
|
||||||
void *index = p->index_base + 256;
|
|
||||||
|
if (p->index_version > 1) {
|
||||||
|
level1_ofs += 2;
|
||||||
|
index += 8;
|
||||||
|
}
|
||||||
|
index += 4 * 256;
|
||||||
|
hi = ntohl(level1_ofs[*sha1]);
|
||||||
|
lo = ((*sha1 == 0x0) ? 0 : ntohl(level1_ofs[*sha1 - 1]));
|
||||||
|
|
||||||
do {
|
do {
|
||||||
int mi = (lo + hi) / 2;
|
unsigned mi = (lo + hi) / 2;
|
||||||
int cmp = hashcmp((unsigned char *)index + (24 * mi) + 4, sha1);
|
unsigned x = (p->index_version > 1) ? (mi * 20) : (mi * 24 + 4);
|
||||||
|
int cmp = hashcmp(index + x, sha1);
|
||||||
if (!cmp)
|
if (!cmp)
|
||||||
return ntohl(*((unsigned int *) ((char *) index + (24 * mi))));
|
return nth_packed_object_offset(p, mi);
|
||||||
if (cmp > 0)
|
if (cmp > 0)
|
||||||
hi = mi;
|
hi = mi;
|
||||||
else
|
else
|
||||||
|
18
sha1_name.c
18
sha1_name.c
@ -71,19 +71,19 @@ static int match_sha(unsigned len, const unsigned char *a, const unsigned char *
|
|||||||
static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1)
|
static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1)
|
||||||
{
|
{
|
||||||
struct packed_git *p;
|
struct packed_git *p;
|
||||||
unsigned char found_sha1[20];
|
const unsigned char *found_sha1 = NULL;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
|
|
||||||
prepare_packed_git();
|
prepare_packed_git();
|
||||||
for (p = packed_git; p && found < 2; p = p->next) {
|
for (p = packed_git; p && found < 2; p = p->next) {
|
||||||
unsigned num = num_packed_objects(p);
|
unsigned num = p->num_objects;
|
||||||
unsigned first = 0, last = num;
|
unsigned first = 0, last = num;
|
||||||
while (first < last) {
|
while (first < last) {
|
||||||
unsigned mid = (first + last) / 2;
|
unsigned mid = (first + last) / 2;
|
||||||
unsigned char now[20];
|
const unsigned char *now;
|
||||||
int cmp;
|
int cmp;
|
||||||
|
|
||||||
nth_packed_object_sha1(p, mid, now);
|
now = nth_packed_object_sha1(p, mid);
|
||||||
cmp = hashcmp(match, now);
|
cmp = hashcmp(match, now);
|
||||||
if (!cmp) {
|
if (!cmp) {
|
||||||
first = mid;
|
first = mid;
|
||||||
@ -96,14 +96,14 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne
|
|||||||
last = mid;
|
last = mid;
|
||||||
}
|
}
|
||||||
if (first < num) {
|
if (first < num) {
|
||||||
unsigned char now[20], next[20];
|
const unsigned char *now, *next;
|
||||||
nth_packed_object_sha1(p, first, now);
|
now = nth_packed_object_sha1(p, first);
|
||||||
if (match_sha(len, match, now)) {
|
if (match_sha(len, match, now)) {
|
||||||
if (nth_packed_object_sha1(p, first+1, next) ||
|
next = nth_packed_object_sha1(p, first+1);
|
||||||
!match_sha(len, match, next)) {
|
if (!next|| !match_sha(len, match, next)) {
|
||||||
/* unique within this pack */
|
/* unique within this pack */
|
||||||
if (!found) {
|
if (!found) {
|
||||||
hashcpy(found_sha1, now);
|
found_sha1 = now;
|
||||||
found++;
|
found++;
|
||||||
}
|
}
|
||||||
else if (hashcmp(found_sha1, now)) {
|
else if (hashcmp(found_sha1, now)) {
|
||||||
|
Reference in New Issue
Block a user