{"thread":{"id":"20905","subject":"[JGIT PATCH 2/3] Don't allow DirCacheEntry with mode of 0","startedAt":"2009-09-11T19:58:47Z","lastAt":"2009-09-15T16:11:38Z","messageCount":4,"participants":["Shawn O. Pearce","Halstrick, Christian"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"122909","messageId":"1252699129-6961-1-git-send-email-spearce@spearce.org","threadId":"20905","inReplyTo":null,"subject":"[JGIT PATCH 1/3] Disallow creating invalid DirCacheEntry records","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-09-11T19:58:47Z","receivedAt":"2009-09-11T19:58:47Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"A dircache record must not use a path string like \"/a\" or \"a//b\"\nas this results in a tree entry being written with a zero length\nname component in the record.  C git does not support an empty name,\nand neither does any modern filesystem.\n\nA record also must not have a stage outside of the standard 0-3\nvalue range, as there are only 2 bits of space available in the\non-disk format of the record to store the stage information.\nAny other values would be truncated into this space, storing a\ndifferent value than the caller expected.\n\nIf an application tries to create a DirCache record with either of\nthese wrong values, we abort with an IllegalArgumentException.\n\nSigned-off-by: Shawn O. Pearce <sop@google.com>\nCC: Adam W. Hawks <awhawks@writeme.com>\n---\n .../spearce/jgit/dircache/DirCacheEntryTest.java   |  115 ++++++++++++++++++++\n .../org/spearce/jgit/dircache/DirCacheEntry.java   |   55 +++++++++-\n 2 files changed, 169 insertions(+), 1 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheEntryTest.java\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheEntryTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheEntryTest.java\nnew file mode 100644\nindex 0000000..a6ff5a8\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheEntryTest.java\n@@ -0,0 +1,115 @@\n+/*\n+ * Copyright (C) 2009, 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.dircache;\n+\n+import junit.framework.TestCase;\n+\n+import org.spearce.jgit.lib.Constants;\n+\n+public class DirCacheEntryTest extends TestCase {\n+\tpublic void testIsValidPath() {\n+\t\tassertTrue(isValidPath(\"a\"));\n+\t\tassertTrue(isValidPath(\"a/b\"));\n+\t\tassertTrue(isValidPath(\"ab/cd/ef\"));\n+\n+\t\tassertFalse(isValidPath(\"\"));\n+\t\tassertFalse(isValidPath(\"/a\"));\n+\t\tassertFalse(isValidPath(\"a//b\"));\n+\t\tassertFalse(isValidPath(\"ab/cd//ef\"));\n+\t\tassertFalse(isValidPath(\"a/\"));\n+\t\tassertFalse(isValidPath(\"ab/cd/ef/\"));\n+\t\tassertFalse(isValidPath(\"a\\u0000b\"));\n+\t}\n+\n+\tprivate static boolean isValidPath(final String path) {\n+\t\treturn DirCacheEntry.isValidPath(Constants.encode(path));\n+\t}\n+\n+\tpublic void testCreate_ByStringPath() {\n+\t\tassertEquals(\"a\", new DirCacheEntry(\"a\").getPathString());\n+\t\tassertEquals(\"a/b\", new DirCacheEntry(\"a/b\").getPathString());\n+\n+\t\ttry {\n+\t\t\tnew DirCacheEntry(\"/a\");\n+\t\t\tfail(\"Incorrectly created DirCacheEntry\");\n+\t\t} catch (IllegalArgumentException err) {\n+\t\t\tassertEquals(\"Invalid path: /a\", err.getMessage());\n+\t\t}\n+\t}\n+\n+\tpublic void testCreate_ByStringPathAndStage() {\n+\t\tDirCacheEntry e;\n+\n+\t\te = new DirCacheEntry(\"a\", 0);\n+\t\tassertEquals(\"a\", e.getPathString());\n+\t\tassertEquals(0, e.getStage());\n+\n+\t\te = new DirCacheEntry(\"a/b\", 1);\n+\t\tassertEquals(\"a/b\", e.getPathString());\n+\t\tassertEquals(1, e.getStage());\n+\n+\t\te = new DirCacheEntry(\"a/c\", 2);\n+\t\tassertEquals(\"a/c\", e.getPathString());\n+\t\tassertEquals(2, e.getStage());\n+\n+\t\te = new DirCacheEntry(\"a/d\", 3);\n+\t\tassertEquals(\"a/d\", e.getPathString());\n+\t\tassertEquals(3, e.getStage());\n+\n+\t\ttry {\n+\t\t\tnew DirCacheEntry(\"/a\", 1);\n+\t\t\tfail(\"Incorrectly created DirCacheEntry\");\n+\t\t} catch (IllegalArgumentException err) {\n+\t\t\tassertEquals(\"Invalid path: /a\", err.getMessage());\n+\t\t}\n+\n+\t\ttry {\n+\t\t\tnew DirCacheEntry(\"a\", -11);\n+\t\t\tfail(\"Incorrectly created DirCacheEntry\");\n+\t\t} catch (IllegalArgumentException err) {\n+\t\t\tassertEquals(\"Invalid stage -11 for path a\", err.getMessage());\n+\t\t}\n+\n+\t\ttry {\n+\t\t\tnew DirCacheEntry(\"a\", 4);\n+\t\t\tfail(\"Incorrectly created DirCacheEntry\");\n+\t\t} catch (IllegalArgumentException err) {\n+\t\t\tassertEquals(\"Invalid stage 4 for path a\", err.getMessage());\n+\t\t}\n+\t}\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 47b1cc5..d7abd6e 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@@ -166,6 +166,10 @@\n \t *\n \t * @param newPath\n \t *            name of the cache entry.\n+\t * @throws IllegalArgumentException\n+\t *             If the path starts or ends with \"/\", or contains \"//\" either\n+\t *             \"\\0\". These sequences are not permitted in a git tree object\n+\t *             or DirCache file.\n \t */\n \tpublic DirCacheEntry(final String newPath) {\n \t\tthis(Constants.encode(newPath));\n@@ -178,6 +182,11 @@ public DirCacheEntry(final String newPath) {\n \t *            name of the cache entry.\n \t * @param stage\n \t *            the stage index of the new entry.\n+\t * @throws IllegalArgumentException\n+\t *             If the path starts or ends with \"/\", or contains \"//\" either\n+\t *             \"\\0\". These sequences are not permitted in a git tree object\n+\t *             or DirCache file.  Or if {@code stage} is outside of the\n+\t *             range 0..3, inclusive.\n \t */\n \tpublic DirCacheEntry(final String newPath, final int stage) {\n \t\tthis(Constants.encode(newPath), stage);\n@@ -188,6 +197,10 @@ public DirCacheEntry(final String newPath, final int stage) {\n \t *\n \t * @param newPath\n \t *            name of the cache entry, in the standard encoding.\n+\t * @throws IllegalArgumentException\n+\t *             If the path starts or ends with \"/\", or contains \"//\" either\n+\t *             \"\\0\". These sequences are not permitted in a git tree object\n+\t *             or DirCache file.\n \t */\n \tpublic DirCacheEntry(final byte[] newPath) {\n \t\tthis(newPath, STAGE_0);\n@@ -200,8 +213,20 @@ public DirCacheEntry(final byte[] newPath) {\n \t *            name of the cache entry, in the standard encoding.\n \t * @param stage\n \t *            the stage index of the new entry.\n+\t * @throws IllegalArgumentException\n+\t *             If the path starts or ends with \"/\", or contains \"//\" either\n+\t *             \"\\0\". These sequences are not permitted in a git tree object\n+\t *             or DirCache file.  Or if {@code stage} is outside of the\n+\t *             range 0..3, inclusive.\n \t */\n \tpublic DirCacheEntry(final byte[] newPath, final int stage) {\n+\t\tif (!isValidPath(newPath))\n+\t\t\tthrow new IllegalArgumentException(\"Invalid path: \"\n+\t\t\t\t\t+ toString(newPath));\n+\t\tif (stage < 0 || 3 < stage)\n+\t\t\tthrow new IllegalArgumentException(\"Invalid stage \" + stage\n+\t\t\t\t\t+ \" for path \" + toString(newPath));\n+\n \t\tinfo = new byte[INFO_LEN];\n \t\tinfoOffset = 0;\n \t\tpath = newPath;\n@@ -461,7 +486,7 @@ public void setObjectIdFromRaw(final byte[] bs, final int p) {\n \t *         returned string.\n \t */\n \tpublic String getPathString() {\n-\t\treturn Constants.CHARSET.decode(ByteBuffer.wrap(path)).toString();\n+\t\treturn toString(path);\n \t}\n \n \t/**\n@@ -492,4 +517,32 @@ private void encodeTS(final int pIdx, final long when) {\n \t\tNB.encodeInt32(info, base, (int) (when / 1000));\n \t\tNB.encodeInt32(info, base + 4, ((int) (when % 1000)) * 1000000);\n \t}\n+\n+\tprivate static String toString(final byte[] path) {\n+\t\treturn Constants.CHARSET.decode(ByteBuffer.wrap(path)).toString();\n+\t}\n+\n+\tstatic boolean isValidPath(final byte[] path) {\n+\t\tif (path.length == 0)\n+\t\t\treturn false; // empty path is not permitted.\n+\n+\t\tboolean componentHasChars = false;\n+\t\tfor (final byte c : path) {\n+\t\t\tswitch (c) {\n+\t\t\tcase 0:\n+\t\t\t\treturn false; // NUL is never allowed within the path.\n+\n+\t\t\tcase '/':\n+\t\t\t\tif (componentHasChars)\n+\t\t\t\t\tcomponentHasChars = false;\n+\t\t\t\telse\n+\t\t\t\t\treturn false;\n+\t\t\t\tbreak;\n+\n+\t\t\tdefault:\n+\t\t\t\tcomponentHasChars = true;\n+\t\t\t}\n+\t\t}\n+\t\treturn componentHasChars;\n+\t}\n }\n-- \n1.6.5.rc0.164.g5f6b0\n"},{"id":"122908","messageId":"1252699129-6961-2-git-send-email-spearce@spearce.org","threadId":"20905","inReplyTo":"1252699129-6961-1-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 2/3] Don't allow DirCacheEntry with mode of 0","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-09-11T19:58:48Z","receivedAt":"2009-09-11T19:58:48Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"A 0 file mode in a DirCacheEntry is not a valid mode.  To C git\nsuch a value indicates the record should not be present.  We already\nwere catching this bad state and exceptioning out when writing tree\nobjects to disk, but we did not fail when writing the dircache back\nto disk.  This allowed JGit applications to create a dircache file\nwhich C git would not like to read.\n\nInstead of checking the mode during writes, we now check during\nmutation.  This allows application bugs to be detected sooner and\ncloser to the cause site.  It also allows us to avoid checking most\nof the records which we read in from disk, as we can assume these\nare formatted correctly.\n\nSome of our unit tests were not setting the FileMode on their test\nentry, so they had to be updated to use REGULAR_FILE.\n\nSigned-off-by: Shawn O. Pearce <sop@google.com>\nCC: Adam W. Hawks <awhawks@writeme.com>\n---\n .../spearce/jgit/dircache/DirCacheBasicTest.java   |    5 ++-\n .../spearce/jgit/dircache/DirCacheBuilderTest.java |   27 +++++++++++++--\n .../spearce/jgit/dircache/DirCacheEntryTest.java   |   37 ++++++++++++++++++++\n .../spearce/jgit/dircache/DirCacheFindTest.java    |    5 ++-\n .../jgit/dircache/DirCacheIteratorTest.java        |    4 ++-\n .../jgit/dircache/DirCacheLargePathTest.java       |    5 +++\n .../spearce/jgit/dircache/DirCacheTreeTest.java    |   13 +++++--\n .../org/spearce/jgit/dircache/DirCacheBuilder.java |    8 +++--\n .../org/spearce/jgit/dircache/DirCacheEditor.java  |   11 ++++--\n .../org/spearce/jgit/dircache/DirCacheEntry.java   |   12 ++++++-\n .../org/spearce/jgit/dircache/DirCacheTree.java    |    4 --\n 11 files changed, 111 insertions(+), 20 deletions(-)\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheBasicTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheBasicTest.java\nindex 4d737c0..3b48b11 100644\n--- a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheBasicTest.java\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheBasicTest.java\n@@ -40,6 +40,7 @@\n import java.io.File;\n \n import org.spearce.jgit.lib.Constants;\n+import org.spearce.jgit.lib.FileMode;\n import org.spearce.jgit.lib.RepositoryTestCase;\n \n public class DirCacheBasicTest extends RepositoryTestCase {\n@@ -170,8 +171,10 @@ public void testBuildThenClear() throws Exception {\n \n \t\tfinal String[] paths = { \"a.\", \"a.b\", \"a/b\", \"a0b\" };\n \t\tfinal DirCacheEntry[] ents = new DirCacheEntry[paths.length];\n-\t\tfor (int i = 0; i < paths.length; i++)\n+\t\tfor (int i = 0; i < paths.length; i++) {\n \t\t\tents[i] = new DirCacheEntry(paths[i]);\n+\t\t\tents[i].setFileMode(FileMode.REGULAR_FILE);\n+\t\t}\n \n \t\tfinal DirCacheBuilder b = dc.builder();\n \t\tfor (int i = 0; i < ents.length; i++)\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheBuilderTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheBuilderTest.java\nindex 2cf1d92..f64e4f6 100644\n--- a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheBuilderTest.java\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheBuilderTest.java\n@@ -59,6 +59,20 @@ public void testBuildEmpty() throws Exception {\n \t\t}\n \t}\n \n+\tpublic void testBuildRejectsUnsetFileMode() throws Exception {\n+\t\tfinal DirCache dc = DirCache.newInCore();\n+\t\tfinal DirCacheBuilder b = dc.builder();\n+\t\tassertNotNull(b);\n+\n+\t\tfinal DirCacheEntry e = new DirCacheEntry(\"a\");\n+\t\tassertEquals(0, e.getRawMode());\n+\t\ttry {\n+\t\t\tb.add(e);\n+\t\t} catch (IllegalArgumentException err) {\n+\t\t\tassertEquals(\"FileMode not set for path a\", err.getMessage());\n+\t\t}\n+\t}\n+\n \tpublic void testBuildOneFile_FinishWriteCommit() throws Exception {\n \t\tfinal String path = \"a-file-path\";\n \t\tfinal FileMode mode = FileMode.REGULAR_FILE;\n@@ -162,6 +176,7 @@ public void testFindSingleFile() throws Exception {\n \t\tassertNotNull(b);\n \n \t\tfinal DirCacheEntry entOrig = new DirCacheEntry(path);\n+\t\tentOrig.setFileMode(FileMode.REGULAR_FILE);\n \t\tassertNotSame(path, entOrig.getPathString());\n \t\tassertEquals(path, entOrig.getPathString());\n \t\tb.add(entOrig);\n@@ -185,8 +200,10 @@ public void testAdd_InGitSortOrder() throws Exception {\n \n \t\tfinal String[] paths = { \"a.\", \"a.b\", \"a/b\", \"a0b\" };\n \t\tfinal DirCacheEntry[] ents = new DirCacheEntry[paths.length];\n-\t\tfor (int i = 0; i < paths.length; i++)\n+\t\tfor (int i = 0; i < paths.length; i++) {\n \t\t\tents[i] = new DirCacheEntry(paths[i]);\n+\t\t\tents[i].setFileMode(FileMode.REGULAR_FILE);\n+\t\t}\n \n \t\tfinal DirCacheBuilder b = dc.builder();\n \t\tfor (int i = 0; i < ents.length; i++)\n@@ -207,8 +224,10 @@ public void testAdd_ReverseGitSortOrder() throws Exception {\n \n \t\tfinal String[] paths = { \"a.\", \"a.b\", \"a/b\", \"a0b\" };\n \t\tfinal DirCacheEntry[] ents = new DirCacheEntry[paths.length];\n-\t\tfor (int i = 0; i < paths.length; i++)\n+\t\tfor (int i = 0; i < paths.length; i++) {\n \t\t\tents[i] = new DirCacheEntry(paths[i]);\n+\t\t\tents[i].setFileMode(FileMode.REGULAR_FILE);\n+\t\t}\n \n \t\tfinal DirCacheBuilder b = dc.builder();\n \t\tfor (int i = ents.length - 1; i >= 0; i--)\n@@ -229,8 +248,10 @@ public void testBuilderClear() throws Exception {\n \n \t\tfinal String[] paths = { \"a.\", \"a.b\", \"a/b\", \"a0b\" };\n \t\tfinal DirCacheEntry[] ents = new DirCacheEntry[paths.length];\n-\t\tfor (int i = 0; i < paths.length; i++)\n+\t\tfor (int i = 0; i < paths.length; i++) {\n \t\t\tents[i] = new DirCacheEntry(paths[i]);\n+\t\t\tents[i].setFileMode(FileMode.REGULAR_FILE);\n+\t\t}\n \t\t{\n \t\t\tfinal DirCacheBuilder b = dc.builder();\n \t\t\tfor (int i = 0; i < ents.length; i++)\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheEntryTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheEntryTest.java\nindex a6ff5a8..971f201 100644\n--- a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheEntryTest.java\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheEntryTest.java\n@@ -40,6 +40,7 @@\n import junit.framework.TestCase;\n \n import org.spearce.jgit.lib.Constants;\n+import org.spearce.jgit.lib.FileMode;\n \n public class DirCacheEntryTest extends TestCase {\n \tpublic void testIsValidPath() {\n@@ -112,4 +113,40 @@ public void testCreate_ByStringPathAndStage() {\n \t\t\tassertEquals(\"Invalid stage 4 for path a\", err.getMessage());\n \t\t}\n \t}\n+\n+\tpublic void testSetFileMode() {\n+\t\tfinal DirCacheEntry e = new DirCacheEntry(\"a\");\n+\n+\t\tassertEquals(0, e.getRawMode());\n+\n+\t\te.setFileMode(FileMode.REGULAR_FILE);\n+\t\tassertSame(FileMode.REGULAR_FILE, e.getFileMode());\n+\t\tassertEquals(FileMode.REGULAR_FILE.getBits(), e.getRawMode());\n+\n+\t\te.setFileMode(FileMode.EXECUTABLE_FILE);\n+\t\tassertSame(FileMode.EXECUTABLE_FILE, e.getFileMode());\n+\t\tassertEquals(FileMode.EXECUTABLE_FILE.getBits(), e.getRawMode());\n+\n+\t\te.setFileMode(FileMode.SYMLINK);\n+\t\tassertSame(FileMode.SYMLINK, e.getFileMode());\n+\t\tassertEquals(FileMode.SYMLINK.getBits(), e.getRawMode());\n+\n+\t\te.setFileMode(FileMode.GITLINK);\n+\t\tassertSame(FileMode.GITLINK, e.getFileMode());\n+\t\tassertEquals(FileMode.GITLINK.getBits(), e.getRawMode());\n+\n+\t\ttry {\n+\t\t\te.setFileMode(FileMode.MISSING);\n+\t\t\tfail(\"incorrectly accepted FileMode.MISSING\");\n+\t\t} catch (IllegalArgumentException err) {\n+\t\t\tassertEquals(\"Invalid mode 0 for path a\", err.getMessage());\n+\t\t}\n+\n+\t\ttry {\n+\t\t\te.setFileMode(FileMode.TREE);\n+\t\t\tfail(\"incorrectly accepted FileMode.TREE\");\n+\t\t} catch (IllegalArgumentException err) {\n+\t\t\tassertEquals(\"Invalid mode 40000 for path a\", err.getMessage());\n+\t\t}\n+\t}\n }\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheFindTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheFindTest.java\nindex 0eb0302..470c80a 100644\n--- a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheFindTest.java\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheFindTest.java\n@@ -37,6 +37,7 @@\n \n package org.spearce.jgit.dircache;\n \n+import org.spearce.jgit.lib.FileMode;\n import org.spearce.jgit.lib.RepositoryTestCase;\n \n public class DirCacheFindTest extends RepositoryTestCase {\n@@ -45,8 +46,10 @@ public void testEntriesWithin() throws Exception {\n \n \t\tfinal String[] paths = { \"a.\", \"a/b\", \"a/c\", \"a/d\", \"a0b\" };\n \t\tfinal DirCacheEntry[] ents = new DirCacheEntry[paths.length];\n-\t\tfor (int i = 0; i < paths.length; i++)\n+\t\tfor (int i = 0; i < paths.length; i++) {\n \t\t\tents[i] = new DirCacheEntry(paths[i]);\n+\t\t\tents[i].setFileMode(FileMode.REGULAR_FILE);\n+\t\t}\n \t\tfinal int aFirst = 1;\n \t\tfinal int aLast = 3;\n \ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheIteratorTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheIteratorTest.java\nindex 047c989..71581dc 100644\n--- a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheIteratorTest.java\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheIteratorTest.java\n@@ -68,8 +68,10 @@ public void testNoSubtree_NoTreeWalk() throws Exception {\n \n \t\tfinal String[] paths = { \"a.\", \"a0b\" };\n \t\tfinal DirCacheEntry[] ents = new DirCacheEntry[paths.length];\n-\t\tfor (int i = 0; i < paths.length; i++)\n+\t\tfor (int i = 0; i < paths.length; i++) {\n \t\t\tents[i] = new DirCacheEntry(paths[i]);\n+\t\t\tents[i].setFileMode(FileMode.REGULAR_FILE);\n+\t\t}\n \n \t\tfinal DirCacheBuilder b = dc.builder();\n \t\tfor (int i = 0; i < ents.length; i++)\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheLargePathTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheLargePathTest.java\nindex 4ea286c..a9945f1 100644\n--- a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheLargePathTest.java\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheLargePathTest.java\n@@ -40,6 +40,7 @@\n import java.io.IOException;\n \n import org.spearce.jgit.errors.CorruptObjectException;\n+import org.spearce.jgit.lib.FileMode;\n import org.spearce.jgit.lib.RepositoryTestCase;\n \n public class DirCacheLargePathTest extends RepositoryTestCase {\n@@ -70,6 +71,10 @@ private void testLongPath(final int len) throws CorruptObjectException,\n \n \t\tfinal DirCacheEntry longEnt = new DirCacheEntry(longPath);\n \t\tfinal DirCacheEntry shortEnt = new DirCacheEntry(shortPath);\n+\n+\t\tlongEnt.setFileMode(FileMode.REGULAR_FILE);\n+\t\tshortEnt.setFileMode(FileMode.REGULAR_FILE);\n+\n \t\tassertEquals(longPath, longEnt.getPathString());\n \t\tassertEquals(shortPath, shortEnt.getPathString());\n \ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheTreeTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheTreeTest.java\nindex aca0b90..6efa207 100644\n--- a/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheTreeTest.java\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheTreeTest.java\n@@ -40,6 +40,7 @@\n import java.io.IOException;\n \n import org.spearce.jgit.errors.CorruptObjectException;\n+import org.spearce.jgit.lib.FileMode;\n import org.spearce.jgit.lib.RepositoryTestCase;\n \n public class DirCacheTreeTest extends RepositoryTestCase {\n@@ -75,8 +76,10 @@ public void testSingleSubtree() throws Exception {\n \n \t\tfinal String[] paths = { \"a.\", \"a/b\", \"a/c\", \"a/d\", \"a0b\" };\n \t\tfinal DirCacheEntry[] ents = new DirCacheEntry[paths.length];\n-\t\tfor (int i = 0; i < paths.length; i++)\n+\t\tfor (int i = 0; i < paths.length; i++) {\n \t\t\tents[i] = new DirCacheEntry(paths[i]);\n+\t\t\tents[i].setFileMode(FileMode.REGULAR_FILE);\n+\t\t}\n \t\tfinal int aFirst = 1;\n \t\tfinal int aLast = 3;\n \n@@ -110,8 +113,10 @@ public void testTwoLevelSubtree() throws Exception {\n \n \t\tfinal String[] paths = { \"a.\", \"a/b\", \"a/c/e\", \"a/c/f\", \"a/d\", \"a0b\" };\n \t\tfinal DirCacheEntry[] ents = new DirCacheEntry[paths.length];\n-\t\tfor (int i = 0; i < paths.length; i++)\n+\t\tfor (int i = 0; i < paths.length; i++) {\n \t\t\tents[i] = new DirCacheEntry(paths[i]);\n+\t\t\tents[i].setFileMode(FileMode.REGULAR_FILE);\n+\t\t}\n \t\tfinal int aFirst = 1;\n \t\tfinal int aLast = 4;\n \t\tfinal int acFirst = 2;\n@@ -167,8 +172,10 @@ public void testWriteReadTree() throws CorruptObjectException, IOException {\n \t\tfinal String B = String.format(\"b%2000s\", \"b\");\n \t\tfinal String[] paths = { A + \".\", A + \".\" + B, A + \"/\" + B, A + \"0\" + B };\n \t\tfinal DirCacheEntry[] ents = new DirCacheEntry[paths.length];\n-\t\tfor (int i = 0; i < paths.length; i++)\n+\t\tfor (int i = 0; i < paths.length; i++) {\n \t\t\tents[i] = new DirCacheEntry(paths[i]);\n+\t\t\tents[i].setFileMode(FileMode.REGULAR_FILE);\n+\t\t}\n \n \t\tfinal DirCacheBuilder b = dc.builder();\n \t\tfor (int i = 0; i < ents.length; i++)\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheBuilder.java b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheBuilder.java\nindex aee12fb..8acb3d0 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheBuilder.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheBuilder.java\n@@ -41,7 +41,6 @@\n import java.util.Arrays;\n \n import org.spearce.jgit.lib.AnyObjectId;\n-import org.spearce.jgit.lib.FileMode;\n import org.spearce.jgit.lib.Repository;\n import org.spearce.jgit.lib.WindowCursor;\n import org.spearce.jgit.treewalk.AbstractTreeIterator;\n@@ -90,8 +89,13 @@ protected DirCacheBuilder(final DirCache dc, final int ecnt) {\n \t *\n \t * @param newEntry\n \t *            the new entry to add.\n+\t * @throws IllegalArgumentException\n+\t *             If the FileMode of the entry was not set by the caller.\n \t */\n \tpublic void add(final DirCacheEntry newEntry) {\n+\t\tif (newEntry.getRawMode() == 0)\n+\t\t\tthrow new IllegalArgumentException(\"FileMode not set for path \"\n+\t\t\t\t\t+ newEntry.getPathString());\t\t\n \t\tbeforeAdd(newEntry);\n \t\tfastAdd(newEntry);\n \t}\n@@ -187,8 +191,6 @@ public void finish() {\n \t}\n \n \tprivate void beforeAdd(final DirCacheEntry newEntry) {\n-\t\tif (FileMode.TREE.equals(newEntry.getRawMode()))\n-\t\t\tthrow bad(newEntry, \"Adding subtree not allowed\");\n \t\tif (sorted && entryCnt > 0) {\n \t\t\tfinal DirCacheEntry lastEntry = entries[entryCnt - 1];\n \t\t\tfinal int cr = DirCache.cmp(lastEntry, newEntry);\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEditor.java b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEditor.java\nindex 10b554e..6eaceb7 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEditor.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheEditor.java\n@@ -138,11 +138,16 @@ private void applyEdits() {\n \t\t\t}\n \n \t\t\tfinal DirCacheEntry ent;\n-\t\t\tif (missing)\n+\t\t\tif (missing) {\n \t\t\t\tent = new DirCacheEntry(e.path);\n-\t\t\telse\n+\t\t\t\te.apply(ent);\n+\t\t\t\tif (ent.getRawMode() == 0)\n+\t\t\t\t\tthrow new IllegalArgumentException(\"FileMode not set\"\n+\t\t\t\t\t\t\t+ \" for path \" + ent.getPathString());\t\t\t\t\t\t\t\n+\t\t\t} else {\n \t\t\t\tent = cache.getEntry(eIdx);\n-\t\t\te.apply(ent);\n+\t\t\t\te.apply(ent);\n+\t\t\t}\n \t\t\tfastAdd(ent);\n \t\t}\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 d7abd6e..872ef33 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@@ -377,11 +377,21 @@ public FileMode getFileMode() {\n \n \t/**\n \t * Set the file mode for this entry.\n-\t *\n+\t * \n \t * @param mode\n \t *            the new mode constant.\n+\t * @throws IllegalArgumentException\n+\t *             If {@code mode} is {@link FileMode#MISSING},\n+\t *             {@link FileMode#TREE}, or any other type code not permitted\n+\t *             in a tree object.\n \t */\n \tpublic void setFileMode(final FileMode mode) {\n+\t\tswitch (mode.getBits() & FileMode.TYPE_MASK) {\n+\t\tcase FileMode.TYPE_MISSING:\n+\t\tcase FileMode.TYPE_TREE:\n+\t\t\tthrow new IllegalArgumentException(\"Invalid mode \" + mode\n+\t\t\t\t\t+ \" for path \" + getPathString());\n+\t\t}\n \t\tNB.encodeInt32(info, infoOffset + P_MODE, mode.getBits());\n \t}\n \ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheTree.java b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheTree.java\nindex 79e95cb..2f2a5ed 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheTree.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheTree.java\n@@ -376,10 +376,6 @@ private int computeSize(final DirCacheEntry[] cache, int cIdx,\n \t\t\t}\n \n \t\t\tfinal FileMode mode = e.getFileMode();\n-\t\t\tif (mode.getObjectType() == Constants.OBJ_BAD)\n-\t\t\t\tthrow new IllegalStateException(\"Entry \\\"\" + e.getPathString()\n-\t\t\t\t\t\t+ \"\\\" has incorrect mode set up.\");\n-\n \t\t\tsize += mode.copyToLength();\n \t\t\tsize += ep.length - pathOffset;\n \t\t\tsize += OBJECT_ID_LENGTH + 2;\n-- \n1.6.5.rc0.164.g5f6b0\n"},{"id":"122910","messageId":"1252699129-6961-3-git-send-email-spearce@spearce.org","threadId":"20905","inReplyTo":"1252699129-6961-2-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 3/3] Use keep(1) instead of add() when skipping an entry","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-09-11T19:58:49Z","receivedAt":"2009-09-11T19:58:49Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Doing a keep call with a length of 1 will copy the current entry just\nlike the previous add was doing, but it avoids doing any validation\non the entry.  This is sane because the entry can be assumed to be\nalready valid, since its originating from the destination index.\n\nSigned-off-by: Shawn O. Pearce <sop@google.com>\n---\n .../jgit/dircache/DirCacheBuildIterator.java       |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheBuildIterator.java b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheBuildIterator.java\nindex 9818b76..94fc071 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheBuildIterator.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/dircache/DirCacheBuildIterator.java\n@@ -111,7 +111,7 @@ public void skip() throws CorruptObjectException {\n \t\tif (currentSubtree != null)\n \t\t\tbuilder.keep(ptr, currentSubtree.getEntrySpan());\n \t\telse\n-\t\t\tbuilder.add(currentEntry);\n+\t\t\tbuilder.keep(ptr, 1);\n \t\tnext(1);\n \t}\n \n-- \n1.6.5.rc0.164.g5f6b0\n"},{"id":"123280","messageId":"D35B4A582834DC418CCF9AF41AB69B70014954E265@DEWDFECCR04.wdf.sap.corp","threadId":"20905","inReplyTo":"1252699129-6961-3-git-send-email-spearce@spearce.org","subject":"git-svn and rebasing refactored (moved) content","fromName":"Halstrick, Christian","fromEmail":"christian.halstrick@sap.com","sentAt":"2009-09-15T16:11:38Z","receivedAt":"2009-09-15T16:11:38Z","isPatch":false,"sender":{"key":"christian.halstrick@sap.com","avatar":"https://gravatar.com/avatar/032940727041870bc7374e44e8f659ac0a8f8d97d679b4c2cbd05bcb39b088bb?d=mp&s=160"},"body":"Hi,\n\nI have a question regarding git rebase operation when content was moved. I have\nthe problem when I transfer stuff from a subversion repo into my git repo, but\nI wouldn't know the solution even if it would be a pure git scenario. Here is\nthe problem:\n\nThere is a SVN repository \"Source\" containing that files\n\"Source\":\nproject/feat1/A.java\nproject/feat1/B.java\nproject/C.java\n\nThere is git repository \"Target\" where I work. That repository get's updates\nfrom \"Source\" by 'git-svn migrate ...'. I had to move the files coming from\n\"Source\" (using 'git mv'). I just moved but did not (and will not in future)\nmodify the files of \"Source\". Additionally I added my own new files. The state\nof target is:\n\"Target\":\nproject/src/feat1/A.java (renamed file)\nproject/src/feat1/B.java (renamed file)\nproject/src/C.java (renamed file)\nproject/pom.xml (created file)\n\nIdeally from time to time I would like to rebase my work I do in \"Target\" on\nthe latest state of \"Source\". I use \"git rebase ...\" for that. But this\nsometimes fails. If in \"Source\" files are only modified everything works fine.\nE.g. modifications to \"Source\":project/feat1/A.java are visible in\n\"Target\":project/src/feat1/A.java.  That's great!\n\nBut the rebase fails with conflicts when things are moved or deleted in\n\"Source\". E.g. if \"Source\":project/feat1/A.java becomes\n\"Source\":project/feat2/A.java and I merge that commit into my branch in\n\"Target\" I get \n\n> CONFLICT (rename/rename): Rename\n> \"project/feat1/A.java\"->\"project/feat2/A.java\" in branch \"HEAD\" rename\n> \"project/feat1/A.java\"->\"project/src/feat1/A.java \" ...\n\nI do understand the conflict but I am asking whether there is a better way to\nuse git so that I can get around these merge problems.\n\nCiao\n  Chris\n"}]}