diff --git a/fast-import.c b/fast-import.c index 309f4d353b..f3376c60ef 100644 --- a/fast-import.c +++ b/fast-import.c @@ -215,8 +215,10 @@ static struct atom_str **atom_table; static int pack_fd; static unsigned long pack_size; static unsigned char pack_sha1[20]; -static void* pack_base; -static size_t pack_mlen; +static unsigned char* pack_base; +static unsigned long pack_moff; +static unsigned long pack_mlen = 128*1024*1024; +static unsigned long page_size; /* Table of objects we've written. */ static unsigned int object_entry_alloc = 1000; @@ -676,23 +678,26 @@ static int store_object( return 0; } -static void* map_pack(unsigned long offset) +static unsigned char* map_pack(unsigned long offset, unsigned int *left) { if (offset >= pack_size) die("object offset outside of pack file"); - if (offset >= pack_mlen) { + if (!pack_base + || offset < pack_moff + || (offset + 20) >= (pack_moff + pack_mlen)) { if (pack_base) munmap(pack_base, pack_mlen); - /* round out how much we map to 16 MB units */ - pack_mlen = pack_size; - if (pack_mlen & ((1 << 24) - 1)) - pack_mlen = ((pack_mlen >> 24) + 1) << 24; - pack_base = mmap(NULL,pack_mlen,PROT_READ,MAP_SHARED,pack_fd,0); + pack_moff = (offset / page_size) * page_size; + pack_base = mmap(NULL,pack_mlen,PROT_READ,MAP_SHARED, + pack_fd,pack_moff); if (pack_base == MAP_FAILED) die("Failed to map generated pack: %s", strerror(errno)); remap_count++; } - return (char*)pack_base + offset; + offset -= pack_moff; + if (left) + *left = pack_mlen - offset; + return pack_base + offset; } static unsigned long unpack_object_header(unsigned long offset, @@ -703,12 +708,12 @@ static unsigned long unpack_object_header(unsigned long offset, unsigned char c; unsigned long size; - c = *(unsigned char*)map_pack(offset++); + c = *map_pack(offset++, NULL); *type = (c >> 4) & 7; size = c & 15; shift = 4; while (c & 0x80) { - c = *(unsigned char*)map_pack(offset++); + c = *map_pack(offset++, NULL); size += (c & 0x7f) << shift; shift += 7; } @@ -725,8 +730,7 @@ static void *unpack_non_delta_entry(unsigned long o, unsigned long sz) result[sz] = 0; memset(&stream, 0, sizeof(stream)); - stream.next_in = map_pack(o); - stream.avail_in = pack_mlen - o; + stream.next_in = map_pack(o, &stream.avail_in); stream.next_out = result; stream.avail_out = sz; @@ -735,13 +739,12 @@ static void *unpack_non_delta_entry(unsigned long o, unsigned long sz) int st = inflate(&stream, Z_FINISH); if (st == Z_STREAM_END) break; - if (st == Z_OK) { - o = stream.next_in - (unsigned char*)pack_base; - stream.next_in = map_pack(o); - stream.avail_in = pack_mlen - o; + if (st == Z_OK || st == Z_BUF_ERROR) { + o = stream.next_in - pack_base + pack_moff; + stream.next_in = map_pack(o, &stream.avail_in); continue; } - die("Error from zlib during inflate."); + die("Error %i from zlib during inflate.", st); } inflateEnd(&stream); if (stream.total_out != sz) @@ -760,7 +763,7 @@ static void *unpack_delta_entry(unsigned long offset, void *delta_data, *base, *result; unsigned long base_size, result_size; - base_sha1 = (unsigned char*)map_pack(offset + 20) - 20; + base_sha1 = map_pack(offset, NULL); base_oe = find_object(base_sha1); if (!base_oe) die("I'm broken; I can't find a base I know must be here."); @@ -1615,6 +1618,7 @@ int main(int argc, const char **argv) setup_ident(); git_config(git_default_config); + page_size = getpagesize(); for (i = 1; i < argc; i++) { const char *a = argv[i];