threads / patch / 15071

patch, 4 partsDetect path names which overflow the name length field in the index

Subject: [EGIT PATCH 1/4] Detect path names which overflow the name length field in the index

## tl;dr

4 messages between Aug 18, 2008 and Aug 18, 2008. Diffs are folded; open one to read it.

replies: 3people: 1as markdown or json

Shawn O. Pearce· Aug 18, 2008, 16:35 UTC · lore

C Git allows a path name to be longer than 4095 bytes by storing 4095 into the path name length field within flags and then searching for a null terminator at the end of the path name, instead of relying on the length indicatior. We cannot do this (easily) from an InputStream so we are currently going to just abort with an exception if we find such an extremely long path name.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 .../org/spearce/jgit/dircache/DirCacheEntry.java   |   13 ++++++++++---
 1 files changed, 10 insertions(+), 3 deletions(-)
Show changes to org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java +10 −3
diff --git a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java
index c481e43..bcf5596 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java
@@ -81,6 +81,9 @@
 
 	private static final int P_FLAGS = 60;
 
+	/** Mask applied to data in {@link #P_FLAGS} to get the name length. */
+	private static final int NAME_MASK = 0xfff;
+
 	static final int INFO_LEN = 62;
 
 	private static final int ASSUME_VALID = 0x80;
@@ -101,7 +104,9 @@ DirCacheEntry(final byte[] sharedInfo, final int infoAt,
 
 		NB.readFully(in, info, infoOffset, INFO_LEN);
 
-		int pathLen = NB.decodeUInt16(info, infoOffset + P_FLAGS) & 0xfff;
+		int pathLen = NB.decodeUInt16(info, infoOffset + P_FLAGS) & NAME_MASK;
+		if (pathLen == NAME_MASK)
+			throw new IOException("Path name too long for jgit");
 		path = new byte[pathLen];
 		NB.readFully(in, path, 0, pathLen);
 
@@ -135,6 +140,8 @@ public DirCacheEntry(final byte[] newPath) {
 		infoOffset = 0;
 
 		path = newPath;
+		if (path.length >= NAME_MASK)
+			throw new IllegalArgumentException("Path name too long for jgit");
 		NB.encodeInt16(info, infoOffset + P_FLAGS, path.length);
 	}
 
@@ -364,10 +371,10 @@ public String getPathString() {
 	 *            the entry to copy ObjectId and meta fields from.
 	 */
 	public void copyMetaData(final DirCacheEntry src) {
-		final int pLen = NB.decodeUInt16(info, infoOffset + P_FLAGS) & 0xfff;
+		final int pLen = NB.decodeUInt16(info, infoOffset + P_FLAGS) & NAME_MASK;
 		System.arraycopy(src.info, src.infoOffset, info, infoOffset, INFO_LEN);
 		NB.encodeInt16(info, infoOffset + P_FLAGS, pLen
-				| NB.decodeUInt16(info, infoOffset + P_FLAGS) & ~0xfff);
+				| NB.decodeUInt16(info, infoOffset + P_FLAGS) & ~NAME_MASK);
 	}
 
 	private long decodeTS(final int pIdx) {
-- 
1.6.0.87.g2858d
Shawn O. Pearce· Aug 18, 2008, 16:35 UTC · re: Shawn O. Pearce · lore

[EGIT PATCH 2/4] Fix NB.decodeUInt16 to correctly handle the high byte

Our decodeUInt16 method was buggy and always cleared the high byte of the pair. This meant we always lost the upper 8 bits when we read in a 16 bit unsigned integer, possibly causing us to misread the data associated with that pair.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 org.spearce.jgit/src/org/spearce/jgit/util/NB.java |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
Show changes to org.spearce.jgit/src/org/spearce/jgit/util/NB.java +1 −1
diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/NB.java b/org.spearce.jgit/src/org/spearce/jgit/util/NB.java
index c6176f8..fa13354 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/util/NB.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/util/NB.java
@@ -102,7 +102,7 @@ public static int compareUInt32(final int a, final int b) {
 	 * @return unsigned integer value that matches the 16 bits read.
 	 */
 	public static int decodeUInt16(final byte[] intbuf, final int offset) {
-		int r = (intbuf[offset] << 8) & 0xff;
+		int r = (intbuf[offset] & 0xff) << 8;
 		return r | (intbuf[offset + 1] & 0xff);
 	}
 
-- 
1.6.0.87.g2858d
Shawn O. Pearce· Aug 18, 2008, 16:35 UTC · re: Shawn O. Pearce · lore

[EGIT PATCH 3/4] Add test cases for NB.encode and NB.decode family of routines

We really need to ensure these methods work correctly, and since we just suffered from a bug in NB.decodeUInt16 we now have a set of test cases for the corner conditions of each encode and decode method pair we support.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 .../tst/org/spearce/jgit/util/NBTest.java          |  328 ++++++++++++++++++++
 1 files changed, 328 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/util/NBTest.java
Show changes to org.spearce.jgit.test/tst/org/spearce/jgit/util/NBTest.java +328 −0
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/util/NBTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/util/NBTest.java
new file mode 100644
index 0000000..217db7f
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/util/NBTest.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.util;
+
+import junit.framework.TestCase;
+
+public class NBTest extends TestCase {
+	public void testCompareUInt32() {
+		assertTrue(NB.compareUInt32(0, 0) == 0);
+		assertTrue(NB.compareUInt32(1, 0) > 0);
+		assertTrue(NB.compareUInt32(0, 1) < 0);
+		assertTrue(NB.compareUInt32(-1, 0) > 0);
+		assertTrue(NB.compareUInt32(0, -1) < 0);
+		assertTrue(NB.compareUInt32(-1, 1) > 0);
+		assertTrue(NB.compareUInt32(1, -1) < 0);
+	}
+
+	public void testDecodeUInt16() {
+		assertEquals(0, NB.decodeUInt16(b(0, 0), 0));
+		assertEquals(0, NB.decodeUInt16(padb(3, 0, 0), 3));
+
+		assertEquals(3, NB.decodeUInt16(b(0, 3), 0));
+		assertEquals(3, NB.decodeUInt16(padb(3, 0, 3), 3));
+
+		assertEquals(0xde03, NB.decodeUInt16(b(0xde, 3), 0));
+		assertEquals(0xde03, NB.decodeUInt16(padb(3, 0xde, 3), 3));
+
+		assertEquals(0x03de, NB.decodeUInt16(b(3, 0xde), 0));
+		assertEquals(0x03de, NB.decodeUInt16(padb(3, 3, 0xde), 3));
+
+		assertEquals(0xffff, NB.decodeUInt16(b(0xff, 0xff), 0));
+		assertEquals(0xffff, NB.decodeUInt16(padb(3, 0xff, 0xff), 3));
+	}
+
+	public void testDecodeInt32() {
+		assertEquals(0, NB.decodeInt32(b(0, 0, 0, 0), 0));
+		assertEquals(0, NB.decodeInt32(padb(3, 0, 0, 0, 0), 3));
+
+		assertEquals(3, NB.decodeInt32(b(0, 0, 0, 3), 0));
+		assertEquals(3, NB.decodeInt32(padb(3, 0, 0, 0, 3), 3));
+
+		assertEquals(0xdeadbeef, NB.decodeInt32(b(0xde, 0xad, 0xbe, 0xef), 0));
+		assertEquals(0xdeadbeef, NB.decodeInt32(
+				padb(3, 0xde, 0xad, 0xbe, 0xef), 3));
+
+		assertEquals(0x0310adef, NB.decodeInt32(b(0x03, 0x10, 0xad, 0xef), 0));
+		assertEquals(0x0310adef, NB.decodeInt32(
+				padb(3, 0x03, 0x10, 0xad, 0xef), 3));
+
+		assertEquals(0xffffffff, NB.decodeInt32(b(0xff, 0xff, 0xff, 0xff), 0));
+		assertEquals(0xffffffff, NB.decodeInt32(
+				padb(3, 0xff, 0xff, 0xff, 0xff), 3));
+	}
+
+	public void testDecodeUInt32() {
+		assertEquals(0L, NB.decodeUInt32(b(0, 0, 0, 0), 0));
+		assertEquals(0L, NB.decodeUInt32(padb(3, 0, 0, 0, 0), 3));
+
+		assertEquals(3L, NB.decodeUInt32(b(0, 0, 0, 3), 0));
+		assertEquals(3L, NB.decodeUInt32(padb(3, 0, 0, 0, 3), 3));
+
+		assertEquals(0xdeadbeefL, NB.decodeUInt32(b(0xde, 0xad, 0xbe, 0xef), 0));
+		assertEquals(0xdeadbeefL, NB.decodeUInt32(padb(3, 0xde, 0xad, 0xbe,
+				0xef), 3));
+
+		assertEquals(0x0310adefL, NB.decodeUInt32(b(0x03, 0x10, 0xad, 0xef), 0));
+		assertEquals(0x0310adefL, NB.decodeUInt32(padb(3, 0x03, 0x10, 0xad,
+				0xef), 3));
+
+		assertEquals(0xffffffffL, NB.decodeUInt32(b(0xff, 0xff, 0xff, 0xff), 0));
+		assertEquals(0xffffffffL, NB.decodeUInt32(padb(3, 0xff, 0xff, 0xff,
+				0xff), 3));
+	}
+
+	public void testDecodeUInt64() {
+		assertEquals(0L, NB.decodeUInt64(b(0, 0, 0, 0, 0, 0, 0, 0), 0));
+		assertEquals(0L, NB.decodeUInt64(padb(3, 0, 0, 0, 0, 0, 0, 0, 0), 3));
+
+		assertEquals(3L, NB.decodeUInt64(b(0, 0, 0, 0, 0, 0, 0, 3), 0));
+		assertEquals(3L, NB.decodeUInt64(padb(3, 0, 0, 0, 0, 0, 0, 0, 3), 3));
+
+		assertEquals(0xdeadbeefL, NB.decodeUInt64(b(0, 0, 0, 0, 0xde, 0xad,
+				0xbe, 0xef), 0));
+		assertEquals(0xdeadbeefL, NB.decodeUInt64(padb(3, 0, 0, 0, 0, 0xde,
+				0xad, 0xbe, 0xef), 3));
+
+		assertEquals(0x0310adefL, NB.decodeUInt64(b(0, 0, 0, 0, 0x03, 0x10,
+				0xad, 0xef), 0));
+		assertEquals(0x0310adefL, NB.decodeUInt64(padb(3, 0, 0, 0, 0, 0x03,
+				0x10, 0xad, 0xef), 3));
+
+		assertEquals(0xc0ffee78deadbeefL, NB.decodeUInt64(b(0xc0, 0xff, 0xee,
+				0x78, 0xde, 0xad, 0xbe, 0xef), 0));
+		assertEquals(0xc0ffee78deadbeefL, NB.decodeUInt64(padb(3, 0xc0, 0xff,
+				0xee, 0x78, 0xde, 0xad, 0xbe, 0xef), 3));
+
+		assertEquals(0x00000000ffffffffL, NB.decodeUInt64(b(0, 0, 0, 0, 0xff,
+				0xff, 0xff, 0xff), 0));
+		assertEquals(0x00000000ffffffffL, NB.decodeUInt64(padb(3, 0, 0, 0, 0,
+				0xff, 0xff, 0xff, 0xff), 3));
+		assertEquals(0xffffffffffffffffL, NB.decodeUInt64(b(0xff, 0xff, 0xff,
+				0xff, 0xff, 0xff, 0xff, 0xff), 0));
+		assertEquals(0xffffffffffffffffL, NB.decodeUInt64(padb(3, 0xff, 0xff,
+				0xff, 0xff, 0xff, 0xff, 0xff, 0xff), 3));
+	}
+
+	public void testEncodeInt16() {
+		final byte[] out = new byte[16];
+
+		prepareOutput(out);
+		NB.encodeInt16(out, 0, 0);
+		assertOutput(b(0, 0), out, 0);
+
+		prepareOutput(out);
+		NB.encodeInt16(out, 3, 0);
+		assertOutput(b(0, 0), out, 3);
+
+		prepareOutput(out);
+		NB.encodeInt16(out, 0, 3);
+		assertOutput(b(0, 3), out, 0);
+
+		prepareOutput(out);
+		NB.encodeInt16(out, 3, 3);
+		assertOutput(b(0, 3), out, 3);
+
+		prepareOutput(out);
+		NB.encodeInt16(out, 0, 0xdeac);
+		assertOutput(b(0xde, 0xac), out, 0);
+
+		prepareOutput(out);
+		NB.encodeInt16(out, 3, 0xdeac);
+		assertOutput(b(0xde, 0xac), out, 3);
+
+		prepareOutput(out);
+		NB.encodeInt16(out, 3, -1);
+		assertOutput(b(0xff, 0xff), out, 3);
+	}
+
+	public void testEncodeInt32() {
+		final byte[] out = new byte[16];
+
+		prepareOutput(out);
+		NB.encodeInt32(out, 0, 0);
+		assertOutput(b(0, 0, 0, 0), out, 0);
+
+		prepareOutput(out);
+		NB.encodeInt32(out, 3, 0);
+		assertOutput(b(0, 0, 0, 0), out, 3);
+
+		prepareOutput(out);
+		NB.encodeInt32(out, 0, 3);
+		assertOutput(b(0, 0, 0, 3), out, 0);
+
+		prepareOutput(out);
+		NB.encodeInt32(out, 3, 3);
+		assertOutput(b(0, 0, 0, 3), out, 3);
+
+		prepareOutput(out);
+		NB.encodeInt32(out, 0, 0xdeac);
+		assertOutput(b(0, 0, 0xde, 0xac), out, 0);
+
+		prepareOutput(out);
+		NB.encodeInt32(out, 3, 0xdeac);
+		assertOutput(b(0, 0, 0xde, 0xac), out, 3);
+
+		prepareOutput(out);
+		NB.encodeInt32(out, 0, 0xdeac9853);
+		assertOutput(b(0xde, 0xac, 0x98, 0x53), out, 0);
+
+		prepareOutput(out);
+		NB.encodeInt32(out, 3, 0xdeac9853);
+		assertOutput(b(0xde, 0xac, 0x98, 0x53), out, 3);
+
+		prepareOutput(out);
+		NB.encodeInt32(out, 3, -1);
+		assertOutput(b(0xff, 0xff, 0xff, 0xff), out, 3);
+	}
+
+	public void testEncodeInt64() {
+		final byte[] out = new byte[16];
+
+		prepareOutput(out);
+		NB.encodeInt64(out, 0, 0L);
+		assertOutput(b(0, 0, 0, 0, 0, 0, 0, 0), out, 0);
+
+		prepareOutput(out);
+		NB.encodeInt64(out, 3, 0L);
+		assertOutput(b(0, 0, 0, 0, 0, 0, 0, 0), out, 3);
+
+		prepareOutput(out);
+		NB.encodeInt64(out, 0, 3L);
+		assertOutput(b(0, 0, 0, 0, 0, 0, 0, 3), out, 0);
+
+		prepareOutput(out);
+		NB.encodeInt64(out, 3, 3L);
+		assertOutput(b(0, 0, 0, 0, 0, 0, 0, 3), out, 3);
+
+		prepareOutput(out);
+		NB.encodeInt64(out, 0, 0xdeacL);
+		assertOutput(b(0, 0, 0, 0, 0, 0, 0xde, 0xac), out, 0);
+
+		prepareOutput(out);
+		NB.encodeInt64(out, 3, 0xdeacL);
+		assertOutput(b(0, 0, 0, 0, 0, 0, 0xde, 0xac), out, 3);
+
+		prepareOutput(out);
+		NB.encodeInt64(out, 0, 0xdeac9853L);
+		assertOutput(b(0, 0, 0, 0, 0xde, 0xac, 0x98, 0x53), out, 0);
+
+		prepareOutput(out);
+		NB.encodeInt64(out, 3, 0xdeac9853L);
+		assertOutput(b(0, 0, 0, 0, 0xde, 0xac, 0x98, 0x53), out, 3);
+
+		prepareOutput(out);
+		NB.encodeInt64(out, 0, 0xac431242deac9853L);
+		assertOutput(b(0xac, 0x43, 0x12, 0x42, 0xde, 0xac, 0x98, 0x53), out, 0);
+
+		prepareOutput(out);
+		NB.encodeInt64(out, 3, 0xac431242deac9853L);
+		assertOutput(b(0xac, 0x43, 0x12, 0x42, 0xde, 0xac, 0x98, 0x53), out, 3);
+
+		prepareOutput(out);
+		NB.encodeInt64(out, 3, -1L);
+		assertOutput(b(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff), out, 3);
+	}
+
+	private static void prepareOutput(final byte[] buf) {
+		for (int i = 0; i < buf.length; i++)
+			buf[i] = (byte) (0x77 + i);
+	}
+
+	private static void assertOutput(final byte[] expect, final byte[] buf,
+			final int offset) {
+		for (int i = 0; i < offset; i++)
+			assertEquals((byte) (0x77 + i), buf[i]);
+		for (int i = 0; i < expect.length; i++)
+			assertEquals(expect[i], buf[offset + i]);
+		for (int i = offset + expect.length; i < buf.length; i++)
+			assertEquals((byte) (0x77 + i), buf[i]);
+	}
+
+	private static byte[] b(final int a, final int b) {
+		return new byte[] { (byte) a, (byte) b };
+	}
+
+	private static byte[] padb(final int len, final int a, final int b) {
+		final byte[] r = new byte[len + 2];
+		for (int i = 0; i < len; i++)
+			r[i] = (byte) 0xaf;
+		r[len] = (byte) a;
+		r[len + 1] = (byte) b;
+		return r;
+	}
+
+	private static byte[] b(final int a, final int b, final int c, final int d) {
+		return new byte[] { (byte) a, (byte) b, (byte) c, (byte) d };
+	}
+
+	private static byte[] padb(final int len, final int a, final int b,
+			final int c, final int d) {
+		final byte[] r = new byte[len + 4];
+		for (int i = 0; i < len; i++)
+			r[i] = (byte) 0xaf;
+		r[len] = (byte) a;
+		r[len + 1] = (byte) b;
+		r[len + 2] = (byte) c;
+		r[len + 3] = (byte) d;
+		return r;
+	}
+
+	private static byte[] b(final int a, final int b, final int c, final int d,
+			final int e, final int f, final int g, final int h) {
+		return new byte[] { (byte) a, (byte) b, (byte) c, (byte) d, (byte) e,
+				(byte) f, (byte) g, (byte) h };
+	}
+
+	private static byte[] padb(final int len, final int a, final int b,
+			final int c, final int d, final int e, final int f, final int g,
+			final int h) {
+		final byte[] r = new byte[len + 8];
+		for (int i = 0; i < len; i++)
+			r[i] = (byte) 0xaf;
+		r[len] = (byte) a;
+		r[len + 1] = (byte) b;
+		r[len + 2] = (byte) c;
+		r[len + 3] = (byte) d;
+		r[len + 4] = (byte) e;
+		r[len + 5] = (byte) f;
+		r[len + 6] = (byte) g;
+		r[len + 7] = (byte) h;
+		return r;
+	}
+}
-- 
1.6.0.87.g2858d
Shawn O. Pearce· Aug 18, 2008, 16:35 UTC · re: Shawn O. Pearce · lore

[EGIT PATCH 4/4] Fix DirCache's skip over null byte padding when reading a DIRC file

Sometimes we hit EOFException while reading from a 'DIRC' file with the new DirCache API. This was caused by BufferedInputStream.skip skipping only part of the range we asked it to skip if the range we asked it to skip spanned over the end of the current buffer block. Two skip requests are necessary in this case: one to force the stream to skip to the end of the buffer, and another to skip over data in the source stream before reading the next buffer block into memory.

NB.skipFully handles this by abstracting the necessary loop into a utility function, much like NB.readFully handles the necessary read loop to ensure we read a full block of data.

DirCacheEntry and DirCache both need to use this routine to skip over the parts of the DIRC file they do not wish to read.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
  This actually fixes the bug EOFException bug identified by John Franey.
 .../src/org/spearce/jgit/dircache/DirCache.java    |    2 +-
 .../org/spearce/jgit/dircache/DirCacheEntry.java   |    2 +-
 org.spearce.jgit/src/org/spearce/jgit/util/NB.java |   27 ++++++++++++++++++++
 3 files changed, 29 insertions(+), 2 deletions(-)
Show changes to 3 files +29 −2

org.spearce.jgit/src/org/spearce/jgit/dircache/DirCache.java, org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java, org.spearce.jgit/src/org/spearce/jgit/util/NB.java

diff --git a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCache.java b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCache.java
index 995942c..76657c4 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCache.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCache.java
@@ -370,7 +370,7 @@ private void readFrom(final FileInputStream inStream) throws IOException,
 					// a performance optimization. Since we do not
 					// understand it, we can safely skip past it.
 					//
-					in.skip(NB.decodeInt32(hdr, 4));
+					NB.skipFully(in, NB.decodeUInt32(hdr, 4));
 				} else {
 					// The extension is not an optimization and is
 					// _required_ to understand this index format.
diff --git a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java
index bcf5596..011bc16 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java
@@ -116,7 +116,7 @@ DirCacheEntry(final byte[] sharedInfo, final int infoAt,
 		final int actLen = INFO_LEN + pathLen;
 		final int expLen = (actLen + 8) & ~7;
 		if (actLen != expLen)
-			in.skip(expLen - actLen);
+			NB.skipFully(in, expLen - actLen);
 	}
 
 	/**
diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/NB.java b/org.spearce.jgit/src/org/spearce/jgit/util/NB.java
index fa13354..759caf5 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/util/NB.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/util/NB.java
@@ -71,6 +71,33 @@ public static void readFully(final InputStream fd, final byte[] dst,
 	}
 
 	/**
+	 * Skip an entire region of an input stream.
+	 * <p>
+	 * The input stream's position is moved forward by the number of requested
+	 * bytes, discarding them from the input. This method does not return until
+	 * the exact number of bytes requested has been skipped.
+	 * 
+	 * @param fd
+	 *            the stream to skip bytes from.
+	 * @param toSkip
+	 *            total number of bytes to be discarded. Must be >= 0.
+	 * @throws EOFException
+	 *             the stream ended before the requested number of bytes were
+	 *             skipped.
+	 * @throws IOException
+	 *             there was an error reading from the stream.
+	 */
+	public static void skipFully(final InputStream fd, long toSkip)
+			throws IOException {
+		while (toSkip > 0) {
+			final long r = fd.skip(toSkip);
+			if (r <= 0)
+				throw new EOFException("Short skip of block");
+			toSkip -= r;
+		}
+	}
+
+	/**
 	 * Compare a 32 bit unsigned integer stored in a 32 bit signed integer.
 	 * <p>
 	 * This function performs an unsigned compare operation, even though Java
-- 
1.6.0.87.g2858d

← back to recent threads