|
|
@ -74,13 +74,14 @@ import org.eclipse.jgit.lib.ObjectDatabase; |
|
|
|
import org.eclipse.jgit.lib.ObjectId; |
|
|
|
import org.eclipse.jgit.lib.ObjectId; |
|
|
|
import org.eclipse.jgit.lib.ObjectIdSubclassMap; |
|
|
|
import org.eclipse.jgit.lib.ObjectIdSubclassMap; |
|
|
|
import org.eclipse.jgit.lib.ObjectLoader; |
|
|
|
import org.eclipse.jgit.lib.ObjectLoader; |
|
|
|
|
|
|
|
import org.eclipse.jgit.lib.ObjectReader; |
|
|
|
import org.eclipse.jgit.lib.ProgressMonitor; |
|
|
|
import org.eclipse.jgit.lib.ProgressMonitor; |
|
|
|
import org.eclipse.jgit.lib.Repository; |
|
|
|
import org.eclipse.jgit.lib.Repository; |
|
|
|
import org.eclipse.jgit.lib.ObjectReader; |
|
|
|
|
|
|
|
import org.eclipse.jgit.storage.file.PackIndexWriter; |
|
|
|
import org.eclipse.jgit.storage.file.PackIndexWriter; |
|
|
|
import org.eclipse.jgit.storage.file.PackLock; |
|
|
|
import org.eclipse.jgit.storage.file.PackLock; |
|
|
|
import org.eclipse.jgit.storage.pack.BinaryDelta; |
|
|
|
import org.eclipse.jgit.storage.pack.BinaryDelta; |
|
|
|
import org.eclipse.jgit.util.FileUtils; |
|
|
|
import org.eclipse.jgit.util.FileUtils; |
|
|
|
|
|
|
|
import org.eclipse.jgit.util.IO; |
|
|
|
import org.eclipse.jgit.util.NB; |
|
|
|
import org.eclipse.jgit.util.NB; |
|
|
|
|
|
|
|
|
|
|
|
/** Indexes Git pack files for local use. */ |
|
|
|
/** Indexes Git pack files for local use. */ |
|
|
@ -148,7 +149,7 @@ public class IndexPack { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private final ObjectDatabase objectDatabase; |
|
|
|
private final ObjectDatabase objectDatabase; |
|
|
|
|
|
|
|
|
|
|
|
private Inflater inflater; |
|
|
|
private InflaterStream inflater; |
|
|
|
|
|
|
|
|
|
|
|
private final MessageDigest objectDigest; |
|
|
|
private final MessageDigest objectDigest; |
|
|
|
|
|
|
|
|
|
|
@ -210,8 +211,6 @@ public class IndexPack { |
|
|
|
|
|
|
|
|
|
|
|
private LongMap<UnresolvedDelta> baseByPos; |
|
|
|
private LongMap<UnresolvedDelta> baseByPos; |
|
|
|
|
|
|
|
|
|
|
|
private byte[] skipBuffer; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private MessageDigest packDigest; |
|
|
|
private MessageDigest packDigest; |
|
|
|
|
|
|
|
|
|
|
|
private RandomAccessFile packOut; |
|
|
|
private RandomAccessFile packOut; |
|
|
@ -239,10 +238,9 @@ public class IndexPack { |
|
|
|
repo = db; |
|
|
|
repo = db; |
|
|
|
objectDatabase = db.getObjectDatabase().newCachedDatabase(); |
|
|
|
objectDatabase = db.getObjectDatabase().newCachedDatabase(); |
|
|
|
in = src; |
|
|
|
in = src; |
|
|
|
inflater = InflaterCache.get(); |
|
|
|
inflater = new InflaterStream(); |
|
|
|
readCurs = objectDatabase.newReader(); |
|
|
|
readCurs = objectDatabase.newReader(); |
|
|
|
buf = new byte[BUFFER_SIZE]; |
|
|
|
buf = new byte[BUFFER_SIZE]; |
|
|
|
skipBuffer = new byte[512]; |
|
|
|
|
|
|
|
objectDigest = Constants.newMessageDigest(); |
|
|
|
objectDigest = Constants.newMessageDigest(); |
|
|
|
tempObjectId = new MutableObjectId(); |
|
|
|
tempObjectId = new MutableObjectId(); |
|
|
|
packDigest = Constants.newMessageDigest(); |
|
|
|
packDigest = Constants.newMessageDigest(); |
|
|
@ -441,7 +439,7 @@ public class IndexPack { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
InflaterCache.release(inflater); |
|
|
|
inflater.release(); |
|
|
|
} finally { |
|
|
|
} finally { |
|
|
|
inflater = null; |
|
|
|
inflater = null; |
|
|
|
objectDatabase.close(); |
|
|
|
objectDatabase.close(); |
|
|
@ -776,7 +774,6 @@ public class IndexPack { |
|
|
|
// Cleanup all resources associated with our input parsing.
|
|
|
|
// Cleanup all resources associated with our input parsing.
|
|
|
|
private void endInput() { |
|
|
|
private void endInput() { |
|
|
|
in = null; |
|
|
|
in = null; |
|
|
|
skipBuffer = null; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Read one entire object or delta from the input.
|
|
|
|
// Read one entire object or delta from the input.
|
|
|
@ -952,65 +949,24 @@ public class IndexPack { |
|
|
|
|
|
|
|
|
|
|
|
private void inflateAndSkip(final Source src, final long inflatedSize) |
|
|
|
private void inflateAndSkip(final Source src, final long inflatedSize) |
|
|
|
throws IOException { |
|
|
|
throws IOException { |
|
|
|
inflate(src, inflatedSize, skipBuffer, false /* do not keep result */); |
|
|
|
final InputStream inf = inflate(src, inflatedSize); |
|
|
|
|
|
|
|
IO.skipFully(inf, inflatedSize); |
|
|
|
|
|
|
|
inf.close(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private byte[] inflateAndReturn(final Source src, final long inflatedSize) |
|
|
|
private byte[] inflateAndReturn(final Source src, final long inflatedSize) |
|
|
|
throws IOException { |
|
|
|
throws IOException { |
|
|
|
final byte[] dst = new byte[(int) inflatedSize]; |
|
|
|
final byte[] dst = new byte[(int) inflatedSize]; |
|
|
|
inflate(src, inflatedSize, dst, true /* keep result in dst */); |
|
|
|
final InputStream inf = inflate(src, inflatedSize); |
|
|
|
|
|
|
|
IO.readFully(inf, dst, 0, dst.length); |
|
|
|
|
|
|
|
inf.close(); |
|
|
|
return dst; |
|
|
|
return dst; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void inflate(final Source src, final long inflatedSize, |
|
|
|
private InputStream inflate(final Source src, final long inflatedSize) |
|
|
|
final byte[] dst, final boolean keep) throws IOException { |
|
|
|
throws IOException { |
|
|
|
final Inflater inf = inflater; |
|
|
|
inflater.open(src, inflatedSize); |
|
|
|
try { |
|
|
|
return inflater; |
|
|
|
int off = 0; |
|
|
|
|
|
|
|
long cnt = 0; |
|
|
|
|
|
|
|
int p = fill(src, 24); |
|
|
|
|
|
|
|
inf.setInput(buf, p, bAvail); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (;;) { |
|
|
|
|
|
|
|
int r = inf.inflate(dst, off, dst.length - off); |
|
|
|
|
|
|
|
if (r == 0) { |
|
|
|
|
|
|
|
if (inf.finished()) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
if (inf.needsInput()) { |
|
|
|
|
|
|
|
if (p >= 0) { |
|
|
|
|
|
|
|
crc.update(buf, p, bAvail); |
|
|
|
|
|
|
|
use(bAvail); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
p = fill(src, 24); |
|
|
|
|
|
|
|
inf.setInput(buf, p, bAvail); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
throw new CorruptObjectException(MessageFormat.format( |
|
|
|
|
|
|
|
JGitText.get().packfileCorruptionDetected, |
|
|
|
|
|
|
|
JGitText.get().unknownZlibError)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
cnt += r; |
|
|
|
|
|
|
|
if (keep) |
|
|
|
|
|
|
|
off += r; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (cnt != inflatedSize) { |
|
|
|
|
|
|
|
throw new CorruptObjectException(MessageFormat.format(JGitText |
|
|
|
|
|
|
|
.get().packfileCorruptionDetected, |
|
|
|
|
|
|
|
JGitText.get().wrongDecompressedLength)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int left = bAvail - inf.getRemaining(); |
|
|
|
|
|
|
|
if (left > 0) { |
|
|
|
|
|
|
|
crc.update(buf, p, left); |
|
|
|
|
|
|
|
use(left); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} catch (DataFormatException dfe) { |
|
|
|
|
|
|
|
throw new CorruptObjectException(MessageFormat.format(JGitText |
|
|
|
|
|
|
|
.get().packfileCorruptionDetected, dfe.getMessage())); |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
inf.reset(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static class DeltaChain extends ObjectId { |
|
|
|
private static class DeltaChain extends ObjectId { |
|
|
@ -1165,4 +1121,111 @@ public class IndexPack { |
|
|
|
if (needNewObjectIds()) |
|
|
|
if (needNewObjectIds()) |
|
|
|
newObjectIds.add(oe); |
|
|
|
newObjectIds.add(oe); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private class InflaterStream extends InputStream { |
|
|
|
|
|
|
|
private final Inflater inf; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final byte[] skipBuffer; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Source src; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private long expectedSize; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private long actualSize; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private int p; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
InflaterStream() { |
|
|
|
|
|
|
|
inf = InflaterCache.get(); |
|
|
|
|
|
|
|
skipBuffer = new byte[512]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void release() { |
|
|
|
|
|
|
|
inf.reset(); |
|
|
|
|
|
|
|
InflaterCache.release(inf); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void open(Source source, long inflatedSize) throws IOException { |
|
|
|
|
|
|
|
src = source; |
|
|
|
|
|
|
|
expectedSize = inflatedSize; |
|
|
|
|
|
|
|
actualSize = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
p = fill(src, 24); |
|
|
|
|
|
|
|
inf.setInput(buf, p, bAvail); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public long skip(long toSkip) throws IOException { |
|
|
|
|
|
|
|
long n = 0; |
|
|
|
|
|
|
|
while (n < toSkip) { |
|
|
|
|
|
|
|
final int cnt = (int) Math.min(skipBuffer.length, toSkip - n); |
|
|
|
|
|
|
|
final int r = read(skipBuffer, 0, cnt); |
|
|
|
|
|
|
|
if (r <= 0) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
n += r; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return n; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public int read() throws IOException { |
|
|
|
|
|
|
|
int n = read(skipBuffer, 0, 1); |
|
|
|
|
|
|
|
return n == 1 ? skipBuffer[0] & 0xff : -1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public int read(byte[] dst, int pos, int cnt) throws IOException { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
int n = 0; |
|
|
|
|
|
|
|
while (n < cnt) { |
|
|
|
|
|
|
|
int r = inf.inflate(dst, pos + n, cnt - n); |
|
|
|
|
|
|
|
if (r == 0) { |
|
|
|
|
|
|
|
if (inf.finished()) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
if (inf.needsInput()) { |
|
|
|
|
|
|
|
crc.update(buf, p, bAvail); |
|
|
|
|
|
|
|
use(bAvail); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
p = fill(src, 24); |
|
|
|
|
|
|
|
inf.setInput(buf, p, bAvail); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
throw new CorruptObjectException( |
|
|
|
|
|
|
|
MessageFormat |
|
|
|
|
|
|
|
.format( |
|
|
|
|
|
|
|
JGitText.get().packfileCorruptionDetected, |
|
|
|
|
|
|
|
JGitText.get().unknownZlibError)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
n += r; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
actualSize += n; |
|
|
|
|
|
|
|
return 0 < n ? n : -1; |
|
|
|
|
|
|
|
} catch (DataFormatException dfe) { |
|
|
|
|
|
|
|
throw new CorruptObjectException(MessageFormat.format(JGitText |
|
|
|
|
|
|
|
.get().packfileCorruptionDetected, dfe.getMessage())); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public void close() throws IOException { |
|
|
|
|
|
|
|
// We need to read here to enter the loop above and pump the
|
|
|
|
|
|
|
|
// trailing checksum into the Inflater. It should return -1 as the
|
|
|
|
|
|
|
|
// caller was supposed to consume all content.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
if (read(skipBuffer) != -1 || actualSize != expectedSize) { |
|
|
|
|
|
|
|
throw new CorruptObjectException(MessageFormat.format(JGitText |
|
|
|
|
|
|
|
.get().packfileCorruptionDetected, |
|
|
|
|
|
|
|
JGitText.get().wrongDecompressedLength)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int used = bAvail - inf.getRemaining(); |
|
|
|
|
|
|
|
if (0 < used) { |
|
|
|
|
|
|
|
crc.update(buf, p, used); |
|
|
|
|
|
|
|
use(used); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inf.reset(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|