shithub: git9

Download patch

ref: 09cdf057aa0db2d8d63eedc7718f3dea0c6075ac
parent: 230bca37cdbc79da43536fe58808db19457a3ed5
parent: 6316f60fcda342ca8bbff85dc8702c0d4db65d88
author: Ori Bernstein <ori@eigenstate.org>
date: Sun Dec 27 20:11:49 EST 2020

packfiles: fix indexing large pack files (thanks Igor Boehm)

This fixes two bugs with packfiles larger than 2
gigs in size.

When writing out the index, we were incremeneting
the index of the 64 bit offset multiple times due
to macro expansion; this patch changes it so that
we only increment it once per iteration.

When reading the index, we were interpreting the
large offset index as the offset of the 64 bit
offset, leading to a garbled index. This diff also
fixes our interpretation of the packfile, so we
read all objects correctly, even when they're at
a large offset.

--- a/pack.c
+++ b/pack.c
@@ -673,11 +673,21 @@
 		goto err;
 	i = GETBE32(idx + oo);
 	o = i & 0xffffffffULL;
+	/*
+	 * Large offsets (i.e. 64-bit) are encoded as an index
+	 * into the next table with the MSB bit set.
+	 */
 	if(o & (1ull << 31)){
-		o &= 0x7fffffff;
-		if(o < 0 || o + 8 >= nidx)
+		o &= 0x7fffffffULL;
+		oo = 8;				/* Header */
+		oo += 256*4;			/* Fanout table */
+		oo += Hashsz*nent;		/* Hashes */
+		oo += 4*nent;			/* Checksums */
+		oo += 4*nent;			/* 32-bit Offsets */
+		oo += 8*o;			/* 64-bit Offset offset */
+		if(oo < 0 || oo + 8 >= nidx)
 			goto err;
-		o = GETBE64(idx + o);
+		o = GETBE64(idx + oo);
 	}
 	return o;
 
@@ -1146,14 +1156,16 @@
 
 	nbig = 0;
 	for(i = 0; i < nobj; i++){
-		if(obj[i]->off <= (1ull<<31))
+		if(obj[i]->off < (1ull<<31))
 			PUTBE32(buf, obj[i]->off);
-		else
-			PUTBE32(buf, (1ull << 31) | nbig++);
+		else{
+			PUTBE32(buf, (1ull << 31) | nbig);
+			nbig++;
+		}
 		hwrite(f, buf, 4, &st);
 	}
 	for(i = 0; i < nobj; i++){
-		if(obj[i]->off > (1ull<<31)){
+		if(obj[i]->off >= (1ull<<31)){
 			PUTBE64(buf, obj[i]->off);
 			hwrite(f, buf, 8, &st);
 		}
--- a/save.c
+++ b/save.c
@@ -254,6 +254,8 @@
 		e = dirent(&ent, &nent, elt);
 		if(e->islink)
 			sysfatal("symlinks may not be modified: %s", *path);
+		if(e->ismod)
+			sysfatal("submodules may not be modified: %s", *path);
 		if(isdir){
 			e->mode = DMDIR | 0755;
 			sub[nsub] = readobject(e->h);