{"thread":{"id":"8391","subject":"[PATCH] Unify write_index_file functions","startedAt":"2007-06-01T19:18:05Z","lastAt":"2007-06-02T02:04:20Z","messageCount":2,"participants":["Geert Bosch","Nicolas Pitre"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"43782","messageId":"20070602014836.0D5644DF122@geert-boschs-computer.local","threadId":"8391","inReplyTo":"alpine.LFD.0.99.0706012126260.12885@xanadu.home","subject":"[PATCH] Unify write_index_file functions","fromName":"Geert Bosch","fromEmail":"bosch@gnat.com","sentAt":"2007-06-01T19:18:05Z","receivedAt":"2007-06-01T19:18:05Z","isPatch":true,"sender":{"key":"bosch@gnat.com","avatar":null},"body":"This patch unifies the write_index_file functions in\nbuiltin-pack-objects.c and index-pack.c.  As the name\n\"index\" is overloaded in git, move in the direction of\nusing \"idx\" and \"pack idx\" when refering to the pack index.\nThere should be no change in functionality.\n\nSigned-off-by: Geert Bosch <bosch@gnat.com>\n---\n builtin-pack-objects.c |  218 +++++++++++-------------------------------------\n index-pack.c           |  208 ++++++++-------------------------------------\n pack-write.c           |  142 +++++++++++++++++++++++++++++++\n pack.h                 |   14 +++\n 4 files changed, 243 insertions(+), 339 deletions(-)\n\nNow with corrected commit message.\n\n  -Geert\n\ndiff --git a/builtin-pack-objects.c b/builtin-pack-objects.c\nindex e52332d..a247238 100644\n--- a/builtin-pack-objects.c\n+++ b/builtin-pack-objects.c\n@@ -23,10 +23,9 @@ git-pack-objects [{ -q | --progress | --all-progress }] [--max-pack-size=N] \\n\\\n \t[--stdout | base-name] [<ref-list | <object-list]\";\n \n struct object_entry {\n-\tunsigned char sha1[20];\n-\tuint32_t crc32;\t\t/* crc of raw pack data for this object */\n-\toff_t offset;\t\t/* offset into the final pack file */\n+\tstruct pack_idx_entry idx;\n \tunsigned long size;\t/* uncompressed size */\n+\n \tunsigned int hash;\t/* name hint hash */\n \tunsigned int depth;\t/* delta depth */\n \tstruct packed_git *in_pack; \t/* already in pack */\n@@ -65,7 +64,6 @@ static int allow_ofs_delta;\n static const char *pack_tmp_name, *idx_tmp_name;\n static char tmpname[PATH_MAX];\n static const char *base_name;\n-static unsigned char pack_file_sha1[20];\n static int progress = 1;\n static int window = 10;\n static uint32_t pack_size_limit;\n@@ -241,11 +239,11 @@ static void *delta_against(void *buf, unsigned long size, struct object_entry *e\n {\n \tunsigned long othersize, delta_size;\n \tenum object_type type;\n-\tvoid *otherbuf = read_sha1_file(entry->delta->sha1, &type, &othersize);\n+\tvoid *otherbuf = read_sha1_file(entry->delta->idx.sha1, &type, &othersize);\n \tvoid *delta_buf;\n \n \tif (!otherbuf)\n-\t\tdie(\"unable to read %s\", sha1_to_hex(entry->delta->sha1));\n+\t\tdie(\"unable to read %s\", sha1_to_hex(entry->delta->idx.sha1));\n         delta_buf = diff_delta(otherbuf, othersize,\n \t\t\t       buf, size, &delta_size, 0);\n         if (!delta_buf || delta_size != entry->delta_size)\n@@ -374,11 +372,11 @@ static unsigned long write_object(struct sha1file *f,\n \t\t\t\t/* yes if unlimited packfile */\n \t\t\t\t!pack_size_limit ? 1 :\n \t\t\t\t/* no if base written to previous pack */\n-\t\t\t\tentry->delta->offset == (off_t)-1 ? 0 :\n+\t\t\t\tentry->delta->idx.offset == (off_t)-1 ? 0 :\n \t\t\t\t/* otherwise double-check written to this\n \t\t\t\t * pack,  like we do below\n \t\t\t\t */\n-\t\t\t\tentry->delta->offset ? 1 : 0;\n+\t\t\t\tentry->delta->idx.offset ? 1 : 0;\n \n \tif (!pack_to_stdout)\n \t\tcrc32_begin(f);\n@@ -405,16 +403,16 @@ static unsigned long write_object(struct sha1file *f,\n \t\tz_stream stream;\n \t\tunsigned long maxsize;\n \t\tvoid *out;\n-\t\tbuf = read_sha1_file(entry->sha1, &type, &size);\n+\t\tbuf = read_sha1_file(entry->idx.sha1, &type, &size);\n \t\tif (!buf)\n-\t\t\tdie(\"unable to read %s\", sha1_to_hex(entry->sha1));\n+\t\t\tdie(\"unable to read %s\", sha1_to_hex(entry->idx.sha1));\n \t\tif (size != entry->size)\n \t\t\tdie(\"object %s size inconsistency (%lu vs %lu)\",\n-\t\t\t    sha1_to_hex(entry->sha1), size, entry->size);\n+\t\t\t    sha1_to_hex(entry->idx.sha1), size, entry->size);\n \t\tif (usable_delta) {\n \t\t\tbuf = delta_against(buf, size, entry);\n \t\t\tsize = entry->delta_size;\n-\t\t\tobj_type = (allow_ofs_delta && entry->delta->offset) ?\n+\t\t\tobj_type = (allow_ofs_delta && entry->delta->idx.offset) ?\n \t\t\t\tOBJ_OFS_DELTA : OBJ_REF_DELTA;\n \t\t} else {\n \t\t\t/*\n@@ -451,7 +449,7 @@ static unsigned long write_object(struct sha1file *f,\n \t\t\t * encoding of the relative offset for the delta\n \t\t\t * base from this object's position in the pack.\n \t\t\t */\n-\t\t\toff_t ofs = entry->offset - entry->delta->offset;\n+\t\t\toff_t ofs = entry->idx.offset - entry->delta->idx.offset;\n \t\t\tunsigned pos = sizeof(dheader) - 1;\n \t\t\tdheader[pos] = ofs & 127;\n \t\t\twhile (ofs >>= 7)\n@@ -475,7 +473,7 @@ static unsigned long write_object(struct sha1file *f,\n \t\t\t\treturn 0;\n \t\t\t}\n \t\t\tsha1write(f, header, hdrlen);\n-\t\t\tsha1write(f, entry->delta->sha1, 20);\n+\t\t\tsha1write(f, entry->delta->idx.sha1, 20);\n \t\t\thdrlen += 20;\n \t\t} else {\n \t\t\tif (limit && hdrlen + datalen + 20 >= limit) {\n@@ -496,7 +494,7 @@ static unsigned long write_object(struct sha1file *f,\n \t\toff_t offset;\n \n \t\tif (entry->delta) {\n-\t\t\tobj_type = (allow_ofs_delta && entry->delta->offset) ?\n+\t\t\tobj_type = (allow_ofs_delta && entry->delta->idx.offset) ?\n \t\t\t\tOBJ_OFS_DELTA : OBJ_REF_DELTA;\n \t\t\treused_delta++;\n \t\t}\n@@ -506,11 +504,11 @@ static unsigned long write_object(struct sha1file *f,\n \t\tdatalen = revidx[1].offset - offset;\n \t\tif (!pack_to_stdout && p->index_version > 1 &&\n \t\t    check_pack_crc(p, &w_curs, offset, datalen, revidx->nr))\n-\t\t\tdie(\"bad packed object CRC for %s\", sha1_to_hex(entry->sha1));\n+\t\t\tdie(\"bad packed object CRC for %s\", sha1_to_hex(entry->idx.sha1));\n \t\toffset += entry->in_pack_header_size;\n \t\tdatalen -= entry->in_pack_header_size;\n \t\tif (obj_type == OBJ_OFS_DELTA) {\n-\t\t\toff_t ofs = entry->offset - entry->delta->offset;\n+\t\t\toff_t ofs = entry->idx.offset - entry->delta->idx.offset;\n \t\t\tunsigned pos = sizeof(dheader) - 1;\n \t\t\tdheader[pos] = ofs & 127;\n \t\t\twhile (ofs >>= 7)\n@@ -524,7 +522,7 @@ static unsigned long write_object(struct sha1file *f,\n \t\t\tif (limit && hdrlen + 20 + datalen + 20 >= limit)\n \t\t\t\treturn 0;\n \t\t\tsha1write(f, header, hdrlen);\n-\t\t\tsha1write(f, entry->delta->sha1, 20);\n+\t\t\tsha1write(f, entry->delta->idx.sha1, 20);\n \t\t\thdrlen += 20;\n \t\t} else {\n \t\t\tif (limit && hdrlen + datalen + 20 >= limit)\n@@ -534,7 +532,7 @@ static unsigned long write_object(struct sha1file *f,\n \n \t\tif (!pack_to_stdout && p->index_version == 1 &&\n \t\t    check_pack_inflate(p, &w_curs, offset, datalen, entry->size))\n-\t\t\tdie(\"corrupt packed object for %s\", sha1_to_hex(entry->sha1));\n+\t\t\tdie(\"corrupt packed object for %s\", sha1_to_hex(entry->idx.sha1));\n \t\tcopy_pack_data(f, p, &w_curs, offset, datalen);\n \t\tunuse_pack(&w_curs);\n \t\treused++;\n@@ -543,7 +541,7 @@ static unsigned long write_object(struct sha1file *f,\n \t\twritten_delta++;\n \twritten++;\n \tif (!pack_to_stdout)\n-\t\tentry->crc32 = crc32_end(f);\n+\t\tentry->idx.crc32 = crc32_end(f);\n \treturn hdrlen + datalen;\n }\n \n@@ -554,7 +552,7 @@ static off_t write_one(struct sha1file *f,\n \tunsigned long size;\n \n \t/* offset is non zero if object is written already. */\n-\tif (e->offset || e->preferred_base)\n+\tif (e->idx.offset || e->preferred_base)\n \t\treturn offset;\n \n \t/* if we are deltified, write out base object first. */\n@@ -564,10 +562,10 @@ static off_t write_one(struct sha1file *f,\n \t\t\treturn 0;\n \t}\n \n-\te->offset = offset;\n+\te->idx.offset = offset;\n \tsize = write_object(f, e, offset);\n \tif (!size) {\n-\t\te->offset = 0;\n+\t\te->idx.offset = 0;\n \t\treturn 0;\n \t}\n \twritten_list[nr_written++] = e;\n@@ -584,8 +582,7 @@ static int open_object_dir_tmp(const char *path)\n     return mkstemp(tmpname);\n }\n \n-/* forward declarations for write_pack_file */\n-static void write_index_file(off_t last_obj_offset, unsigned char *sha1);\n+/* forward declaration for write_pack_file */\n static int adjust_perm(const char *path, mode_t mode);\n \n static void write_pack_file(void)\n@@ -602,6 +599,8 @@ static void write_pack_file(void)\n \twritten_list = xmalloc(nr_objects * sizeof(struct object_entry *));\n \n \tdo {\n+\t\tunsigned char sha1[20];\n+\n \t\tif (pack_to_stdout) {\n \t\t\tf = sha1fd(1, \"<stdout>\");\n \t\t} else {\n@@ -633,23 +632,23 @@ static void write_pack_file(void)\n \t\t * If so, rewrite it like in fast-import\n \t\t */\n \t\tif (pack_to_stdout || nr_written == nr_remaining) {\n-\t\t\tsha1close(f, pack_file_sha1, 1);\n+\t\t\tsha1close(f, sha1, 1);\n \t\t} else {\n-\t\t\tsha1close(f, pack_file_sha1, 0);\n-\t\t\tfixup_pack_header_footer(f->fd, pack_file_sha1, pack_tmp_name, nr_written);\n+\t\t\tsha1close(f, sha1, 0);\n+\t\t\tfixup_pack_header_footer(f->fd, sha1, pack_tmp_name, nr_written);\n \t\t\tclose(f->fd);\n \t\t}\n \n \t\tif (!pack_to_stdout) {\n-\t\t\tunsigned char object_list_sha1[20];\n \t\t\tmode_t mode = umask(0);\n \n \t\t\tumask(mode);\n \t\t\tmode = 0444 & ~mode;\n \n-\t\t\twrite_index_file(last_obj_offset, object_list_sha1);\n+\t\t\tidx_tmp_name = write_idx_file(NULL,\n+\t\t\t\t(struct pack_idx_entry **) written_list, nr_written, sha1);\n \t\t\tsnprintf(tmpname, sizeof(tmpname), \"%s-%s.pack\",\n-\t\t\t\t base_name, sha1_to_hex(object_list_sha1));\n+\t\t\t\t base_name, sha1_to_hex(sha1));\n \t\t\tif (adjust_perm(pack_tmp_name, mode))\n \t\t\t\tdie(\"unable to make temporary pack file readable: %s\",\n \t\t\t\t    strerror(errno));\n@@ -657,19 +656,19 @@ static void write_pack_file(void)\n \t\t\t\tdie(\"unable to rename temporary pack file: %s\",\n \t\t\t\t    strerror(errno));\n \t\t\tsnprintf(tmpname, sizeof(tmpname), \"%s-%s.idx\",\n-\t\t\t\t base_name, sha1_to_hex(object_list_sha1));\n+\t\t\t\t base_name, sha1_to_hex(sha1));\n \t\t\tif (adjust_perm(idx_tmp_name, mode))\n \t\t\t\tdie(\"unable to make temporary index file readable: %s\",\n \t\t\t\t    strerror(errno));\n \t\t\tif (rename(idx_tmp_name, tmpname))\n \t\t\t\tdie(\"unable to rename temporary index file: %s\",\n \t\t\t\t    strerror(errno));\n-\t\t\tputs(sha1_to_hex(object_list_sha1));\n+\t\t\tputs(sha1_to_hex(sha1));\n \t\t}\n \n \t\t/* mark written objects as written to previous pack */\n \t\tfor (j = 0; j < nr_written; j++) {\n-\t\t\twritten_list[j]->offset = (off_t)-1;\n+\t\t\twritten_list[j]->idx.offset = (off_t)-1;\n \t\t}\n \t\tnr_remaining -= nr_written;\n \t} while (nr_remaining && i < nr_objects);\n@@ -687,129 +686,12 @@ static void write_pack_file(void)\n \t */\n \tfor (j = 0; i < nr_objects; i++) {\n \t\tstruct object_entry *e = objects + i;\n-\t\tj += !e->offset && !e->preferred_base;\n+\t\tj += !e->idx.offset && !e->preferred_base;\n \t}\n \tif (j)\n \t\tdie(\"wrote %u objects as expected but %u unwritten\", written, j);\n }\n \n-static int sha1_sort(const void *_a, const void *_b)\n-{\n-\tconst struct object_entry *a = *(struct object_entry **)_a;\n-\tconst struct object_entry *b = *(struct object_entry **)_b;\n-\treturn hashcmp(a->sha1, b->sha1);\n-}\n-\n-static uint32_t index_default_version = 1;\n-static uint32_t index_off32_limit = 0x7fffffff;\n-\n-static void write_index_file(off_t last_obj_offset, unsigned char *sha1)\n-{\n-\tstruct sha1file *f;\n-\tstruct object_entry **sorted_by_sha, **list, **last;\n-\tuint32_t array[256];\n-\tuint32_t i, index_version;\n-\tSHA_CTX ctx;\n-\n-\tint fd = open_object_dir_tmp(\"tmp_idx_XXXXXX\");\n-\tif (fd < 0)\n-\t\tdie(\"unable to create %s: %s\\n\", tmpname, strerror(errno));\n-\tidx_tmp_name = xstrdup(tmpname);\n-\tf = sha1fd(fd, idx_tmp_name);\n-\n-\tif (nr_written) {\n-\t\tsorted_by_sha = written_list;\n-\t\tqsort(sorted_by_sha, nr_written, sizeof(*sorted_by_sha), sha1_sort);\n-\t\tlist = sorted_by_sha;\n-\t\tlast = sorted_by_sha + nr_written;\n-\t} else\n-\t\tsorted_by_sha = list = last = NULL;\n-\n-\t/* if last object's offset is >= 2^31 we should use index V2 */\n-\tindex_version = (last_obj_offset >> 31) ? 2 : index_default_version;\n-\n-\t/* index versions 2 and above need a header */\n-\tif (index_version >= 2) {\n-\t\tstruct pack_idx_header hdr;\n-\t\thdr.idx_signature = htonl(PACK_IDX_SIGNATURE);\n-\t\thdr.idx_version = htonl(index_version);\n-\t\tsha1write(f, &hdr, sizeof(hdr));\n-\t}\n-\n-\t/*\n-\t * Write the first-level table (the list is sorted,\n-\t * but we use a 256-entry lookup to be able to avoid\n-\t * having to do eight extra binary search iterations).\n-\t */\n-\tfor (i = 0; i < 256; i++) {\n-\t\tstruct object_entry **next = list;\n-\t\twhile (next < last) {\n-\t\t\tstruct object_entry *entry = *next;\n-\t\t\tif (entry->sha1[0] != i)\n-\t\t\t\tbreak;\n-\t\t\tnext++;\n-\t\t}\n-\t\tarray[i] = htonl(next - sorted_by_sha);\n-\t\tlist = next;\n-\t}\n-\tsha1write(f, array, 256 * 4);\n-\n-\t/* Compute the SHA1 hash of sorted object names. */\n-\tSHA1_Init(&ctx);\n-\n-\t/* Write the actual SHA1 entries. */\n-\tlist = sorted_by_sha;\n-\tfor (i = 0; i < nr_written; i++) {\n-\t\tstruct object_entry *entry = *list++;\n-\t\tif (index_version < 2) {\n-\t\t\tuint32_t offset = htonl(entry->offset);\n-\t\t\tsha1write(f, &offset, 4);\n-\t\t}\n-\t\tsha1write(f, entry->sha1, 20);\n-\t\tSHA1_Update(&ctx, entry->sha1, 20);\n-\t}\n-\n-\tif (index_version >= 2) {\n-\t\tunsigned int nr_large_offset = 0;\n-\n-\t\t/* write the crc32 table */\n-\t\tlist = sorted_by_sha;\n-\t\tfor (i = 0; i < nr_written; i++) {\n-\t\t\tstruct object_entry *entry = *list++;\n-\t\t\tuint32_t crc32_val = htonl(entry->crc32);\n-\t\t\tsha1write(f, &crc32_val, 4);\n-\t\t}\n-\n-\t\t/* write the 32-bit offset table */\n-\t\tlist = sorted_by_sha;\n-\t\tfor (i = 0; i < nr_written; i++) {\n-\t\t\tstruct object_entry *entry = *list++;\n-\t\t\tuint32_t offset = (entry->offset <= index_off32_limit) ?\n-\t\t\t\tentry->offset : (0x80000000 | nr_large_offset++);\n-\t\t\toffset = htonl(offset);\n-\t\t\tsha1write(f, &offset, 4);\n-\t\t}\n-\n-\t\t/* write the large offset table */\n-\t\tlist = sorted_by_sha;\n-\t\twhile (nr_large_offset) {\n-\t\t\tstruct object_entry *entry = *list++;\n-\t\t\tuint64_t offset = entry->offset;\n-\t\t\tif (offset > index_off32_limit) {\n-\t\t\t\tuint32_t split[2];\n-\t\t\t\tsplit[0]        = htonl(offset >> 32);\n-\t\t\t\tsplit[1] = htonl(offset & 0xffffffff);\n-\t\t\t\tsha1write(f, split, 8);\n-\t\t\t\tnr_large_offset--;\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-\tsha1write(f, pack_file_sha1, 20);\n-\tsha1close(f, NULL, 1);\n-\tSHA1_Final(sha1, &ctx);\n-}\n-\n static int locate_object_entry_hash(const unsigned char *sha1)\n {\n \tint i;\n@@ -817,7 +699,7 @@ static int locate_object_entry_hash(const unsigned char *sha1)\n \tmemcpy(&ui, sha1, sizeof(unsigned int));\n \ti = ui % object_ix_hashsz;\n \twhile (0 < object_ix[i]) {\n-\t\tif (!hashcmp(sha1, objects[object_ix[i] - 1].sha1))\n+\t\tif (!hashcmp(sha1, objects[object_ix[i] - 1].idx.sha1))\n \t\t\treturn i;\n \t\tif (++i == object_ix_hashsz)\n \t\t\ti = 0;\n@@ -849,7 +731,7 @@ static void rehash_objects(void)\n \tobject_ix = xrealloc(object_ix, sizeof(int) * object_ix_hashsz);\n \tmemset(object_ix, 0, sizeof(int) * object_ix_hashsz);\n \tfor (i = 0, oe = objects; i < nr_objects; i++, oe++) {\n-\t\tint ix = locate_object_entry_hash(oe->sha1);\n+\t\tint ix = locate_object_entry_hash(oe->idx.sha1);\n \t\tif (0 <= ix)\n \t\t\tcontinue;\n \t\tix = -1 - ix;\n@@ -943,7 +825,7 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,\n \n \tentry = objects + nr_objects++;\n \tmemset(entry, 0, sizeof(*entry));\n-\thashcpy(entry->sha1, sha1);\n+\thashcpy(entry->idx.sha1, sha1);\n \tentry->hash = hash;\n \tif (type)\n \t\tentry->type = type;\n@@ -1263,13 +1145,13 @@ static void check_object(struct object_entry *entry)\n \t\t\t\tofs += 1;\n \t\t\t\tif (!ofs || MSB(ofs, 7))\n \t\t\t\t\tdie(\"delta base offset overflow in pack for %s\",\n-\t\t\t\t\t    sha1_to_hex(entry->sha1));\n+\t\t\t\t\t    sha1_to_hex(entry->idx.sha1));\n \t\t\t\tc = buf[used_0++];\n \t\t\t\tofs = (ofs << 7) + (c & 127);\n \t\t\t}\n \t\t\tif (ofs >= entry->in_pack_offset)\n \t\t\t\tdie(\"delta base offset out of bound for %s\",\n-\t\t\t\t    sha1_to_hex(entry->sha1));\n+\t\t\t\t    sha1_to_hex(entry->idx.sha1));\n \t\t\tofs = entry->in_pack_offset - ofs;\n \t\t\tif (!no_reuse_delta && !entry->preferred_base)\n \t\t\t\tbase_ref = find_packed_object_name(p, ofs);\n@@ -1316,10 +1198,10 @@ static void check_object(struct object_entry *entry)\n \t\tunuse_pack(&w_curs);\n \t}\n \n-\tentry->type = sha1_object_info(entry->sha1, &entry->size);\n+\tentry->type = sha1_object_info(entry->idx.sha1, &entry->size);\n \tif (entry->type < 0)\n \t\tdie(\"unable to get type of object %s\",\n-\t\t    sha1_to_hex(entry->sha1));\n+\t\t    sha1_to_hex(entry->idx.sha1));\n }\n \n static int pack_offset_sort(const void *_a, const void *_b)\n@@ -1329,7 +1211,7 @@ static int pack_offset_sort(const void *_a, const void *_b)\n \n \t/* avoid filesystem trashing with loose objects */\n \tif (!a->in_pack && !b->in_pack)\n-\t\treturn hashcmp(a->sha1, b->sha1);\n+\t\treturn hashcmp(a->idx.sha1, b->idx.sha1);\n \n \tif (a->in_pack < b->in_pack)\n \t\treturn -1;\n@@ -1441,16 +1323,16 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,\n \n \t/* Load data if not already done */\n \tif (!trg->data) {\n-\t\ttrg->data = read_sha1_file(trg_entry->sha1, &type, &sz);\n+\t\ttrg->data = read_sha1_file(trg_entry->idx.sha1, &type, &sz);\n \t\tif (sz != trg_size)\n \t\t\tdie(\"object %s inconsistent object length (%lu vs %lu)\",\n-\t\t\t    sha1_to_hex(trg_entry->sha1), sz, trg_size);\n+\t\t\t    sha1_to_hex(trg_entry->idx.sha1), sz, trg_size);\n \t}\n \tif (!src->data) {\n-\t\tsrc->data = read_sha1_file(src_entry->sha1, &type, &sz);\n+\t\tsrc->data = read_sha1_file(src_entry->idx.sha1, &type, &sz);\n \t\tif (sz != src_size)\n \t\t\tdie(\"object %s inconsistent object length (%lu vs %lu)\",\n-\t\t\t    sha1_to_hex(src_entry->sha1), sz, src_size);\n+\t\t\t    sha1_to_hex(src_entry->idx.sha1), sz, src_size);\n \t}\n \tif (!src->index) {\n \t\tsrc->index = create_delta_index(src->data, src_size);\n@@ -1825,12 +1707,12 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)\n \t\t}\n \t\tif (!prefixcmp(arg, \"--index-version=\")) {\n \t\t\tchar *c;\n-\t\t\tindex_default_version = strtoul(arg + 16, &c, 10);\n-\t\t\tif (index_default_version > 2)\n+\t\t\tpack_idx_default_version = strtoul(arg + 16, &c, 10);\n+\t\t\tif (pack_idx_default_version > 2)\n \t\t\t\tdie(\"bad %s\", arg);\n \t\t\tif (*c == ',')\n-\t\t\t\tindex_off32_limit = strtoul(c+1, &c, 0);\n-\t\t\tif (*c || index_off32_limit & 0x80000000)\n+\t\t\t\tpack_idx_off32_limit = strtoul(c+1, &c, 0);\n+\t\t\tif (*c || pack_idx_off32_limit & 0x80000000)\n \t\t\t\tdie(\"bad %s\", arg);\n \t\t\tcontinue;\n \t\t}\ndiff --git a/index-pack.c b/index-pack.c\nindex 58c4a9c..82c8da3 100644\n--- a/index-pack.c\n+++ b/index-pack.c\n@@ -13,13 +13,11 @@ static const char index_pack_usage[] =\n \n struct object_entry\n {\n-\toff_t offset;\n+\tstruct pack_idx_entry idx;\n \tunsigned long size;\n \tunsigned int hdr_size;\n-\tuint32_t crc32;\n \tenum object_type type;\n \tenum object_type real_type;\n-\tunsigned char sha1[20];\n };\n \n union delta_base {\n@@ -197,7 +195,7 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_\n \tunsigned shift;\n \tvoid *data;\n \n-\tobj->offset = consumed_bytes;\n+\tobj->idx.offset = consumed_bytes;\n \tinput_crc32 = crc32(0, Z_NULL, 0);\n \n \tp = fill(1);\n@@ -229,15 +227,15 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_\n \t\twhile (c & 128) {\n \t\t\tbase_offset += 1;\n \t\t\tif (!base_offset || MSB(base_offset, 7))\n-\t\t\t\tbad_object(obj->offset, \"offset value overflow for delta base object\");\n+\t\t\t\tbad_object(obj->idx.offset, \"offset value overflow for delta base object\");\n \t\t\tp = fill(1);\n \t\t\tc = *p;\n \t\t\tuse(1);\n \t\t\tbase_offset = (base_offset << 7) + (c & 127);\n \t\t}\n-\t\tdelta_base->offset = obj->offset - base_offset;\n-\t\tif (delta_base->offset >= obj->offset)\n-\t\t\tbad_object(obj->offset, \"delta base offset is out of bound\");\n+\t\tdelta_base->offset = obj->idx.offset - base_offset;\n+\t\tif (delta_base->offset >= obj->idx.offset)\n+\t\t\tbad_object(obj->idx.offset, \"delta base offset is out of bound\");\n \t\tbreak;\n \tcase OBJ_COMMIT:\n \tcase OBJ_TREE:\n@@ -245,19 +243,19 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_\n \tcase OBJ_TAG:\n \t\tbreak;\n \tdefault:\n-\t\tbad_object(obj->offset, \"unknown object type %d\", obj->type);\n+\t\tbad_object(obj->idx.offset, \"unknown object type %d\", obj->type);\n \t}\n-\tobj->hdr_size = consumed_bytes - obj->offset;\n+\tobj->hdr_size = consumed_bytes - obj->idx.offset;\n \n-\tdata = unpack_entry_data(obj->offset, obj->size);\n-\tobj->crc32 = input_crc32;\n+\tdata = unpack_entry_data(obj->idx.offset, obj->size);\n+\tobj->idx.crc32 = input_crc32;\n \treturn data;\n }\n \n static void *get_data_from_pack(struct object_entry *obj)\n {\n-\tunsigned long from = obj[0].offset + obj[0].hdr_size;\n-\tunsigned long len = obj[1].offset - from;\n+\tunsigned long from = obj[0].idx.offset + obj[0].hdr_size;\n+\tunsigned long len = obj[1].idx.offset - from;\n \tunsigned long rdy = 0;\n \tunsigned char *src, *data;\n \tz_stream stream;\n@@ -360,11 +358,11 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data,\n \t\t\t     &result_size);\n \tfree(delta_data);\n \tif (!result)\n-\t\tbad_object(delta_obj->offset, \"failed to apply delta\");\n-\tsha1_object(result, result_size, type, delta_obj->sha1);\n+\t\tbad_object(delta_obj->idx.offset, \"failed to apply delta\");\n+\tsha1_object(result, result_size, type, delta_obj->idx.sha1);\n \tnr_resolved_deltas++;\n \n-\thashcpy(delta_base.sha1, delta_obj->sha1);\n+\thashcpy(delta_base.sha1, delta_obj->idx.sha1);\n \tif (!find_delta_children(&delta_base, &first, &last)) {\n \t\tfor (j = first; j <= last; j++) {\n \t\t\tstruct object_entry *child = objects + deltas[j].obj_no;\n@@ -374,7 +372,7 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data,\n \t}\n \n \tmemset(&delta_base, 0, sizeof(delta_base));\n-\tdelta_base.offset = delta_obj->offset;\n+\tdelta_base.offset = delta_obj->idx.offset;\n \tif (!find_delta_children(&delta_base, &first, &last)) {\n \t\tfor (j = first; j <= last; j++) {\n \t\t\tstruct object_entry *child = objects + deltas[j].obj_no;\n@@ -418,12 +416,12 @@ static void parse_pack_objects(unsigned char *sha1)\n \t\t\tdelta->obj_no = i;\n \t\t\tdelta++;\n \t\t} else\n-\t\t\tsha1_object(data, obj->size, obj->type, obj->sha1);\n+\t\t\tsha1_object(data, obj->size, obj->type, obj->idx.sha1);\n \t\tfree(data);\n \t\tif (verbose)\n \t\t\tdisplay_progress(&progress, i+1);\n \t}\n-\tobjects[i].offset = consumed_bytes;\n+\tobjects[i].idx.offset = consumed_bytes;\n \tif (verbose)\n \t\tstop_progress(&progress);\n \n@@ -465,10 +463,10 @@ static void parse_pack_objects(unsigned char *sha1)\n \n \t\tif (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA)\n \t\t\tcontinue;\n-\t\thashcpy(base.sha1, obj->sha1);\n+\t\thashcpy(base.sha1, obj->idx.sha1);\n \t\tref = !find_delta_children(&base, &ref_first, &ref_last);\n \t\tmemset(&base, 0, sizeof(base));\n-\t\tbase.offset = obj->offset;\n+\t\tbase.offset = obj->idx.offset;\n \t\tofs = !find_delta_children(&base, &ofs_first, &ofs_last);\n \t\tif (!ref && !ofs)\n \t\t\tcontinue;\n@@ -535,11 +533,11 @@ static void append_obj_to_pack(const unsigned char *sha1, void *buf,\n \t}\n \theader[n++] = c;\n \twrite_or_die(output_fd, header, n);\n-\tobj[0].crc32 = crc32(0, Z_NULL, 0);\n-\tobj[0].crc32 = crc32(obj[0].crc32, header, n);\n-\tobj[1].offset = obj[0].offset + n;\n-\tobj[1].offset += write_compressed(output_fd, buf, size, &obj[0].crc32);\n-\thashcpy(obj->sha1, sha1);\n+\tobj[0].idx.crc32 = crc32(0, Z_NULL, 0);\n+\tobj[0].idx.crc32 = crc32(obj[0].idx.crc32, header, n);\n+\tobj[1].idx.offset = obj[0].idx.offset + n;\n+\tobj[1].idx.offset += write_compressed(output_fd, buf, size, &obj[0].idx.crc32);\n+\thashcpy(obj->idx.sha1, sha1);\n }\n \n static int delta_pos_compare(const void *_a, const void *_b)\n@@ -602,145 +600,6 @@ static void fix_unresolved_deltas(int nr_unresolved)\n \tfree(sorted_by_pos);\n }\n \n-static uint32_t index_default_version = 1;\n-static uint32_t index_off32_limit = 0x7fffffff;\n-\n-static int sha1_compare(const void *_a, const void *_b)\n-{\n-\tstruct object_entry *a = *(struct object_entry **)_a;\n-\tstruct object_entry *b = *(struct object_entry **)_b;\n-\treturn hashcmp(a->sha1, b->sha1);\n-}\n-\n-/*\n- * On entry *sha1 contains the pack content SHA1 hash, on exit it is\n- * the SHA1 hash of sorted object names.\n- */\n-static const char *write_index_file(const char *index_name, unsigned char *sha1)\n-{\n-\tstruct sha1file *f;\n-\tstruct object_entry **sorted_by_sha, **list, **last;\n-\tuint32_t array[256];\n-\tint i, fd;\n-\tSHA_CTX ctx;\n-\tuint32_t index_version;\n-\n-\tif (nr_objects) {\n-\t\tsorted_by_sha =\n-\t\t\txcalloc(nr_objects, sizeof(struct object_entry *));\n-\t\tlist = sorted_by_sha;\n-\t\tlast = sorted_by_sha + nr_objects;\n-\t\tfor (i = 0; i < nr_objects; ++i)\n-\t\t\tsorted_by_sha[i] = &objects[i];\n-\t\tqsort(sorted_by_sha, nr_objects, sizeof(sorted_by_sha[0]),\n-\t\t      sha1_compare);\n-\t}\n-\telse\n-\t\tsorted_by_sha = list = last = NULL;\n-\n-\tif (!index_name) {\n-\t\tstatic char tmpfile[PATH_MAX];\n-\t\tsnprintf(tmpfile, sizeof(tmpfile),\n-\t\t\t \"%s/tmp_idx_XXXXXX\", get_object_directory());\n-\t\tfd = mkstemp(tmpfile);\n-\t\tindex_name = xstrdup(tmpfile);\n-\t} else {\n-\t\tunlink(index_name);\n-\t\tfd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);\n-\t}\n-\tif (fd < 0)\n-\t\tdie(\"unable to create %s: %s\", index_name, strerror(errno));\n-\tf = sha1fd(fd, index_name);\n-\n-\t/* if last object's offset is >= 2^31 we should use index V2 */\n-\tindex_version = (objects[nr_objects-1].offset >> 31) ? 2 : index_default_version;\n-\n-\t/* index versions 2 and above need a header */\n-\tif (index_version >= 2) {\n-\t\tstruct pack_idx_header hdr;\n-\t\thdr.idx_signature = htonl(PACK_IDX_SIGNATURE);\n-\t\thdr.idx_version = htonl(index_version);\n-\t\tsha1write(f, &hdr, sizeof(hdr));\n-\t}\n-\n-\t/*\n-\t * Write the first-level table (the list is sorted,\n-\t * but we use a 256-entry lookup to be able to avoid\n-\t * having to do eight extra binary search iterations).\n-\t */\n-\tfor (i = 0; i < 256; i++) {\n-\t\tstruct object_entry **next = list;\n-\t\twhile (next < last) {\n-\t\t\tstruct object_entry *obj = *next;\n-\t\t\tif (obj->sha1[0] != i)\n-\t\t\t\tbreak;\n-\t\t\tnext++;\n-\t\t}\n-\t\tarray[i] = htonl(next - sorted_by_sha);\n-\t\tlist = next;\n-\t}\n-\tsha1write(f, array, 256 * 4);\n-\n-\t/* compute the SHA1 hash of sorted object names. */\n-\tSHA1_Init(&ctx);\n-\n-\t/*\n-\t * Write the actual SHA1 entries..\n-\t */\n-\tlist = sorted_by_sha;\n-\tfor (i = 0; i < nr_objects; i++) {\n-\t\tstruct object_entry *obj = *list++;\n-\t\tif (index_version < 2) {\n-\t\t\tuint32_t offset = htonl(obj->offset);\n-\t\t\tsha1write(f, &offset, 4);\n-\t\t}\n-\t\tsha1write(f, obj->sha1, 20);\n-\t\tSHA1_Update(&ctx, obj->sha1, 20);\n-\t}\n-\n-\tif (index_version >= 2) {\n-\t\tunsigned int nr_large_offset = 0;\n-\n-\t\t/* write the crc32 table */\n-\t\tlist = sorted_by_sha;\n-\t\tfor (i = 0; i < nr_objects; i++) {\n-\t\t\tstruct object_entry *obj = *list++;\n-\t\t\tuint32_t crc32_val = htonl(obj->crc32);\n-\t\t\tsha1write(f, &crc32_val, 4);\n-\t\t}\n-\n-\t\t/* write the 32-bit offset table */\n-\t\tlist = sorted_by_sha;\n-\t\tfor (i = 0; i < nr_objects; i++) {\n-\t\t\tstruct object_entry *obj = *list++;\n-\t\t\tuint32_t offset = (obj->offset <= index_off32_limit) ?\n-\t\t\t\tobj->offset : (0x80000000 | nr_large_offset++);\n-\t\t\toffset = htonl(offset);\n-\t\t\tsha1write(f, &offset, 4);\n-\t\t}\n-\n-\t\t/* write the large offset table */\n-\t\tlist = sorted_by_sha;\n-\t\twhile (nr_large_offset) {\n-\t\t\tstruct object_entry *obj = *list++;\n-\t\t\tuint64_t offset = obj->offset;\n-\t\t\tif (offset > index_off32_limit) {\n-\t\t\t\tuint32_t split[2];\n-\t\t\t\tsplit[0]\t= htonl(offset >> 32);\n-\t\t\t\tsplit[1] = htonl(offset & 0xffffffff);\n-\t\t\t\tsha1write(f, split, 8);\n-\t\t\t\tnr_large_offset--;\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-\tsha1write(f, sha1, 20);\n-\tsha1close(f, NULL, 1);\n-\tfree(sorted_by_sha);\n-\tSHA1_Final(sha1, &ctx);\n-\treturn index_name;\n-}\n-\n static void final(const char *final_pack_name, const char *curr_pack_name,\n \t\t  const char *final_index_name, const char *curr_index_name,\n \t\t  const char *keep_name, const char *keep_msg,\n@@ -830,6 +689,7 @@ int main(int argc, char **argv)\n \tconst char *curr_index, *index_name = NULL;\n \tconst char *keep_name = NULL, *keep_msg = NULL;\n \tchar *index_name_buf = NULL, *keep_name_buf = NULL;\n+\tstruct pack_idx_entry **idx_objects;\n \tunsigned char sha1[20];\n \n \tfor (i = 1; i < argc; i++) {\n@@ -865,12 +725,12 @@ int main(int argc, char **argv)\n \t\t\t\tindex_name = argv[++i];\n \t\t\t} else if (!prefixcmp(arg, \"--index-version=\")) {\n \t\t\t\tchar *c;\n-\t\t\t\tindex_default_version = strtoul(arg + 16, &c, 10);\n-\t\t\t\tif (index_default_version > 2)\n+\t\t\t\tpack_idx_default_version = strtoul(arg + 16, &c, 10);\n+\t\t\t\tif (pack_idx_default_version > 2)\n \t\t\t\t\tdie(\"bad %s\", arg);\n \t\t\t\tif (*c == ',')\n-\t\t\t\t\tindex_off32_limit = strtoul(c+1, &c, 0);\n-\t\t\t\tif (*c || index_off32_limit & 0x80000000)\n+\t\t\t\t\tpack_idx_off32_limit = strtoul(c+1, &c, 0);\n+\t\t\t\tif (*c || pack_idx_off32_limit & 0x80000000)\n \t\t\t\t\tdie(\"bad %s\", arg);\n \t\t\t} else\n \t\t\t\tusage(index_pack_usage);\n@@ -940,7 +800,13 @@ int main(int argc, char **argv)\n \t\t\t    nr_deltas - nr_resolved_deltas);\n \t}\n \tfree(deltas);\n-\tcurr_index = write_index_file(index_name, sha1);\n+\n+\tidx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *));\n+\tfor (i = 0; i < nr_objects; i++)\n+\t\tidx_objects[i] = &objects[i].idx;\n+\tcurr_index = write_idx_file(index_name, idx_objects, nr_objects, sha1);\n+\tfree(idx_objects);\n+\n \tfinal(pack_name, curr_pack,\n \t\tindex_name, curr_index,\n \t\tkeep_name, keep_msg,\ndiff --git a/pack-write.c b/pack-write.c\nindex ae2e481..1cf5f7c 100644\n--- a/pack-write.c\n+++ b/pack-write.c\n@@ -1,5 +1,147 @@\n #include \"cache.h\"\n #include \"pack.h\"\n+#include \"csum-file.h\"\n+\n+uint32_t pack_idx_default_version = 1;\n+uint32_t pack_idx_off32_limit = 0x7fffffff;\n+\n+static int sha1_compare(const void *_a, const void *_b)\n+{\n+\tstruct pack_idx_entry *a = *(struct pack_idx_entry **)_a;\n+\tstruct pack_idx_entry *b = *(struct pack_idx_entry **)_b;\n+\treturn hashcmp(a->sha1, b->sha1);\n+}\n+\n+/*\n+ * On entry *sha1 contains the pack content SHA1 hash, on exit it is\n+ * the SHA1 hash of sorted object names. The objects array passed in\n+ * will be sorted by SHA1 on exit.\n+ */\n+const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1)\n+{\n+\tstruct sha1file *f;\n+\tstruct pack_idx_entry **sorted_by_sha, **list, **last;\n+\toff_t last_obj_offset = 0;\n+\tuint32_t array[256];\n+\tint i, fd;\n+\tSHA_CTX ctx;\n+\tuint32_t index_version;\n+\n+\tif (nr_objects) {\n+\t\tsorted_by_sha = objects;\n+\t\tlist = sorted_by_sha;\n+\t\tlast = sorted_by_sha + nr_objects;\n+\t\tfor (i = 0; i < nr_objects; ++i) {\n+\t\t\tif (objects[i]->offset > last_obj_offset)\n+\t\t\t\tlast_obj_offset = objects[i]->offset;\n+\t\t}\n+\t\tqsort(sorted_by_sha, nr_objects, sizeof(sorted_by_sha[0]),\n+\t\t      sha1_compare);\n+\t}\n+\telse\n+\t\tsorted_by_sha = list = last = NULL;\n+\n+\tif (!index_name) {\n+\t\tstatic char tmpfile[PATH_MAX];\n+\t\tsnprintf(tmpfile, sizeof(tmpfile),\n+\t\t\t \"%s/tmp_idx_XXXXXX\", get_object_directory());\n+\t\tfd = mkstemp(tmpfile);\n+\t\tindex_name = xstrdup(tmpfile);\n+\t} else {\n+\t\tunlink(index_name);\n+\t\tfd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);\n+\t}\n+\tif (fd < 0)\n+\t\tdie(\"unable to create %s: %s\", index_name, strerror(errno));\n+\tf = sha1fd(fd, index_name);\n+\n+\t/* if last object's offset is >= 2^31 we should use index V2 */\n+\tindex_version = (last_obj_offset >> 31) ? 2 : pack_idx_default_version;\n+\n+\t/* index versions 2 and above need a header */\n+\tif (index_version >= 2) {\n+\t\tstruct pack_idx_header hdr;\n+\t\thdr.idx_signature = htonl(PACK_IDX_SIGNATURE);\n+\t\thdr.idx_version = htonl(index_version);\n+\t\tsha1write(f, &hdr, sizeof(hdr));\n+\t}\n+\n+\t/*\n+\t * Write the first-level table (the list is sorted,\n+\t * but we use a 256-entry lookup to be able to avoid\n+\t * having to do eight extra binary search iterations).\n+\t */\n+\tfor (i = 0; i < 256; i++) {\n+\t\tstruct pack_idx_entry **next = list;\n+\t\twhile (next < last) {\n+\t\t\tstruct pack_idx_entry *obj = *next;\n+\t\t\tif (obj->sha1[0] != i)\n+\t\t\t\tbreak;\n+\t\t\tnext++;\n+\t\t}\n+\t\tarray[i] = htonl(next - sorted_by_sha);\n+\t\tlist = next;\n+\t}\n+\tsha1write(f, array, 256 * 4);\n+\n+\t/* compute the SHA1 hash of sorted object names. */\n+\tSHA1_Init(&ctx);\n+\n+\t/*\n+\t * Write the actual SHA1 entries..\n+\t */\n+\tlist = sorted_by_sha;\n+\tfor (i = 0; i < nr_objects; i++) {\n+\t\tstruct pack_idx_entry *obj = *list++;\n+\t\tif (index_version < 2) {\n+\t\t\tuint32_t offset = htonl(obj->offset);\n+\t\t\tsha1write(f, &offset, 4);\n+\t\t}\n+\t\tsha1write(f, obj->sha1, 20);\n+\t\tSHA1_Update(&ctx, obj->sha1, 20);\n+\t}\n+\n+\tif (index_version >= 2) {\n+\t\tunsigned int nr_large_offset = 0;\n+\n+\t\t/* write the crc32 table */\n+\t\tlist = sorted_by_sha;\n+\t\tfor (i = 0; i < nr_objects; i++) {\n+\t\t\tstruct pack_idx_entry *obj = *list++;\n+\t\t\tuint32_t crc32_val = htonl(obj->crc32);\n+\t\t\tsha1write(f, &crc32_val, 4);\n+\t\t}\n+\n+\t\t/* write the 32-bit offset table */\n+\t\tlist = sorted_by_sha;\n+\t\tfor (i = 0; i < nr_objects; i++) {\n+\t\t\tstruct pack_idx_entry *obj = *list++;\n+\t\t\tuint32_t offset = (obj->offset <= pack_idx_off32_limit) ?\n+\t\t\t\tobj->offset : (0x80000000 | nr_large_offset++);\n+\t\t\toffset = htonl(offset);\n+\t\t\tsha1write(f, &offset, 4);\n+\t\t}\n+\n+\t\t/* write the large offset table */\n+\t\tlist = sorted_by_sha;\n+\t\twhile (nr_large_offset) {\n+\t\t\tstruct pack_idx_entry *obj = *list++;\n+\t\t\tuint64_t offset = obj->offset;\n+\t\t\tif (offset > pack_idx_off32_limit) {\n+\t\t\t\tuint32_t split[2];\n+\t\t\t\tsplit[0] = htonl(offset >> 32);\n+\t\t\t\tsplit[1] = htonl(offset & 0xffffffff);\n+\t\t\t\tsha1write(f, split, 8);\n+\t\t\t\tnr_large_offset--;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tsha1write(f, sha1, 20);\n+\tsha1close(f, NULL, 1);\n+\tSHA1_Final(sha1, &ctx);\n+\treturn index_name;\n+}\n \n void fixup_pack_header_footer(int pack_fd,\n \t\t\t unsigned char *pack_file_sha1,\ndiff --git a/pack.h b/pack.h\nindex d667fb8..f357c9f 100644\n--- a/pack.h\n+++ b/pack.h\n@@ -34,6 +34,10 @@ struct pack_header {\n  */\n #define PACK_IDX_SIGNATURE 0xff744f63\t/* \"\\377tOc\" */\n \n+/* These may be overridden by command-line parameters */\n+extern uint32_t pack_idx_default_version;\n+extern uint32_t pack_idx_off32_limit;\n+\n /*\n  * Packed object index header\n  */\n@@ -42,6 +46,16 @@ struct pack_idx_header {\n \tuint32_t idx_version;\n };\n \n+/*\n+ * Common part of object structure used for write_idx_file\n+ */\n+struct pack_idx_entry {\n+\tunsigned char sha1[20];\n+\tuint32_t crc32;\n+\toff_t offset;\n+};\n+\n+extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1);\n \n extern int verify_pack(struct packed_git *, int);\n extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t);\n-- \n1.5.1\n"},{"id":"43784","messageId":"alpine.LFD.0.99.0706012203170.12885@xanadu.home","threadId":"8391","inReplyTo":"20070602014836.0D5644DF122@geert-boschs-computer.local","subject":"Re: [PATCH] Unify write_index_file functions","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2007-06-02T02:04:20Z","receivedAt":"2007-06-02T02:04:20Z","isPatch":true,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Fri, 1 Jun 2007, Geert Bosch wrote:\n\n> This patch unifies the write_index_file functions in\n> builtin-pack-objects.c and index-pack.c.  As the name\n> \"index\" is overloaded in git, move in the direction of\n> using \"idx\" and \"pack idx\" when refering to the pack index.\n> There should be no change in functionality.\n> \n> Signed-off-by: Geert Bosch <bosch@gnat.com>\n\nAcked-by: Nicolas Pitre <nico@cam.org>\n\n> ---\n>  builtin-pack-objects.c |  218 +++++++++++-------------------------------------\n>  index-pack.c           |  208 ++++++++-------------------------------------\n>  pack-write.c           |  142 +++++++++++++++++++++++++++++++\n>  pack.h                 |   14 +++\n>  4 files changed, 243 insertions(+), 339 deletions(-)\n> \n> Now with corrected commit message.\n> \n>   -Geert\n> \n> diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c\n> index e52332d..a247238 100644\n> --- a/builtin-pack-objects.c\n> +++ b/builtin-pack-objects.c\n> @@ -23,10 +23,9 @@ git-pack-objects [{ -q | --progress | --all-progress }] [--max-pack-size=N] \\n\\\n>  \t[--stdout | base-name] [<ref-list | <object-list]\";\n>  \n>  struct object_entry {\n> -\tunsigned char sha1[20];\n> -\tuint32_t crc32;\t\t/* crc of raw pack data for this object */\n> -\toff_t offset;\t\t/* offset into the final pack file */\n> +\tstruct pack_idx_entry idx;\n>  \tunsigned long size;\t/* uncompressed size */\n> +\n>  \tunsigned int hash;\t/* name hint hash */\n>  \tunsigned int depth;\t/* delta depth */\n>  \tstruct packed_git *in_pack; \t/* already in pack */\n> @@ -65,7 +64,6 @@ static int allow_ofs_delta;\n>  static const char *pack_tmp_name, *idx_tmp_name;\n>  static char tmpname[PATH_MAX];\n>  static const char *base_name;\n> -static unsigned char pack_file_sha1[20];\n>  static int progress = 1;\n>  static int window = 10;\n>  static uint32_t pack_size_limit;\n> @@ -241,11 +239,11 @@ static void *delta_against(void *buf, unsigned long size, struct object_entry *e\n>  {\n>  \tunsigned long othersize, delta_size;\n>  \tenum object_type type;\n> -\tvoid *otherbuf = read_sha1_file(entry->delta->sha1, &type, &othersize);\n> +\tvoid *otherbuf = read_sha1_file(entry->delta->idx.sha1, &type, &othersize);\n>  \tvoid *delta_buf;\n>  \n>  \tif (!otherbuf)\n> -\t\tdie(\"unable to read %s\", sha1_to_hex(entry->delta->sha1));\n> +\t\tdie(\"unable to read %s\", sha1_to_hex(entry->delta->idx.sha1));\n>          delta_buf = diff_delta(otherbuf, othersize,\n>  \t\t\t       buf, size, &delta_size, 0);\n>          if (!delta_buf || delta_size != entry->delta_size)\n> @@ -374,11 +372,11 @@ static unsigned long write_object(struct sha1file *f,\n>  \t\t\t\t/* yes if unlimited packfile */\n>  \t\t\t\t!pack_size_limit ? 1 :\n>  \t\t\t\t/* no if base written to previous pack */\n> -\t\t\t\tentry->delta->offset == (off_t)-1 ? 0 :\n> +\t\t\t\tentry->delta->idx.offset == (off_t)-1 ? 0 :\n>  \t\t\t\t/* otherwise double-check written to this\n>  \t\t\t\t * pack,  like we do below\n>  \t\t\t\t */\n> -\t\t\t\tentry->delta->offset ? 1 : 0;\n> +\t\t\t\tentry->delta->idx.offset ? 1 : 0;\n>  \n>  \tif (!pack_to_stdout)\n>  \t\tcrc32_begin(f);\n> @@ -405,16 +403,16 @@ static unsigned long write_object(struct sha1file *f,\n>  \t\tz_stream stream;\n>  \t\tunsigned long maxsize;\n>  \t\tvoid *out;\n> -\t\tbuf = read_sha1_file(entry->sha1, &type, &size);\n> +\t\tbuf = read_sha1_file(entry->idx.sha1, &type, &size);\n>  \t\tif (!buf)\n> -\t\t\tdie(\"unable to read %s\", sha1_to_hex(entry->sha1));\n> +\t\t\tdie(\"unable to read %s\", sha1_to_hex(entry->idx.sha1));\n>  \t\tif (size != entry->size)\n>  \t\t\tdie(\"object %s size inconsistency (%lu vs %lu)\",\n> -\t\t\t    sha1_to_hex(entry->sha1), size, entry->size);\n> +\t\t\t    sha1_to_hex(entry->idx.sha1), size, entry->size);\n>  \t\tif (usable_delta) {\n>  \t\t\tbuf = delta_against(buf, size, entry);\n>  \t\t\tsize = entry->delta_size;\n> -\t\t\tobj_type = (allow_ofs_delta && entry->delta->offset) ?\n> +\t\t\tobj_type = (allow_ofs_delta && entry->delta->idx.offset) ?\n>  \t\t\t\tOBJ_OFS_DELTA : OBJ_REF_DELTA;\n>  \t\t} else {\n>  \t\t\t/*\n> @@ -451,7 +449,7 @@ static unsigned long write_object(struct sha1file *f,\n>  \t\t\t * encoding of the relative offset for the delta\n>  \t\t\t * base from this object's position in the pack.\n>  \t\t\t */\n> -\t\t\toff_t ofs = entry->offset - entry->delta->offset;\n> +\t\t\toff_t ofs = entry->idx.offset - entry->delta->idx.offset;\n>  \t\t\tunsigned pos = sizeof(dheader) - 1;\n>  \t\t\tdheader[pos] = ofs & 127;\n>  \t\t\twhile (ofs >>= 7)\n> @@ -475,7 +473,7 @@ static unsigned long write_object(struct sha1file *f,\n>  \t\t\t\treturn 0;\n>  \t\t\t}\n>  \t\t\tsha1write(f, header, hdrlen);\n> -\t\t\tsha1write(f, entry->delta->sha1, 20);\n> +\t\t\tsha1write(f, entry->delta->idx.sha1, 20);\n>  \t\t\thdrlen += 20;\n>  \t\t} else {\n>  \t\t\tif (limit && hdrlen + datalen + 20 >= limit) {\n> @@ -496,7 +494,7 @@ static unsigned long write_object(struct sha1file *f,\n>  \t\toff_t offset;\n>  \n>  \t\tif (entry->delta) {\n> -\t\t\tobj_type = (allow_ofs_delta && entry->delta->offset) ?\n> +\t\t\tobj_type = (allow_ofs_delta && entry->delta->idx.offset) ?\n>  \t\t\t\tOBJ_OFS_DELTA : OBJ_REF_DELTA;\n>  \t\t\treused_delta++;\n>  \t\t}\n> @@ -506,11 +504,11 @@ static unsigned long write_object(struct sha1file *f,\n>  \t\tdatalen = revidx[1].offset - offset;\n>  \t\tif (!pack_to_stdout && p->index_version > 1 &&\n>  \t\t    check_pack_crc(p, &w_curs, offset, datalen, revidx->nr))\n> -\t\t\tdie(\"bad packed object CRC for %s\", sha1_to_hex(entry->sha1));\n> +\t\t\tdie(\"bad packed object CRC for %s\", sha1_to_hex(entry->idx.sha1));\n>  \t\toffset += entry->in_pack_header_size;\n>  \t\tdatalen -= entry->in_pack_header_size;\n>  \t\tif (obj_type == OBJ_OFS_DELTA) {\n> -\t\t\toff_t ofs = entry->offset - entry->delta->offset;\n> +\t\t\toff_t ofs = entry->idx.offset - entry->delta->idx.offset;\n>  \t\t\tunsigned pos = sizeof(dheader) - 1;\n>  \t\t\tdheader[pos] = ofs & 127;\n>  \t\t\twhile (ofs >>= 7)\n> @@ -524,7 +522,7 @@ static unsigned long write_object(struct sha1file *f,\n>  \t\t\tif (limit && hdrlen + 20 + datalen + 20 >= limit)\n>  \t\t\t\treturn 0;\n>  \t\t\tsha1write(f, header, hdrlen);\n> -\t\t\tsha1write(f, entry->delta->sha1, 20);\n> +\t\t\tsha1write(f, entry->delta->idx.sha1, 20);\n>  \t\t\thdrlen += 20;\n>  \t\t} else {\n>  \t\t\tif (limit && hdrlen + datalen + 20 >= limit)\n> @@ -534,7 +532,7 @@ static unsigned long write_object(struct sha1file *f,\n>  \n>  \t\tif (!pack_to_stdout && p->index_version == 1 &&\n>  \t\t    check_pack_inflate(p, &w_curs, offset, datalen, entry->size))\n> -\t\t\tdie(\"corrupt packed object for %s\", sha1_to_hex(entry->sha1));\n> +\t\t\tdie(\"corrupt packed object for %s\", sha1_to_hex(entry->idx.sha1));\n>  \t\tcopy_pack_data(f, p, &w_curs, offset, datalen);\n>  \t\tunuse_pack(&w_curs);\n>  \t\treused++;\n> @@ -543,7 +541,7 @@ static unsigned long write_object(struct sha1file *f,\n>  \t\twritten_delta++;\n>  \twritten++;\n>  \tif (!pack_to_stdout)\n> -\t\tentry->crc32 = crc32_end(f);\n> +\t\tentry->idx.crc32 = crc32_end(f);\n>  \treturn hdrlen + datalen;\n>  }\n>  \n> @@ -554,7 +552,7 @@ static off_t write_one(struct sha1file *f,\n>  \tunsigned long size;\n>  \n>  \t/* offset is non zero if object is written already. */\n> -\tif (e->offset || e->preferred_base)\n> +\tif (e->idx.offset || e->preferred_base)\n>  \t\treturn offset;\n>  \n>  \t/* if we are deltified, write out base object first. */\n> @@ -564,10 +562,10 @@ static off_t write_one(struct sha1file *f,\n>  \t\t\treturn 0;\n>  \t}\n>  \n> -\te->offset = offset;\n> +\te->idx.offset = offset;\n>  \tsize = write_object(f, e, offset);\n>  \tif (!size) {\n> -\t\te->offset = 0;\n> +\t\te->idx.offset = 0;\n>  \t\treturn 0;\n>  \t}\n>  \twritten_list[nr_written++] = e;\n> @@ -584,8 +582,7 @@ static int open_object_dir_tmp(const char *path)\n>      return mkstemp(tmpname);\n>  }\n>  \n> -/* forward declarations for write_pack_file */\n> -static void write_index_file(off_t last_obj_offset, unsigned char *sha1);\n> +/* forward declaration for write_pack_file */\n>  static int adjust_perm(const char *path, mode_t mode);\n>  \n>  static void write_pack_file(void)\n> @@ -602,6 +599,8 @@ static void write_pack_file(void)\n>  \twritten_list = xmalloc(nr_objects * sizeof(struct object_entry *));\n>  \n>  \tdo {\n> +\t\tunsigned char sha1[20];\n> +\n>  \t\tif (pack_to_stdout) {\n>  \t\t\tf = sha1fd(1, \"<stdout>\");\n>  \t\t} else {\n> @@ -633,23 +632,23 @@ static void write_pack_file(void)\n>  \t\t * If so, rewrite it like in fast-import\n>  \t\t */\n>  \t\tif (pack_to_stdout || nr_written == nr_remaining) {\n> -\t\t\tsha1close(f, pack_file_sha1, 1);\n> +\t\t\tsha1close(f, sha1, 1);\n>  \t\t} else {\n> -\t\t\tsha1close(f, pack_file_sha1, 0);\n> -\t\t\tfixup_pack_header_footer(f->fd, pack_file_sha1, pack_tmp_name, nr_written);\n> +\t\t\tsha1close(f, sha1, 0);\n> +\t\t\tfixup_pack_header_footer(f->fd, sha1, pack_tmp_name, nr_written);\n>  \t\t\tclose(f->fd);\n>  \t\t}\n>  \n>  \t\tif (!pack_to_stdout) {\n> -\t\t\tunsigned char object_list_sha1[20];\n>  \t\t\tmode_t mode = umask(0);\n>  \n>  \t\t\tumask(mode);\n>  \t\t\tmode = 0444 & ~mode;\n>  \n> -\t\t\twrite_index_file(last_obj_offset, object_list_sha1);\n> +\t\t\tidx_tmp_name = write_idx_file(NULL,\n> +\t\t\t\t(struct pack_idx_entry **) written_list, nr_written, sha1);\n>  \t\t\tsnprintf(tmpname, sizeof(tmpname), \"%s-%s.pack\",\n> -\t\t\t\t base_name, sha1_to_hex(object_list_sha1));\n> +\t\t\t\t base_name, sha1_to_hex(sha1));\n>  \t\t\tif (adjust_perm(pack_tmp_name, mode))\n>  \t\t\t\tdie(\"unable to make temporary pack file readable: %s\",\n>  \t\t\t\t    strerror(errno));\n> @@ -657,19 +656,19 @@ static void write_pack_file(void)\n>  \t\t\t\tdie(\"unable to rename temporary pack file: %s\",\n>  \t\t\t\t    strerror(errno));\n>  \t\t\tsnprintf(tmpname, sizeof(tmpname), \"%s-%s.idx\",\n> -\t\t\t\t base_name, sha1_to_hex(object_list_sha1));\n> +\t\t\t\t base_name, sha1_to_hex(sha1));\n>  \t\t\tif (adjust_perm(idx_tmp_name, mode))\n>  \t\t\t\tdie(\"unable to make temporary index file readable: %s\",\n>  \t\t\t\t    strerror(errno));\n>  \t\t\tif (rename(idx_tmp_name, tmpname))\n>  \t\t\t\tdie(\"unable to rename temporary index file: %s\",\n>  \t\t\t\t    strerror(errno));\n> -\t\t\tputs(sha1_to_hex(object_list_sha1));\n> +\t\t\tputs(sha1_to_hex(sha1));\n>  \t\t}\n>  \n>  \t\t/* mark written objects as written to previous pack */\n>  \t\tfor (j = 0; j < nr_written; j++) {\n> -\t\t\twritten_list[j]->offset = (off_t)-1;\n> +\t\t\twritten_list[j]->idx.offset = (off_t)-1;\n>  \t\t}\n>  \t\tnr_remaining -= nr_written;\n>  \t} while (nr_remaining && i < nr_objects);\n> @@ -687,129 +686,12 @@ static void write_pack_file(void)\n>  \t */\n>  \tfor (j = 0; i < nr_objects; i++) {\n>  \t\tstruct object_entry *e = objects + i;\n> -\t\tj += !e->offset && !e->preferred_base;\n> +\t\tj += !e->idx.offset && !e->preferred_base;\n>  \t}\n>  \tif (j)\n>  \t\tdie(\"wrote %u objects as expected but %u unwritten\", written, j);\n>  }\n>  \n> -static int sha1_sort(const void *_a, const void *_b)\n> -{\n> -\tconst struct object_entry *a = *(struct object_entry **)_a;\n> -\tconst struct object_entry *b = *(struct object_entry **)_b;\n> -\treturn hashcmp(a->sha1, b->sha1);\n> -}\n> -\n> -static uint32_t index_default_version = 1;\n> -static uint32_t index_off32_limit = 0x7fffffff;\n> -\n> -static void write_index_file(off_t last_obj_offset, unsigned char *sha1)\n> -{\n> -\tstruct sha1file *f;\n> -\tstruct object_entry **sorted_by_sha, **list, **last;\n> -\tuint32_t array[256];\n> -\tuint32_t i, index_version;\n> -\tSHA_CTX ctx;\n> -\n> -\tint fd = open_object_dir_tmp(\"tmp_idx_XXXXXX\");\n> -\tif (fd < 0)\n> -\t\tdie(\"unable to create %s: %s\\n\", tmpname, strerror(errno));\n> -\tidx_tmp_name = xstrdup(tmpname);\n> -\tf = sha1fd(fd, idx_tmp_name);\n> -\n> -\tif (nr_written) {\n> -\t\tsorted_by_sha = written_list;\n> -\t\tqsort(sorted_by_sha, nr_written, sizeof(*sorted_by_sha), sha1_sort);\n> -\t\tlist = sorted_by_sha;\n> -\t\tlast = sorted_by_sha + nr_written;\n> -\t} else\n> -\t\tsorted_by_sha = list = last = NULL;\n> -\n> -\t/* if last object's offset is >= 2^31 we should use index V2 */\n> -\tindex_version = (last_obj_offset >> 31) ? 2 : index_default_version;\n> -\n> -\t/* index versions 2 and above need a header */\n> -\tif (index_version >= 2) {\n> -\t\tstruct pack_idx_header hdr;\n> -\t\thdr.idx_signature = htonl(PACK_IDX_SIGNATURE);\n> -\t\thdr.idx_version = htonl(index_version);\n> -\t\tsha1write(f, &hdr, sizeof(hdr));\n> -\t}\n> -\n> -\t/*\n> -\t * Write the first-level table (the list is sorted,\n> -\t * but we use a 256-entry lookup to be able to avoid\n> -\t * having to do eight extra binary search iterations).\n> -\t */\n> -\tfor (i = 0; i < 256; i++) {\n> -\t\tstruct object_entry **next = list;\n> -\t\twhile (next < last) {\n> -\t\t\tstruct object_entry *entry = *next;\n> -\t\t\tif (entry->sha1[0] != i)\n> -\t\t\t\tbreak;\n> -\t\t\tnext++;\n> -\t\t}\n> -\t\tarray[i] = htonl(next - sorted_by_sha);\n> -\t\tlist = next;\n> -\t}\n> -\tsha1write(f, array, 256 * 4);\n> -\n> -\t/* Compute the SHA1 hash of sorted object names. */\n> -\tSHA1_Init(&ctx);\n> -\n> -\t/* Write the actual SHA1 entries. */\n> -\tlist = sorted_by_sha;\n> -\tfor (i = 0; i < nr_written; i++) {\n> -\t\tstruct object_entry *entry = *list++;\n> -\t\tif (index_version < 2) {\n> -\t\t\tuint32_t offset = htonl(entry->offset);\n> -\t\t\tsha1write(f, &offset, 4);\n> -\t\t}\n> -\t\tsha1write(f, entry->sha1, 20);\n> -\t\tSHA1_Update(&ctx, entry->sha1, 20);\n> -\t}\n> -\n> -\tif (index_version >= 2) {\n> -\t\tunsigned int nr_large_offset = 0;\n> -\n> -\t\t/* write the crc32 table */\n> -\t\tlist = sorted_by_sha;\n> -\t\tfor (i = 0; i < nr_written; i++) {\n> -\t\t\tstruct object_entry *entry = *list++;\n> -\t\t\tuint32_t crc32_val = htonl(entry->crc32);\n> -\t\t\tsha1write(f, &crc32_val, 4);\n> -\t\t}\n> -\n> -\t\t/* write the 32-bit offset table */\n> -\t\tlist = sorted_by_sha;\n> -\t\tfor (i = 0; i < nr_written; i++) {\n> -\t\t\tstruct object_entry *entry = *list++;\n> -\t\t\tuint32_t offset = (entry->offset <= index_off32_limit) ?\n> -\t\t\t\tentry->offset : (0x80000000 | nr_large_offset++);\n> -\t\t\toffset = htonl(offset);\n> -\t\t\tsha1write(f, &offset, 4);\n> -\t\t}\n> -\n> -\t\t/* write the large offset table */\n> -\t\tlist = sorted_by_sha;\n> -\t\twhile (nr_large_offset) {\n> -\t\t\tstruct object_entry *entry = *list++;\n> -\t\t\tuint64_t offset = entry->offset;\n> -\t\t\tif (offset > index_off32_limit) {\n> -\t\t\t\tuint32_t split[2];\n> -\t\t\t\tsplit[0]        = htonl(offset >> 32);\n> -\t\t\t\tsplit[1] = htonl(offset & 0xffffffff);\n> -\t\t\t\tsha1write(f, split, 8);\n> -\t\t\t\tnr_large_offset--;\n> -\t\t\t}\n> -\t\t}\n> -\t}\n> -\n> -\tsha1write(f, pack_file_sha1, 20);\n> -\tsha1close(f, NULL, 1);\n> -\tSHA1_Final(sha1, &ctx);\n> -}\n> -\n>  static int locate_object_entry_hash(const unsigned char *sha1)\n>  {\n>  \tint i;\n> @@ -817,7 +699,7 @@ static int locate_object_entry_hash(const unsigned char *sha1)\n>  \tmemcpy(&ui, sha1, sizeof(unsigned int));\n>  \ti = ui % object_ix_hashsz;\n>  \twhile (0 < object_ix[i]) {\n> -\t\tif (!hashcmp(sha1, objects[object_ix[i] - 1].sha1))\n> +\t\tif (!hashcmp(sha1, objects[object_ix[i] - 1].idx.sha1))\n>  \t\t\treturn i;\n>  \t\tif (++i == object_ix_hashsz)\n>  \t\t\ti = 0;\n> @@ -849,7 +731,7 @@ static void rehash_objects(void)\n>  \tobject_ix = xrealloc(object_ix, sizeof(int) * object_ix_hashsz);\n>  \tmemset(object_ix, 0, sizeof(int) * object_ix_hashsz);\n>  \tfor (i = 0, oe = objects; i < nr_objects; i++, oe++) {\n> -\t\tint ix = locate_object_entry_hash(oe->sha1);\n> +\t\tint ix = locate_object_entry_hash(oe->idx.sha1);\n>  \t\tif (0 <= ix)\n>  \t\t\tcontinue;\n>  \t\tix = -1 - ix;\n> @@ -943,7 +825,7 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,\n>  \n>  \tentry = objects + nr_objects++;\n>  \tmemset(entry, 0, sizeof(*entry));\n> -\thashcpy(entry->sha1, sha1);\n> +\thashcpy(entry->idx.sha1, sha1);\n>  \tentry->hash = hash;\n>  \tif (type)\n>  \t\tentry->type = type;\n> @@ -1263,13 +1145,13 @@ static void check_object(struct object_entry *entry)\n>  \t\t\t\tofs += 1;\n>  \t\t\t\tif (!ofs || MSB(ofs, 7))\n>  \t\t\t\t\tdie(\"delta base offset overflow in pack for %s\",\n> -\t\t\t\t\t    sha1_to_hex(entry->sha1));\n> +\t\t\t\t\t    sha1_to_hex(entry->idx.sha1));\n>  \t\t\t\tc = buf[used_0++];\n>  \t\t\t\tofs = (ofs << 7) + (c & 127);\n>  \t\t\t}\n>  \t\t\tif (ofs >= entry->in_pack_offset)\n>  \t\t\t\tdie(\"delta base offset out of bound for %s\",\n> -\t\t\t\t    sha1_to_hex(entry->sha1));\n> +\t\t\t\t    sha1_to_hex(entry->idx.sha1));\n>  \t\t\tofs = entry->in_pack_offset - ofs;\n>  \t\t\tif (!no_reuse_delta && !entry->preferred_base)\n>  \t\t\t\tbase_ref = find_packed_object_name(p, ofs);\n> @@ -1316,10 +1198,10 @@ static void check_object(struct object_entry *entry)\n>  \t\tunuse_pack(&w_curs);\n>  \t}\n>  \n> -\tentry->type = sha1_object_info(entry->sha1, &entry->size);\n> +\tentry->type = sha1_object_info(entry->idx.sha1, &entry->size);\n>  \tif (entry->type < 0)\n>  \t\tdie(\"unable to get type of object %s\",\n> -\t\t    sha1_to_hex(entry->sha1));\n> +\t\t    sha1_to_hex(entry->idx.sha1));\n>  }\n>  \n>  static int pack_offset_sort(const void *_a, const void *_b)\n> @@ -1329,7 +1211,7 @@ static int pack_offset_sort(const void *_a, const void *_b)\n>  \n>  \t/* avoid filesystem trashing with loose objects */\n>  \tif (!a->in_pack && !b->in_pack)\n> -\t\treturn hashcmp(a->sha1, b->sha1);\n> +\t\treturn hashcmp(a->idx.sha1, b->idx.sha1);\n>  \n>  \tif (a->in_pack < b->in_pack)\n>  \t\treturn -1;\n> @@ -1441,16 +1323,16 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,\n>  \n>  \t/* Load data if not already done */\n>  \tif (!trg->data) {\n> -\t\ttrg->data = read_sha1_file(trg_entry->sha1, &type, &sz);\n> +\t\ttrg->data = read_sha1_file(trg_entry->idx.sha1, &type, &sz);\n>  \t\tif (sz != trg_size)\n>  \t\t\tdie(\"object %s inconsistent object length (%lu vs %lu)\",\n> -\t\t\t    sha1_to_hex(trg_entry->sha1), sz, trg_size);\n> +\t\t\t    sha1_to_hex(trg_entry->idx.sha1), sz, trg_size);\n>  \t}\n>  \tif (!src->data) {\n> -\t\tsrc->data = read_sha1_file(src_entry->sha1, &type, &sz);\n> +\t\tsrc->data = read_sha1_file(src_entry->idx.sha1, &type, &sz);\n>  \t\tif (sz != src_size)\n>  \t\t\tdie(\"object %s inconsistent object length (%lu vs %lu)\",\n> -\t\t\t    sha1_to_hex(src_entry->sha1), sz, src_size);\n> +\t\t\t    sha1_to_hex(src_entry->idx.sha1), sz, src_size);\n>  \t}\n>  \tif (!src->index) {\n>  \t\tsrc->index = create_delta_index(src->data, src_size);\n> @@ -1825,12 +1707,12 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)\n>  \t\t}\n>  \t\tif (!prefixcmp(arg, \"--index-version=\")) {\n>  \t\t\tchar *c;\n> -\t\t\tindex_default_version = strtoul(arg + 16, &c, 10);\n> -\t\t\tif (index_default_version > 2)\n> +\t\t\tpack_idx_default_version = strtoul(arg + 16, &c, 10);\n> +\t\t\tif (pack_idx_default_version > 2)\n>  \t\t\t\tdie(\"bad %s\", arg);\n>  \t\t\tif (*c == ',')\n> -\t\t\t\tindex_off32_limit = strtoul(c+1, &c, 0);\n> -\t\t\tif (*c || index_off32_limit & 0x80000000)\n> +\t\t\t\tpack_idx_off32_limit = strtoul(c+1, &c, 0);\n> +\t\t\tif (*c || pack_idx_off32_limit & 0x80000000)\n>  \t\t\t\tdie(\"bad %s\", arg);\n>  \t\t\tcontinue;\n>  \t\t}\n> diff --git a/index-pack.c b/index-pack.c\n> index 58c4a9c..82c8da3 100644\n> --- a/index-pack.c\n> +++ b/index-pack.c\n> @@ -13,13 +13,11 @@ static const char index_pack_usage[] =\n>  \n>  struct object_entry\n>  {\n> -\toff_t offset;\n> +\tstruct pack_idx_entry idx;\n>  \tunsigned long size;\n>  \tunsigned int hdr_size;\n> -\tuint32_t crc32;\n>  \tenum object_type type;\n>  \tenum object_type real_type;\n> -\tunsigned char sha1[20];\n>  };\n>  \n>  union delta_base {\n> @@ -197,7 +195,7 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_\n>  \tunsigned shift;\n>  \tvoid *data;\n>  \n> -\tobj->offset = consumed_bytes;\n> +\tobj->idx.offset = consumed_bytes;\n>  \tinput_crc32 = crc32(0, Z_NULL, 0);\n>  \n>  \tp = fill(1);\n> @@ -229,15 +227,15 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_\n>  \t\twhile (c & 128) {\n>  \t\t\tbase_offset += 1;\n>  \t\t\tif (!base_offset || MSB(base_offset, 7))\n> -\t\t\t\tbad_object(obj->offset, \"offset value overflow for delta base object\");\n> +\t\t\t\tbad_object(obj->idx.offset, \"offset value overflow for delta base object\");\n>  \t\t\tp = fill(1);\n>  \t\t\tc = *p;\n>  \t\t\tuse(1);\n>  \t\t\tbase_offset = (base_offset << 7) + (c & 127);\n>  \t\t}\n> -\t\tdelta_base->offset = obj->offset - base_offset;\n> -\t\tif (delta_base->offset >= obj->offset)\n> -\t\t\tbad_object(obj->offset, \"delta base offset is out of bound\");\n> +\t\tdelta_base->offset = obj->idx.offset - base_offset;\n> +\t\tif (delta_base->offset >= obj->idx.offset)\n> +\t\t\tbad_object(obj->idx.offset, \"delta base offset is out of bound\");\n>  \t\tbreak;\n>  \tcase OBJ_COMMIT:\n>  \tcase OBJ_TREE:\n> @@ -245,19 +243,19 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_\n>  \tcase OBJ_TAG:\n>  \t\tbreak;\n>  \tdefault:\n> -\t\tbad_object(obj->offset, \"unknown object type %d\", obj->type);\n> +\t\tbad_object(obj->idx.offset, \"unknown object type %d\", obj->type);\n>  \t}\n> -\tobj->hdr_size = consumed_bytes - obj->offset;\n> +\tobj->hdr_size = consumed_bytes - obj->idx.offset;\n>  \n> -\tdata = unpack_entry_data(obj->offset, obj->size);\n> -\tobj->crc32 = input_crc32;\n> +\tdata = unpack_entry_data(obj->idx.offset, obj->size);\n> +\tobj->idx.crc32 = input_crc32;\n>  \treturn data;\n>  }\n>  \n>  static void *get_data_from_pack(struct object_entry *obj)\n>  {\n> -\tunsigned long from = obj[0].offset + obj[0].hdr_size;\n> -\tunsigned long len = obj[1].offset - from;\n> +\tunsigned long from = obj[0].idx.offset + obj[0].hdr_size;\n> +\tunsigned long len = obj[1].idx.offset - from;\n>  \tunsigned long rdy = 0;\n>  \tunsigned char *src, *data;\n>  \tz_stream stream;\n> @@ -360,11 +358,11 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data,\n>  \t\t\t     &result_size);\n>  \tfree(delta_data);\n>  \tif (!result)\n> -\t\tbad_object(delta_obj->offset, \"failed to apply delta\");\n> -\tsha1_object(result, result_size, type, delta_obj->sha1);\n> +\t\tbad_object(delta_obj->idx.offset, \"failed to apply delta\");\n> +\tsha1_object(result, result_size, type, delta_obj->idx.sha1);\n>  \tnr_resolved_deltas++;\n>  \n> -\thashcpy(delta_base.sha1, delta_obj->sha1);\n> +\thashcpy(delta_base.sha1, delta_obj->idx.sha1);\n>  \tif (!find_delta_children(&delta_base, &first, &last)) {\n>  \t\tfor (j = first; j <= last; j++) {\n>  \t\t\tstruct object_entry *child = objects + deltas[j].obj_no;\n> @@ -374,7 +372,7 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data,\n>  \t}\n>  \n>  \tmemset(&delta_base, 0, sizeof(delta_base));\n> -\tdelta_base.offset = delta_obj->offset;\n> +\tdelta_base.offset = delta_obj->idx.offset;\n>  \tif (!find_delta_children(&delta_base, &first, &last)) {\n>  \t\tfor (j = first; j <= last; j++) {\n>  \t\t\tstruct object_entry *child = objects + deltas[j].obj_no;\n> @@ -418,12 +416,12 @@ static void parse_pack_objects(unsigned char *sha1)\n>  \t\t\tdelta->obj_no = i;\n>  \t\t\tdelta++;\n>  \t\t} else\n> -\t\t\tsha1_object(data, obj->size, obj->type, obj->sha1);\n> +\t\t\tsha1_object(data, obj->size, obj->type, obj->idx.sha1);\n>  \t\tfree(data);\n>  \t\tif (verbose)\n>  \t\t\tdisplay_progress(&progress, i+1);\n>  \t}\n> -\tobjects[i].offset = consumed_bytes;\n> +\tobjects[i].idx.offset = consumed_bytes;\n>  \tif (verbose)\n>  \t\tstop_progress(&progress);\n>  \n> @@ -465,10 +463,10 @@ static void parse_pack_objects(unsigned char *sha1)\n>  \n>  \t\tif (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA)\n>  \t\t\tcontinue;\n> -\t\thashcpy(base.sha1, obj->sha1);\n> +\t\thashcpy(base.sha1, obj->idx.sha1);\n>  \t\tref = !find_delta_children(&base, &ref_first, &ref_last);\n>  \t\tmemset(&base, 0, sizeof(base));\n> -\t\tbase.offset = obj->offset;\n> +\t\tbase.offset = obj->idx.offset;\n>  \t\tofs = !find_delta_children(&base, &ofs_first, &ofs_last);\n>  \t\tif (!ref && !ofs)\n>  \t\t\tcontinue;\n> @@ -535,11 +533,11 @@ static void append_obj_to_pack(const unsigned char *sha1, void *buf,\n>  \t}\n>  \theader[n++] = c;\n>  \twrite_or_die(output_fd, header, n);\n> -\tobj[0].crc32 = crc32(0, Z_NULL, 0);\n> -\tobj[0].crc32 = crc32(obj[0].crc32, header, n);\n> -\tobj[1].offset = obj[0].offset + n;\n> -\tobj[1].offset += write_compressed(output_fd, buf, size, &obj[0].crc32);\n> -\thashcpy(obj->sha1, sha1);\n> +\tobj[0].idx.crc32 = crc32(0, Z_NULL, 0);\n> +\tobj[0].idx.crc32 = crc32(obj[0].idx.crc32, header, n);\n> +\tobj[1].idx.offset = obj[0].idx.offset + n;\n> +\tobj[1].idx.offset += write_compressed(output_fd, buf, size, &obj[0].idx.crc32);\n> +\thashcpy(obj->idx.sha1, sha1);\n>  }\n>  \n>  static int delta_pos_compare(const void *_a, const void *_b)\n> @@ -602,145 +600,6 @@ static void fix_unresolved_deltas(int nr_unresolved)\n>  \tfree(sorted_by_pos);\n>  }\n>  \n> -static uint32_t index_default_version = 1;\n> -static uint32_t index_off32_limit = 0x7fffffff;\n> -\n> -static int sha1_compare(const void *_a, const void *_b)\n> -{\n> -\tstruct object_entry *a = *(struct object_entry **)_a;\n> -\tstruct object_entry *b = *(struct object_entry **)_b;\n> -\treturn hashcmp(a->sha1, b->sha1);\n> -}\n> -\n> -/*\n> - * On entry *sha1 contains the pack content SHA1 hash, on exit it is\n> - * the SHA1 hash of sorted object names.\n> - */\n> -static const char *write_index_file(const char *index_name, unsigned char *sha1)\n> -{\n> -\tstruct sha1file *f;\n> -\tstruct object_entry **sorted_by_sha, **list, **last;\n> -\tuint32_t array[256];\n> -\tint i, fd;\n> -\tSHA_CTX ctx;\n> -\tuint32_t index_version;\n> -\n> -\tif (nr_objects) {\n> -\t\tsorted_by_sha =\n> -\t\t\txcalloc(nr_objects, sizeof(struct object_entry *));\n> -\t\tlist = sorted_by_sha;\n> -\t\tlast = sorted_by_sha + nr_objects;\n> -\t\tfor (i = 0; i < nr_objects; ++i)\n> -\t\t\tsorted_by_sha[i] = &objects[i];\n> -\t\tqsort(sorted_by_sha, nr_objects, sizeof(sorted_by_sha[0]),\n> -\t\t      sha1_compare);\n> -\t}\n> -\telse\n> -\t\tsorted_by_sha = list = last = NULL;\n> -\n> -\tif (!index_name) {\n> -\t\tstatic char tmpfile[PATH_MAX];\n> -\t\tsnprintf(tmpfile, sizeof(tmpfile),\n> -\t\t\t \"%s/tmp_idx_XXXXXX\", get_object_directory());\n> -\t\tfd = mkstemp(tmpfile);\n> -\t\tindex_name = xstrdup(tmpfile);\n> -\t} else {\n> -\t\tunlink(index_name);\n> -\t\tfd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);\n> -\t}\n> -\tif (fd < 0)\n> -\t\tdie(\"unable to create %s: %s\", index_name, strerror(errno));\n> -\tf = sha1fd(fd, index_name);\n> -\n> -\t/* if last object's offset is >= 2^31 we should use index V2 */\n> -\tindex_version = (objects[nr_objects-1].offset >> 31) ? 2 : index_default_version;\n> -\n> -\t/* index versions 2 and above need a header */\n> -\tif (index_version >= 2) {\n> -\t\tstruct pack_idx_header hdr;\n> -\t\thdr.idx_signature = htonl(PACK_IDX_SIGNATURE);\n> -\t\thdr.idx_version = htonl(index_version);\n> -\t\tsha1write(f, &hdr, sizeof(hdr));\n> -\t}\n> -\n> -\t/*\n> -\t * Write the first-level table (the list is sorted,\n> -\t * but we use a 256-entry lookup to be able to avoid\n> -\t * having to do eight extra binary search iterations).\n> -\t */\n> -\tfor (i = 0; i < 256; i++) {\n> -\t\tstruct object_entry **next = list;\n> -\t\twhile (next < last) {\n> -\t\t\tstruct object_entry *obj = *next;\n> -\t\t\tif (obj->sha1[0] != i)\n> -\t\t\t\tbreak;\n> -\t\t\tnext++;\n> -\t\t}\n> -\t\tarray[i] = htonl(next - sorted_by_sha);\n> -\t\tlist = next;\n> -\t}\n> -\tsha1write(f, array, 256 * 4);\n> -\n> -\t/* compute the SHA1 hash of sorted object names. */\n> -\tSHA1_Init(&ctx);\n> -\n> -\t/*\n> -\t * Write the actual SHA1 entries..\n> -\t */\n> -\tlist = sorted_by_sha;\n> -\tfor (i = 0; i < nr_objects; i++) {\n> -\t\tstruct object_entry *obj = *list++;\n> -\t\tif (index_version < 2) {\n> -\t\t\tuint32_t offset = htonl(obj->offset);\n> -\t\t\tsha1write(f, &offset, 4);\n> -\t\t}\n> -\t\tsha1write(f, obj->sha1, 20);\n> -\t\tSHA1_Update(&ctx, obj->sha1, 20);\n> -\t}\n> -\n> -\tif (index_version >= 2) {\n> -\t\tunsigned int nr_large_offset = 0;\n> -\n> -\t\t/* write the crc32 table */\n> -\t\tlist = sorted_by_sha;\n> -\t\tfor (i = 0; i < nr_objects; i++) {\n> -\t\t\tstruct object_entry *obj = *list++;\n> -\t\t\tuint32_t crc32_val = htonl(obj->crc32);\n> -\t\t\tsha1write(f, &crc32_val, 4);\n> -\t\t}\n> -\n> -\t\t/* write the 32-bit offset table */\n> -\t\tlist = sorted_by_sha;\n> -\t\tfor (i = 0; i < nr_objects; i++) {\n> -\t\t\tstruct object_entry *obj = *list++;\n> -\t\t\tuint32_t offset = (obj->offset <= index_off32_limit) ?\n> -\t\t\t\tobj->offset : (0x80000000 | nr_large_offset++);\n> -\t\t\toffset = htonl(offset);\n> -\t\t\tsha1write(f, &offset, 4);\n> -\t\t}\n> -\n> -\t\t/* write the large offset table */\n> -\t\tlist = sorted_by_sha;\n> -\t\twhile (nr_large_offset) {\n> -\t\t\tstruct object_entry *obj = *list++;\n> -\t\t\tuint64_t offset = obj->offset;\n> -\t\t\tif (offset > index_off32_limit) {\n> -\t\t\t\tuint32_t split[2];\n> -\t\t\t\tsplit[0]\t= htonl(offset >> 32);\n> -\t\t\t\tsplit[1] = htonl(offset & 0xffffffff);\n> -\t\t\t\tsha1write(f, split, 8);\n> -\t\t\t\tnr_large_offset--;\n> -\t\t\t}\n> -\t\t}\n> -\t}\n> -\n> -\tsha1write(f, sha1, 20);\n> -\tsha1close(f, NULL, 1);\n> -\tfree(sorted_by_sha);\n> -\tSHA1_Final(sha1, &ctx);\n> -\treturn index_name;\n> -}\n> -\n>  static void final(const char *final_pack_name, const char *curr_pack_name,\n>  \t\t  const char *final_index_name, const char *curr_index_name,\n>  \t\t  const char *keep_name, const char *keep_msg,\n> @@ -830,6 +689,7 @@ int main(int argc, char **argv)\n>  \tconst char *curr_index, *index_name = NULL;\n>  \tconst char *keep_name = NULL, *keep_msg = NULL;\n>  \tchar *index_name_buf = NULL, *keep_name_buf = NULL;\n> +\tstruct pack_idx_entry **idx_objects;\n>  \tunsigned char sha1[20];\n>  \n>  \tfor (i = 1; i < argc; i++) {\n> @@ -865,12 +725,12 @@ int main(int argc, char **argv)\n>  \t\t\t\tindex_name = argv[++i];\n>  \t\t\t} else if (!prefixcmp(arg, \"--index-version=\")) {\n>  \t\t\t\tchar *c;\n> -\t\t\t\tindex_default_version = strtoul(arg + 16, &c, 10);\n> -\t\t\t\tif (index_default_version > 2)\n> +\t\t\t\tpack_idx_default_version = strtoul(arg + 16, &c, 10);\n> +\t\t\t\tif (pack_idx_default_version > 2)\n>  \t\t\t\t\tdie(\"bad %s\", arg);\n>  \t\t\t\tif (*c == ',')\n> -\t\t\t\t\tindex_off32_limit = strtoul(c+1, &c, 0);\n> -\t\t\t\tif (*c || index_off32_limit & 0x80000000)\n> +\t\t\t\t\tpack_idx_off32_limit = strtoul(c+1, &c, 0);\n> +\t\t\t\tif (*c || pack_idx_off32_limit & 0x80000000)\n>  \t\t\t\t\tdie(\"bad %s\", arg);\n>  \t\t\t} else\n>  \t\t\t\tusage(index_pack_usage);\n> @@ -940,7 +800,13 @@ int main(int argc, char **argv)\n>  \t\t\t    nr_deltas - nr_resolved_deltas);\n>  \t}\n>  \tfree(deltas);\n> -\tcurr_index = write_index_file(index_name, sha1);\n> +\n> +\tidx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *));\n> +\tfor (i = 0; i < nr_objects; i++)\n> +\t\tidx_objects[i] = &objects[i].idx;\n> +\tcurr_index = write_idx_file(index_name, idx_objects, nr_objects, sha1);\n> +\tfree(idx_objects);\n> +\n>  \tfinal(pack_name, curr_pack,\n>  \t\tindex_name, curr_index,\n>  \t\tkeep_name, keep_msg,\n> diff --git a/pack-write.c b/pack-write.c\n> index ae2e481..1cf5f7c 100644\n> --- a/pack-write.c\n> +++ b/pack-write.c\n> @@ -1,5 +1,147 @@\n>  #include \"cache.h\"\n>  #include \"pack.h\"\n> +#include \"csum-file.h\"\n> +\n> +uint32_t pack_idx_default_version = 1;\n> +uint32_t pack_idx_off32_limit = 0x7fffffff;\n> +\n> +static int sha1_compare(const void *_a, const void *_b)\n> +{\n> +\tstruct pack_idx_entry *a = *(struct pack_idx_entry **)_a;\n> +\tstruct pack_idx_entry *b = *(struct pack_idx_entry **)_b;\n> +\treturn hashcmp(a->sha1, b->sha1);\n> +}\n> +\n> +/*\n> + * On entry *sha1 contains the pack content SHA1 hash, on exit it is\n> + * the SHA1 hash of sorted object names. The objects array passed in\n> + * will be sorted by SHA1 on exit.\n> + */\n> +const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1)\n> +{\n> +\tstruct sha1file *f;\n> +\tstruct pack_idx_entry **sorted_by_sha, **list, **last;\n> +\toff_t last_obj_offset = 0;\n> +\tuint32_t array[256];\n> +\tint i, fd;\n> +\tSHA_CTX ctx;\n> +\tuint32_t index_version;\n> +\n> +\tif (nr_objects) {\n> +\t\tsorted_by_sha = objects;\n> +\t\tlist = sorted_by_sha;\n> +\t\tlast = sorted_by_sha + nr_objects;\n> +\t\tfor (i = 0; i < nr_objects; ++i) {\n> +\t\t\tif (objects[i]->offset > last_obj_offset)\n> +\t\t\t\tlast_obj_offset = objects[i]->offset;\n> +\t\t}\n> +\t\tqsort(sorted_by_sha, nr_objects, sizeof(sorted_by_sha[0]),\n> +\t\t      sha1_compare);\n> +\t}\n> +\telse\n> +\t\tsorted_by_sha = list = last = NULL;\n> +\n> +\tif (!index_name) {\n> +\t\tstatic char tmpfile[PATH_MAX];\n> +\t\tsnprintf(tmpfile, sizeof(tmpfile),\n> +\t\t\t \"%s/tmp_idx_XXXXXX\", get_object_directory());\n> +\t\tfd = mkstemp(tmpfile);\n> +\t\tindex_name = xstrdup(tmpfile);\n> +\t} else {\n> +\t\tunlink(index_name);\n> +\t\tfd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);\n> +\t}\n> +\tif (fd < 0)\n> +\t\tdie(\"unable to create %s: %s\", index_name, strerror(errno));\n> +\tf = sha1fd(fd, index_name);\n> +\n> +\t/* if last object's offset is >= 2^31 we should use index V2 */\n> +\tindex_version = (last_obj_offset >> 31) ? 2 : pack_idx_default_version;\n> +\n> +\t/* index versions 2 and above need a header */\n> +\tif (index_version >= 2) {\n> +\t\tstruct pack_idx_header hdr;\n> +\t\thdr.idx_signature = htonl(PACK_IDX_SIGNATURE);\n> +\t\thdr.idx_version = htonl(index_version);\n> +\t\tsha1write(f, &hdr, sizeof(hdr));\n> +\t}\n> +\n> +\t/*\n> +\t * Write the first-level table (the list is sorted,\n> +\t * but we use a 256-entry lookup to be able to avoid\n> +\t * having to do eight extra binary search iterations).\n> +\t */\n> +\tfor (i = 0; i < 256; i++) {\n> +\t\tstruct pack_idx_entry **next = list;\n> +\t\twhile (next < last) {\n> +\t\t\tstruct pack_idx_entry *obj = *next;\n> +\t\t\tif (obj->sha1[0] != i)\n> +\t\t\t\tbreak;\n> +\t\t\tnext++;\n> +\t\t}\n> +\t\tarray[i] = htonl(next - sorted_by_sha);\n> +\t\tlist = next;\n> +\t}\n> +\tsha1write(f, array, 256 * 4);\n> +\n> +\t/* compute the SHA1 hash of sorted object names. */\n> +\tSHA1_Init(&ctx);\n> +\n> +\t/*\n> +\t * Write the actual SHA1 entries..\n> +\t */\n> +\tlist = sorted_by_sha;\n> +\tfor (i = 0; i < nr_objects; i++) {\n> +\t\tstruct pack_idx_entry *obj = *list++;\n> +\t\tif (index_version < 2) {\n> +\t\t\tuint32_t offset = htonl(obj->offset);\n> +\t\t\tsha1write(f, &offset, 4);\n> +\t\t}\n> +\t\tsha1write(f, obj->sha1, 20);\n> +\t\tSHA1_Update(&ctx, obj->sha1, 20);\n> +\t}\n> +\n> +\tif (index_version >= 2) {\n> +\t\tunsigned int nr_large_offset = 0;\n> +\n> +\t\t/* write the crc32 table */\n> +\t\tlist = sorted_by_sha;\n> +\t\tfor (i = 0; i < nr_objects; i++) {\n> +\t\t\tstruct pack_idx_entry *obj = *list++;\n> +\t\t\tuint32_t crc32_val = htonl(obj->crc32);\n> +\t\t\tsha1write(f, &crc32_val, 4);\n> +\t\t}\n> +\n> +\t\t/* write the 32-bit offset table */\n> +\t\tlist = sorted_by_sha;\n> +\t\tfor (i = 0; i < nr_objects; i++) {\n> +\t\t\tstruct pack_idx_entry *obj = *list++;\n> +\t\t\tuint32_t offset = (obj->offset <= pack_idx_off32_limit) ?\n> +\t\t\t\tobj->offset : (0x80000000 | nr_large_offset++);\n> +\t\t\toffset = htonl(offset);\n> +\t\t\tsha1write(f, &offset, 4);\n> +\t\t}\n> +\n> +\t\t/* write the large offset table */\n> +\t\tlist = sorted_by_sha;\n> +\t\twhile (nr_large_offset) {\n> +\t\t\tstruct pack_idx_entry *obj = *list++;\n> +\t\t\tuint64_t offset = obj->offset;\n> +\t\t\tif (offset > pack_idx_off32_limit) {\n> +\t\t\t\tuint32_t split[2];\n> +\t\t\t\tsplit[0] = htonl(offset >> 32);\n> +\t\t\t\tsplit[1] = htonl(offset & 0xffffffff);\n> +\t\t\t\tsha1write(f, split, 8);\n> +\t\t\t\tnr_large_offset--;\n> +\t\t\t}\n> +\t\t}\n> +\t}\n> +\n> +\tsha1write(f, sha1, 20);\n> +\tsha1close(f, NULL, 1);\n> +\tSHA1_Final(sha1, &ctx);\n> +\treturn index_name;\n> +}\n>  \n>  void fixup_pack_header_footer(int pack_fd,\n>  \t\t\t unsigned char *pack_file_sha1,\n> diff --git a/pack.h b/pack.h\n> index d667fb8..f357c9f 100644\n> --- a/pack.h\n> +++ b/pack.h\n> @@ -34,6 +34,10 @@ struct pack_header {\n>   */\n>  #define PACK_IDX_SIGNATURE 0xff744f63\t/* \"\\377tOc\" */\n>  \n> +/* These may be overridden by command-line parameters */\n> +extern uint32_t pack_idx_default_version;\n> +extern uint32_t pack_idx_off32_limit;\n> +\n>  /*\n>   * Packed object index header\n>   */\n> @@ -42,6 +46,16 @@ struct pack_idx_header {\n>  \tuint32_t idx_version;\n>  };\n>  \n> +/*\n> + * Common part of object structure used for write_idx_file\n> + */\n> +struct pack_idx_entry {\n> +\tunsigned char sha1[20];\n> +\tuint32_t crc32;\n> +\toff_t offset;\n> +};\n> +\n> +extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1);\n>  \n>  extern int verify_pack(struct packed_git *, int);\n>  extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t);\n> -- \n> 1.5.1\n> \n> -\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n> \n\n\nNicolas\n"}]}