{"thread":{"id":"15735","subject":"[JGIT PATCH 2/5] Fix UnpackedObjectLoader.getBytes to return a copy","startedAt":"2008-10-01T01:31:25Z","lastAt":"2008-10-09T22:09:36Z","messageCount":11,"participants":["Shawn O. Pearce","Robin Rosenberg","Jonas Fonseca"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"92011","messageId":"1222824690-7632-1-git-send-email-spearce@spearce.org","threadId":"15735","inReplyTo":null,"subject":"[JGIT PATCH 0/5] Support receive.fsckobjects","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-10-01T01:31:25Z","receivedAt":"2008-10-01T01:31:25Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"This series adds support for receive.fsckobjects, but on the fetch\nside of the connection.  Perhaps it should be transfer.fsckobjects\nor fetch.fsckobjects, but git.git doesn't support either of those\nright now.\n\nI mainly need this series because I'm fetching out of untrusted\nbundles.  The content of the bundle has to pass git-fsck for it\nto be considered safe.\n\nThe ObjectChecker class covers the same rules as git-fsck does, and\nis perhaps even stricter on some of the things git-fsck lets slide.\nI think git-fsck is too lenient in some areas, and I'd like to try\nand improve the rules more in git.git, but I don't have time for\nit right now.\n\nShawn O. Pearce (5):\n  Expose RawParseUtils.match to application callers\n  Fix UnpackedObjectLoader.getBytes to return a copy\n  Object validation tests for \"jgit fsck\"\n  Expose the critical receive configuration options to JGit\n  Honor receive.fsckobjects during any fetch connection\n\n .../org/spearce/jgit/lib/ObjectCheckerTest.java    | 1294 ++++++++++++++++++++\n .../src/org/spearce/jgit/lib/ObjectChecker.java    |  352 ++++++\n .../src/org/spearce/jgit/lib/ObjectLoader.java     |    7 +-\n .../org/spearce/jgit/lib/PackedObjectLoader.java   |    7 -\n .../src/org/spearce/jgit/lib/RepositoryConfig.java |   10 +\n .../src/org/spearce/jgit/lib/TransferConfig.java   |   56 +\n .../org/spearce/jgit/lib/UnpackedObjectLoader.java |    4 -\n .../jgit/transport/BasePackFetchConnection.java    |    1 +\n .../src/org/spearce/jgit/transport/IndexPack.java  |   60 +-\n .../src/org/spearce/jgit/transport/Transport.java  |   24 +\n .../spearce/jgit/transport/TransportBundle.java    |   10 +-\n .../jgit/transport/WalkFetchConnection.java        |   26 +-\n .../src/org/spearce/jgit/util/RawParseUtils.java   |   23 +-\n 13 files changed, 1842 insertions(+), 32 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/lib/ObjectCheckerTest.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/ObjectChecker.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/TransferConfig.java\n"},{"id":"92008","messageId":"1222824690-7632-2-git-send-email-spearce@spearce.org","threadId":"15735","inReplyTo":"1222824690-7632-1-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 1/5] Expose RawParseUtils.match to application callers","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-10-01T01:31:26Z","receivedAt":"2008-10-01T01:31:26Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"This utility can be useful when parsing a buffer directly, such as\nfor a commit or tag object's header lines.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../src/org/spearce/jgit/util/RawParseUtils.java   |   13 ++++++++++++-\n 1 files changed, 12 insertions(+), 1 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java\nindex dbc2e83..2ab3bfe 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java\n@@ -61,7 +61,18 @@\n \t\t\tdigits[i] = (byte) (i - '0');\n \t}\n \n-\tprivate static final int match(final byte[] b, int ptr, final byte[] src) {\n+\t/**\n+\t * Determine if b[ptr] matches src.\n+\t * \n+\t * @param b\n+\t *            the buffer to scan.\n+\t * @param ptr\n+\t *            first position within b, this should match src[0].\n+\t * @param src\n+\t *            the buffer to test for equality with b.\n+\t * @return ptr += src.length if b[ptr..src.length] == src; else -1.\n+\t */\n+\tpublic static final int match(final byte[] b, int ptr, final byte[] src) {\n \t\tif (ptr + src.length >= b.length)\n \t\t\treturn -1;\n \t\tfor (int i = 0; i < src.length; i++, ptr++)\n-- \n1.6.0.2.569.g798a2a\n"},{"id":"92006","messageId":"1222824690-7632-3-git-send-email-spearce@spearce.org","threadId":"15735","inReplyTo":"1222824690-7632-2-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 2/5] Fix UnpackedObjectLoader.getBytes to return a copy","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-10-01T01:31:27Z","receivedAt":"2008-10-01T01:31:27Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"The contract for ObjectLoader.getBytes() says the caller can modify\nthe returned array.  UnpackedObjectLoader must copy the data and not\nreturn its internal cached byte array.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../src/org/spearce/jgit/lib/ObjectLoader.java     |    7 ++++++-\n .../org/spearce/jgit/lib/PackedObjectLoader.java   |    7 -------\n .../org/spearce/jgit/lib/UnpackedObjectLoader.java |    4 ----\n 3 files changed, 6 insertions(+), 12 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectLoader.java b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectLoader.java\nindex 5282491..87e861f 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectLoader.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectLoader.java\n@@ -105,7 +105,12 @@ protected void setId(final ObjectId id) {\n \t * @throws IOException\n \t *             the object cannot be read.\n \t */\n-\tpublic abstract byte[] getBytes() throws IOException;\n+\tpublic final byte[] getBytes() throws IOException {\n+\t\tfinal byte[] data = getCachedBytes();\n+\t\tfinal byte[] copy = new byte[data.length];\n+\t\tSystem.arraycopy(data, 0, copy, 0, data.length);\n+\t\treturn data;\n+\t}\n \n \t/**\n \t * Obtain a reference to the (possibly cached) bytes of this object.\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/PackedObjectLoader.java b/org.spearce.jgit/src/org/spearce/jgit/lib/PackedObjectLoader.java\nindex fa414d6..35983fe 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/PackedObjectLoader.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/PackedObjectLoader.java\n@@ -80,13 +80,6 @@ public long getDataOffset() {\n \t\treturn dataOffset;\n \t}\n \n-\tpublic final byte[] getBytes() throws IOException {\n-\t\tfinal byte[] data = getCachedBytes();\n-\t\tfinal byte[] copy = new byte[data.length];\n-\t\tSystem.arraycopy(data, 0, copy, 0, data.length);\n-\t\treturn data;\n-\t}\n-\n \t/**\n \t * Copy raw object representation from storage to provided output stream.\n \t * <p>\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/UnpackedObjectLoader.java b/org.spearce.jgit/src/org/spearce/jgit/lib/UnpackedObjectLoader.java\nindex 3c61254..3ad273f 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/UnpackedObjectLoader.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/UnpackedObjectLoader.java\n@@ -200,10 +200,6 @@ public long getSize() {\n \t\treturn objectSize;\n \t}\n \n-\tpublic byte[] getBytes() {\n-\t\treturn bytes;\n-\t}\n-\n \t@Override\n \tpublic byte[] getCachedBytes() throws IOException {\n \t\treturn bytes;\n-- \n1.6.0.2.569.g798a2a\n"},{"id":"92010","messageId":"1222824690-7632-4-git-send-email-spearce@spearce.org","threadId":"15735","inReplyTo":"1222824690-7632-3-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 3/5] Object validation tests for \"jgit fsck\"","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-10-01T01:31:28Z","receivedAt":"2008-10-01T01:31:28Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"The ObjectChecker provides strict validation rules for objects.  If\nany commit, tag or tree object is malformed in a way that might cause\na Git implementation to misinterpret the data CorruptObjectException\nis thrown back to the caller for error handling.\n\nDue to the shear size of the validation code this change provides\nonly the validation code and its unit tests.  It is at least as\nparanoid as git.git's \"git-fsck\" is on the same object types, but\nis actually a bit stricter about the commit and tag objects having\nthe well known header fields populated correctly.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../org/spearce/jgit/lib/ObjectCheckerTest.java    | 1294 ++++++++++++++++++++\n .../src/org/spearce/jgit/lib/ObjectChecker.java    |  352 ++++++\n .../src/org/spearce/jgit/util/RawParseUtils.java   |   10 +-\n 3 files changed, 1650 insertions(+), 6 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/lib/ObjectCheckerTest.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/ObjectChecker.java\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/ObjectCheckerTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/ObjectCheckerTest.java\nnew file mode 100644\nindex 0000000..fa37fb5\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/ObjectCheckerTest.java\n@@ -0,0 +1,1294 @@\n+/*\n+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>\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.lib;\n+\n+import junit.framework.TestCase;\n+\n+import org.spearce.jgit.errors.CorruptObjectException;\n+\n+public class ObjectCheckerTest extends TestCase {\n+\tprivate ObjectChecker checker;\n+\n+\tprotected void setUp() throws Exception {\n+\t\tsuper.setUp();\n+\t\tchecker = new ObjectChecker();\n+\t}\n+\n+\tpublic void testInvalidType() {\n+\t\ttry {\n+\t\t\tchecker.check(Constants.OBJ_BAD, new byte[0]);\n+\t\t\tfail(\"Did not throw CorruptObjectException\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tfinal String m = e.getMessage();\n+\t\t\tassertEquals(\"Invalid object type: \" + Constants.OBJ_BAD, m);\n+\t\t}\n+\t}\n+\n+\tpublic void testCheckBlob() throws CorruptObjectException {\n+\t\t// Any blob should pass...\n+\t\tchecker.checkBlob(new byte[0]);\n+\t\tchecker.checkBlob(new byte[1]);\n+\n+\t\tchecker.check(Constants.OBJ_BLOB, new byte[0]);\n+\t\tchecker.check(Constants.OBJ_BLOB, new byte[1]);\n+\t}\n+\n+\tpublic void testValidCommitNoParent() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"author A. U. Thor <author@localhost> 1 +0000\\n\");\n+\t\tb.append(\"committer A. U. Thor <author@localhost> 1 +0000\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkCommit(data);\n+\t\tchecker.check(Constants.OBJ_COMMIT, data);\n+\t}\n+\n+\tpublic void testValidCommitBlankAuthor() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"author <> 0 +0000\\n\");\n+\t\tb.append(\"committer <> 0 +0000\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkCommit(data);\n+\t\tchecker.check(Constants.OBJ_COMMIT, data);\n+\t}\n+\n+\tpublic void testValidCommit1Parent() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"parent \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"author A. U. Thor <author@localhost> 1 +0000\\n\");\n+\t\tb.append(\"committer A. U. Thor <author@localhost> 1 +0000\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkCommit(data);\n+\t\tchecker.check(Constants.OBJ_COMMIT, data);\n+\t}\n+\n+\tpublic void testValidCommit2Parent() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"parent \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"parent \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"author A. U. Thor <author@localhost> 1 +0000\\n\");\n+\t\tb.append(\"committer A. U. Thor <author@localhost> 1 +0000\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkCommit(data);\n+\t\tchecker.check(Constants.OBJ_COMMIT, data);\n+\t}\n+\n+\tpublic void testValidCommit128Parent() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tfor (int i = 0; i < 128; i++) {\n+\t\t\tb.append(\"parent \");\n+\t\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\t\tb.append('\\n');\n+\t\t}\n+\n+\t\tb.append(\"author A. U. Thor <author@localhost> 1 +0000\\n\");\n+\t\tb.append(\"committer A. U. Thor <author@localhost> 1 +0000\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkCommit(data);\n+\t\tchecker.check(Constants.OBJ_COMMIT, data);\n+\t}\n+\n+\tpublic void testValidCommitNormalTime() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tfinal String when = \"1222757360 -0730\";\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"author A. U. Thor <author@localhost> \" + when + \"\\n\");\n+\t\tb.append(\"committer A. U. Thor <author@localhost> \" + when + \"\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkCommit(data);\n+\t\tchecker.check(Constants.OBJ_COMMIT, data);\n+\t}\n+\n+\tpublic void testInvalidCommitNoTree1() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"parent \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"no tree header\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitNoTree2() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"trie \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"no tree header\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitNoTree3() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree\");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"no tree header\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitNoTree4() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree\\t\");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"no tree header\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidTree1() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"zzzzfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid tree\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidTree2() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append(\"z\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid tree\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidTree3() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9b\");\n+\t\tb.append(\"\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid tree\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidTree4() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree  \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid tree\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidParent1() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"parent \");\n+\t\tb.append(\"\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid parent\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidParent2() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"parent \");\n+\t\tb.append(\"zzzzfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append(\"\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid parent\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidParent3() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"parent  \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append(\"\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid parent\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidParent4() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"parent  \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append(\"z\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid parent\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidParent5() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"parent\\t\");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append(\"\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\t// Yes, really, we complain about author not being\n+\t\t\t// found as the invalid parent line wasn't consumed.\n+\t\t\tassertEquals(\"no author\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitNoAuthor() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"committer A. U. Thor <author@localhost> 1 +0000\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\t// Yes, really, we complain about author not being\n+\t\t\t// found as the invalid parent line wasn't consumed.\n+\t\t\tassertEquals(\"no author\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitNoCommitter1() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"author A. U. Thor <author@localhost> 1 +0000\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\t// Yes, really, we complain about author not being\n+\t\t\t// found as the invalid parent line wasn't consumed.\n+\t\t\tassertEquals(\"no committer\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitNoCommitter2() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"author A. U. Thor <author@localhost> 1 +0000\\n\");\n+\t\tb.append(\"\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\t// Yes, really, we complain about author not being\n+\t\t\t// found as the invalid parent line wasn't consumed.\n+\t\t\tassertEquals(\"no committer\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidAuthor1() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"author A. U. Thor <foo 1 +0000\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\t// Yes, really, we complain about author not being\n+\t\t\t// found as the invalid parent line wasn't consumed.\n+\t\t\tassertEquals(\"invalid author\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidAuthor2() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"author A. U. Thor foo> 1 +0000\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\t// Yes, really, we complain about author not being\n+\t\t\t// found as the invalid parent line wasn't consumed.\n+\t\t\tassertEquals(\"invalid author\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidAuthor3() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"author 1 +0000\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\t// Yes, really, we complain about author not being\n+\t\t\t// found as the invalid parent line wasn't consumed.\n+\t\t\tassertEquals(\"invalid author\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidAuthor4() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"author a <b> +0000\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\t// Yes, really, we complain about author not being\n+\t\t\t// found as the invalid parent line wasn't consumed.\n+\t\t\tassertEquals(\"invalid author\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidAuthor5() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"author a <b>\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\t// Yes, really, we complain about author not being\n+\t\t\t// found as the invalid parent line wasn't consumed.\n+\t\t\tassertEquals(\"invalid author\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidAuthor6() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"author a <b> z\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\t// Yes, really, we complain about author not being\n+\t\t\t// found as the invalid parent line wasn't consumed.\n+\t\t\tassertEquals(\"invalid author\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidAuthor7() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"author a <b> 1 z\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\t// Yes, really, we complain about author not being\n+\t\t\t// found as the invalid parent line wasn't consumed.\n+\t\t\tassertEquals(\"invalid author\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidCommitInvalidCommitter() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"tree \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"author a <b> 1 +0000\\n\");\n+\t\tb.append(\"committer a <\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkCommit(data);\n+\t\t\tfail(\"Did not catch corrupt object\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\t// Yes, really, we complain about author not being\n+\t\t\t// found as the invalid parent line wasn't consumed.\n+\t\t\tassertEquals(\"invalid committer\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testValidTag() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"object \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"type commit\\n\");\n+\t\tb.append(\"tag test-tag\\n\");\n+\t\tb.append(\"tagger A. U. Thor <author@localhost> 1 +0000\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkTag(data);\n+\t\tchecker.check(Constants.OBJ_TAG, data);\n+\t}\n+\n+\tpublic void testInvalidTagNoObject1() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"no object header\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTagNoObject2() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"object\\t\");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"no object header\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTagNoObject3() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"obejct \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"no object header\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTagNoObject4() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"object \");\n+\t\tb.append(\"zz9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid object\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTagNoObject5() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"object \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append(\" \\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid object\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTagNoObject6() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"object \");\n+\t\tb.append(\"be9\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid object\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTagNoType1() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"object \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"no type header\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTagNoType2() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"object \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"type\\tcommit\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"no type header\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTagNoType3() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"object \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"tpye commit\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"no type header\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTagNoType4() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"object \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"type commit\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"no tag header\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTagNoTagHeader1() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"object \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"type commit\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"no tag header\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTagNoTagHeader2() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"object \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"type commit\\n\");\n+\t\tb.append(\"tag\\tfoo\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"no tag header\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTagNoTagHeader3() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"object \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"type commit\\n\");\n+\t\tb.append(\"tga foo\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"no tag header\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTagNoTagHeader4() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"object \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"type commit\\n\");\n+\t\tb.append(\"tag foo\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"no tagger header\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTagNoTaggerHeader1() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"object \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"type commit\\n\");\n+\t\tb.append(\"tag foo\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"no tagger header\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTagInvalidTaggerHeader1() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"object \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"type commit\\n\");\n+\t\tb.append(\"tag foo\\n\");\n+\t\tb.append(\"tagger \\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid tagger\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTagInvalidTaggerHeader3() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\n+\t\tb.append(\"object \");\n+\t\tb.append(\"be9bfa841874ccc9f2ef7c48d0c76226f89b7189\");\n+\t\tb.append('\\n');\n+\n+\t\tb.append(\"type commit\\n\");\n+\t\tb.append(\"tag foo\\n\");\n+\t\tb.append(\"tagger a < 1 +000\\n\");\n+\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTag(data);\n+\t\t\tfail(\"incorrectly accepted invalid tag\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid tagger\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testValidEmptyTree() throws CorruptObjectException {\n+\t\tchecker.checkTree(new byte[0]);\n+\t\tchecker.check(Constants.OBJ_TREE, new byte[0]);\n+\t}\n+\n+\tpublic void testValidTree1() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"100644 regular-file\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkTree(data);\n+\t}\n+\n+\tpublic void testValidTree2() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"100755 executable\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkTree(data);\n+\t}\n+\n+\tpublic void testValidTree3() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"40000 tree\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkTree(data);\n+\t}\n+\n+\tpublic void testValidTree4() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"120000 symlink\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkTree(data);\n+\t}\n+\n+\tpublic void testValidTree5() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"160000 git link\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkTree(data);\n+\t}\n+\n+\tpublic void testValidTreeSorting1() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"100644 fooaaa\");\n+\t\tentry(b, \"100755 foobar\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkTree(data);\n+\t}\n+\n+\tpublic void testValidTreeSorting2() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"100755 fooaaa\");\n+\t\tentry(b, \"100644 foobar\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkTree(data);\n+\t}\n+\n+\tpublic void testValidTreeSorting3() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"40000 a\");\n+\t\tentry(b, \"100644 b\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkTree(data);\n+\t}\n+\n+\tpublic void testValidTreeSorting4() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"100644 a\");\n+\t\tentry(b, \"40000 b\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkTree(data);\n+\t}\n+\n+\tpublic void testValidTreeSorting5() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"100644 a.c\");\n+\t\tentry(b, \"40000 a\");\n+\t\tentry(b, \"100644 a0c\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkTree(data);\n+\t}\n+\n+\tpublic void testValidTreeSorting6() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"40000 a\");\n+\t\tentry(b, \"100644 apple\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkTree(data);\n+\t}\n+\n+\tpublic void testValidTreeSorting7() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"40000 an orang\");\n+\t\tentry(b, \"40000 an orange\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkTree(data);\n+\t}\n+\n+\tpublic void testValidTreeSorting8() throws CorruptObjectException {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"100644 a\");\n+\t\tentry(b, \"100644 a0c\");\n+\t\tentry(b, \"100644 b\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\tchecker.checkTree(data);\n+\t}\n+\n+\tpublic void testInvalidTreeModeStartsWithZero1() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"0 a\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"mode starts with '0'\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeModeStartsWithZero2() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"0100644 a\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"mode starts with '0'\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeModeStartsWithZero3() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"040000 a\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"mode starts with '0'\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeModeNotOctal1() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"8 a\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid mode character\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeModeNotOctal2() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"Z a\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid mode character\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeModeNotSupportedMode1() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"1 a\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid mode 1\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeModeNotSupportedMode2() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"170000 a\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"invalid mode \" + 0170000, e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeModeMissingName() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tb.append(\"100644\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"truncated in mode\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeNameContainsSlash() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"100644 a/b\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"name contains '/'\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeNameIsEmpty() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"100644 \");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"zero length name\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeTruncatedInName() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tb.append(\"100644 b\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"truncated in name\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeTruncatedInObjectId() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tb.append(\"100644 b\\0\\1\\2\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"truncated in object id\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeBadSorting1() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"100644 foobar\");\n+\t\tentry(b, \"100644 fooaaa\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"incorrectly sorted\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeBadSorting2() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"40000 a\");\n+\t\tentry(b, \"100644 a.c\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"incorrectly sorted\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeBadSorting3() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"100644 a0c\");\n+\t\tentry(b, \"40000 a\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"incorrectly sorted\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeDuplicateNames1() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"100644 a\");\n+\t\tentry(b, \"100644 a\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"duplicate entry names\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeDuplicateNames2() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"100644 a\");\n+\t\tentry(b, \"100755 a\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"duplicate entry names\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeDuplicateNames3() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"100644 a\");\n+\t\tentry(b, \"40000 a\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"duplicate entry names\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testInvalidTreeDuplicateNames4() {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tentry(b, \"100644 a\");\n+\t\tentry(b, \"100644 a.c\");\n+\t\tentry(b, \"100644 a.d\");\n+\t\tentry(b, \"100644 a.e\");\n+\t\tentry(b, \"40000 a\");\n+\t\tentry(b, \"100644 zoo\");\n+\t\tfinal byte[] data = Constants.encodeASCII(b.toString());\n+\t\ttry {\n+\t\t\tchecker.checkTree(data);\n+\t\t\tfail(\"incorrectly accepted an invalid tree\");\n+\t\t} catch (CorruptObjectException e) {\n+\t\t\tassertEquals(\"duplicate entry names\", e.getMessage());\n+\t\t}\n+\t}\n+\n+\tprivate static void entry(final StringBuilder b, final String modeName) {\n+\t\tb.append(modeName);\n+\t\tb.append('\\0');\n+\t\tfor (int i = 0; i < Constants.OBJECT_ID_LENGTH; i++)\n+\t\t\tb.append((char) i);\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectChecker.java b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectChecker.java\nnew file mode 100644\nindex 0000000..0d165af\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectChecker.java\n@@ -0,0 +1,352 @@\n+/*\n+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>\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.lib;\n+\n+import static org.spearce.jgit.util.RawParseUtils.match;\n+import static org.spearce.jgit.util.RawParseUtils.nextLF;\n+import static org.spearce.jgit.util.RawParseUtils.parseBase10;\n+\n+import org.spearce.jgit.errors.CorruptObjectException;\n+import org.spearce.jgit.util.MutableInteger;\n+\n+/**\n+ * Verifies that an object is formatted correctly.\n+ * <p>\n+ * Verifications made by this class only check that the fields of an object are\n+ * formatted correctly. The ObjectId checksum of the object is not verified, and\n+ * connectivity links between objects are also not verified. Its assumed that\n+ * the caller can provide both of these validations on its own.\n+ * <p>\n+ * Instances of this class are not thread safe, but they may be reused to\n+ * perform multiple object validations.\n+ */\n+public class ObjectChecker {\n+\t/** Header \"tree \" */\n+\tpublic static final byte[] tree = Constants.encodeASCII(\"tree \");\n+\n+\t/** Header \"parent \" */\n+\tpublic static final byte[] parent = Constants.encodeASCII(\"parent \");\n+\n+\t/** Header \"author \" */\n+\tpublic static final byte[] author = Constants.encodeASCII(\"author \");\n+\n+\t/** Header \"committer \" */\n+\tpublic static final byte[] committer = Constants.encodeASCII(\"committer \");\n+\n+\t/** Header \"encoding \" */\n+\tpublic static final byte[] encoding = Constants.encodeASCII(\"encoding \");\n+\n+\t/** Header \"object \" */\n+\tpublic static final byte[] object = Constants.encodeASCII(\"object \");\n+\n+\t/** Header \"type \" */\n+\tpublic static final byte[] type = Constants.encodeASCII(\"type \");\n+\n+\t/** Header \"tag \" */\n+\tpublic static final byte[] tag = Constants.encodeASCII(\"tag \");\n+\n+\t/** Header \"tagger \" */\n+\tpublic static final byte[] tagger = Constants.encodeASCII(\"tagger \");\n+\n+\tprivate final MutableObjectId tempId = new MutableObjectId();\n+\n+\tprivate final MutableInteger ptrout = new MutableInteger();\n+\n+\t/**\n+\t * Check an object for parsing errors.\n+\t * \n+\t * @param objType\n+\t *            type of the object. Must be a valid object type code in\n+\t *            {@link Constants}.\n+\t * @param raw\n+\t *            the raw data which comprises the object. This should be in the\n+\t *            canonical format (that is the format used to generate the\n+\t *            ObjectId of the object). The array is never modified.\n+\t * @throws CorruptObjectException\n+\t *             if an error is identified.\n+\t */\n+\tpublic void check(final int objType, final byte[] raw)\n+\t\t\tthrows CorruptObjectException {\n+\t\tswitch (objType) {\n+\t\tcase Constants.OBJ_COMMIT:\n+\t\t\tcheckCommit(raw);\n+\t\t\tbreak;\n+\t\tcase Constants.OBJ_TAG:\n+\t\t\tcheckTag(raw);\n+\t\t\tbreak;\n+\t\tcase Constants.OBJ_TREE:\n+\t\t\tcheckTree(raw);\n+\t\t\tbreak;\n+\t\tcase Constants.OBJ_BLOB:\n+\t\t\tcheckBlob(raw);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tthrow new CorruptObjectException(\"Invalid object type: \" + objType);\n+\t\t}\n+\t}\n+\n+\tprivate int id(final byte[] raw, final int ptr) {\n+\t\ttry {\n+\t\t\ttempId.fromString(raw, ptr);\n+\t\t\treturn ptr + AnyObjectId.STR_LEN;\n+\t\t} catch (IllegalArgumentException e) {\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\tprivate int personIdent(final byte[] raw, int ptr) {\n+\t\tfinal int emailB = nextLF(raw, ptr, '<');\n+\t\tif (emailB == ptr || raw[emailB - 1] != '<')\n+\t\t\treturn -1;\n+\n+\t\tfinal int emailE = nextLF(raw, emailB, '>');\n+\t\tif (emailE == emailB || raw[emailE - 1] != '>')\n+\t\t\treturn -1;\n+\t\tif (emailE == raw.length || raw[emailE] != ' ')\n+\t\t\treturn -1;\n+\n+\t\tparseBase10(raw, emailE + 1, ptrout); // when\n+\t\tptr = ptrout.value;\n+\t\tif (emailE + 1 == ptr)\n+\t\t\treturn -1;\n+\t\tif (ptr == raw.length || raw[ptr] != ' ')\n+\t\t\treturn -1;\n+\n+\t\tparseBase10(raw, ptr + 1, ptrout); // tz offset\n+\t\tif (ptr + 1 == ptrout.value)\n+\t\t\treturn -1;\n+\t\treturn ptrout.value;\n+\t}\n+\n+\t/**\n+\t * Check a commit for errors.\n+\t * \n+\t * @param raw\n+\t *            the commit data. The array is never modified.\n+\t * @throws CorruptObjectException\n+\t *             if any error was detected.\n+\t */\n+\tpublic void checkCommit(final byte[] raw) throws CorruptObjectException {\n+\t\tint ptr = 0;\n+\n+\t\tif ((ptr = match(raw, ptr, tree)) < 0)\n+\t\t\tthrow new CorruptObjectException(\"no tree header\");\n+\t\tif ((ptr = id(raw, ptr)) < 0 || raw[ptr++] != '\\n')\n+\t\t\tthrow new CorruptObjectException(\"invalid tree\");\n+\n+\t\twhile (match(raw, ptr, parent) >= 0) {\n+\t\t\tptr += parent.length;\n+\t\t\tif ((ptr = id(raw, ptr)) < 0 || raw[ptr++] != '\\n')\n+\t\t\t\tthrow new CorruptObjectException(\"invalid parent\");\n+\t\t}\n+\n+\t\tif ((ptr = match(raw, ptr, author)) < 0)\n+\t\t\tthrow new CorruptObjectException(\"no author\");\n+\t\tif ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\\n')\n+\t\t\tthrow new CorruptObjectException(\"invalid author\");\n+\n+\t\tif ((ptr = match(raw, ptr, committer)) < 0)\n+\t\t\tthrow new CorruptObjectException(\"no committer\");\n+\t\tif ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\\n')\n+\t\t\tthrow new CorruptObjectException(\"invalid committer\");\n+\t}\n+\n+\t/**\n+\t * Check an annotated tag for errors.\n+\t * \n+\t * @param raw\n+\t *            the tag data. The array is never modified.\n+\t * @throws CorruptObjectException\n+\t *             if any error was detected.\n+\t */\n+\tpublic void checkTag(final byte[] raw) throws CorruptObjectException {\n+\t\tint ptr = 0;\n+\n+\t\tif ((ptr = match(raw, ptr, object)) < 0)\n+\t\t\tthrow new CorruptObjectException(\"no object header\");\n+\t\tif ((ptr = id(raw, ptr)) < 0 || raw[ptr++] != '\\n')\n+\t\t\tthrow new CorruptObjectException(\"invalid object\");\n+\n+\t\tif ((ptr = match(raw, ptr, type)) < 0)\n+\t\t\tthrow new CorruptObjectException(\"no type header\");\n+\t\tptr = nextLF(raw, ptr, '\\n');\n+\n+\t\tif ((ptr = match(raw, ptr, tag)) < 0)\n+\t\t\tthrow new CorruptObjectException(\"no tag header\");\n+\t\tptr = nextLF(raw, ptr, '\\n');\n+\n+\t\tif ((ptr = match(raw, ptr, tagger)) < 0)\n+\t\t\tthrow new CorruptObjectException(\"no tagger header\");\n+\t\tif ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\\n')\n+\t\t\tthrow new CorruptObjectException(\"invalid tagger\");\n+\t}\n+\n+\tprivate static int lastPathChar(final int mode) {\n+\t\treturn FileMode.TREE.equals(mode) ? '/' : '\\0';\n+\t}\n+\n+\tprivate static int pathCompare(final byte[] raw, int aPos, final int aEnd,\n+\t\t\tfinal int aMode, int bPos, final int bEnd, final int bMode) {\n+\t\twhile (aPos < aEnd && bPos < bEnd) {\n+\t\t\tfinal int cmp = (raw[aPos++] & 0xff) - (raw[bPos++] & 0xff);\n+\t\t\tif (cmp != 0)\n+\t\t\t\treturn cmp;\n+\t\t}\n+\n+\t\tif (aPos < aEnd)\n+\t\t\treturn (raw[aPos] & 0xff) - lastPathChar(bMode);\n+\t\tif (bPos < bEnd)\n+\t\t\treturn lastPathChar(aMode) - (raw[bPos] & 0xff);\n+\t\treturn 0;\n+\t}\n+\n+\tprivate static boolean duplicateName(final byte[] raw,\n+\t\t\tfinal int thisNamePos, final int thisNameEnd) {\n+\t\tfinal int sz = raw.length;\n+\t\tint nextPtr = thisNameEnd + 1 + Constants.OBJECT_ID_LENGTH;\n+\t\tfor (;;) {\n+\t\t\tint nextMode = 0;\n+\t\t\tfor (;;) {\n+\t\t\t\tif (nextPtr >= sz)\n+\t\t\t\t\treturn false;\n+\t\t\t\tfinal byte c = raw[nextPtr++];\n+\t\t\t\tif (' ' == c)\n+\t\t\t\t\tbreak;\n+\t\t\t\tnextMode <<= 3;\n+\t\t\t\tnextMode += c - '0';\n+\t\t\t}\n+\n+\t\t\tfinal int nextNamePos = nextPtr;\n+\t\t\tfor (;;) {\n+\t\t\t\tif (nextPtr == sz)\n+\t\t\t\t\treturn false;\n+\t\t\t\tfinal byte c = raw[nextPtr++];\n+\t\t\t\tif (c == 0)\n+\t\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (nextNamePos + 1 == nextPtr)\n+\t\t\t\treturn false;\n+\n+\t\t\tfinal int cmp = pathCompare(raw, thisNamePos, thisNameEnd,\n+\t\t\t\t\tFileMode.TREE.getBits(), nextNamePos, nextPtr - 1, nextMode);\n+\t\t\tif (cmp < 0)\n+\t\t\t\treturn false;\n+\t\t\telse if (cmp == 0)\n+\t\t\t\treturn true;\n+\n+\t\t\tnextPtr += Constants.OBJECT_ID_LENGTH;\n+\t\t}\n+\t}\n+\n+\t/**\n+\t * Check a canonical formatted tree for errors.\n+\t * \n+\t * @param raw\n+\t *            the raw tree data. The array is never modified.\n+\t * @throws CorruptObjectException\n+\t *             if any error was detected.\n+\t */\n+\tpublic void checkTree(final byte[] raw) throws CorruptObjectException {\n+\t\tfinal int sz = raw.length;\n+\t\tint ptr = 0;\n+\t\tint lastNameB = 0, lastNameE = 0, lastMode = 0;\n+\n+\t\twhile (ptr < sz) {\n+\t\t\tint thisMode = 0;\n+\t\t\tfor (;;) {\n+\t\t\t\tif (ptr == sz)\n+\t\t\t\t\tthrow new CorruptObjectException(\"truncated in mode\");\n+\t\t\t\tfinal byte c = raw[ptr++];\n+\t\t\t\tif (' ' == c)\n+\t\t\t\t\tbreak;\n+\t\t\t\tif (c < '0' || c > '7')\n+\t\t\t\t\tthrow new CorruptObjectException(\"invalid mode character\");\n+\t\t\t\tif (thisMode == 0 && c == '0')\n+\t\t\t\t\tthrow new CorruptObjectException(\"mode starts with '0'\");\n+\t\t\t\tthisMode <<= 3;\n+\t\t\t\tthisMode += c - '0';\n+\t\t\t}\n+\n+\t\t\tif (FileMode.fromBits(thisMode).getObjectType() == Constants.OBJ_BAD)\n+\t\t\t\tthrow new CorruptObjectException(\"invalid mode \" + thisMode);\n+\n+\t\t\tfinal int thisNameB = ptr;\n+\t\t\tfor (;;) {\n+\t\t\t\tif (ptr == sz)\n+\t\t\t\t\tthrow new CorruptObjectException(\"truncated in name\");\n+\t\t\t\tfinal byte c = raw[ptr++];\n+\t\t\t\tif (c == 0)\n+\t\t\t\t\tbreak;\n+\t\t\t\tif (c == '/')\n+\t\t\t\t\tthrow new CorruptObjectException(\"name contains '/'\");\n+\t\t\t}\n+\t\t\tif (thisNameB + 1 == ptr)\n+\t\t\t\tthrow new CorruptObjectException(\"zero length name\");\n+\t\t\tif (duplicateName(raw, thisNameB, ptr - 1))\n+\t\t\t\tthrow new CorruptObjectException(\"duplicate entry names\");\n+\n+\t\t\tif (lastNameB != 0) {\n+\t\t\t\tfinal int cmp = pathCompare(raw, lastNameB, lastNameE,\n+\t\t\t\t\t\tlastMode, thisNameB, ptr - 1, thisMode);\n+\t\t\t\tif (cmp > 0)\n+\t\t\t\t\tthrow new CorruptObjectException(\"incorrectly sorted\");\n+\t\t\t}\n+\n+\t\t\tlastNameB = thisNameB;\n+\t\t\tlastNameE = ptr - 1;\n+\t\t\tlastMode = thisMode;\n+\n+\t\t\tptr += Constants.OBJECT_ID_LENGTH;\n+\t\t\tif (ptr > sz)\n+\t\t\t\tthrow new CorruptObjectException(\"truncated in object id\");\n+\t\t}\n+\t}\n+\n+\t/**\n+\t * Check a blob for errors.\n+\t * \n+\t * @param raw\n+\t *            the blob data. The array is never modified.\n+\t * @throws CorruptObjectException\n+\t *             if any error was detected.\n+\t */\n+\tpublic void checkBlob(final byte[] raw) throws CorruptObjectException {\n+\t\t// We can always assume the blob is valid.\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java\nindex 2ab3bfe..c2c9b00 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java\n@@ -37,6 +37,10 @@\n \n package org.spearce.jgit.util;\n \n+import static org.spearce.jgit.lib.ObjectChecker.author;\n+import static org.spearce.jgit.lib.ObjectChecker.committer;\n+import static org.spearce.jgit.lib.ObjectChecker.encoding;\n+\n import java.nio.ByteBuffer;\n import java.nio.charset.Charset;\n import java.util.Arrays;\n@@ -46,12 +50,6 @@\n \n /** Handy utility functions to parse raw object contents. */\n public final class RawParseUtils {\n-\tprivate static final byte[] author = Constants.encodeASCII(\"author \");\n-\n-\tprivate static final byte[] committer = Constants.encodeASCII(\"committer \");\n-\n-\tprivate static final byte[] encoding = Constants.encodeASCII(\"encoding \");\n-\n \tprivate static final byte[] digits;\n \n \tstatic {\n-- \n1.6.0.2.569.g798a2a\n"},{"id":"92009","messageId":"1222824690-7632-5-git-send-email-spearce@spearce.org","threadId":"15735","inReplyTo":"1222824690-7632-4-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 4/5] Expose the critical receive configuration options to JGit","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-10-01T01:31:29Z","receivedAt":"2008-10-01T01:31:29Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"The TransferConfig object keeps track of basic transfer related options\nfrom the transfer, receive and fetch groups within a git config file.\n\nRight now we only care about receive.fsckobjects.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../src/org/spearce/jgit/lib/RepositoryConfig.java |   10 ++++\n .../src/org/spearce/jgit/lib/TransferConfig.java   |   56 ++++++++++++++++++++\n 2 files changed, 66 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/TransferConfig.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java\nindex d3c29ac..d8fd2fa 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java\n@@ -92,6 +92,8 @@ public static RepositoryConfig openUserConfig() {\n \n \tprivate CoreConfig core;\n \n+\tprivate TransferConfig transfer;\n+\n \tprivate List<Entry> entries;\n \n \tprivate Map<String, Object> byName;\n@@ -126,6 +128,13 @@ public CoreConfig getCore() {\n \t}\n \n \t/**\n+\t * @return transfer, fetch and receive configuration values\n+\t */\n+\tpublic TransferConfig getTransfer() {\n+\t\treturn transfer;\n+\t}\n+\n+\t/**\n \t * Obtain an integer value from the configuration.\n \t *\n \t * @param section\n@@ -667,6 +676,7 @@ public void load() throws IOException {\n \t\t}\n \n \t\tcore = new CoreConfig(this);\n+\t\ttransfer = new TransferConfig(this);\n \t}\n \n \tprivate void clear() {\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/TransferConfig.java b/org.spearce.jgit/src/org/spearce/jgit/lib/TransferConfig.java\nnew file mode 100644\nindex 0000000..ff3a5eb\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/TransferConfig.java\n@@ -0,0 +1,56 @@\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.lib;\n+\n+/**\n+ * The standard \"transfer\", \"fetch\" and \"receive\" configuration parameters.\n+ */\n+public class TransferConfig {\n+\tprivate final boolean fsckObjects;\n+\n+\tTransferConfig(final RepositoryConfig rc) {\n+\t\tfsckObjects = rc.getBoolean(\"receive\", \"fsckobjects\", false);\n+\t}\n+\n+\t/**\n+\t * @return strictly verify received objects?\n+\t */\n+\tpublic boolean isFsckObjects() {\n+\t\treturn fsckObjects;\n+\t}\n+}\n-- \n1.6.0.2.569.g798a2a\n"},{"id":"92007","messageId":"1222824690-7632-6-git-send-email-spearce@spearce.org","threadId":"15735","inReplyTo":"1222824690-7632-5-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 5/5] Honor receive.fsckobjects during any fetch connection","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-10-01T01:31:30Z","receivedAt":"2008-10-01T01:31:30Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"If the configuration option receive.fsckobjects is true or if the\napplication requests it on the Transport each object received over\nthe wire is validated to pass \"git fsck\" style rules.  This can be\nuseful when fetching data from an untrusted source, to ensure that\nthe incoming objects comply with parsing standards.\n\nThe optional checking does require extra CPU on the client side. A\ntest against git.git (69601 objects 49719 deltas) showed:\n\n    receive.fsckobjects       average time\n    --------------------------------------\n    false (default)           0m17.588s\n    true                      0m18.465s\n\nSo the additional checking costs about 5% more in client side time.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../jgit/transport/BasePackFetchConnection.java    |    1 +\n .../src/org/spearce/jgit/transport/IndexPack.java  |   60 ++++++++++++++++++--\n .../src/org/spearce/jgit/transport/Transport.java  |   24 ++++++++\n .../spearce/jgit/transport/TransportBundle.java    |   10 +++-\n .../jgit/transport/WalkFetchConnection.java        |   26 +++++++--\n 5 files changed, 108 insertions(+), 13 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java\nindex a22b33d..a542eb7 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java\n@@ -452,6 +452,7 @@ private void receivePack(final ProgressMonitor monitor) throws IOException {\n \n \t\tip = IndexPack.create(local, sideband ? pckIn.sideband(monitor) : in);\n \t\tip.setFixThin(thinPack);\n+\t\tip.setObjectChecking(transport.isCheckFetchedObjects());\n \t\tip.index(monitor);\n \t\tip.renameAndOpenPack();\n \t}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/IndexPack.java b/org.spearce.jgit/src/org/spearce/jgit/transport/IndexPack.java\nindex 8a66ec9..ef1ee52 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/IndexPack.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/IndexPack.java\n@@ -56,10 +56,12 @@\n \n import org.spearce.jgit.errors.CorruptObjectException;\n import org.spearce.jgit.errors.MissingObjectException;\n+import org.spearce.jgit.lib.AnyObjectId;\n import org.spearce.jgit.lib.BinaryDelta;\n import org.spearce.jgit.lib.Constants;\n import org.spearce.jgit.lib.InflaterCache;\n import org.spearce.jgit.lib.MutableObjectId;\n+import org.spearce.jgit.lib.ObjectChecker;\n import org.spearce.jgit.lib.ObjectId;\n import org.spearce.jgit.lib.ObjectIdMap;\n import org.spearce.jgit.lib.ObjectLoader;\n@@ -136,6 +138,8 @@ public static IndexPack create(final Repository db, final InputStream is)\n \n \tprivate int bAvail;\n \n+\tprivate ObjectChecker objCheck;\n+\n \tprivate boolean fixThin;\n \n \tprivate int outputVersion;\n@@ -231,6 +235,40 @@ public void setFixThin(final boolean fix) {\n \t}\n \n \t/**\n+\t * Configure the checker used to validate received objects.\n+\t * <p>\n+\t * Usually object checking isn't necessary, as Git implementations only\n+\t * create valid objects in pack files. However, additional checking may be\n+\t * useful if processing data from an untrusted source.\n+\t * \n+\t * @param oc\n+\t *            the checker instance; null to disable object checking.\n+\t */\n+\tpublic void setObjectChecker(final ObjectChecker oc) {\n+\t\tobjCheck = oc;\n+\t}\n+\n+\t/**\n+\t * Configure the checker used to validate received objects.\n+\t * <p>\n+\t * Usually object checking isn't necessary, as Git implementations only\n+\t * create valid objects in pack files. However, additional checking may be\n+\t * useful if processing data from an untrusted source.\n+\t * <p>\n+\t * This is shorthand for:\n+\t * \n+\t * <pre>\n+\t * setObjectChecker(on ? new ObjectChecker() : null);\n+\t * </pre>\n+\t * \n+\t * @param on\n+\t *            true to enable the default checker; false to disable it.\n+\t */\n+\tpublic void setObjectChecking(final boolean on) {\n+\t\tsetObjectChecker(on ? new ObjectChecker() : null);\n+\t}\n+\n+\t/**\n \t * Consume data from the input stream until the packfile is indexed.\n \t * \n \t * @param progress\n@@ -375,7 +413,7 @@ private void resolveDeltas(final long pos, final int oldCRC, int type,\n \t\t\tobjectDigest.update(data);\n \t\t\ttempObjectId.fromRaw(objectDigest.digest(), 0);\n \n-\t\t\tverifyNoCollision(type, data);\n+\t\t\tverifySafeObject(tempObjectId, type, data);\n \t\t\toe = new PackedObjectInfo(pos, crc32, tempObjectId);\n \t\t\tentries[entryCount++] = oe;\n \t\t}\n@@ -658,18 +696,28 @@ private void whole(final int type, final long pos, final long sz)\n \t\tobjectDigest.update(data);\n \t\ttempObjectId.fromRaw(objectDigest.digest(), 0);\n \n-\t\tverifyNoCollision(type, data);\n+\t\tverifySafeObject(tempObjectId, type, data);\n \t\tfinal int crc32 = (int) crc.getValue();\n \t\tentries[entryCount++] = new PackedObjectInfo(pos, crc32, tempObjectId);\n \t}\n \n-\tprivate void verifyNoCollision(final int type, final byte[] data)\n-\t\t\tthrows IOException {\n-\t\tfinal ObjectLoader ldr = repo.openObject(tempObjectId);\n+\tprivate void verifySafeObject(final AnyObjectId id, final int type,\n+\t\t\tfinal byte[] data) throws IOException {\n+\t\tif (objCheck != null) {\n+\t\t\ttry {\n+\t\t\t\tobjCheck.check(type, data);\n+\t\t\t} catch (CorruptObjectException e) {\n+\t\t\t\tthrow new IOException(\"Invalid \"\n+\t\t\t\t\t\t+ Constants.encodedTypeString(type) + \" \" + id.name()\n+\t\t\t\t\t\t+ \":\" + e.getMessage());\n+\t\t\t}\n+\t\t}\n+\n+\t\tfinal ObjectLoader ldr = repo.openObject(id);\n \t\tif (ldr != null) {\n \t\t\tfinal byte[] existingData = ldr.getCachedBytes();\n \t\t\tif (ldr.getType() != type || !Arrays.equals(data, existingData)) {\n-\t\t\t\tthrow new IOException(\"collision in \" + tempObjectId.name());\n+\t\t\t\tthrow new IOException(\"Collision on \" + id.name());\n \t\t\t}\n \t\t}\n \t}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java b/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java\nindex 7284b28..28700b7 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java\n@@ -55,6 +55,7 @@\n import org.spearce.jgit.lib.ProgressMonitor;\n import org.spearce.jgit.lib.Ref;\n import org.spearce.jgit.lib.Repository;\n+import org.spearce.jgit.lib.TransferConfig;\n \n /**\n  * Connects two Git repositories together and copies objects between them.\n@@ -351,6 +352,9 @@ private static String findTrackingRefName(final String remoteName,\n \t/** Should push just check for operation result, not really push. */\n \tprivate boolean dryRun;\n \n+\t/** Should an incoming (fetch) transfer validate objects? */\n+\tprivate boolean checkFetchedObjects;\n+\n \t/**\n \t * Create a new transport instance.\n \t * \n@@ -363,8 +367,10 @@ private static String findTrackingRefName(final String remoteName,\n \t *            URI passed to {@link #open(Repository, URIish)}.\n \t */\n \tprotected Transport(final Repository local, final URIish uri) {\n+\t\tfinal TransferConfig tc = local.getConfig().getTransfer();\n \t\tthis.local = local;\n \t\tthis.uri = uri;\n+\t\tthis.checkFetchedObjects = tc.isFsckObjects();\n \t}\n \n \t/**\n@@ -444,6 +450,24 @@ public void setFetchThin(final boolean fetchThin) {\n \t}\n \n \t/**\n+\t * @return true if fetch will verify received objects are formatted\n+\t *         correctly. Validating objects requires more CPU time on the\n+\t *         client side of the connection.\n+\t */\n+\tpublic boolean isCheckFetchedObjects() {\n+\t\treturn checkFetchedObjects;\n+\t}\n+\n+\t/**\n+\t * @param check\n+\t *            true to enable checking received objects; false to assume all\n+\t *            received objects are valid.\n+\t */\n+\tpublic void setCheckFetchedObjects(final boolean check) {\n+\t\tcheckFetchedObjects = check;\n+\t}\n+\n+\t/**\n \t * Default setting is: {@value RemoteConfig#DEFAULT_RECEIVE_PACK}\n \t *\n \t * @return remote executable providing receive-pack service for pack\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\nindex d43a18f..5b321a0 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\n@@ -170,8 +170,7 @@ protected void doFetch(final ProgressMonitor monitor,\n \t\t\t\tfinal Collection<Ref> want) throws TransportException {\n \t\t\tverifyPrerequisites();\n \t\t\ttry {\n-\t\t\t\tfinal IndexPack ip = IndexPack.create(local, bin);\n-\t\t\t\tip.setFixThin(true);\n+\t\t\t\tfinal IndexPack ip = newIndexPack();\n \t\t\t\tip.index(monitor);\n \t\t\t\tip.renameAndOpenPack();\n \t\t\t} catch (IOException err) {\n@@ -183,6 +182,13 @@ protected void doFetch(final ProgressMonitor monitor,\n \t\t\t}\n \t\t}\n \n+\t\tprivate IndexPack newIndexPack() throws IOException {\n+\t\t\tfinal IndexPack ip = IndexPack.create(local, bin);\n+\t\t\tip.setFixThin(true);\n+\t\t\tip.setObjectChecking(TransportBundle.this.isCheckFetchedObjects());\n+\t\t\treturn ip;\n+\t\t}\n+\n \t\tprivate void verifyPrerequisites() throws TransportException {\n \t\t\tif (prereqs.isEmpty())\n \t\t\t\treturn;\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java\nindex f309fe1..5638454 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java\n@@ -59,6 +59,7 @@\n import org.spearce.jgit.lib.AnyObjectId;\n import org.spearce.jgit.lib.Constants;\n import org.spearce.jgit.lib.FileMode;\n+import org.spearce.jgit.lib.ObjectChecker;\n import org.spearce.jgit.lib.ObjectId;\n import org.spearce.jgit.lib.PackIndex;\n import org.spearce.jgit.lib.ProgressMonitor;\n@@ -99,6 +100,9 @@\n \t/** The repository this transport fetches into, or pushes out of. */\n \tprivate final Repository local;\n \n+\t/** If not null the validator for received objects. */\n+\tprivate final ObjectChecker objCheck;\n+\n \t/**\n \t * List of all remote repositories we may need to get objects out of.\n \t * <p>\n@@ -157,9 +161,9 @@\n \t */\n \tprivate final HashMap<ObjectId, List<Throwable>> fetchErrors;\n \n-\tWalkFetchConnection(final WalkTransport walkTransport,\n-\t\t\tfinal WalkRemoteObjectDatabase w) {\n-\t\tlocal = walkTransport.local;\n+\tWalkFetchConnection(final WalkTransport wt, final WalkRemoteObjectDatabase w) {\n+\t\tlocal = wt.local;\n+\t\tobjCheck = wt.isCheckFetchedObjects() ? new ObjectChecker() : null;\n \n \t\tremotes = new ArrayList<WalkRemoteObjectDatabase>();\n \t\tremotes.add(w);\n@@ -560,10 +564,21 @@ private void verifyLooseObject(final AnyObjectId id, final byte[] compressed)\n \t\t\tthrow e;\n \t\t}\n \n-\t\tif (!AnyObjectId.equals(id, uol.getId()))\n+\t\tif (!AnyObjectId.equals(id, uol.getId())) {\n \t\t\tthrow new TransportException(\"Incorrect hash for \" + id.name()\n \t\t\t\t\t+ \"; computed \" + uol.getId().name() + \" as a \"\n-\t\t\t\t\t+ uol.getType() + \" from \" + compressed.length + \" bytes.\");\n+\t\t\t\t\t+ Constants.encodedTypeString(uol.getType()) + \" from \"\n+\t\t\t\t\t+ compressed.length + \" bytes.\");\n+\t\t}\n+\t\tif (objCheck != null) {\n+\t\t\ttry {\n+\t\t\t\tobjCheck.check(uol.getType(), uol.getCachedBytes());\n+\t\t\t} catch (CorruptObjectException e) {\n+\t\t\t\tthrow new TransportException(\"Invalid \"\n+\t\t\t\t\t\t+ Constants.encodedTypeString(uol.getType()) + \" \"\n+\t\t\t\t\t\t+ id.name() + \":\" + e.getMessage());\n+\t\t\t}\n+\t\t}\n \t}\n \n \tprivate void saveLooseObject(final AnyObjectId id, final byte[] compressed)\n@@ -811,6 +826,7 @@ void downloadPack(final ProgressMonitor monitor) throws IOException {\n \t\t\ts = connection.open(\"pack/\" + packName);\n \t\t\tip = IndexPack.create(local, s.in);\n \t\t\tip.setFixThin(false);\n+\t\t\tip.setObjectChecker(objCheck);\n \t\t\tip.index(monitor);\n \t\t\tip.renameAndOpenPack();\n \t\t}\n-- \n1.6.0.2.569.g798a2a\n"},{"id":"92094","messageId":"200810012254.09169.robin.rosenberg.lists@dewire.com","threadId":"15735","inReplyTo":"1222824690-7632-5-git-send-email-spearce@spearce.org","subject":"Re: [JGIT PATCH 4/5] Expose the critical receive configuration options to JGit","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg.lists@dewire.com","sentAt":"2008-10-01T20:54:09Z","receivedAt":"2008-10-01T20:54:09Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"\nThe repo configuration setup fails. I'll squash this in\n\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java\n@@ -534,6 +534,7 @@ public void create() {\n                add(e);\n\n                core = new CoreConfig(this);\n+               transfer = new TransferConfig(this);\n        }\n\n        /**\n\ni.e. initialize the transfer object when creating a new repo in junit tests.\n\nI also noted we try to read ~/.gitconfig which may give us som headaches\nlater on.\n\n-- robin\n"},{"id":"92204","messageId":"20081002224643.GR21310@spearce.org","threadId":"15735","inReplyTo":"200810012254.09169.robin.rosenberg.lists@dewire.com","subject":"Re: [JGIT PATCH 4/5] Expose the critical receive configuration options to JGit","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-10-02T22:46:43Z","receivedAt":"2008-10-02T22:46:43Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Robin Rosenberg <robin.rosenberg.lists@dewire.com> wrote:\n> \n> The repo configuration setup fails. I'll squash this in\n\nWhoops.  Thanks.\n \n> I also noted we try to read ~/.gitconfig which may give us som headaches\n> later on.\n\nOy.  Issue #42 on the issue tracker for it.  We shouldn't be reading\nthat during the tests.\n\n-- \nShawn.\n"},{"id":"92712","messageId":"2c6b72b30810091446y22cb2e00te7a25676ee21ddac@mail.gmail.com","threadId":"15735","inReplyTo":"1222824690-7632-3-git-send-email-spearce@spearce.org","subject":"Re: [JGIT PATCH 2/5] Fix UnpackedObjectLoader.getBytes to return a copy","fromName":"Jonas Fonseca","fromEmail":"jonas.fonseca@gmail.com","sentAt":"2008-10-09T21:46:48Z","receivedAt":"2008-10-09T21:46:48Z","isPatch":true,"sender":{"key":"jonas.fonseca@gmail.com","avatar":"https://gravatar.com/avatar/9b7fa23cce50269e5d164312b6ac5ae818a180f837b38f28f3bdf689dd7f96cd?d=mp&s=160"},"body":"On Wed, Oct 1, 2008 at 03:31, Shawn O. Pearce <spearce@spearce.org> wrote:\n> diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectLoader.java b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectLoader.java\n> index 5282491..87e861f 100644\n> --- a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectLoader.java\n> +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectLoader.java\n> @@ -105,7 +105,12 @@ protected void setId(final ObjectId id) {\n>         * @throws IOException\n>         *             the object cannot be read.\n>         */\n> -       public abstract byte[] getBytes() throws IOException;\n> +       public final byte[] getBytes() throws IOException {\n> +               final byte[] data = getCachedBytes();\n> +               final byte[] copy = new byte[data.length];\n> +               System.arraycopy(data, 0, copy, 0, data.length);\n> +               return data;\n> +       }\n\nIf I understand correctly, shouldn't this return the copy variable?\n\n-- \nJonas Fonseca\n"},{"id":"92713","messageId":"20081009214926.GA8203@spearce.org","threadId":"15735","inReplyTo":"2c6b72b30810091446y22cb2e00te7a25676ee21ddac@mail.gmail.com","subject":"Re: [JGIT PATCH 2/5] Fix UnpackedObjectLoader.getBytes to return a copy","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-10-09T21:49:26Z","receivedAt":"2008-10-09T21:49:26Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Jonas Fonseca <jonas.fonseca@gmail.com> wrote:\n> On Wed, Oct 1, 2008 at 03:31, Shawn O. Pearce <spearce@spearce.org> wrote:\n> > diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectLoader.java b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectLoader.java\n> > index 5282491..87e861f 100644\n> > --- a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectLoader.java\n> > +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectLoader.java\n> > @@ -105,7 +105,12 @@ protected void setId(final ObjectId id) {\n> >         * @throws IOException\n> >         *             the object cannot be read.\n> >         */\n> > -       public abstract byte[] getBytes() throws IOException;\n> > +       public final byte[] getBytes() throws IOException {\n> > +               final byte[] data = getCachedBytes();\n> > +               final byte[] copy = new byte[data.length];\n> > +               System.arraycopy(data, 0, copy, 0, data.length);\n> > +               return data;\n> > +       }\n> \n> If I understand correctly, shouldn't this return the copy variable?\n\nF&@!#*@#&@!#*@!@!&#@#@*@!\n\nYes.  :-)\n\nI think its already committed to master too.  Can you send a patch\nalong to fix, and point out how stupid I am?\n\n-- \nShawn.\n"},{"id":"92716","messageId":"20081009220932.GA30350@diku.dk","threadId":"15735","inReplyTo":"20081009214926.GA8203@spearce.org","subject":"[JGIT PATCH] Fix ObjectLoader.getBytes to really return the created copy","fromName":"Jonas Fonseca","fromEmail":"fonseca@diku.dk","sentAt":"2008-10-09T22:09:36Z","receivedAt":"2008-10-09T22:09:36Z","isPatch":true,"sender":{"key":"fonseca@diku.dk","avatar":"https://gravatar.com/avatar/f82f3ad698717c51873b020c750a92438c820a24056dc39fe4d07baa10a92264?d=mp&s=160"},"body":"The bug was carried over from the original code in PackedObjectLoader by\ncommit 4c49ab5a4ec8555681ceabf17142a15bf90c2c24.\n\nSigned-off-by: Jonas Fonseca <fonseca@diku.dk>\n---\n .../src/org/spearce/jgit/lib/ObjectLoader.java     |    2 +-\n\n Shawn O. Pearce <spearce@spearce.org> wrote Thu, Oct 09, 2008:\n > I think its already committed to master too.  Can you send a patch\n > along to fix, and point out how stupid I am?\n\n Yes, I noticed it has already been applied. I am lagging behind a bit.\n Anyway, here is a trivial patch.\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectLoader.java b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectLoader.java\nindex 87e861f..8d745dd 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectLoader.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectLoader.java\n@@ -109,7 +109,7 @@ protected void setId(final ObjectId id) {\n \t\tfinal byte[] data = getCachedBytes();\n \t\tfinal byte[] copy = new byte[data.length];\n \t\tSystem.arraycopy(data, 0, copy, 0, data.length);\n-\t\treturn data;\n+\t\treturn copy;\n \t}\n \n \t/**\n-- \n1.6.0.2.665.g48ddf\n\n\n-- \nJonas Fonseca\n"}]}