fix reading pack files larger than 2GB; ok tb@; problem found by mpi@
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
diff --git a/lib/got_lib_pack.h b/lib/got_lib_pack.h
index 7e7c697..654dfa8 100644
--- a/lib/got_lib_pack.h
+++ b/lib/got_lib_pack.h
@@ -89,6 +89,7 @@ struct got_packidx {
int fd;
uint8_t *map;
size_t len;
+ size_t nlargeobj;
struct got_packidx_v2_hdr hdr; /* convenient pointers into map */
};
diff --git a/lib/pack.c b/lib/pack.c
index b6f49c5..f4d0993 100644
--- a/lib/pack.c
+++ b/lib/pack.c
@@ -75,6 +75,7 @@ got_packidx_init_hdr(struct got_packidx *p, int verify)
uint8_t sha1[SHA1_DIGEST_LENGTH];
size_t nobj, len_fanout, len_ids, offset, remain;
ssize_t n;
+ int i;
SHA1Init(&ctx);
@@ -255,35 +256,41 @@ got_packidx_init_hdr(struct got_packidx *p, int verify)
offset += nobj * sizeof(*h->offsets);
/* Large file offsets are contained only in files > 2GB. */
- if (p->len <= 0x80000000)
+ for (i = 0; i < nobj; i++) {
+ uint32_t o = betoh32(h->offsets[i]);
+ if (o & GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX)
+ p->nlargeobj++;
+ }
+ if (p->nlargeobj == 0)
goto checksum;
- if (remain < nobj * sizeof(*h->large_offsets)) {
+ if (remain < p->nlargeobj * sizeof(*h->large_offsets)) {
err = got_error(GOT_ERR_BAD_PACKIDX);
goto done;
}
if (p->map)
h->large_offsets = (uint64_t *)((uint8_t*)(p->map + offset));
else {
- h->large_offsets = malloc(nobj * sizeof(*h->large_offsets));
+ h->large_offsets = malloc(p->nlargeobj *
+ sizeof(*h->large_offsets));
if (h->large_offsets == NULL) {
err = got_error_from_errno("malloc");
goto done;
}
n = read(p->fd, h->large_offsets,
- nobj * sizeof(*h->large_offsets));
+ p->nlargeobj * sizeof(*h->large_offsets));
if (n < 0)
err = got_error_from_errno("read");
- else if (n != nobj * sizeof(*h->large_offsets)) {
+ else if (n != p->nlargeobj * sizeof(*h->large_offsets)) {
err = got_error(GOT_ERR_BAD_PACKIDX);
goto done;
}
}
if (verify)
SHA1Update(&ctx, (uint8_t*)h->large_offsets,
- nobj * sizeof(*h->large_offsets));
- remain -= nobj * sizeof(*h->large_offsets);
- offset += nobj * sizeof(*h->large_offsets);
+ p->nlargeobj * sizeof(*h->large_offsets));
+ remain -= p->nlargeobj * sizeof(*h->large_offsets);
+ offset += p->nlargeobj * sizeof(*h->large_offsets);
checksum:
if (remain < sizeof(*h->trailer)) {
@@ -408,12 +415,11 @@ got_packidx_close(struct got_packidx *packidx)
static off_t
get_object_offset(struct got_packidx *packidx, int idx)
{
- uint32_t totobj = betoh32(packidx->hdr.fanout_table[0xff]);
uint32_t offset = betoh32(packidx->hdr.offsets[idx]);
if (offset & GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX) {
uint64_t loffset;
idx = offset & GOT_PACKIDX_OFFSET_VAL_MASK;
- if (idx < 0 || idx > totobj ||
+ if (idx < 0 || idx >= packidx->nlargeobj ||
packidx->hdr.large_offsets == NULL)
return -1;
loffset = betoh64(packidx->hdr.large_offsets[idx]);