[PATCH] Support 64-bit indexes for pack files.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



As I've not been involved with git development before, I'm
aware that this may already be on somebody's 'todo' list.  It was an itch
I needed to scratch, as I have a repository whose size is multiple gigabytes,
and 'git clone' (by default) forces everything into a single
packfile with >=git-1.5.0.

Since I'm an insane form of lazy, needed the C practice, and wanted to
avoid those few keystrokes needed to tweak the default push/fetch behavior,
I'm attempting to either fix git or break it in a new and interesting way.

The patch introduces a new packfile index version, which adds a:
 * header to the index file (index version info).
 * leaves the object indexes within the index at 32-bit
 * extends the offsets used to describe the packfile to 64-bit.

The new index format is only used when the associated  packfile 
becomes large enough to warrant a 64-bit index; otherwise the original
index format is used.

Operations such as git-fsck, checkouts, diffs, and branches
all appear to work properly on x86-64 architectures.  I've done
testing on both x86 and x86_64 architectures, using a git repository
with a single 5.4 GB packfile.

32-bit architectures still have issues using the 64-bit
indexes (git- fsck, pull/fetch return various errors) so it's not yet
complete.

I did have quite a bit of help from Eric Biederman, whom
I'd like to acknowledge and thank for his help.

Signed-off-by: Troy Telford <ttelford.groups@xxxxxxxxx>
---
 builtin-pack-objects.c |   50 ++++++++++++-
 cache.h                |   13 ++-
 index-pack.c           |   30 ++++++-
 pack-check.c           |    8 +-
 pack-redundant.c       |   83 +++++++++++++++------
 pack.h                 |    4 +
 sha1_file.c            |  193 +++++++++++++++++++++++++++++++++++-------------
 show-index.c           |   81 +++++++++++++++-----
 8 files changed, 349 insertions(+), 113 deletions(-)

diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index b5ed9ce..92087c1 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -101,7 +101,7 @@ static int object_ix_hashsz;
  * get the object sha1 from the main index.
  */
 struct revindex_entry {
-	unsigned int offset;
+	off_t offset;
 	unsigned int nr;
 };
 struct pack_revindex {
@@ -163,12 +163,12 @@ static int cmp_offset(const void *a_, const void *b_)
 /*
  * Ordered list of offsets of objects in the pack.
  */
-static void prepare_pack_revindex(struct pack_revindex *rix)
+static void prepare_pack_revindex_v0(struct pack_revindex *rix)
 {
 	struct packed_git *p = rix->p;
 	int num_ent = num_packed_objects(p);
 	int i;
-	void *index = p->index_base + 256;
+	void *index = p->index.base + 256;
 
 	rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1));
 	for (i = 0; i < num_ent; i++) {
@@ -184,6 +184,43 @@ static void prepare_pack_revindex(struct pack_revindex *rix)
 	qsort(rix->revindex, num_ent, sizeof(*rix->revindex), cmp_offset);
 }
 
+static void prepare_pack_revindex_v1(struct pack_revindex *rix)
+{
+	struct packed_git *p = rix->p;
+	int num_ent = num_packed_objects(p);
+	int i;
+	uint32_t *index = p->index.base + 256 + 2;
+
+	rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1));
+	for (i = 0; i < num_ent; i++) {
+		off_t offset;
+		offset = ntohl(*(index + (7 * i)));
+		offset <<=32;
+		offset |= ntohl(*(index + ((7 * i) + 1)));
+		rix->revindex[i].offset = offset;
+		rix->revindex[i].nr = i;
+	}
+	/* This knows the pack format -- the 20-byte trailer
+	 * follows immediately after the last object data.
+	 */
+	rix->revindex[num_ent].offset = p->pack_size - 20;
+	rix->revindex[num_ent].nr = -1;
+	qsort(rix->revindex, num_ent, sizeof(*rix->revindex), cmp_offset);
+}
+static void prepare_pack_revindex(struct pack_revindex *rix)
+{
+	switch (rix->p->index.version)
+	{
+	case 0:
+		return prepare_pack_revindex_v0(rix);
+	case 1:
+		return prepare_pack_revindex_v1(rix);
+	default:
+		die("Unsupported Pack Version");
+
+	}
+}
+
 static struct revindex_entry * find_packed_object(struct packed_git *p,
 						  unsigned int ofs)
 {
@@ -224,7 +261,12 @@ static unsigned char *find_packed_object_name(struct packed_git *p,
 					      unsigned long ofs)
 {
 	struct revindex_entry *entry = find_packed_object(p, ofs);
-	return (unsigned char *)(p->index_base + 256) + 24 * entry->nr + 4;
+	if (p->index.version == 0)
+		return (unsigned char *)(p->index.base + 256) + 24 * entry->nr + 4;
+	else if (p->index.version == 1)
+		return (unsigned char *)(p->index.base + 256 + 2) + 28 * entry->nr + 8;
+	else
+		die("Unsupported index version");
 }
 
 static void *delta_against(void *buf, unsigned long size, struct object_entry *entry)
diff --git a/cache.h b/cache.h
index 04f8e63..b329ca4 100644
--- a/cache.h
+++ b/cache.h
@@ -362,12 +362,17 @@ struct pack_window {
 	unsigned int inuse_cnt;
 };
 
+struct index_info {
+	off_t	size;
+	uint32_t *base;
+	uint32_t version;
+};
+
 extern struct packed_git {
 	struct packed_git *next;
 	struct pack_window *windows;
-	uint32_t *index_base;
-	off_t index_size;
 	off_t pack_size;
+	struct index_info index;
 	int pack_fd;
 	int pack_local;
 	unsigned char sha1[20];
@@ -376,7 +381,7 @@ extern struct packed_git {
 } *packed_git;
 
 struct pack_entry {
-	unsigned int offset;
+	off_t offset;
 	unsigned char sha1[20];
 	struct packed_git *p;
 };
@@ -420,7 +425,7 @@ 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 off_t find_pack_entry_one(const unsigned char *, struct packed_git *);
 extern void *unpack_entry(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 void packed_object_info_detail(struct packed_git *, unsigned long, char *, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
diff --git a/index-pack.c b/index-pack.c
index fa9a0e7..cc22ea2 100644
--- a/index-pack.c
+++ b/index-pack.c
@@ -12,7 +12,7 @@ static const char index_pack_usage[] =
 
 struct object_entry
 {
-	unsigned long offset;
+	off_t offset;
 	unsigned long size;
 	unsigned int hdr_size;
 	enum object_type type;
@@ -83,7 +83,7 @@ static unsigned display_progress(unsigned n, unsigned total, unsigned last_pc)
 
 /* We always read in 4kB chunks. */
 static unsigned char input_buffer[4096];
-static unsigned long input_offset, input_len, consumed_bytes;
+static off_t input_offset, input_len, consumed_bytes;
 static SHA_CTX input_ctx;
 static int input_fd, output_fd, pack_fd;
 
@@ -707,6 +707,13 @@ static const char *write_index_file(const char *index_name, unsigned char *sha1)
 		die("unable to create %s: %s", index_name, strerror(errno));
 	f = sha1fd(fd, index_name);
 
+	if ( consumed_bytes >= 0xffffffffUL )
+	{
+		struct pack_idx_header hdr;
+		hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
+		hdr.idx_version = htonl(1);
+		sha1write(f, &hdr, sizeof(hdr));
+	}
 	/*
 	 * Write the first-level table (the list is sorted,
 	 * but we use a 256-entry lookup to be able to avoid
@@ -736,9 +743,22 @@ static const char *write_index_file(const char *index_name, unsigned char *sha1)
 	list = sorted_by_sha;
 	for (i = 0; i < nr_objects; i++) {
 		struct object_entry *obj = *list++;
-		unsigned int offset = htonl(obj->offset);
-		sha1write(f, &offset, 4);
-		sha1write(f, obj->sha1, 20);
+		if ( consumed_bytes < 0xffffffffUL )
+		{
+			unsigned int offset = htonl(obj->offset);
+			sha1write(f, &offset, 4);
+			sha1write(f, obj->sha1, 20);
+		}
+		else
+		{
+			uint32_t low;
+			uint32_t high;
+			low=htonl(obj->offset & 0xffffffff);
+			high=htonl((obj->offset >>32) & 0xffffffff);
+			sha1write(f, &high, 4);
+			sha1write(f, &low, 4);
+			sha1write(f, obj->sha1, 20);
+		}
 		SHA1_Update(&ctx, obj->sha1, 20);
 	}
 	sha1write(f, sha1, 20);
diff --git a/pack-check.c b/pack-check.c
index 08a9fd8..12ee933 100644
--- a/pack-check.c
+++ b/pack-check.c
@@ -4,8 +4,8 @@
 static int verify_packfile(struct packed_git *p,
 		struct pack_window **w_curs)
 {
-	unsigned long index_size = p->index_size;
-	void *index_base = p->index_base;
+	off_t index_size = p->index.size;
+	void *index_base = p->index.base;
 	SHA_CTX ctx;
 	unsigned char sha1[20];
 	unsigned long offset = 0, pack_sig = p->pack_size - 20;
@@ -123,8 +123,8 @@ static void show_pack_info(struct packed_git *p)
 
 int verify_pack(struct packed_git *p, int verbose)
 {
-	unsigned long index_size = p->index_size;
-	void *index_base = p->index_base;
+	off_t index_size = p->index.size;
+	void *index_base = p->index.base;
 	SHA_CTX ctx;
 	unsigned char sha1[20];
 	int ret;
diff --git a/pack-redundant.c b/pack-redundant.c
index edb5524..d327ae4 100644
--- a/pack-redundant.c
+++ b/pack-redundant.c
@@ -246,15 +246,29 @@ 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)
 {
 	int p1_off, p2_off;
+	int p1_inc, p2_inc;
 	unsigned char *p1_base, *p2_base;
 	struct llist_item *p1_hint = NULL, *p2_hint = NULL;
 
-	p1_off = p2_off = 256 * 4 + 4;
-	p1_base = (unsigned char *) p1->pack->index_base;
-	p2_base = (unsigned char *) p2->pack->index_base;
+	if (p1->pack->index.version == 0) {
+		p1_off = 256 * 4 + 4;
+		p1_inc = 24;
+	} else {
+		p1_off = 256 * 4 + 8 + 8;
+		p1_inc = 28;
+	}
+	if (p2->pack->index.version == 0) {
+		p2_off = 256 * 4 + 4;
+		p2_inc = 24;
+	} else {
+		p2_off = 256 * 4 + 8 + 8;
+		p2_inc = 28;
+	}
+	p1_base = (unsigned char *) p1->pack->index.base;
+	p2_base = (unsigned char *) p2->pack->index.base;
 
-	while (p1_off <= p1->pack->index_size - 3 * 20 &&
-	       p2_off <= p2->pack->index_size - 3 * 20)
+	while (p1_off <= p1->pack->index.size - 3 * 20 &&
+	       p2_off <= p2->pack->index.size - 3 * 20)
 	{
 		int cmp = hashcmp(p1_base + p1_off, p2_base + p2_off);
 		/* cmp ~ p1 - p2 */
@@ -263,14 +277,14 @@ static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
 					p1_base + p1_off, p1_hint);
 			p2_hint = llist_sorted_remove(p2->unique_objects,
 					p1_base + p1_off, p2_hint);
-			p1_off+=24;
-			p2_off+=24;
+			p1_off+=p1_inc;
+			p2_off+=p2_inc;
 			continue;
 		}
 		if (cmp < 0) { /* p1 has the object, p2 doesn't */
-			p1_off+=24;
+			p1_off+=p1_inc;
 		} else { /* p2 has the object, p1 doesn't */
-			p2_off+=24;
+			p2_off+=p2_inc;
 		}
 	}
 }
@@ -351,27 +365,41 @@ static size_t sizeof_union(struct packed_git *p1, struct packed_git *p2)
 {
 	size_t ret = 0;
 	int p1_off, p2_off;
+	int p1_inc, p2_inc;
 	unsigned char *p1_base, *p2_base;
 
-	p1_off = p2_off = 256 * 4 + 4;
-	p1_base = (unsigned char *)p1->index_base;
-	p2_base = (unsigned char *)p2->index_base;
+	if (p1->index.version == 0) {
+		p1_off = 256 * 4 + 4;
+		p1_inc = 24;
+	} else {
+		p1_off = 256 * 4 + 8 + 8;
+		p1_inc = 28;
+	}
+	if (p2->index.version == 0) {
+		p2_off = 256 * 4 + 4;
+		p2_inc = 24;
+	} else {
+		p2_off = 256 * 4 + 8 + 8;
+		p2_inc = 28;
+	}
+	p1_base = (unsigned char *)p1->index.base;
+	p2_base = (unsigned char *)p2->index.base;
 
-	while (p1_off <= p1->index_size - 3 * 20 &&
-	       p2_off <= p2->index_size - 3 * 20)
+	while (p1_off <= p1->index.size - 3 * 20 &&
+	       p2_off <= p2->index.size - 3 * 20)
 	{
 		int cmp = hashcmp(p1_base + p1_off, p2_base + p2_off);
 		/* cmp ~ p1 - p2 */
 		if (cmp == 0) {
 			ret++;
-			p1_off+=24;
-			p2_off+=24;
+			p1_off+=p1_inc;
+			p2_off+=p2_inc;
 			continue;
 		}
 		if (cmp < 0) { /* p1 has the object, p2 doesn't */
-			p1_off+=24;
+			p1_off+=p1_inc;
 		} else { /* p2 has the object, p1 doesn't */
-			p2_off+=24;
+			p2_off+=p2_inc;
 		}
 	}
 	return ret;
@@ -401,7 +429,7 @@ static inline size_t pack_set_bytecount(struct pack_list *pl)
 	size_t ret = 0;
 	while (pl) {
 		ret += pl->pack->pack_size;
-		ret += pl->pack->index_size;
+		ret += pl->pack->index.size;
 		pl = pl->next;
 	}
 	return ret;
@@ -534,6 +562,7 @@ static struct pack_list * add_pack(struct packed_git *p)
 {
 	struct pack_list l;
 	size_t off;
+	int inc;
 	unsigned char *base;
 
 	if (!p->pack_local && !(alt_odb || verbose))
@@ -541,12 +570,18 @@ static struct pack_list * add_pack(struct packed_git *p)
 
 	l.pack = p;
 	llist_init(&l.all_objects);
-
-	off = 256 * 4 + 4;
-	base = (unsigned char *)p->index_base;
-	while (off <= p->index_size - 3 * 20) {
+	if (p->index.version == 0) {
+		off = 256 * 4 + 4;
+		inc = 24;
+	}
+	if (p->index.version == 1) {
+		off = 256 * 4 + 8 + 8;
+		inc = 28;
+	}
+	base = (unsigned char *)p->index.base;
+	while (off <= p->index.size - 3 * 20) {
 		llist_insert_back(l.all_objects, base + off);
-		off += 24;
+		off += inc;
 	}
 	/* this list will be pruned in cmp_two_packs later */
 	l.unique_objects = llist_copy(l.all_objects);
diff --git a/pack.h b/pack.h
index deb427e..fbf7992 100644
--- a/pack.h
+++ b/pack.h
@@ -41,6 +41,10 @@ struct pack_header {
  * byte word.  This would be true in the proposed future index
  * format as idx_signature would be greater than idx_version.
  */
+struct pack_idx_header {
+	uint32_t idx_signature;
+	uint32_t idx_version;
+};
 #define PACK_IDX_SIGNATURE 0xff744f63	/* "\377tOc" */
 
 extern int verify_pack(struct packed_git *, int);
diff --git a/sha1_file.c b/sha1_file.c
index 2c87031..c5ab5cc 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -430,12 +430,9 @@ 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, struct index_info * idx )
 {
-	void *idx_map;
 	uint32_t *index;
-	unsigned long idx_size;
 	int nr, i;
 	int fd = open(path, O_RDONLY);
 	struct stat st;
@@ -445,46 +442,73 @@ static int check_packed_git_idx(const char *path, unsigned long *idx_size_,
 		close(fd);
 		return -1;
 	}
-	idx_size = st.st_size;
-	idx_map = xmmap(NULL, idx_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	idx->size = st.st_size;
+	idx->base = xmmap(NULL, idx->size, PROT_READ, MAP_PRIVATE, fd, 0);
 	close(fd);
 
-	index = idx_map;
-	*idx_map_ = idx_map;
-	*idx_size_ = idx_size;
+	index = idx->base;
 
-	/* check index map */
-	if (idx_size < 4*256 + 20 + 20)
+	if (idx->size < 8)
 		return error("index file %s is too small", path);
-
+	if (index[0] != htonl(PACK_IDX_SIGNATURE))
+	{
+		/* check index map */
+		if (idx->size < 4*256 + 20 + 20)
+			return error("index file %s is too small", path);
+		nr = 0;
+		for (i = 0; i < 256; i++) {
+			unsigned int n = ntohl(index[i]);
+			if (n < nr)
+				return error("non-monotonic index %s", path);
+			nr = n;
+		}
+		/*
+		 * Total size:
+		 *  - 256 index entries 4 bytes each
+		 *  - 24-byte entries * nr (20-byte sha1 + 4-byte offset)
+		 *  	(on 32-bit indexes)
+		 *  - 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 in %s", path);
+		idx->version = 0;
+	}
+	else if (index[0] == htonl(PACK_IDX_SIGNATURE) && ntohl(index[1]) == 1 )
+	{
+		index += 2;
+		/* check index map */
+		if (idx->size < 8 + 4*256 + 20 + 20 )
+			return error("index file %s is too small", path);
+		nr = 0;
+		for (i = 0; i < 256; i++) {
+			unsigned int n = ntohl(index[i]);
+			if (n < nr)
+				return error("non-monotonic index %s", path);
+			nr = n;
+		}
+		/*
+		 * Total size:
+		 *  - (4+4) byte header
+		 *  - 256 index entries 4 bytes each
+		 *  - 28-byte entries * nr (20-byte sha1 + 8 byte offset)
+		 *  	(on 64-bit indexes)
+		 *  - 20-byte SHA1 of the packfile
+		 *  - 20-byte SHA1 file checksum
+		 */
+		if (idx->size != 8 + 4*256 + nr * 28 + 20 + 20)
+			return error("wrong index file size in %s", path);
+		idx->version = 1;
+	}
 	/* 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))
+	else if (index[0] == htonl(PACK_IDX_SIGNATURE))
 		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)
-			return error("non-monotonic index %s", path);
-		nr = n;
-	}
-
-	/*
-	 * Total size:
-	 *  - 256 index entries 4 bytes each
-	 *  - 24-byte entries * nr (20-byte sha1 + 4-byte offset)
-	 *  - 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 in %s", path);
-
 	return 0;
 }
 
@@ -605,7 +629,7 @@ static int open_packed_git_1(struct packed_git *p)
 		return error("end of packfile %s is unavailable", p->pack_name);
 	if (read_in_full(p->pack_fd, sha1, sizeof(sha1)) != sizeof(sha1))
 		return error("packfile %s signature is unavailable", p->pack_name);
-	idx_sha1 = ((unsigned char *)p->index_base) + p->index_size - 40;
+	idx_sha1 = ((unsigned char *)p->index.base) + p->index.size - 40;
 	if (hashcmp(sha1, idx_sha1))
 		return error("packfile %s does not match index", p->pack_name);
 	return 0;
@@ -703,17 +727,16 @@ struct packed_git *add_packed_git(char *path, int path_len, int local)
 {
 	struct stat st;
 	struct packed_git *p;
-	unsigned long idx_size;
-	void *idx_map;
+	struct index_info idx;
 	unsigned char sha1[20];
 
-	if (check_packed_git_idx(path, &idx_size, &idx_map))
+	if (check_packed_git_idx(path, &idx))
 		return NULL;
 
 	/* do we have a corresponding .pack file? */
 	strcpy(path + path_len - 4, ".pack");
 	if (stat(path, &st) || !S_ISREG(st.st_mode)) {
-		munmap(idx_map, idx_size);
+		munmap(idx.base, idx.size);
 		return NULL;
 	}
 	/* ok, it looks sane as far as we can check without
@@ -721,9 +744,8 @@ struct packed_git *add_packed_git(char *path, int path_len, int local)
 	 */
 	p = xmalloc(sizeof(*p) + path_len + 2);
 	strcpy(p->pack_name, path);
-	p->index_size = idx_size;
+	p->index = idx;
 	p->pack_size = st.st_size;
-	p->index_base = idx_map;
 	p->next = NULL;
 	p->windows = NULL;
 	p->pack_fd = -1;
@@ -742,20 +764,18 @@ struct packed_git *parse_pack_index(unsigned char *sha1)
 struct packed_git *parse_pack_index_file(const unsigned char *sha1, char *idx_path)
 {
 	struct packed_git *p;
-	unsigned long idx_size;
-	void *idx_map;
+	struct index_info idx;
 	char *path;
 
-	if (check_packed_git_idx(idx_path, &idx_size, &idx_map))
+	if (check_packed_git_idx(idx_path, &idx))
 		return NULL;
 
 	path = sha1_pack_name(sha1);
 
 	p = xmalloc(sizeof(*p) + strlen(path) + 2);
 	strcpy(p->pack_name, path);
-	p->index_size = idx_size;
+	p->index = idx;
 	p->pack_size = 0;
-	p->index_base = idx_map;
 	p->next = NULL;
 	p->windows = NULL;
 	p->pack_fd = -1;
@@ -1318,7 +1338,7 @@ static void *unpack_delta_entry(struct packed_git *p,
 	return result;
 }
 
-void *unpack_entry(struct packed_git *p, unsigned long offset,
+void *unpack_entry(struct packed_git *p, off_t offset,
 			  char *type, unsigned long *sizep)
 {
 	struct pack_window *w_curs = NULL;
@@ -1350,27 +1370,56 @@ void *unpack_entry(struct packed_git *p, unsigned long offset,
 
 int num_packed_objects(const struct packed_git *p)
 {
+	int objects = 0;
 	/* See check_packed_git_idx() */
-	return (p->index_size - 20 - 20 - 4*256) / 24;
+	if (p->index.version == 0)
+		objects = (p->index.size - 20 - 20 - 4*256) / 24;
+	else if (p->index.version == 1)
+		objects = (p->index.size - 8 - 20 - 20 - 4*256) / 28;
+	return objects;
 }
 
-int nth_packed_object_sha1(const struct packed_git *p, int n,
-			   unsigned char* sha1)
+static int nth_packed_object_sha1_v0(const struct packed_git *p, int n,
+					unsigned char* sha1)
 {
-	void *index = p->index_base + 256;
+	void *index = p->index.base + 256;
 	if (n < 0 || 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,
+static int nth_packed_object_sha1_v1(const struct packed_git *p, int n,
+					unsigned char* sha1)
+{
+	void *index = p->index.base + 256 + 2;
+	if (n < 0 || num_packed_objects(p) <= n)
+		return -1;
+	hashcpy(sha1, (unsigned char *) index + (28 * n) + 8);
+	return 0;
+}
+
+int nth_packed_object_sha1(const struct packed_git *p, int n,
+			   unsigned char* sha1)
+{
+	switch  (p->index.version)
+	{
+	case 0:
+		return nth_packed_object_sha1_v0(p, n, sha1);
+	case 1:
+		return nth_packed_object_sha1_v1(p, n, sha1);
+	default:
+		die("Unsupported Pack Version v%d\n", p->index.version);
+	}
+}
+
+static off_t find_pack_entry_one_v0(const unsigned char *sha1,
 				  struct packed_git *p)
 {
-	uint32_t *level1_ofs = p->index_base;
+	uint32_t *level1_ofs = p->index.base;
 	int hi = ntohl(level1_ofs[*sha1]);
 	int lo = ((*sha1 == 0x0) ? 0 : ntohl(level1_ofs[*sha1 - 1]));
-	void *index = p->index_base + 256;
+	void *index = p->index.base + 256;
 
 	do {
 		int mi = (lo + hi) / 2;
@@ -1385,6 +1434,46 @@ unsigned long find_pack_entry_one(const unsigned char *sha1,
 	return 0;
 }
 
+static off_t find_pack_entry_one_v1(const unsigned char *sha1,
+				  struct packed_git *p)
+{
+	uint32_t *level1_ofs = p->index.base + 2;
+	int hi = ntohl(level1_ofs[*sha1]);
+	int lo = ((*sha1 == 0x0) ? 0 : ntohl(level1_ofs[*sha1 - 1]));
+	uint32_t *index = p->index.base + 256 + 2;
+
+	do {
+		int mi = (lo + hi) / 2;
+		int cmp = hashcmp((unsigned char *)(index + (7 * mi) + 2), sha1);
+		if (!cmp){
+			off_t offset;
+			offset = ntohl(*(index + (7 * mi)));
+			offset <<=32;
+			offset |= ntohl(*(index + ((7 * mi) + 1)));
+			return  offset;
+		}
+		if (cmp > 0)
+			hi = mi;
+		else
+			lo = mi+1;
+	} while (lo < hi);
+	return 0;
+}
+
+off_t find_pack_entry_one(const unsigned char *sha1,
+				  struct packed_git *p)
+{
+	switch (p->index.version)
+	{
+	case 0:
+		return find_pack_entry_one_v0(sha1, p);
+	case 1:
+		return find_pack_entry_one_v1(sha1, p);
+	default:
+		die("Unsupported Pack Version: v%d\n", p->index.version);
+	}
+}
+
 static int matches_pack_name(struct packed_git *p, const char *ig)
 {
 	const char *last_c, *c;
diff --git a/show-index.c b/show-index.c
index a30a2de..c7ff161 100644
--- a/show-index.c
+++ b/show-index.c
@@ -1,28 +1,69 @@
 #include "cache.h"
+#include "pack.h"
+#include <stdio.h>
 
 int main(int argc, char **argv)
 {
-	int i;
-	unsigned nr;
-	unsigned int entry[6];
-	static unsigned int top_index[256];
+	struct pack_idx_header hdr;
 
-	if (fread(top_index, sizeof(top_index), 1, stdin) != 1)
-		die("unable to read index");
-	nr = 0;
-	for (i = 0; i < 256; i++) {
-		unsigned n = ntohl(top_index[i]);
-		if (n < nr)
-			die("corrupt index file");
-		nr = n;
-	}
-	for (i = 0; i < nr; i++) {
-		unsigned offset;
+	if (fread(&hdr, sizeof(hdr), 1, stdin) != 1)
+		die("unable to read header");
+	if (PACK_IDX_SIGNATURE != ntohl(hdr.idx_signature))
+	{
+		int i;
+		unsigned nr;
+		unsigned int entry[6];
+		static unsigned int top_index[256];
+		top_index[0] = hdr.idx_signature;
+		top_index[1] = hdr.idx_version;
+		if (fread(top_index+2, sizeof(top_index) - sizeof(top_index[0])*2, 1, stdin) != 1)
+			die("unable to read index");
+		nr = 0;
+		for (i = 0; i < 256; i++) {
+			unsigned n = ntohl(top_index[i]);
+			if (n < nr)
+				die("corrupt index file");
+			nr = n;
+		}
+		for (i = 0; i < nr; i++) {
+			unsigned offset;
 
-		if (fread(entry, 24, 1, stdin) != 1)
-			die("unable to read entry %u/%u", i, nr);
-		offset = ntohl(entry[0]);
-		printf("%u %s\n", offset, sha1_to_hex((void *)(entry+1)));
+			if (fread(entry, 24, 1, stdin) != 1)
+				die("unable to read entry %u/%u", i, nr);
+			offset = ntohl(entry[0]);
+			printf("%u %s\n", offset, sha1_to_hex((void *)(entry+1)));
+		}
+		return 0;
+	}
+	else if (1 == ntohl(hdr.idx_version))
+	{
+		unsigned int nr;
+		unsigned int i;
+		unsigned int entry[7];
+		uint32_t top_index[256];
+		if (fread(top_index, sizeof(top_index), 1, stdin) != 1)
+			die("unable to read index");
+		nr = 0;
+		for (i = 0; i < 256; i++) {
+			unsigned int n;
+			n = ntohl(top_index[i]);
+			if (n < nr)
+				die("corrupt version 1 index file");
+			nr = n;
+		}
+		for (i = 0; i < nr; i++) {
+			off_t offset;
+			if (fread(entry, 28, 1, stdin) != 1)
+				die("unable to read entry %u/%u", i, nr);
+			offset = ntohl(entry[0]);
+			offset <<= 32;
+			offset |= ntohl (entry[1]);
+			printf("%llu %s\n", (unsigned long long) offset,
+				sha1_to_hex((void *)(entry+2)));
+		}
+		return 0;
 	}
-	return 0;
+	else
+		die("Unsupported header version %d.",
+			hdr.idx_version);
 }
-- 
1.5.0.1
-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]