Browse Source

Don't allow DirCacheEntry with mode of 0

A 0 file mode in a DirCacheEntry is not a valid mode.  To C git
such a value indicates the record should not be present.  We already
were catching this bad state and exceptioning out when writing tree
objects to disk, but we did not fail when writing the dircache back
to disk.  This allowed JGit applications to create a dircache file
which C git would not like to read.

Instead of checking the mode during writes, we now check during
mutation.  This allows application bugs to be detected sooner and
closer to the cause site.  It also allows us to avoid checking most
of the records which we read in from disk, as we can assume these
are formatted correctly.

Some of our unit tests were not setting the FileMode on their test
entry, so they had to be updated to use REGULAR_FILE.

Change-Id: Ie412053c390b737c0ece57b8e063e4355ee32437
Originally: http://thread.gmane.org/gmane.comp.version-control.git/128214/focus=128213
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
CC: Adam W. Hawks <awhawks@writeme.com>
tags/v0.7.0
Shawn O. Pearce 14 years ago
parent
commit
29b8fa84e6

+ 4
- 1
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java View File

@@ -46,6 +46,7 @@ package org.eclipse.jgit.dircache;
import java.io.File;

import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.RepositoryTestCase;

public class DirCacheBasicTest extends RepositoryTestCase {
@@ -176,8 +177,10 @@ public class DirCacheBasicTest extends RepositoryTestCase {

final String[] paths = { "a.", "a.b", "a/b", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
for (int i = 0; i < paths.length; i++)
for (int i = 0; i < paths.length; i++) {
ents[i] = new DirCacheEntry(paths[i]);
ents[i].setFileMode(FileMode.REGULAR_FILE);
}

final DirCacheBuilder b = dc.builder();
for (int i = 0; i < ents.length; i++)

+ 25
- 4
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008, Google Inc.
* Copyright (C) 2008-2009, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -65,6 +65,20 @@ public class DirCacheBuilderTest extends RepositoryTestCase {
}
}

public void testBuildRejectsUnsetFileMode() throws Exception {
final DirCache dc = DirCache.newInCore();
final DirCacheBuilder b = dc.builder();
assertNotNull(b);

final DirCacheEntry e = new DirCacheEntry("a");
assertEquals(0, e.getRawMode());
try {
b.add(e);
} catch (IllegalArgumentException err) {
assertEquals("FileMode not set for path a", err.getMessage());
}
}

public void testBuildOneFile_FinishWriteCommit() throws Exception {
final String path = "a-file-path";
final FileMode mode = FileMode.REGULAR_FILE;
@@ -168,6 +182,7 @@ public class DirCacheBuilderTest extends RepositoryTestCase {
assertNotNull(b);

final DirCacheEntry entOrig = new DirCacheEntry(path);
entOrig.setFileMode(FileMode.REGULAR_FILE);
assertNotSame(path, entOrig.getPathString());
assertEquals(path, entOrig.getPathString());
b.add(entOrig);
@@ -191,8 +206,10 @@ public class DirCacheBuilderTest extends RepositoryTestCase {

final String[] paths = { "a.", "a.b", "a/b", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
for (int i = 0; i < paths.length; i++)
for (int i = 0; i < paths.length; i++) {
ents[i] = new DirCacheEntry(paths[i]);
ents[i].setFileMode(FileMode.REGULAR_FILE);
}

final DirCacheBuilder b = dc.builder();
for (int i = 0; i < ents.length; i++)
@@ -213,8 +230,10 @@ public class DirCacheBuilderTest extends RepositoryTestCase {

final String[] paths = { "a.", "a.b", "a/b", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
for (int i = 0; i < paths.length; i++)
for (int i = 0; i < paths.length; i++) {
ents[i] = new DirCacheEntry(paths[i]);
ents[i].setFileMode(FileMode.REGULAR_FILE);
}

final DirCacheBuilder b = dc.builder();
for (int i = ents.length - 1; i >= 0; i--)
@@ -235,8 +254,10 @@ public class DirCacheBuilderTest extends RepositoryTestCase {

final String[] paths = { "a.", "a.b", "a/b", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
for (int i = 0; i < paths.length; i++)
for (int i = 0; i < paths.length; i++) {
ents[i] = new DirCacheEntry(paths[i]);
ents[i].setFileMode(FileMode.REGULAR_FILE);
}
{
final DirCacheBuilder b = dc.builder();
for (int i = 0; i < ents.length; i++)

org.spearce.jgit.test/tst/org/spearce/jgit/dircache/DirCacheEntryTest.java → org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java View File

@@ -41,11 +41,12 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.spearce.jgit.dircache;
package org.eclipse.jgit.dircache;

import junit.framework.TestCase;

import org.spearce.jgit.lib.Constants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;

public class DirCacheEntryTest extends TestCase {
public void testIsValidPath() {
@@ -118,4 +119,40 @@ public class DirCacheEntryTest extends TestCase {
assertEquals("Invalid stage 4 for path a", err.getMessage());
}
}

public void testSetFileMode() {
final DirCacheEntry e = new DirCacheEntry("a");

assertEquals(0, e.getRawMode());

e.setFileMode(FileMode.REGULAR_FILE);
assertSame(FileMode.REGULAR_FILE, e.getFileMode());
assertEquals(FileMode.REGULAR_FILE.getBits(), e.getRawMode());

e.setFileMode(FileMode.EXECUTABLE_FILE);
assertSame(FileMode.EXECUTABLE_FILE, e.getFileMode());
assertEquals(FileMode.EXECUTABLE_FILE.getBits(), e.getRawMode());

e.setFileMode(FileMode.SYMLINK);
assertSame(FileMode.SYMLINK, e.getFileMode());
assertEquals(FileMode.SYMLINK.getBits(), e.getRawMode());

e.setFileMode(FileMode.GITLINK);
assertSame(FileMode.GITLINK, e.getFileMode());
assertEquals(FileMode.GITLINK.getBits(), e.getRawMode());

try {
e.setFileMode(FileMode.MISSING);
fail("incorrectly accepted FileMode.MISSING");
} catch (IllegalArgumentException err) {
assertEquals("Invalid mode 0 for path a", err.getMessage());
}

try {
e.setFileMode(FileMode.TREE);
fail("incorrectly accepted FileMode.TREE");
} catch (IllegalArgumentException err) {
assertEquals("Invalid mode 40000 for path a", err.getMessage());
}
}
}

+ 5
- 2
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheFindTest.java View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008, Google Inc.
* Copyright (C) 2008-2009, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -43,6 +43,7 @@

package org.eclipse.jgit.dircache;

import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.RepositoryTestCase;

public class DirCacheFindTest extends RepositoryTestCase {
@@ -51,8 +52,10 @@ public class DirCacheFindTest extends RepositoryTestCase {

final String[] paths = { "a.", "a/b", "a/c", "a/d", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
for (int i = 0; i < paths.length; i++)
for (int i = 0; i < paths.length; i++) {
ents[i] = new DirCacheEntry(paths[i]);
ents[i].setFileMode(FileMode.REGULAR_FILE);
}
final int aFirst = 1;
final int aLast = 3;


+ 4
- 2
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008, Google Inc.
* Copyright (C) 2008-2009, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -74,8 +74,10 @@ public class DirCacheIteratorTest extends RepositoryTestCase {

final String[] paths = { "a.", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
for (int i = 0; i < paths.length; i++)
for (int i = 0; i < paths.length; i++) {
ents[i] = new DirCacheEntry(paths[i]);
ents[i].setFileMode(FileMode.REGULAR_FILE);
}

final DirCacheBuilder b = dc.builder();
for (int i = 0; i < ents.length; i++)

+ 6
- 1
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheLargePathTest.java View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008, Google Inc.
* Copyright (C) 2008-2009, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -46,6 +46,7 @@ package org.eclipse.jgit.dircache;
import java.io.IOException;

import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.RepositoryTestCase;

public class DirCacheLargePathTest extends RepositoryTestCase {
@@ -76,6 +77,10 @@ public class DirCacheLargePathTest extends RepositoryTestCase {

final DirCacheEntry longEnt = new DirCacheEntry(longPath);
final DirCacheEntry shortEnt = new DirCacheEntry(shortPath);

longEnt.setFileMode(FileMode.REGULAR_FILE);
shortEnt.setFileMode(FileMode.REGULAR_FILE);

assertEquals(longPath, longEnt.getPathString());
assertEquals(shortPath, shortEnt.getPathString());


+ 11
- 4
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheTreeTest.java View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008, Google Inc.
* Copyright (C) 2008-2009, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -46,6 +46,7 @@ package org.eclipse.jgit.dircache;
import java.io.IOException;

import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.RepositoryTestCase;

public class DirCacheTreeTest extends RepositoryTestCase {
@@ -81,8 +82,10 @@ public class DirCacheTreeTest extends RepositoryTestCase {

final String[] paths = { "a.", "a/b", "a/c", "a/d", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
for (int i = 0; i < paths.length; i++)
for (int i = 0; i < paths.length; i++) {
ents[i] = new DirCacheEntry(paths[i]);
ents[i].setFileMode(FileMode.REGULAR_FILE);
}
final int aFirst = 1;
final int aLast = 3;

@@ -116,8 +119,10 @@ public class DirCacheTreeTest extends RepositoryTestCase {

final String[] paths = { "a.", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
for (int i = 0; i < paths.length; i++)
for (int i = 0; i < paths.length; i++) {
ents[i] = new DirCacheEntry(paths[i]);
ents[i].setFileMode(FileMode.REGULAR_FILE);
}
final int aFirst = 1;
final int aLast = 4;
final int acFirst = 2;
@@ -173,8 +178,10 @@ public class DirCacheTreeTest extends RepositoryTestCase {
final String B = String.format("b%2000s", "b");
final String[] paths = { A + ".", A + "." + B, A + "/" + B, A + "0" + B };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
for (int i = 0; i < paths.length; i++)
for (int i = 0; i < paths.length; i++) {
ents[i] = new DirCacheEntry(paths[i]);
ents[i].setFileMode(FileMode.REGULAR_FILE);
}

final DirCacheBuilder b = dc.builder();
for (int i = 0; i < ents.length; i++)

+ 5
- 3
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java View File

@@ -48,7 +48,6 @@ import java.io.IOException;
import java.util.Arrays;

import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.WindowCursor;
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
@@ -97,8 +96,13 @@ public class DirCacheBuilder extends BaseDirCacheEditor {
*
* @param newEntry
* the new entry to add.
* @throws IllegalArgumentException
* If the FileMode of the entry was not set by the caller.
*/
public void add(final DirCacheEntry newEntry) {
if (newEntry.getRawMode() == 0)
throw new IllegalArgumentException("FileMode not set for path "
+ newEntry.getPathString());
beforeAdd(newEntry);
fastAdd(newEntry);
}
@@ -194,8 +198,6 @@ public class DirCacheBuilder extends BaseDirCacheEditor {
}

private void beforeAdd(final DirCacheEntry newEntry) {
if (FileMode.TREE.equals(newEntry.getRawMode()))
throw bad(newEntry, "Adding subtree not allowed");
if (sorted && entryCnt > 0) {
final DirCacheEntry lastEntry = entries[entryCnt - 1];
final int cr = DirCache.cmp(lastEntry, newEntry);

+ 9
- 4
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008, Google Inc.
* Copyright (C) 2008-2009, Google Inc.
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
* and other copyright owners as documented in the project's IP log.
*
@@ -145,11 +145,16 @@ public class DirCacheEditor extends BaseDirCacheEditor {
}

final DirCacheEntry ent;
if (missing)
if (missing) {
ent = new DirCacheEntry(e.path);
else
e.apply(ent);
if (ent.getRawMode() == 0)
throw new IllegalArgumentException("FileMode not set"
+ " for path " + ent.getPathString());
} else {
ent = cache.getEntry(eIdx);
e.apply(ent);
e.apply(ent);
}
fastAdd(ent);
}


+ 10
- 0
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java View File

@@ -388,8 +388,18 @@ public class DirCacheEntry {
*
* @param mode
* the new mode constant.
* @throws IllegalArgumentException
* If {@code mode} is {@link FileMode#MISSING},
* {@link FileMode#TREE}, or any other type code not permitted
* in a tree object.
*/
public void setFileMode(final FileMode mode) {
switch (mode.getBits() & FileMode.TYPE_MASK) {
case FileMode.TYPE_MISSING:
case FileMode.TYPE_TREE:
throw new IllegalArgumentException("Invalid mode " + mode
+ " for path " + getPathString());
}
NB.encodeInt32(info, infoOffset + P_MODE, mode.getBits());
}


+ 0
- 4
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java View File

@@ -382,10 +382,6 @@ public class DirCacheTree {
}

final FileMode mode = e.getFileMode();
if (mode.getObjectType() == Constants.OBJ_BAD)
throw new IllegalStateException("Entry \"" + e.getPathString()
+ "\" has incorrect mode set up.");

size += mode.copyToLength();
size += ep.length - pathOffset;
size += OBJECT_ID_LENGTH + 2;

Loading…
Cancel
Save