From: Troy Telford <ttelford.groups@gmail.com>
To: "Shawn O. Pearce" <spearce@spearce.org>
Cc: git@vger.kernel.org
Subject: [PATCH] Support 64-bit indexes for pack files.
Date: Mon, 26 Feb 2007 15:40:26 -0700 [thread overview]
Message-ID: <200702261540.27080.ttelford.groups@gmail.com> (raw)
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@gmail.com>
---
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
next reply other threads:[~2007-02-27 0:41 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-02-26 22:40 Troy Telford [this message]
2007-02-26 23:55 ` [PATCH] Support 64-bit indexes for pack files Shawn O. Pearce
2007-02-27 0:24 ` Nicolas Pitre
2007-02-27 0:31 ` Shawn O. Pearce
2007-02-27 4:32 ` Nicolas Pitre
2007-02-27 4:55 ` Geert Bosch
2007-02-27 5:11 ` Nicolas Pitre
2007-02-27 16:04 ` Geert Bosch
2007-02-27 16:11 ` Shawn O. Pearce
2007-02-27 16:55 ` Geert Bosch
2007-02-27 17:36 ` Nicolas Pitre
2007-02-28 3:52 ` Shawn O. Pearce
2007-02-28 4:12 ` Nicolas Pitre
2007-02-27 17:03 ` Nicolas Pitre
2007-02-27 20:05 ` Johannes Schindelin
2007-02-27 20:25 ` Geert Bosch
2007-02-27 20:35 ` Johannes Schindelin
2007-02-27 1:16 ` Troy Telford
2007-02-27 4:56 ` Nicolas Pitre
2007-02-28 19:46 ` Troy Telford
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200702261540.27080.ttelford.groups@gmail.com \
--to=ttelford.groups@gmail.com \
--cc=git@vger.kernel.org \
--cc=spearce@spearce.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.