Merge branch 'gb/idx'
* gb/idx: Unify write_index_file functions
This commit is contained in:
commit
7be003b026
@ -23,10 +23,9 @@ git-pack-objects [{ -q | --progress | --all-progress }] [--max-pack-size=N] \n\
|
||||
[--stdout | base-name] [<ref-list | <object-list]";
|
||||
|
||||
struct object_entry {
|
||||
unsigned char sha1[20];
|
||||
uint32_t crc32; /* crc of raw pack data for this object */
|
||||
off_t offset; /* offset into the final pack file */
|
||||
struct pack_idx_entry idx;
|
||||
unsigned long size; /* uncompressed size */
|
||||
|
||||
unsigned int hash; /* name hint hash */
|
||||
unsigned int depth; /* delta depth */
|
||||
struct packed_git *in_pack; /* already in pack */
|
||||
@ -66,7 +65,6 @@ static int allow_ofs_delta;
|
||||
static const char *pack_tmp_name, *idx_tmp_name;
|
||||
static char tmpname[PATH_MAX];
|
||||
static const char *base_name;
|
||||
static unsigned char pack_file_sha1[20];
|
||||
static int progress = 1;
|
||||
static int window = 10;
|
||||
static uint32_t pack_size_limit;
|
||||
@ -246,11 +244,11 @@ static void *delta_against(void *buf, unsigned long size, struct object_entry *e
|
||||
{
|
||||
unsigned long othersize, delta_size;
|
||||
enum object_type type;
|
||||
void *otherbuf = read_sha1_file(entry->delta->sha1, &type, &othersize);
|
||||
void *otherbuf = read_sha1_file(entry->delta->idx.sha1, &type, &othersize);
|
||||
void *delta_buf;
|
||||
|
||||
if (!otherbuf)
|
||||
die("unable to read %s", sha1_to_hex(entry->delta->sha1));
|
||||
die("unable to read %s", sha1_to_hex(entry->delta->idx.sha1));
|
||||
delta_buf = diff_delta(otherbuf, othersize,
|
||||
buf, size, &delta_size, 0);
|
||||
if (!delta_buf || delta_size != entry->delta_size)
|
||||
@ -379,11 +377,11 @@ static unsigned long write_object(struct sha1file *f,
|
||||
/* yes if unlimited packfile */
|
||||
!pack_size_limit ? 1 :
|
||||
/* no if base written to previous pack */
|
||||
entry->delta->offset == (off_t)-1 ? 0 :
|
||||
entry->delta->idx.offset == (off_t)-1 ? 0 :
|
||||
/* otherwise double-check written to this
|
||||
* pack, like we do below
|
||||
*/
|
||||
entry->delta->offset ? 1 : 0;
|
||||
entry->delta->idx.offset ? 1 : 0;
|
||||
|
||||
if (!pack_to_stdout)
|
||||
crc32_begin(f);
|
||||
@ -411,22 +409,22 @@ static unsigned long write_object(struct sha1file *f,
|
||||
unsigned long maxsize;
|
||||
void *out;
|
||||
if (!usable_delta) {
|
||||
buf = read_sha1_file(entry->sha1, &obj_type, &size);
|
||||
buf = read_sha1_file(entry->idx.sha1, &obj_type, &size);
|
||||
if (!buf)
|
||||
die("unable to read %s", sha1_to_hex(entry->sha1));
|
||||
die("unable to read %s", sha1_to_hex(entry->idx.sha1));
|
||||
} else if (entry->delta_data) {
|
||||
size = entry->delta_size;
|
||||
buf = entry->delta_data;
|
||||
entry->delta_data = NULL;
|
||||
obj_type = (allow_ofs_delta && entry->delta->offset) ?
|
||||
obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
|
||||
OBJ_OFS_DELTA : OBJ_REF_DELTA;
|
||||
} else {
|
||||
buf = read_sha1_file(entry->sha1, &type, &size);
|
||||
buf = read_sha1_file(entry->idx.sha1, &type, &size);
|
||||
if (!buf)
|
||||
die("unable to read %s", sha1_to_hex(entry->sha1));
|
||||
die("unable to read %s", sha1_to_hex(entry->idx.sha1));
|
||||
buf = delta_against(buf, size, entry);
|
||||
size = entry->delta_size;
|
||||
obj_type = (allow_ofs_delta && entry->delta->offset) ?
|
||||
obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
|
||||
OBJ_OFS_DELTA : OBJ_REF_DELTA;
|
||||
}
|
||||
/* compress the data to store and put compressed length in datalen */
|
||||
@ -456,7 +454,7 @@ static unsigned long write_object(struct sha1file *f,
|
||||
* encoding of the relative offset for the delta
|
||||
* base from this object's position in the pack.
|
||||
*/
|
||||
off_t ofs = entry->offset - entry->delta->offset;
|
||||
off_t ofs = entry->idx.offset - entry->delta->idx.offset;
|
||||
unsigned pos = sizeof(dheader) - 1;
|
||||
dheader[pos] = ofs & 127;
|
||||
while (ofs >>= 7)
|
||||
@ -480,7 +478,7 @@ static unsigned long write_object(struct sha1file *f,
|
||||
return 0;
|
||||
}
|
||||
sha1write(f, header, hdrlen);
|
||||
sha1write(f, entry->delta->sha1, 20);
|
||||
sha1write(f, entry->delta->idx.sha1, 20);
|
||||
hdrlen += 20;
|
||||
} else {
|
||||
if (limit && hdrlen + datalen + 20 >= limit) {
|
||||
@ -501,7 +499,7 @@ static unsigned long write_object(struct sha1file *f,
|
||||
off_t offset;
|
||||
|
||||
if (entry->delta) {
|
||||
obj_type = (allow_ofs_delta && entry->delta->offset) ?
|
||||
obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
|
||||
OBJ_OFS_DELTA : OBJ_REF_DELTA;
|
||||
reused_delta++;
|
||||
}
|
||||
@ -511,11 +509,11 @@ static unsigned long write_object(struct sha1file *f,
|
||||
datalen = revidx[1].offset - offset;
|
||||
if (!pack_to_stdout && p->index_version > 1 &&
|
||||
check_pack_crc(p, &w_curs, offset, datalen, revidx->nr))
|
||||
die("bad packed object CRC for %s", sha1_to_hex(entry->sha1));
|
||||
die("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
|
||||
offset += entry->in_pack_header_size;
|
||||
datalen -= entry->in_pack_header_size;
|
||||
if (obj_type == OBJ_OFS_DELTA) {
|
||||
off_t ofs = entry->offset - entry->delta->offset;
|
||||
off_t ofs = entry->idx.offset - entry->delta->idx.offset;
|
||||
unsigned pos = sizeof(dheader) - 1;
|
||||
dheader[pos] = ofs & 127;
|
||||
while (ofs >>= 7)
|
||||
@ -529,7 +527,7 @@ static unsigned long write_object(struct sha1file *f,
|
||||
if (limit && hdrlen + 20 + datalen + 20 >= limit)
|
||||
return 0;
|
||||
sha1write(f, header, hdrlen);
|
||||
sha1write(f, entry->delta->sha1, 20);
|
||||
sha1write(f, entry->delta->idx.sha1, 20);
|
||||
hdrlen += 20;
|
||||
} else {
|
||||
if (limit && hdrlen + datalen + 20 >= limit)
|
||||
@ -539,7 +537,7 @@ static unsigned long write_object(struct sha1file *f,
|
||||
|
||||
if (!pack_to_stdout && p->index_version == 1 &&
|
||||
check_pack_inflate(p, &w_curs, offset, datalen, entry->size))
|
||||
die("corrupt packed object for %s", sha1_to_hex(entry->sha1));
|
||||
die("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1));
|
||||
copy_pack_data(f, p, &w_curs, offset, datalen);
|
||||
unuse_pack(&w_curs);
|
||||
reused++;
|
||||
@ -548,7 +546,7 @@ static unsigned long write_object(struct sha1file *f,
|
||||
written_delta++;
|
||||
written++;
|
||||
if (!pack_to_stdout)
|
||||
entry->crc32 = crc32_end(f);
|
||||
entry->idx.crc32 = crc32_end(f);
|
||||
return hdrlen + datalen;
|
||||
}
|
||||
|
||||
@ -559,7 +557,7 @@ static off_t write_one(struct sha1file *f,
|
||||
unsigned long size;
|
||||
|
||||
/* offset is non zero if object is written already. */
|
||||
if (e->offset || e->preferred_base)
|
||||
if (e->idx.offset || e->preferred_base)
|
||||
return offset;
|
||||
|
||||
/* if we are deltified, write out base object first. */
|
||||
@ -569,10 +567,10 @@ static off_t write_one(struct sha1file *f,
|
||||
return 0;
|
||||
}
|
||||
|
||||
e->offset = offset;
|
||||
e->idx.offset = offset;
|
||||
size = write_object(f, e, offset);
|
||||
if (!size) {
|
||||
e->offset = 0;
|
||||
e->idx.offset = 0;
|
||||
return 0;
|
||||
}
|
||||
written_list[nr_written++] = e;
|
||||
@ -589,8 +587,7 @@ static int open_object_dir_tmp(const char *path)
|
||||
return mkstemp(tmpname);
|
||||
}
|
||||
|
||||
/* forward declarations for write_pack_file */
|
||||
static void write_index_file(off_t last_obj_offset, unsigned char *sha1);
|
||||
/* forward declaration for write_pack_file */
|
||||
static int adjust_perm(const char *path, mode_t mode);
|
||||
|
||||
static void write_pack_file(void)
|
||||
@ -607,6 +604,8 @@ static void write_pack_file(void)
|
||||
written_list = xmalloc(nr_objects * sizeof(struct object_entry *));
|
||||
|
||||
do {
|
||||
unsigned char sha1[20];
|
||||
|
||||
if (pack_to_stdout) {
|
||||
f = sha1fd(1, "<stdout>");
|
||||
} else {
|
||||
@ -638,23 +637,23 @@ static void write_pack_file(void)
|
||||
* If so, rewrite it like in fast-import
|
||||
*/
|
||||
if (pack_to_stdout || nr_written == nr_remaining) {
|
||||
sha1close(f, pack_file_sha1, 1);
|
||||
sha1close(f, sha1, 1);
|
||||
} else {
|
||||
sha1close(f, pack_file_sha1, 0);
|
||||
fixup_pack_header_footer(f->fd, pack_file_sha1, pack_tmp_name, nr_written);
|
||||
sha1close(f, sha1, 0);
|
||||
fixup_pack_header_footer(f->fd, sha1, pack_tmp_name, nr_written);
|
||||
close(f->fd);
|
||||
}
|
||||
|
||||
if (!pack_to_stdout) {
|
||||
unsigned char object_list_sha1[20];
|
||||
mode_t mode = umask(0);
|
||||
|
||||
umask(mode);
|
||||
mode = 0444 & ~mode;
|
||||
|
||||
write_index_file(last_obj_offset, object_list_sha1);
|
||||
idx_tmp_name = write_idx_file(NULL,
|
||||
(struct pack_idx_entry **) written_list, nr_written, sha1);
|
||||
snprintf(tmpname, sizeof(tmpname), "%s-%s.pack",
|
||||
base_name, sha1_to_hex(object_list_sha1));
|
||||
base_name, sha1_to_hex(sha1));
|
||||
if (adjust_perm(pack_tmp_name, mode))
|
||||
die("unable to make temporary pack file readable: %s",
|
||||
strerror(errno));
|
||||
@ -662,19 +661,19 @@ static void write_pack_file(void)
|
||||
die("unable to rename temporary pack file: %s",
|
||||
strerror(errno));
|
||||
snprintf(tmpname, sizeof(tmpname), "%s-%s.idx",
|
||||
base_name, sha1_to_hex(object_list_sha1));
|
||||
base_name, sha1_to_hex(sha1));
|
||||
if (adjust_perm(idx_tmp_name, mode))
|
||||
die("unable to make temporary index file readable: %s",
|
||||
strerror(errno));
|
||||
if (rename(idx_tmp_name, tmpname))
|
||||
die("unable to rename temporary index file: %s",
|
||||
strerror(errno));
|
||||
puts(sha1_to_hex(object_list_sha1));
|
||||
puts(sha1_to_hex(sha1));
|
||||
}
|
||||
|
||||
/* mark written objects as written to previous pack */
|
||||
for (j = 0; j < nr_written; j++) {
|
||||
written_list[j]->offset = (off_t)-1;
|
||||
written_list[j]->idx.offset = (off_t)-1;
|
||||
}
|
||||
nr_remaining -= nr_written;
|
||||
} while (nr_remaining && i < nr_objects);
|
||||
@ -692,129 +691,12 @@ static void write_pack_file(void)
|
||||
*/
|
||||
for (j = 0; i < nr_objects; i++) {
|
||||
struct object_entry *e = objects + i;
|
||||
j += !e->offset && !e->preferred_base;
|
||||
j += !e->idx.offset && !e->preferred_base;
|
||||
}
|
||||
if (j)
|
||||
die("wrote %u objects as expected but %u unwritten", written, j);
|
||||
}
|
||||
|
||||
static int sha1_sort(const void *_a, const void *_b)
|
||||
{
|
||||
const struct object_entry *a = *(struct object_entry **)_a;
|
||||
const struct object_entry *b = *(struct object_entry **)_b;
|
||||
return hashcmp(a->sha1, b->sha1);
|
||||
}
|
||||
|
||||
static uint32_t index_default_version = 1;
|
||||
static uint32_t index_off32_limit = 0x7fffffff;
|
||||
|
||||
static void write_index_file(off_t last_obj_offset, unsigned char *sha1)
|
||||
{
|
||||
struct sha1file *f;
|
||||
struct object_entry **sorted_by_sha, **list, **last;
|
||||
uint32_t array[256];
|
||||
uint32_t i, index_version;
|
||||
SHA_CTX ctx;
|
||||
|
||||
int fd = open_object_dir_tmp("tmp_idx_XXXXXX");
|
||||
if (fd < 0)
|
||||
die("unable to create %s: %s\n", tmpname, strerror(errno));
|
||||
idx_tmp_name = xstrdup(tmpname);
|
||||
f = sha1fd(fd, idx_tmp_name);
|
||||
|
||||
if (nr_written) {
|
||||
sorted_by_sha = written_list;
|
||||
qsort(sorted_by_sha, nr_written, sizeof(*sorted_by_sha), sha1_sort);
|
||||
list = sorted_by_sha;
|
||||
last = sorted_by_sha + nr_written;
|
||||
} else
|
||||
sorted_by_sha = list = last = NULL;
|
||||
|
||||
/* if last object's offset is >= 2^31 we should use index V2 */
|
||||
index_version = (last_obj_offset >> 31) ? 2 : index_default_version;
|
||||
|
||||
/* index versions 2 and above need a header */
|
||||
if (index_version >= 2) {
|
||||
struct pack_idx_header hdr;
|
||||
hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
|
||||
hdr.idx_version = htonl(index_version);
|
||||
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
|
||||
* having to do eight extra binary search iterations).
|
||||
*/
|
||||
for (i = 0; i < 256; i++) {
|
||||
struct object_entry **next = list;
|
||||
while (next < last) {
|
||||
struct object_entry *entry = *next;
|
||||
if (entry->sha1[0] != i)
|
||||
break;
|
||||
next++;
|
||||
}
|
||||
array[i] = htonl(next - sorted_by_sha);
|
||||
list = next;
|
||||
}
|
||||
sha1write(f, array, 256 * 4);
|
||||
|
||||
/* Compute the SHA1 hash of sorted object names. */
|
||||
SHA1_Init(&ctx);
|
||||
|
||||
/* Write the actual SHA1 entries. */
|
||||
list = sorted_by_sha;
|
||||
for (i = 0; i < nr_written; i++) {
|
||||
struct object_entry *entry = *list++;
|
||||
if (index_version < 2) {
|
||||
uint32_t offset = htonl(entry->offset);
|
||||
sha1write(f, &offset, 4);
|
||||
}
|
||||
sha1write(f, entry->sha1, 20);
|
||||
SHA1_Update(&ctx, entry->sha1, 20);
|
||||
}
|
||||
|
||||
if (index_version >= 2) {
|
||||
unsigned int nr_large_offset = 0;
|
||||
|
||||
/* write the crc32 table */
|
||||
list = sorted_by_sha;
|
||||
for (i = 0; i < nr_written; i++) {
|
||||
struct object_entry *entry = *list++;
|
||||
uint32_t crc32_val = htonl(entry->crc32);
|
||||
sha1write(f, &crc32_val, 4);
|
||||
}
|
||||
|
||||
/* write the 32-bit offset table */
|
||||
list = sorted_by_sha;
|
||||
for (i = 0; i < nr_written; i++) {
|
||||
struct object_entry *entry = *list++;
|
||||
uint32_t offset = (entry->offset <= index_off32_limit) ?
|
||||
entry->offset : (0x80000000 | nr_large_offset++);
|
||||
offset = htonl(offset);
|
||||
sha1write(f, &offset, 4);
|
||||
}
|
||||
|
||||
/* write the large offset table */
|
||||
list = sorted_by_sha;
|
||||
while (nr_large_offset) {
|
||||
struct object_entry *entry = *list++;
|
||||
uint64_t offset = entry->offset;
|
||||
if (offset > index_off32_limit) {
|
||||
uint32_t split[2];
|
||||
split[0] = htonl(offset >> 32);
|
||||
split[1] = htonl(offset & 0xffffffff);
|
||||
sha1write(f, split, 8);
|
||||
nr_large_offset--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sha1write(f, pack_file_sha1, 20);
|
||||
sha1close(f, NULL, 1);
|
||||
SHA1_Final(sha1, &ctx);
|
||||
}
|
||||
|
||||
static int locate_object_entry_hash(const unsigned char *sha1)
|
||||
{
|
||||
int i;
|
||||
@ -822,7 +704,7 @@ static int locate_object_entry_hash(const unsigned char *sha1)
|
||||
memcpy(&ui, sha1, sizeof(unsigned int));
|
||||
i = ui % object_ix_hashsz;
|
||||
while (0 < object_ix[i]) {
|
||||
if (!hashcmp(sha1, objects[object_ix[i] - 1].sha1))
|
||||
if (!hashcmp(sha1, objects[object_ix[i] - 1].idx.sha1))
|
||||
return i;
|
||||
if (++i == object_ix_hashsz)
|
||||
i = 0;
|
||||
@ -854,7 +736,7 @@ static void rehash_objects(void)
|
||||
object_ix = xrealloc(object_ix, sizeof(int) * object_ix_hashsz);
|
||||
memset(object_ix, 0, sizeof(int) * object_ix_hashsz);
|
||||
for (i = 0, oe = objects; i < nr_objects; i++, oe++) {
|
||||
int ix = locate_object_entry_hash(oe->sha1);
|
||||
int ix = locate_object_entry_hash(oe->idx.sha1);
|
||||
if (0 <= ix)
|
||||
continue;
|
||||
ix = -1 - ix;
|
||||
@ -948,7 +830,7 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
|
||||
|
||||
entry = objects + nr_objects++;
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
hashcpy(entry->sha1, sha1);
|
||||
hashcpy(entry->idx.sha1, sha1);
|
||||
entry->hash = hash;
|
||||
if (type)
|
||||
entry->type = type;
|
||||
@ -1268,13 +1150,13 @@ static void check_object(struct object_entry *entry)
|
||||
ofs += 1;
|
||||
if (!ofs || MSB(ofs, 7))
|
||||
die("delta base offset overflow in pack for %s",
|
||||
sha1_to_hex(entry->sha1));
|
||||
sha1_to_hex(entry->idx.sha1));
|
||||
c = buf[used_0++];
|
||||
ofs = (ofs << 7) + (c & 127);
|
||||
}
|
||||
if (ofs >= entry->in_pack_offset)
|
||||
die("delta base offset out of bound for %s",
|
||||
sha1_to_hex(entry->sha1));
|
||||
sha1_to_hex(entry->idx.sha1));
|
||||
ofs = entry->in_pack_offset - ofs;
|
||||
if (!no_reuse_delta && !entry->preferred_base)
|
||||
base_ref = find_packed_object_name(p, ofs);
|
||||
@ -1321,10 +1203,10 @@ static void check_object(struct object_entry *entry)
|
||||
unuse_pack(&w_curs);
|
||||
}
|
||||
|
||||
entry->type = sha1_object_info(entry->sha1, &entry->size);
|
||||
entry->type = sha1_object_info(entry->idx.sha1, &entry->size);
|
||||
if (entry->type < 0)
|
||||
die("unable to get type of object %s",
|
||||
sha1_to_hex(entry->sha1));
|
||||
sha1_to_hex(entry->idx.sha1));
|
||||
}
|
||||
|
||||
static int pack_offset_sort(const void *_a, const void *_b)
|
||||
@ -1334,7 +1216,7 @@ static int pack_offset_sort(const void *_a, const void *_b)
|
||||
|
||||
/* avoid filesystem trashing with loose objects */
|
||||
if (!a->in_pack && !b->in_pack)
|
||||
return hashcmp(a->sha1, b->sha1);
|
||||
return hashcmp(a->idx.sha1, b->idx.sha1);
|
||||
|
||||
if (a->in_pack < b->in_pack)
|
||||
return -1;
|
||||
@ -1463,16 +1345,16 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
|
||||
|
||||
/* Load data if not already done */
|
||||
if (!trg->data) {
|
||||
trg->data = read_sha1_file(trg_entry->sha1, &type, &sz);
|
||||
trg->data = read_sha1_file(trg_entry->idx.sha1, &type, &sz);
|
||||
if (sz != trg_size)
|
||||
die("object %s inconsistent object length (%lu vs %lu)",
|
||||
sha1_to_hex(trg_entry->sha1), sz, trg_size);
|
||||
sha1_to_hex(trg_entry->idx.sha1), sz, trg_size);
|
||||
}
|
||||
if (!src->data) {
|
||||
src->data = read_sha1_file(src_entry->sha1, &type, &sz);
|
||||
src->data = read_sha1_file(src_entry->idx.sha1, &type, &sz);
|
||||
if (sz != src_size)
|
||||
die("object %s inconsistent object length (%lu vs %lu)",
|
||||
sha1_to_hex(src_entry->sha1), sz, src_size);
|
||||
sha1_to_hex(src_entry->idx.sha1), sz, src_size);
|
||||
}
|
||||
if (!src->index) {
|
||||
src->index = create_delta_index(src->data, src_size);
|
||||
@ -1869,12 +1751,12 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
if (!prefixcmp(arg, "--index-version=")) {
|
||||
char *c;
|
||||
index_default_version = strtoul(arg + 16, &c, 10);
|
||||
if (index_default_version > 2)
|
||||
pack_idx_default_version = strtoul(arg + 16, &c, 10);
|
||||
if (pack_idx_default_version > 2)
|
||||
die("bad %s", arg);
|
||||
if (*c == ',')
|
||||
index_off32_limit = strtoul(c+1, &c, 0);
|
||||
if (*c || index_off32_limit & 0x80000000)
|
||||
pack_idx_off32_limit = strtoul(c+1, &c, 0);
|
||||
if (*c || pack_idx_off32_limit & 0x80000000)
|
||||
die("bad %s", arg);
|
||||
continue;
|
||||
}
|
||||
|
208
index-pack.c
208
index-pack.c
@ -13,13 +13,11 @@ static const char index_pack_usage[] =
|
||||
|
||||
struct object_entry
|
||||
{
|
||||
off_t offset;
|
||||
struct pack_idx_entry idx;
|
||||
unsigned long size;
|
||||
unsigned int hdr_size;
|
||||
uint32_t crc32;
|
||||
enum object_type type;
|
||||
enum object_type real_type;
|
||||
unsigned char sha1[20];
|
||||
};
|
||||
|
||||
union delta_base {
|
||||
@ -197,7 +195,7 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
|
||||
unsigned shift;
|
||||
void *data;
|
||||
|
||||
obj->offset = consumed_bytes;
|
||||
obj->idx.offset = consumed_bytes;
|
||||
input_crc32 = crc32(0, Z_NULL, 0);
|
||||
|
||||
p = fill(1);
|
||||
@ -229,15 +227,15 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
|
||||
while (c & 128) {
|
||||
base_offset += 1;
|
||||
if (!base_offset || MSB(base_offset, 7))
|
||||
bad_object(obj->offset, "offset value overflow for delta base object");
|
||||
bad_object(obj->idx.offset, "offset value overflow for delta base object");
|
||||
p = fill(1);
|
||||
c = *p;
|
||||
use(1);
|
||||
base_offset = (base_offset << 7) + (c & 127);
|
||||
}
|
||||
delta_base->offset = obj->offset - base_offset;
|
||||
if (delta_base->offset >= obj->offset)
|
||||
bad_object(obj->offset, "delta base offset is out of bound");
|
||||
delta_base->offset = obj->idx.offset - base_offset;
|
||||
if (delta_base->offset >= obj->idx.offset)
|
||||
bad_object(obj->idx.offset, "delta base offset is out of bound");
|
||||
break;
|
||||
case OBJ_COMMIT:
|
||||
case OBJ_TREE:
|
||||
@ -245,19 +243,19 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
|
||||
case OBJ_TAG:
|
||||
break;
|
||||
default:
|
||||
bad_object(obj->offset, "unknown object type %d", obj->type);
|
||||
bad_object(obj->idx.offset, "unknown object type %d", obj->type);
|
||||
}
|
||||
obj->hdr_size = consumed_bytes - obj->offset;
|
||||
obj->hdr_size = consumed_bytes - obj->idx.offset;
|
||||
|
||||
data = unpack_entry_data(obj->offset, obj->size);
|
||||
obj->crc32 = input_crc32;
|
||||
data = unpack_entry_data(obj->idx.offset, obj->size);
|
||||
obj->idx.crc32 = input_crc32;
|
||||
return data;
|
||||
}
|
||||
|
||||
static void *get_data_from_pack(struct object_entry *obj)
|
||||
{
|
||||
unsigned long from = obj[0].offset + obj[0].hdr_size;
|
||||
unsigned long len = obj[1].offset - from;
|
||||
unsigned long from = obj[0].idx.offset + obj[0].hdr_size;
|
||||
unsigned long len = obj[1].idx.offset - from;
|
||||
unsigned long rdy = 0;
|
||||
unsigned char *src, *data;
|
||||
z_stream stream;
|
||||
@ -360,11 +358,11 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data,
|
||||
&result_size);
|
||||
free(delta_data);
|
||||
if (!result)
|
||||
bad_object(delta_obj->offset, "failed to apply delta");
|
||||
sha1_object(result, result_size, type, delta_obj->sha1);
|
||||
bad_object(delta_obj->idx.offset, "failed to apply delta");
|
||||
sha1_object(result, result_size, type, delta_obj->idx.sha1);
|
||||
nr_resolved_deltas++;
|
||||
|
||||
hashcpy(delta_base.sha1, delta_obj->sha1);
|
||||
hashcpy(delta_base.sha1, delta_obj->idx.sha1);
|
||||
if (!find_delta_children(&delta_base, &first, &last)) {
|
||||
for (j = first; j <= last; j++) {
|
||||
struct object_entry *child = objects + deltas[j].obj_no;
|
||||
@ -374,7 +372,7 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data,
|
||||
}
|
||||
|
||||
memset(&delta_base, 0, sizeof(delta_base));
|
||||
delta_base.offset = delta_obj->offset;
|
||||
delta_base.offset = delta_obj->idx.offset;
|
||||
if (!find_delta_children(&delta_base, &first, &last)) {
|
||||
for (j = first; j <= last; j++) {
|
||||
struct object_entry *child = objects + deltas[j].obj_no;
|
||||
@ -418,12 +416,12 @@ static void parse_pack_objects(unsigned char *sha1)
|
||||
delta->obj_no = i;
|
||||
delta++;
|
||||
} else
|
||||
sha1_object(data, obj->size, obj->type, obj->sha1);
|
||||
sha1_object(data, obj->size, obj->type, obj->idx.sha1);
|
||||
free(data);
|
||||
if (verbose)
|
||||
display_progress(&progress, i+1);
|
||||
}
|
||||
objects[i].offset = consumed_bytes;
|
||||
objects[i].idx.offset = consumed_bytes;
|
||||
if (verbose)
|
||||
stop_progress(&progress);
|
||||
|
||||
@ -465,10 +463,10 @@ static void parse_pack_objects(unsigned char *sha1)
|
||||
|
||||
if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA)
|
||||
continue;
|
||||
hashcpy(base.sha1, obj->sha1);
|
||||
hashcpy(base.sha1, obj->idx.sha1);
|
||||
ref = !find_delta_children(&base, &ref_first, &ref_last);
|
||||
memset(&base, 0, sizeof(base));
|
||||
base.offset = obj->offset;
|
||||
base.offset = obj->idx.offset;
|
||||
ofs = !find_delta_children(&base, &ofs_first, &ofs_last);
|
||||
if (!ref && !ofs)
|
||||
continue;
|
||||
@ -535,11 +533,11 @@ static void append_obj_to_pack(const unsigned char *sha1, void *buf,
|
||||
}
|
||||
header[n++] = c;
|
||||
write_or_die(output_fd, header, n);
|
||||
obj[0].crc32 = crc32(0, Z_NULL, 0);
|
||||
obj[0].crc32 = crc32(obj[0].crc32, header, n);
|
||||
obj[1].offset = obj[0].offset + n;
|
||||
obj[1].offset += write_compressed(output_fd, buf, size, &obj[0].crc32);
|
||||
hashcpy(obj->sha1, sha1);
|
||||
obj[0].idx.crc32 = crc32(0, Z_NULL, 0);
|
||||
obj[0].idx.crc32 = crc32(obj[0].idx.crc32, header, n);
|
||||
obj[1].idx.offset = obj[0].idx.offset + n;
|
||||
obj[1].idx.offset += write_compressed(output_fd, buf, size, &obj[0].idx.crc32);
|
||||
hashcpy(obj->idx.sha1, sha1);
|
||||
}
|
||||
|
||||
static int delta_pos_compare(const void *_a, const void *_b)
|
||||
@ -602,145 +600,6 @@ static void fix_unresolved_deltas(int nr_unresolved)
|
||||
free(sorted_by_pos);
|
||||
}
|
||||
|
||||
static uint32_t index_default_version = 1;
|
||||
static uint32_t index_off32_limit = 0x7fffffff;
|
||||
|
||||
static int sha1_compare(const void *_a, const void *_b)
|
||||
{
|
||||
struct object_entry *a = *(struct object_entry **)_a;
|
||||
struct object_entry *b = *(struct object_entry **)_b;
|
||||
return hashcmp(a->sha1, b->sha1);
|
||||
}
|
||||
|
||||
/*
|
||||
* On entry *sha1 contains the pack content SHA1 hash, on exit it is
|
||||
* the SHA1 hash of sorted object names.
|
||||
*/
|
||||
static const char *write_index_file(const char *index_name, unsigned char *sha1)
|
||||
{
|
||||
struct sha1file *f;
|
||||
struct object_entry **sorted_by_sha, **list, **last;
|
||||
uint32_t array[256];
|
||||
int i, fd;
|
||||
SHA_CTX ctx;
|
||||
uint32_t index_version;
|
||||
|
||||
if (nr_objects) {
|
||||
sorted_by_sha =
|
||||
xcalloc(nr_objects, sizeof(struct object_entry *));
|
||||
list = sorted_by_sha;
|
||||
last = sorted_by_sha + nr_objects;
|
||||
for (i = 0; i < nr_objects; ++i)
|
||||
sorted_by_sha[i] = &objects[i];
|
||||
qsort(sorted_by_sha, nr_objects, sizeof(sorted_by_sha[0]),
|
||||
sha1_compare);
|
||||
}
|
||||
else
|
||||
sorted_by_sha = list = last = NULL;
|
||||
|
||||
if (!index_name) {
|
||||
static char tmpfile[PATH_MAX];
|
||||
snprintf(tmpfile, sizeof(tmpfile),
|
||||
"%s/tmp_idx_XXXXXX", get_object_directory());
|
||||
fd = mkstemp(tmpfile);
|
||||
index_name = xstrdup(tmpfile);
|
||||
} else {
|
||||
unlink(index_name);
|
||||
fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
|
||||
}
|
||||
if (fd < 0)
|
||||
die("unable to create %s: %s", index_name, strerror(errno));
|
||||
f = sha1fd(fd, index_name);
|
||||
|
||||
/* if last object's offset is >= 2^31 we should use index V2 */
|
||||
index_version = (objects[nr_objects-1].offset >> 31) ? 2 : index_default_version;
|
||||
|
||||
/* index versions 2 and above need a header */
|
||||
if (index_version >= 2) {
|
||||
struct pack_idx_header hdr;
|
||||
hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
|
||||
hdr.idx_version = htonl(index_version);
|
||||
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
|
||||
* having to do eight extra binary search iterations).
|
||||
*/
|
||||
for (i = 0; i < 256; i++) {
|
||||
struct object_entry **next = list;
|
||||
while (next < last) {
|
||||
struct object_entry *obj = *next;
|
||||
if (obj->sha1[0] != i)
|
||||
break;
|
||||
next++;
|
||||
}
|
||||
array[i] = htonl(next - sorted_by_sha);
|
||||
list = next;
|
||||
}
|
||||
sha1write(f, array, 256 * 4);
|
||||
|
||||
/* compute the SHA1 hash of sorted object names. */
|
||||
SHA1_Init(&ctx);
|
||||
|
||||
/*
|
||||
* Write the actual SHA1 entries..
|
||||
*/
|
||||
list = sorted_by_sha;
|
||||
for (i = 0; i < nr_objects; i++) {
|
||||
struct object_entry *obj = *list++;
|
||||
if (index_version < 2) {
|
||||
uint32_t offset = htonl(obj->offset);
|
||||
sha1write(f, &offset, 4);
|
||||
}
|
||||
sha1write(f, obj->sha1, 20);
|
||||
SHA1_Update(&ctx, obj->sha1, 20);
|
||||
}
|
||||
|
||||
if (index_version >= 2) {
|
||||
unsigned int nr_large_offset = 0;
|
||||
|
||||
/* write the crc32 table */
|
||||
list = sorted_by_sha;
|
||||
for (i = 0; i < nr_objects; i++) {
|
||||
struct object_entry *obj = *list++;
|
||||
uint32_t crc32_val = htonl(obj->crc32);
|
||||
sha1write(f, &crc32_val, 4);
|
||||
}
|
||||
|
||||
/* write the 32-bit offset table */
|
||||
list = sorted_by_sha;
|
||||
for (i = 0; i < nr_objects; i++) {
|
||||
struct object_entry *obj = *list++;
|
||||
uint32_t offset = (obj->offset <= index_off32_limit) ?
|
||||
obj->offset : (0x80000000 | nr_large_offset++);
|
||||
offset = htonl(offset);
|
||||
sha1write(f, &offset, 4);
|
||||
}
|
||||
|
||||
/* write the large offset table */
|
||||
list = sorted_by_sha;
|
||||
while (nr_large_offset) {
|
||||
struct object_entry *obj = *list++;
|
||||
uint64_t offset = obj->offset;
|
||||
if (offset > index_off32_limit) {
|
||||
uint32_t split[2];
|
||||
split[0] = htonl(offset >> 32);
|
||||
split[1] = htonl(offset & 0xffffffff);
|
||||
sha1write(f, split, 8);
|
||||
nr_large_offset--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sha1write(f, sha1, 20);
|
||||
sha1close(f, NULL, 1);
|
||||
free(sorted_by_sha);
|
||||
SHA1_Final(sha1, &ctx);
|
||||
return index_name;
|
||||
}
|
||||
|
||||
static void final(const char *final_pack_name, const char *curr_pack_name,
|
||||
const char *final_index_name, const char *curr_index_name,
|
||||
const char *keep_name, const char *keep_msg,
|
||||
@ -830,6 +689,7 @@ int main(int argc, char **argv)
|
||||
const char *curr_index, *index_name = NULL;
|
||||
const char *keep_name = NULL, *keep_msg = NULL;
|
||||
char *index_name_buf = NULL, *keep_name_buf = NULL;
|
||||
struct pack_idx_entry **idx_objects;
|
||||
unsigned char sha1[20];
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
@ -865,12 +725,12 @@ int main(int argc, char **argv)
|
||||
index_name = argv[++i];
|
||||
} else if (!prefixcmp(arg, "--index-version=")) {
|
||||
char *c;
|
||||
index_default_version = strtoul(arg + 16, &c, 10);
|
||||
if (index_default_version > 2)
|
||||
pack_idx_default_version = strtoul(arg + 16, &c, 10);
|
||||
if (pack_idx_default_version > 2)
|
||||
die("bad %s", arg);
|
||||
if (*c == ',')
|
||||
index_off32_limit = strtoul(c+1, &c, 0);
|
||||
if (*c || index_off32_limit & 0x80000000)
|
||||
pack_idx_off32_limit = strtoul(c+1, &c, 0);
|
||||
if (*c || pack_idx_off32_limit & 0x80000000)
|
||||
die("bad %s", arg);
|
||||
} else
|
||||
usage(index_pack_usage);
|
||||
@ -940,7 +800,13 @@ int main(int argc, char **argv)
|
||||
nr_deltas - nr_resolved_deltas);
|
||||
}
|
||||
free(deltas);
|
||||
curr_index = write_index_file(index_name, sha1);
|
||||
|
||||
idx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *));
|
||||
for (i = 0; i < nr_objects; i++)
|
||||
idx_objects[i] = &objects[i].idx;
|
||||
curr_index = write_idx_file(index_name, idx_objects, nr_objects, sha1);
|
||||
free(idx_objects);
|
||||
|
||||
final(pack_name, curr_pack,
|
||||
index_name, curr_index,
|
||||
keep_name, keep_msg,
|
||||
|
142
pack-write.c
142
pack-write.c
@ -1,5 +1,147 @@
|
||||
#include "cache.h"
|
||||
#include "pack.h"
|
||||
#include "csum-file.h"
|
||||
|
||||
uint32_t pack_idx_default_version = 1;
|
||||
uint32_t pack_idx_off32_limit = 0x7fffffff;
|
||||
|
||||
static int sha1_compare(const void *_a, const void *_b)
|
||||
{
|
||||
struct pack_idx_entry *a = *(struct pack_idx_entry **)_a;
|
||||
struct pack_idx_entry *b = *(struct pack_idx_entry **)_b;
|
||||
return hashcmp(a->sha1, b->sha1);
|
||||
}
|
||||
|
||||
/*
|
||||
* On entry *sha1 contains the pack content SHA1 hash, on exit it is
|
||||
* the SHA1 hash of sorted object names. The objects array passed in
|
||||
* will be sorted by SHA1 on exit.
|
||||
*/
|
||||
const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1)
|
||||
{
|
||||
struct sha1file *f;
|
||||
struct pack_idx_entry **sorted_by_sha, **list, **last;
|
||||
off_t last_obj_offset = 0;
|
||||
uint32_t array[256];
|
||||
int i, fd;
|
||||
SHA_CTX ctx;
|
||||
uint32_t index_version;
|
||||
|
||||
if (nr_objects) {
|
||||
sorted_by_sha = objects;
|
||||
list = sorted_by_sha;
|
||||
last = sorted_by_sha + nr_objects;
|
||||
for (i = 0; i < nr_objects; ++i) {
|
||||
if (objects[i]->offset > last_obj_offset)
|
||||
last_obj_offset = objects[i]->offset;
|
||||
}
|
||||
qsort(sorted_by_sha, nr_objects, sizeof(sorted_by_sha[0]),
|
||||
sha1_compare);
|
||||
}
|
||||
else
|
||||
sorted_by_sha = list = last = NULL;
|
||||
|
||||
if (!index_name) {
|
||||
static char tmpfile[PATH_MAX];
|
||||
snprintf(tmpfile, sizeof(tmpfile),
|
||||
"%s/tmp_idx_XXXXXX", get_object_directory());
|
||||
fd = mkstemp(tmpfile);
|
||||
index_name = xstrdup(tmpfile);
|
||||
} else {
|
||||
unlink(index_name);
|
||||
fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
|
||||
}
|
||||
if (fd < 0)
|
||||
die("unable to create %s: %s", index_name, strerror(errno));
|
||||
f = sha1fd(fd, index_name);
|
||||
|
||||
/* if last object's offset is >= 2^31 we should use index V2 */
|
||||
index_version = (last_obj_offset >> 31) ? 2 : pack_idx_default_version;
|
||||
|
||||
/* index versions 2 and above need a header */
|
||||
if (index_version >= 2) {
|
||||
struct pack_idx_header hdr;
|
||||
hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
|
||||
hdr.idx_version = htonl(index_version);
|
||||
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
|
||||
* having to do eight extra binary search iterations).
|
||||
*/
|
||||
for (i = 0; i < 256; i++) {
|
||||
struct pack_idx_entry **next = list;
|
||||
while (next < last) {
|
||||
struct pack_idx_entry *obj = *next;
|
||||
if (obj->sha1[0] != i)
|
||||
break;
|
||||
next++;
|
||||
}
|
||||
array[i] = htonl(next - sorted_by_sha);
|
||||
list = next;
|
||||
}
|
||||
sha1write(f, array, 256 * 4);
|
||||
|
||||
/* compute the SHA1 hash of sorted object names. */
|
||||
SHA1_Init(&ctx);
|
||||
|
||||
/*
|
||||
* Write the actual SHA1 entries..
|
||||
*/
|
||||
list = sorted_by_sha;
|
||||
for (i = 0; i < nr_objects; i++) {
|
||||
struct pack_idx_entry *obj = *list++;
|
||||
if (index_version < 2) {
|
||||
uint32_t offset = htonl(obj->offset);
|
||||
sha1write(f, &offset, 4);
|
||||
}
|
||||
sha1write(f, obj->sha1, 20);
|
||||
SHA1_Update(&ctx, obj->sha1, 20);
|
||||
}
|
||||
|
||||
if (index_version >= 2) {
|
||||
unsigned int nr_large_offset = 0;
|
||||
|
||||
/* write the crc32 table */
|
||||
list = sorted_by_sha;
|
||||
for (i = 0; i < nr_objects; i++) {
|
||||
struct pack_idx_entry *obj = *list++;
|
||||
uint32_t crc32_val = htonl(obj->crc32);
|
||||
sha1write(f, &crc32_val, 4);
|
||||
}
|
||||
|
||||
/* write the 32-bit offset table */
|
||||
list = sorted_by_sha;
|
||||
for (i = 0; i < nr_objects; i++) {
|
||||
struct pack_idx_entry *obj = *list++;
|
||||
uint32_t offset = (obj->offset <= pack_idx_off32_limit) ?
|
||||
obj->offset : (0x80000000 | nr_large_offset++);
|
||||
offset = htonl(offset);
|
||||
sha1write(f, &offset, 4);
|
||||
}
|
||||
|
||||
/* write the large offset table */
|
||||
list = sorted_by_sha;
|
||||
while (nr_large_offset) {
|
||||
struct pack_idx_entry *obj = *list++;
|
||||
uint64_t offset = obj->offset;
|
||||
if (offset > pack_idx_off32_limit) {
|
||||
uint32_t split[2];
|
||||
split[0] = htonl(offset >> 32);
|
||||
split[1] = htonl(offset & 0xffffffff);
|
||||
sha1write(f, split, 8);
|
||||
nr_large_offset--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sha1write(f, sha1, 20);
|
||||
sha1close(f, NULL, 1);
|
||||
SHA1_Final(sha1, &ctx);
|
||||
return index_name;
|
||||
}
|
||||
|
||||
void fixup_pack_header_footer(int pack_fd,
|
||||
unsigned char *pack_file_sha1,
|
||||
|
14
pack.h
14
pack.h
@ -34,6 +34,10 @@ struct pack_header {
|
||||
*/
|
||||
#define PACK_IDX_SIGNATURE 0xff744f63 /* "\377tOc" */
|
||||
|
||||
/* These may be overridden by command-line parameters */
|
||||
extern uint32_t pack_idx_default_version;
|
||||
extern uint32_t pack_idx_off32_limit;
|
||||
|
||||
/*
|
||||
* Packed object index header
|
||||
*/
|
||||
@ -42,6 +46,16 @@ struct pack_idx_header {
|
||||
uint32_t idx_version;
|
||||
};
|
||||
|
||||
/*
|
||||
* Common part of object structure used for write_idx_file
|
||||
*/
|
||||
struct pack_idx_entry {
|
||||
unsigned char sha1[20];
|
||||
uint32_t crc32;
|
||||
off_t offset;
|
||||
};
|
||||
|
||||
extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1);
|
||||
|
||||
extern int verify_pack(struct packed_git *, int);
|
||||
extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t);
|
||||
|
Loading…
Reference in New Issue
Block a user