{"thread":{"id":"15071","subject":"[EGIT PATCH 1/4] Detect path names which overflow the name length field in the index","startedAt":"2008-08-18T16:35:30Z","lastAt":"2008-08-18T16:35:33Z","messageCount":4,"participants":["Shawn O. Pearce"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"87544","messageId":"1219077333-29226-1-git-send-email-spearce@spearce.org","threadId":"15071","inReplyTo":null,"subject":"[EGIT PATCH 1/4] Detect path names which overflow the name length field in the index","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-08-18T16:35:30Z","receivedAt":"2008-08-18T16:35:30Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"C Git allows a path name to be longer than 4095 bytes by storing 4095\ninto the path name length field within flags and then searching for a\nnull terminator at the end of the path name, instead of relying on the\nlength indicatior.  We cannot do this (easily) from an InputStream so\nwe are currently going to just abort with an exception if we find such\nan extremely long path name.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../org/spearce/jgit/dircache/DirCacheEntry.java   |   13 ++++++++++---\n 1 files changed, 10 insertions(+), 3 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java\nindex c481e43..bcf5596 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java\n@@ -81,6 +81,9 @@\n \n \tprivate static final int P_FLAGS = 60;\n \n+\t/** Mask applied to data in {@link #P_FLAGS} to get the name length. */\n+\tprivate static final int NAME_MASK = 0xfff;\n+\n \tstatic final int INFO_LEN = 62;\n \n \tprivate static final int ASSUME_VALID = 0x80;\n@@ -101,7 +104,9 @@ DirCacheEntry(final byte[] sharedInfo, final int infoAt,\n \n \t\tNB.readFully(in, info, infoOffset, INFO_LEN);\n \n-\t\tint pathLen = NB.decodeUInt16(info, infoOffset + P_FLAGS) & 0xfff;\n+\t\tint pathLen = NB.decodeUInt16(info, infoOffset + P_FLAGS) & NAME_MASK;\n+\t\tif (pathLen == NAME_MASK)\n+\t\t\tthrow new IOException(\"Path name too long for jgit\");\n \t\tpath = new byte[pathLen];\n \t\tNB.readFully(in, path, 0, pathLen);\n \n@@ -135,6 +140,8 @@ public DirCacheEntry(final byte[] newPath) {\n \t\tinfoOffset = 0;\n \n \t\tpath = newPath;\n+\t\tif (path.length >= NAME_MASK)\n+\t\t\tthrow new IllegalArgumentException(\"Path name too long for jgit\");\n \t\tNB.encodeInt16(info, infoOffset + P_FLAGS, path.length);\n \t}\n \n@@ -364,10 +371,10 @@ public String getPathString() {\n \t *            the entry to copy ObjectId and meta fields from.\n \t */\n \tpublic void copyMetaData(final DirCacheEntry src) {\n-\t\tfinal int pLen = NB.decodeUInt16(info, infoOffset + P_FLAGS) & 0xfff;\n+\t\tfinal int pLen = NB.decodeUInt16(info, infoOffset + P_FLAGS) & NAME_MASK;\n \t\tSystem.arraycopy(src.info, src.infoOffset, info, infoOffset, INFO_LEN);\n \t\tNB.encodeInt16(info, infoOffset + P_FLAGS, pLen\n-\t\t\t\t| NB.decodeUInt16(info, infoOffset + P_FLAGS) & ~0xfff);\n+\t\t\t\t| NB.decodeUInt16(info, infoOffset + P_FLAGS) & ~NAME_MASK);\n \t}\n \n \tprivate long decodeTS(final int pIdx) {\n-- \n1.6.0.87.g2858d\n"},{"id":"87547","messageId":"1219077333-29226-2-git-send-email-spearce@spearce.org","threadId":"15071","inReplyTo":"1219077333-29226-1-git-send-email-spearce@spearce.org","subject":"[EGIT PATCH 2/4] Fix NB.decodeUInt16 to correctly handle the high byte","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-08-18T16:35:31Z","receivedAt":"2008-08-18T16:35:31Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Our decodeUInt16 method was buggy and always cleared the high byte\nof the pair.  This meant we always lost the upper 8 bits when we\nread in a 16 bit unsigned integer, possibly causing us to misread\nthe data associated with that pair.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n org.spearce.jgit/src/org/spearce/jgit/util/NB.java |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/util/NB.java b/org.spearce.jgit/src/org/spearce/jgit/util/NB.java\nindex c6176f8..fa13354 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/util/NB.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/util/NB.java\n@@ -102,7 +102,7 @@ public static int compareUInt32(final int a, final int b) {\n \t * @return unsigned integer value that matches the 16 bits read.\n \t */\n \tpublic static int decodeUInt16(final byte[] intbuf, final int offset) {\n-\t\tint r = (intbuf[offset] << 8) & 0xff;\n+\t\tint r = (intbuf[offset] & 0xff) << 8;\n \t\treturn r | (intbuf[offset + 1] & 0xff);\n \t}\n \n-- \n1.6.0.87.g2858d\n"},{"id":"87546","messageId":"1219077333-29226-3-git-send-email-spearce@spearce.org","threadId":"15071","inReplyTo":"1219077333-29226-2-git-send-email-spearce@spearce.org","subject":"[EGIT PATCH 3/4] Add test cases for NB.encode and NB.decode family of routines","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-08-18T16:35:32Z","receivedAt":"2008-08-18T16:35:32Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"We really need to ensure these methods work correctly, and since\nwe just suffered from a bug in NB.decodeUInt16 we now have a set\nof test cases for the corner conditions of each encode and decode\nmethod pair we support.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../tst/org/spearce/jgit/util/NBTest.java          |  328 ++++++++++++++++++++\n 1 files changed, 328 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/util/NBTest.java\n\ndiff --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\nnew file mode 100644\nindex 0000000..217db7f\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/util/NBTest.java\n@@ -0,0 +1,328 @@\n+/*\n+ * Copyright (C) 2008, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.util;\n+\n+import junit.framework.TestCase;\n+\n+public class NBTest extends TestCase {\n+\tpublic void testCompareUInt32() {\n+\t\tassertTrue(NB.compareUInt32(0, 0) == 0);\n+\t\tassertTrue(NB.compareUInt32(1, 0) > 0);\n+\t\tassertTrue(NB.compareUInt32(0, 1) < 0);\n+\t\tassertTrue(NB.compareUInt32(-1, 0) > 0);\n+\t\tassertTrue(NB.compareUInt32(0, -1) < 0);\n+\t\tassertTrue(NB.compareUInt32(-1, 1) > 0);\n+\t\tassertTrue(NB.compareUInt32(1, -1) < 0);\n+\t}\n+\n+\tpublic void testDecodeUInt16() {\n+\t\tassertEquals(0, NB.decodeUInt16(b(0, 0), 0));\n+\t\tassertEquals(0, NB.decodeUInt16(padb(3, 0, 0), 3));\n+\n+\t\tassertEquals(3, NB.decodeUInt16(b(0, 3), 0));\n+\t\tassertEquals(3, NB.decodeUInt16(padb(3, 0, 3), 3));\n+\n+\t\tassertEquals(0xde03, NB.decodeUInt16(b(0xde, 3), 0));\n+\t\tassertEquals(0xde03, NB.decodeUInt16(padb(3, 0xde, 3), 3));\n+\n+\t\tassertEquals(0x03de, NB.decodeUInt16(b(3, 0xde), 0));\n+\t\tassertEquals(0x03de, NB.decodeUInt16(padb(3, 3, 0xde), 3));\n+\n+\t\tassertEquals(0xffff, NB.decodeUInt16(b(0xff, 0xff), 0));\n+\t\tassertEquals(0xffff, NB.decodeUInt16(padb(3, 0xff, 0xff), 3));\n+\t}\n+\n+\tpublic void testDecodeInt32() {\n+\t\tassertEquals(0, NB.decodeInt32(b(0, 0, 0, 0), 0));\n+\t\tassertEquals(0, NB.decodeInt32(padb(3, 0, 0, 0, 0), 3));\n+\n+\t\tassertEquals(3, NB.decodeInt32(b(0, 0, 0, 3), 0));\n+\t\tassertEquals(3, NB.decodeInt32(padb(3, 0, 0, 0, 3), 3));\n+\n+\t\tassertEquals(0xdeadbeef, NB.decodeInt32(b(0xde, 0xad, 0xbe, 0xef), 0));\n+\t\tassertEquals(0xdeadbeef, NB.decodeInt32(\n+\t\t\t\tpadb(3, 0xde, 0xad, 0xbe, 0xef), 3));\n+\n+\t\tassertEquals(0x0310adef, NB.decodeInt32(b(0x03, 0x10, 0xad, 0xef), 0));\n+\t\tassertEquals(0x0310adef, NB.decodeInt32(\n+\t\t\t\tpadb(3, 0x03, 0x10, 0xad, 0xef), 3));\n+\n+\t\tassertEquals(0xffffffff, NB.decodeInt32(b(0xff, 0xff, 0xff, 0xff), 0));\n+\t\tassertEquals(0xffffffff, NB.decodeInt32(\n+\t\t\t\tpadb(3, 0xff, 0xff, 0xff, 0xff), 3));\n+\t}\n+\n+\tpublic void testDecodeUInt32() {\n+\t\tassertEquals(0L, NB.decodeUInt32(b(0, 0, 0, 0), 0));\n+\t\tassertEquals(0L, NB.decodeUInt32(padb(3, 0, 0, 0, 0), 3));\n+\n+\t\tassertEquals(3L, NB.decodeUInt32(b(0, 0, 0, 3), 0));\n+\t\tassertEquals(3L, NB.decodeUInt32(padb(3, 0, 0, 0, 3), 3));\n+\n+\t\tassertEquals(0xdeadbeefL, NB.decodeUInt32(b(0xde, 0xad, 0xbe, 0xef), 0));\n+\t\tassertEquals(0xdeadbeefL, NB.decodeUInt32(padb(3, 0xde, 0xad, 0xbe,\n+\t\t\t\t0xef), 3));\n+\n+\t\tassertEquals(0x0310adefL, NB.decodeUInt32(b(0x03, 0x10, 0xad, 0xef), 0));\n+\t\tassertEquals(0x0310adefL, NB.decodeUInt32(padb(3, 0x03, 0x10, 0xad,\n+\t\t\t\t0xef), 3));\n+\n+\t\tassertEquals(0xffffffffL, NB.decodeUInt32(b(0xff, 0xff, 0xff, 0xff), 0));\n+\t\tassertEquals(0xffffffffL, NB.decodeUInt32(padb(3, 0xff, 0xff, 0xff,\n+\t\t\t\t0xff), 3));\n+\t}\n+\n+\tpublic void testDecodeUInt64() {\n+\t\tassertEquals(0L, NB.decodeUInt64(b(0, 0, 0, 0, 0, 0, 0, 0), 0));\n+\t\tassertEquals(0L, NB.decodeUInt64(padb(3, 0, 0, 0, 0, 0, 0, 0, 0), 3));\n+\n+\t\tassertEquals(3L, NB.decodeUInt64(b(0, 0, 0, 0, 0, 0, 0, 3), 0));\n+\t\tassertEquals(3L, NB.decodeUInt64(padb(3, 0, 0, 0, 0, 0, 0, 0, 3), 3));\n+\n+\t\tassertEquals(0xdeadbeefL, NB.decodeUInt64(b(0, 0, 0, 0, 0xde, 0xad,\n+\t\t\t\t0xbe, 0xef), 0));\n+\t\tassertEquals(0xdeadbeefL, NB.decodeUInt64(padb(3, 0, 0, 0, 0, 0xde,\n+\t\t\t\t0xad, 0xbe, 0xef), 3));\n+\n+\t\tassertEquals(0x0310adefL, NB.decodeUInt64(b(0, 0, 0, 0, 0x03, 0x10,\n+\t\t\t\t0xad, 0xef), 0));\n+\t\tassertEquals(0x0310adefL, NB.decodeUInt64(padb(3, 0, 0, 0, 0, 0x03,\n+\t\t\t\t0x10, 0xad, 0xef), 3));\n+\n+\t\tassertEquals(0xc0ffee78deadbeefL, NB.decodeUInt64(b(0xc0, 0xff, 0xee,\n+\t\t\t\t0x78, 0xde, 0xad, 0xbe, 0xef), 0));\n+\t\tassertEquals(0xc0ffee78deadbeefL, NB.decodeUInt64(padb(3, 0xc0, 0xff,\n+\t\t\t\t0xee, 0x78, 0xde, 0xad, 0xbe, 0xef), 3));\n+\n+\t\tassertEquals(0x00000000ffffffffL, NB.decodeUInt64(b(0, 0, 0, 0, 0xff,\n+\t\t\t\t0xff, 0xff, 0xff), 0));\n+\t\tassertEquals(0x00000000ffffffffL, NB.decodeUInt64(padb(3, 0, 0, 0, 0,\n+\t\t\t\t0xff, 0xff, 0xff, 0xff), 3));\n+\t\tassertEquals(0xffffffffffffffffL, NB.decodeUInt64(b(0xff, 0xff, 0xff,\n+\t\t\t\t0xff, 0xff, 0xff, 0xff, 0xff), 0));\n+\t\tassertEquals(0xffffffffffffffffL, NB.decodeUInt64(padb(3, 0xff, 0xff,\n+\t\t\t\t0xff, 0xff, 0xff, 0xff, 0xff, 0xff), 3));\n+\t}\n+\n+\tpublic void testEncodeInt16() {\n+\t\tfinal byte[] out = new byte[16];\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt16(out, 0, 0);\n+\t\tassertOutput(b(0, 0), out, 0);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt16(out, 3, 0);\n+\t\tassertOutput(b(0, 0), out, 3);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt16(out, 0, 3);\n+\t\tassertOutput(b(0, 3), out, 0);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt16(out, 3, 3);\n+\t\tassertOutput(b(0, 3), out, 3);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt16(out, 0, 0xdeac);\n+\t\tassertOutput(b(0xde, 0xac), out, 0);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt16(out, 3, 0xdeac);\n+\t\tassertOutput(b(0xde, 0xac), out, 3);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt16(out, 3, -1);\n+\t\tassertOutput(b(0xff, 0xff), out, 3);\n+\t}\n+\n+\tpublic void testEncodeInt32() {\n+\t\tfinal byte[] out = new byte[16];\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt32(out, 0, 0);\n+\t\tassertOutput(b(0, 0, 0, 0), out, 0);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt32(out, 3, 0);\n+\t\tassertOutput(b(0, 0, 0, 0), out, 3);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt32(out, 0, 3);\n+\t\tassertOutput(b(0, 0, 0, 3), out, 0);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt32(out, 3, 3);\n+\t\tassertOutput(b(0, 0, 0, 3), out, 3);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt32(out, 0, 0xdeac);\n+\t\tassertOutput(b(0, 0, 0xde, 0xac), out, 0);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt32(out, 3, 0xdeac);\n+\t\tassertOutput(b(0, 0, 0xde, 0xac), out, 3);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt32(out, 0, 0xdeac9853);\n+\t\tassertOutput(b(0xde, 0xac, 0x98, 0x53), out, 0);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt32(out, 3, 0xdeac9853);\n+\t\tassertOutput(b(0xde, 0xac, 0x98, 0x53), out, 3);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt32(out, 3, -1);\n+\t\tassertOutput(b(0xff, 0xff, 0xff, 0xff), out, 3);\n+\t}\n+\n+\tpublic void testEncodeInt64() {\n+\t\tfinal byte[] out = new byte[16];\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt64(out, 0, 0L);\n+\t\tassertOutput(b(0, 0, 0, 0, 0, 0, 0, 0), out, 0);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt64(out, 3, 0L);\n+\t\tassertOutput(b(0, 0, 0, 0, 0, 0, 0, 0), out, 3);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt64(out, 0, 3L);\n+\t\tassertOutput(b(0, 0, 0, 0, 0, 0, 0, 3), out, 0);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt64(out, 3, 3L);\n+\t\tassertOutput(b(0, 0, 0, 0, 0, 0, 0, 3), out, 3);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt64(out, 0, 0xdeacL);\n+\t\tassertOutput(b(0, 0, 0, 0, 0, 0, 0xde, 0xac), out, 0);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt64(out, 3, 0xdeacL);\n+\t\tassertOutput(b(0, 0, 0, 0, 0, 0, 0xde, 0xac), out, 3);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt64(out, 0, 0xdeac9853L);\n+\t\tassertOutput(b(0, 0, 0, 0, 0xde, 0xac, 0x98, 0x53), out, 0);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt64(out, 3, 0xdeac9853L);\n+\t\tassertOutput(b(0, 0, 0, 0, 0xde, 0xac, 0x98, 0x53), out, 3);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt64(out, 0, 0xac431242deac9853L);\n+\t\tassertOutput(b(0xac, 0x43, 0x12, 0x42, 0xde, 0xac, 0x98, 0x53), out, 0);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt64(out, 3, 0xac431242deac9853L);\n+\t\tassertOutput(b(0xac, 0x43, 0x12, 0x42, 0xde, 0xac, 0x98, 0x53), out, 3);\n+\n+\t\tprepareOutput(out);\n+\t\tNB.encodeInt64(out, 3, -1L);\n+\t\tassertOutput(b(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff), out, 3);\n+\t}\n+\n+\tprivate static void prepareOutput(final byte[] buf) {\n+\t\tfor (int i = 0; i < buf.length; i++)\n+\t\t\tbuf[i] = (byte) (0x77 + i);\n+\t}\n+\n+\tprivate static void assertOutput(final byte[] expect, final byte[] buf,\n+\t\t\tfinal int offset) {\n+\t\tfor (int i = 0; i < offset; i++)\n+\t\t\tassertEquals((byte) (0x77 + i), buf[i]);\n+\t\tfor (int i = 0; i < expect.length; i++)\n+\t\t\tassertEquals(expect[i], buf[offset + i]);\n+\t\tfor (int i = offset + expect.length; i < buf.length; i++)\n+\t\t\tassertEquals((byte) (0x77 + i), buf[i]);\n+\t}\n+\n+\tprivate static byte[] b(final int a, final int b) {\n+\t\treturn new byte[] { (byte) a, (byte) b };\n+\t}\n+\n+\tprivate static byte[] padb(final int len, final int a, final int b) {\n+\t\tfinal byte[] r = new byte[len + 2];\n+\t\tfor (int i = 0; i < len; i++)\n+\t\t\tr[i] = (byte) 0xaf;\n+\t\tr[len] = (byte) a;\n+\t\tr[len + 1] = (byte) b;\n+\t\treturn r;\n+\t}\n+\n+\tprivate static byte[] b(final int a, final int b, final int c, final int d) {\n+\t\treturn new byte[] { (byte) a, (byte) b, (byte) c, (byte) d };\n+\t}\n+\n+\tprivate static byte[] padb(final int len, final int a, final int b,\n+\t\t\tfinal int c, final int d) {\n+\t\tfinal byte[] r = new byte[len + 4];\n+\t\tfor (int i = 0; i < len; i++)\n+\t\t\tr[i] = (byte) 0xaf;\n+\t\tr[len] = (byte) a;\n+\t\tr[len + 1] = (byte) b;\n+\t\tr[len + 2] = (byte) c;\n+\t\tr[len + 3] = (byte) d;\n+\t\treturn r;\n+\t}\n+\n+\tprivate static byte[] b(final int a, final int b, final int c, final int d,\n+\t\t\tfinal int e, final int f, final int g, final int h) {\n+\t\treturn new byte[] { (byte) a, (byte) b, (byte) c, (byte) d, (byte) e,\n+\t\t\t\t(byte) f, (byte) g, (byte) h };\n+\t}\n+\n+\tprivate static byte[] padb(final int len, final int a, final int b,\n+\t\t\tfinal int c, final int d, final int e, final int f, final int g,\n+\t\t\tfinal int h) {\n+\t\tfinal byte[] r = new byte[len + 8];\n+\t\tfor (int i = 0; i < len; i++)\n+\t\t\tr[i] = (byte) 0xaf;\n+\t\tr[len] = (byte) a;\n+\t\tr[len + 1] = (byte) b;\n+\t\tr[len + 2] = (byte) c;\n+\t\tr[len + 3] = (byte) d;\n+\t\tr[len + 4] = (byte) e;\n+\t\tr[len + 5] = (byte) f;\n+\t\tr[len + 6] = (byte) g;\n+\t\tr[len + 7] = (byte) h;\n+\t\treturn r;\n+\t}\n+}\n-- \n1.6.0.87.g2858d\n"},{"id":"87545","messageId":"1219077333-29226-4-git-send-email-spearce@spearce.org","threadId":"15071","inReplyTo":"1219077333-29226-3-git-send-email-spearce@spearce.org","subject":"[EGIT PATCH 4/4] Fix DirCache's skip over null byte padding when reading a DIRC file","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-08-18T16:35:33Z","receivedAt":"2008-08-18T16:35:33Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Sometimes we hit EOFException while reading from a 'DIRC' file with\nthe new DirCache API.  This was caused by BufferedInputStream.skip\nskipping only part of the range we asked it to skip if the range we\nasked it to skip spanned over the end of the current buffer block.\nTwo skip requests are necessary in this case: one to force the stream\nto skip to the end of the buffer, and another to skip over data in\nthe source stream before reading the next buffer block into memory.\n\nNB.skipFully handles this by abstracting the necessary loop into\na utility function, much like NB.readFully handles the necessary\nread loop to ensure we read a full block of data.\n\nDirCacheEntry and DirCache both need to use this routine to skip\nover the parts of the DIRC file they do not wish to read.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n\n  This actually fixes the bug EOFException bug identified by John Franey.\n\n .../src/org/spearce/jgit/dircache/DirCache.java    |    2 +-\n .../org/spearce/jgit/dircache/DirCacheEntry.java   |    2 +-\n org.spearce.jgit/src/org/spearce/jgit/util/NB.java |   27 ++++++++++++++++++++\n 3 files changed, 29 insertions(+), 2 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCache.java b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCache.java\nindex 995942c..76657c4 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCache.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCache.java\n@@ -370,7 +370,7 @@ private void readFrom(final FileInputStream inStream) throws IOException,\n \t\t\t\t\t// a performance optimization. Since we do not\n \t\t\t\t\t// understand it, we can safely skip past it.\n \t\t\t\t\t//\n-\t\t\t\t\tin.skip(NB.decodeInt32(hdr, 4));\n+\t\t\t\t\tNB.skipFully(in, NB.decodeUInt32(hdr, 4));\n \t\t\t\t} else {\n \t\t\t\t\t// The extension is not an optimization and is\n \t\t\t\t\t// _required_ to understand this index format.\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java\nindex bcf5596..011bc16 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEntry.java\n@@ -116,7 +116,7 @@ DirCacheEntry(final byte[] sharedInfo, final int infoAt,\n \t\tfinal int actLen = INFO_LEN + pathLen;\n \t\tfinal int expLen = (actLen + 8) & ~7;\n \t\tif (actLen != expLen)\n-\t\t\tin.skip(expLen - actLen);\n+\t\t\tNB.skipFully(in, expLen - actLen);\n \t}\n \n \t/**\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/util/NB.java b/org.spearce.jgit/src/org/spearce/jgit/util/NB.java\nindex fa13354..759caf5 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/util/NB.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/util/NB.java\n@@ -71,6 +71,33 @@ public static void readFully(final InputStream fd, final byte[] dst,\n \t}\n \n \t/**\n+\t * Skip an entire region of an input stream.\n+\t * <p>\n+\t * The input stream's position is moved forward by the number of requested\n+\t * bytes, discarding them from the input. This method does not return until\n+\t * the exact number of bytes requested has been skipped.\n+\t * \n+\t * @param fd\n+\t *            the stream to skip bytes from.\n+\t * @param toSkip\n+\t *            total number of bytes to be discarded. Must be >= 0.\n+\t * @throws EOFException\n+\t *             the stream ended before the requested number of bytes were\n+\t *             skipped.\n+\t * @throws IOException\n+\t *             there was an error reading from the stream.\n+\t */\n+\tpublic static void skipFully(final InputStream fd, long toSkip)\n+\t\t\tthrows IOException {\n+\t\twhile (toSkip > 0) {\n+\t\t\tfinal long r = fd.skip(toSkip);\n+\t\t\tif (r <= 0)\n+\t\t\t\tthrow new EOFException(\"Short skip of block\");\n+\t\t\ttoSkip -= r;\n+\t\t}\n+\t}\n+\n+\t/**\n \t * Compare a 32 bit unsigned integer stored in a 32 bit signed integer.\n \t * <p>\n \t * This function performs an unsigned compare operation, even though Java\n-- \n1.6.0.87.g2858d\n"}]}