git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [JGIT PATCH] index-pack: Avoid disk corruption in objects appended to thin packs
@ 2008-08-29  5:54 Shawn O. Pearce
  0 siblings, 0 replies; only message in thread
From: Shawn O. Pearce @ 2008-08-29  5:54 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

When we are appending onto a thin pack we need to make sure the whole
object we wrote into the pack is what is there when we re-read the
pack to compute the final footer.

Nicolas Pitre pointed out the need to perform this sort of compare
in C Git.  We missed it in my first round of index-pack improvements.

We also now take advantage of "roughly" block aligned reads during
the fixup operation.  4k is a popular filesystem block size and by
arranging the code a little differently we can always perform reads
on 4k alignments within the file.  This should make it easier for
the OS to move data to us.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 .../src/org/spearce/jgit/transport/IndexPack.java  |   47 ++++++++++++++-----
 1 files changed, 34 insertions(+), 13 deletions(-)

diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/IndexPack.java b/org.spearce.jgit/src/org/spearce/jgit/transport/IndexPack.java
index 7b1f7ee..d8e6548 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/IndexPack.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/IndexPack.java
@@ -76,7 +76,7 @@
 	/** Progress message when computing names of delta compressed objects. */
 	public static final String PROGRESS_RESOLVE_DELTA = "Resolving deltas";
 
-	private static final int BUFFER_SIZE = 2048;
+	private static final int BUFFER_SIZE = 4096;
 
 	/**
 	 * Create an index pack instance to load a new pack into a repository.
@@ -403,6 +403,7 @@ while (bi < b.size()) {
 	private void fixThinPack(final ProgressMonitor progress) throws IOException {
 		growEntries();
 
+		packDigest.reset();
 		originalEOF = packOut.length() - 20;
 		final Deflater def = new Deflater(Deflater.DEFAULT_COMPRESSION, false);
 		long end = originalEOF;
@@ -432,7 +433,7 @@ if (!baseById.isEmpty()) {
 			throw new MissingObjectException(need, "delta base");
 		}
 
-		fixHeaderFooter();
+		fixHeaderFooter(packcsum, packDigest.digest());
 	}
 
 	private void writeWhole(final Deflater def, final int typeCode,
@@ -446,6 +447,7 @@ while (sz > 0) {
 			buf[hdrlen++] = (byte) (sz & 0x7f);
 			sz >>>= 7;
 		}
+		packDigest.update(buf, 0, hdrlen);
 		crc.update(buf, 0, hdrlen);
 		packOut.write(buf, 0, hdrlen);
 		def.reset();
@@ -453,37 +455,56 @@ while (sz > 0) {
 		def.finish();
 		while (!def.finished()) {
 			final int datlen = def.deflate(buf);
+			packDigest.update(buf, 0, datlen);
 			crc.update(buf, 0, datlen);
 			packOut.write(buf, 0, datlen);
 		}
 	}
 
-	private void fixHeaderFooter() throws IOException {
+	private void fixHeaderFooter(final byte[] origcsum, final byte[] tailcsum)
+			throws IOException {
 		final MessageDigest origDigest = Constants.newMessageDigest();
-		long origRemaining = originalEOF - 12;
+		final MessageDigest tailDigest = Constants.newMessageDigest();
+		long origRemaining = originalEOF;
 
 		packOut.seek(0);
-		if (packOut.read(buf, 0, 12) != 12)
-			throw new IOException("Cannot re-read pack header to fix count");
-		origDigest.update(buf, 0, 12);
+		bAvail = 0;
+		bOffset = 0;
+		fillFromFile(12);
+
+		{
+			final int origCnt = (int) Math.min(bAvail, origRemaining);
+			origDigest.update(buf, 0, origCnt);
+			origRemaining -= origCnt;
+			if (origRemaining == 0)
+				tailDigest.update(buf, origCnt, bAvail - origCnt);
+		}
+
 		NB.encodeInt32(buf, 8, entryCount);
 		packOut.seek(0);
 		packOut.write(buf, 0, 12);
+		packOut.seek(bAvail);
 
 		packDigest.reset();
-		packDigest.update(buf, 0, 12);
+		packDigest.update(buf, 0, bAvail);
 		for (;;) {
 			final int n = packOut.read(buf);
 			if (n < 0)
 				break;
-			if (origRemaining > 0) {
-				origDigest.update(buf, 0, (int) Math.min(n, origRemaining));
-				origRemaining -= n;
-			}
+			if (origRemaining != 0) {
+				final int origCnt = (int) Math.min(n, origRemaining);
+				origDigest.update(buf, 0, origCnt);
+				origRemaining -= origCnt;
+				if (origRemaining == 0)
+					tailDigest.update(buf, origCnt, n - origCnt);
+			} else
+				tailDigest.update(buf, 0, n);
+
 			packDigest.update(buf, 0, n);
 		}
 
-		if (!Arrays.equals(origDigest.digest(), packcsum))
+		if (!Arrays.equals(origDigest.digest(), origcsum)
+				|| !Arrays.equals(tailDigest.digest(), tailcsum))
 			throw new IOException("Pack corrupted while writing to filesystem");
 
 		packcsum = packDigest.digest();
-- 
1.6.0.272.g9ab4

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2008-08-29  5:55 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-08-29  5:54 [JGIT PATCH] index-pack: Avoid disk corruption in objects appended to thin packs Shawn O. Pearce

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).