Browse Source

Merge branch 'stable-3.5' into stable-3.6

* stable-3.5:
  JGit v3.5.3.201412180710-r
  JGit v3.4.2.201412180340-r
  ObjectChecker: Disallow names potentially mapping to ".git" on HFS+
  ObjectChecker: Disallow Windows shortname "GIT~1"
  ObjectChecker: Disallow ".git." and ".git<space>"
  Always ignore case when forbidding .git in ObjectChecker
  DirCache: Refuse to read files with invalid paths
  DirCache: Replace isValidPath with DirCacheCheckout.checkValidPath
  Replace "a." with "a-" in unit tests
  Apache HttpClientConnection: replace calls to deprecated LocalFile()
  Fix two nits about DirCacheEntry constructors
  Detect buffering failures while writing rebase todo file
  Deprecate TemporaryBuffer.LocalFile without parent directory
  Switch FileHeader.extractFileLines to TemporaryBuffer.Heap
  AmazonS3: Buffer pushed pack content under $GIT_DIR
  DirCache: Buffer TREE extension to $GIT_DIR

Change-Id: Iee8acbaa9d4d9047b550641db1b8845d64530785
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
stable-3.6
Matthias Sohn 10 years ago
parent
commit
75272ccdfc
  1. 6
      org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
  2. 2
      org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java
  3. 46
      org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java
  4. 2
      org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java
  5. 6
      org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java
  6. 2
      org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
  7. 8
      org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
  8. 10
      org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheFindTest.java
  9. 24
      org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java
  10. 8
      org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java
  11. 6
      org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheTreeTest.java
  12. 10
      org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java
  13. 247
      org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
  14. 2
      org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java
  15. 24
      org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TemporaryBufferTest.java
  16. 25
      org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
  17. 4
      org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
  18. 53
      org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
  19. 134
      org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
  20. 13
      org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java
  21. 7
      org.eclipse.jgit/src/org/eclipse/jgit/patch/FileHeader.java
  22. 12
      org.eclipse.jgit/src/org/eclipse/jgit/patch/Patch.java
  23. 8
      org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java
  24. 6
      org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java
  25. 9
      org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java

6
org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java

@ -309,19 +309,19 @@ public class HttpClientConnection implements HttpConnection {
public void setFixedLengthStreamingMode(int contentLength) { public void setFixedLengthStreamingMode(int contentLength) {
if (entity != null) if (entity != null)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
entity = new TemporaryBufferEntity(new LocalFile()); entity = new TemporaryBufferEntity(new LocalFile(null));
entity.setContentLength(contentLength); entity.setContentLength(contentLength);
} }
public OutputStream getOutputStream() throws IOException { public OutputStream getOutputStream() throws IOException {
if (entity == null) if (entity == null)
entity = new TemporaryBufferEntity(new LocalFile()); entity = new TemporaryBufferEntity(new LocalFile(null));
return entity.getBuffer(); return entity.getBuffer();
} }
public void setChunkedStreamingMode(int chunklen) { public void setChunkedStreamingMode(int chunklen) {
if (entity == null) if (entity == null)
entity = new TemporaryBufferEntity(new LocalFile()); entity = new TemporaryBufferEntity(new LocalFile(null));
entity.setChunked(true); entity.setChunked(true);
} }

2
org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java

@ -216,7 +216,7 @@ public class EGitPatchHistoryTest {
buf.destroy(); buf.destroy();
} }
commitId = line.substring("commit ".length()); commitId = line.substring("commit ".length());
buf = new TemporaryBuffer.LocalFile(); buf = new TemporaryBuffer.LocalFile(null);
} else if (buf != null) { } else if (buf != null) {
buf.write(line.getBytes("ISO-8859-1")); buf.write(line.getBytes("ISO-8859-1"));
buf.write('\n'); buf.write('\n');

46
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java vendored

@ -47,12 +47,19 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File; import java.io.File;
import java.text.MessageFormat;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.junit.MockSystemReader;
import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.util.SystemReader;
import org.junit.Test; import org.junit.Test;
public class DirCacheBasicTest extends RepositoryTestCase { public class DirCacheBasicTest extends RepositoryTestCase {
@ -190,7 +197,7 @@ public class DirCacheBasicTest extends RepositoryTestCase {
public void testBuildThenClear() throws Exception { public void testBuildThenClear() throws Exception {
final DirCache dc = db.readDirCache(); final DirCache dc = db.readDirCache();
final String[] paths = { "a.", "a.b", "a/b", "a0b" }; final String[] paths = { "a-", "a.b", "a/b", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; 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] = new DirCacheEntry(paths[i]);
@ -234,4 +241,41 @@ public class DirCacheBasicTest extends RepositoryTestCase {
final byte[] path = Constants.encode("a"); final byte[] path = Constants.encode("a");
assertEquals(-1, dc.findEntry(path, path.length)); assertEquals(-1, dc.findEntry(path, path.length));
} }
@Test
public void testRejectInvalidWindowsPaths() throws Exception {
SystemReader.setInstance(new MockSystemReader() {
{
setUnix();
}
});
String path = "src/con.txt";
DirCache dc = db.lockDirCache();
DirCacheBuilder b = dc.builder();
DirCacheEntry e = new DirCacheEntry(path);
e.setFileMode(FileMode.REGULAR_FILE);
e.setObjectId(new ObjectInserter.Formatter().idFor(
Constants.OBJ_BLOB,
Constants.encode(path)));
b.add(e);
b.commit();
db.readDirCache();
SystemReader.setInstance(new MockSystemReader() {
{
setWindows();
}
});
try {
db.readDirCache();
fail("should have rejected " + path);
} catch (CorruptObjectException err) {
assertEquals(MessageFormat.format(JGitText.get().invalidPath, path),
err.getMessage());
assertNotNull(err.getCause());
assertEquals("invalid name 'CON'", err.getCause().getMessage());
}
}
} }

2
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java vendored

@ -63,7 +63,7 @@ public class DirCacheBuilderIteratorTest extends RepositoryTestCase {
final DirCache dc = db.readDirCache(); final DirCache dc = db.readDirCache();
final FileMode mode = FileMode.REGULAR_FILE; final FileMode mode = FileMode.REGULAR_FILE;
final String[] paths = { "a.", "a/b", "a/c", "a/d", "a0b" }; final String[] paths = { "a-", "a/b", "a/c", "a/d", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; 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] = new DirCacheEntry(paths[i]);

6
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java vendored

@ -290,7 +290,7 @@ public class DirCacheBuilderTest extends RepositoryTestCase {
public void testAdd_InGitSortOrder() throws Exception { public void testAdd_InGitSortOrder() throws Exception {
final DirCache dc = db.readDirCache(); final DirCache dc = db.readDirCache();
final String[] paths = { "a.", "a.b", "a/b", "a0b" }; final String[] paths = { "a-", "a.b", "a/b", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; 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] = new DirCacheEntry(paths[i]);
@ -315,7 +315,7 @@ public class DirCacheBuilderTest extends RepositoryTestCase {
public void testAdd_ReverseGitSortOrder() throws Exception { public void testAdd_ReverseGitSortOrder() throws Exception {
final DirCache dc = db.readDirCache(); final DirCache dc = db.readDirCache();
final String[] paths = { "a.", "a.b", "a/b", "a0b" }; final String[] paths = { "a-", "a.b", "a/b", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; 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] = new DirCacheEntry(paths[i]);
@ -340,7 +340,7 @@ public class DirCacheBuilderTest extends RepositoryTestCase {
public void testBuilderClear() throws Exception { public void testBuilderClear() throws Exception {
final DirCache dc = db.readDirCache(); final DirCache dc = db.readDirCache();
final String[] paths = { "a.", "a.b", "a/b", "a0b" }; final String[] paths = { "a-", "a.b", "a/b", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; 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] = new DirCacheEntry(paths[i]);

2
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java vendored

@ -213,7 +213,7 @@ public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
assertV3TreeEntry(9, "newfile.txt", false, true, dc); assertV3TreeEntry(9, "newfile.txt", false, true, dc);
final ByteArrayOutputStream bos = new ByteArrayOutputStream(); final ByteArrayOutputStream bos = new ByteArrayOutputStream();
dc.writeTo(bos); dc.writeTo(null, bos);
final byte[] indexBytes = bos.toByteArray(); final byte[] indexBytes = bos.toByteArray();
final byte[] expectedBytes = IO.readFully(file); final byte[] expectedBytes = IO.readFully(file);
assertArrayEquals(expectedBytes, indexBytes); assertArrayEquals(expectedBytes, indexBytes);

8
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java vendored

@ -49,7 +49,6 @@ import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.junit.Test; import org.junit.Test;
@ -71,7 +70,12 @@ public class DirCacheEntryTest {
} }
private static boolean isValidPath(final String path) { private static boolean isValidPath(final String path) {
return DirCacheEntry.isValidPath(Constants.encode(path)); try {
DirCacheCheckout.checkValidPath(path);
return true;
} catch (InvalidPathException e) {
return false;
}
} }
@Test @Test

10
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheFindTest.java vendored

@ -56,7 +56,7 @@ public class DirCacheFindTest extends RepositoryTestCase {
public void testEntriesWithin() throws Exception { public void testEntriesWithin() throws Exception {
final DirCache dc = db.readDirCache(); final DirCache dc = db.readDirCache();
final String[] paths = { "a.", "a/b", "a/c", "a/d", "a0b" }; final String[] paths = { "a-", "a/b", "a/c", "a/d", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; 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] = new DirCacheEntry(paths[i]);
@ -96,13 +96,13 @@ public class DirCacheFindTest extends RepositoryTestCase {
assertSame(ents[i], aContents[i]); assertSame(ents[i], aContents[i]);
} }
assertNotNull(dc.getEntriesWithin("a.")); assertNotNull(dc.getEntriesWithin("a-"));
assertEquals(0, dc.getEntriesWithin("a.").length); assertEquals(0, dc.getEntriesWithin("a-").length);
assertNotNull(dc.getEntriesWithin("a0b")); assertNotNull(dc.getEntriesWithin("a0b"));
assertEquals(0, dc.getEntriesWithin("a0b.").length); assertEquals(0, dc.getEntriesWithin("a0b-").length);
assertNotNull(dc.getEntriesWithin("zoo")); assertNotNull(dc.getEntriesWithin("zoo"));
assertEquals(0, dc.getEntriesWithin("zoo.").length); assertEquals(0, dc.getEntriesWithin("zoo-").length);
} }
} }

24
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java vendored

@ -85,7 +85,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase {
public void testNoSubtree_NoTreeWalk() throws Exception { public void testNoSubtree_NoTreeWalk() throws Exception {
final DirCache dc = DirCache.newInCore(); final DirCache dc = DirCache.newInCore();
final String[] paths = { "a.", "a0b" }; final String[] paths = { "a-", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; 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] = new DirCacheEntry(paths[i]);
@ -111,7 +111,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase {
public void testNoSubtree_WithTreeWalk() throws Exception { public void testNoSubtree_WithTreeWalk() throws Exception {
final DirCache dc = DirCache.newInCore(); final DirCache dc = DirCache.newInCore();
final String[] paths = { "a.", "a0b" }; final String[] paths = { "a-", "a0b" };
final FileMode[] modes = { FileMode.EXECUTABLE_FILE, FileMode.GITLINK }; final FileMode[] modes = { FileMode.EXECUTABLE_FILE, FileMode.GITLINK };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
for (int i = 0; i < paths.length; i++) { for (int i = 0; i < paths.length; i++) {
@ -144,7 +144,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase {
public void testSingleSubtree_NoRecursion() throws Exception { public void testSingleSubtree_NoRecursion() throws Exception {
final DirCache dc = DirCache.newInCore(); final DirCache dc = DirCache.newInCore();
final String[] paths = { "a.", "a/b", "a/c", "a/d", "a0b" }; final String[] paths = { "a-", "a/b", "a/c", "a/d", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; 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] = new DirCacheEntry(paths[i]);
@ -156,7 +156,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase {
b.add(ents[i]); b.add(ents[i]);
b.finish(); b.finish();
final String[] expPaths = { "a.", "a", "a0b" }; final String[] expPaths = { "a-", "a", "a0b" };
final FileMode[] expModes = { FileMode.REGULAR_FILE, FileMode.TREE, final FileMode[] expModes = { FileMode.REGULAR_FILE, FileMode.TREE,
FileMode.REGULAR_FILE }; FileMode.REGULAR_FILE };
final int expPos[] = { 0, -1, 4 }; final int expPos[] = { 0, -1, 4 };
@ -189,7 +189,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase {
final DirCache dc = DirCache.newInCore(); final DirCache dc = DirCache.newInCore();
final FileMode mode = FileMode.REGULAR_FILE; final FileMode mode = FileMode.REGULAR_FILE;
final String[] paths = { "a.", "a/b", "a/c", "a/d", "a0b" }; final String[] paths = { "a-", "a/b", "a/c", "a/d", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; 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] = new DirCacheEntry(paths[i]);
@ -224,7 +224,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase {
final DirCache dc = DirCache.newInCore(); final DirCache dc = DirCache.newInCore();
final FileMode mode = FileMode.REGULAR_FILE; final FileMode mode = FileMode.REGULAR_FILE;
final String[] paths = { "a.", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" }; final String[] paths = { "a-", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; 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] = new DirCacheEntry(paths[i]);
@ -258,7 +258,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase {
final DirCache dc = DirCache.newInCore(); final DirCache dc = DirCache.newInCore();
final FileMode mode = FileMode.REGULAR_FILE; final FileMode mode = FileMode.REGULAR_FILE;
final String[] paths = { "a.", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" }; final String[] paths = { "a-", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; 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] = new DirCacheEntry(paths[i]);
@ -272,7 +272,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase {
DirCacheIterator dci = new DirCacheIterator(dc); DirCacheIterator dci = new DirCacheIterator(dc);
assertFalse(dci.eof()); assertFalse(dci.eof());
assertEquals("a.", dci.getEntryPathString()); assertEquals("a-", dci.getEntryPathString());
dci.next(1); dci.next(1);
assertFalse(dci.eof()); assertFalse(dci.eof());
assertEquals("a", dci.getEntryPathString()); assertEquals("a", dci.getEntryPathString());
@ -285,7 +285,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase {
// same entries the second time // same entries the second time
dci.reset(); dci.reset();
assertFalse(dci.eof()); assertFalse(dci.eof());
assertEquals("a.", dci.getEntryPathString()); assertEquals("a-", dci.getEntryPathString());
dci.next(1); dci.next(1);
assertFalse(dci.eof()); assertFalse(dci.eof());
assertEquals("a", dci.getEntryPathString()); assertEquals("a", dci.getEntryPathString());
@ -304,12 +304,12 @@ public class DirCacheIteratorTest extends RepositoryTestCase {
assertEquals("a", dci.getEntryPathString()); assertEquals("a", dci.getEntryPathString());
dci.back(1); dci.back(1);
assertFalse(dci.eof()); assertFalse(dci.eof());
assertEquals("a.", dci.getEntryPathString()); assertEquals("a-", dci.getEntryPathString());
assertTrue(dci.first()); assertTrue(dci.first());
// forward // forward
assertFalse(dci.eof()); assertFalse(dci.eof());
assertEquals("a.", dci.getEntryPathString()); assertEquals("a-", dci.getEntryPathString());
dci.next(1); dci.next(1);
assertFalse(dci.eof()); assertFalse(dci.eof());
assertEquals("a", dci.getEntryPathString()); assertEquals("a", dci.getEntryPathString());
@ -385,7 +385,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase {
final DirCache dc = DirCache.newInCore(); final DirCache dc = DirCache.newInCore();
final FileMode mode = FileMode.REGULAR_FILE; final FileMode mode = FileMode.REGULAR_FILE;
final String[] paths = { "a.", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" }; final String[] paths = { "a-", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; 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] = new DirCacheEntry(paths[i]);

8
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java vendored

@ -113,21 +113,23 @@ public class DirCachePathEditTest {
DirCache dc = DirCache.newInCore(); DirCache dc = DirCache.newInCore();
DirCacheEditor editor = dc.editor(); DirCacheEditor editor = dc.editor();
editor.add(new AddEdit("a/b")); editor.add(new AddEdit("a/b"));
editor.add(new AddEdit("a.")); editor.add(new AddEdit("a-"));
editor.add(new AddEdit("ab")); editor.add(new AddEdit("ab"));
editor.finish(); editor.finish();
assertEquals(3, dc.getEntryCount()); assertEquals(3, dc.getEntryCount());
// Validate sort order // Validate sort order
assertEquals("a.", dc.getEntry(0).getPathString()); assertEquals("a-", dc.getEntry(0).getPathString());
assertEquals("a/b", dc.getEntry(1).getPathString()); assertEquals("a/b", dc.getEntry(1).getPathString());
assertEquals("ab", dc.getEntry(2).getPathString()); assertEquals("ab", dc.getEntry(2).getPathString());
editor = dc.editor(); editor = dc.editor();
// Sort order should not confuse DeleteTree // Sort order should not confuse DeleteTree
editor.add(new DirCacheEditor.DeleteTree("a")); editor.add(new DirCacheEditor.DeleteTree("a"));
editor.finish(); editor.finish();
assertEquals(2, dc.getEntryCount()); assertEquals(2, dc.getEntryCount());
assertEquals("a.", dc.getEntry(0).getPathString()); assertEquals("a-", dc.getEntry(0).getPathString());
assertEquals("ab", dc.getEntry(1).getPathString()); assertEquals("ab", dc.getEntry(1).getPathString());
} }

6
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheTreeTest.java vendored

@ -92,7 +92,7 @@ public class DirCacheTreeTest extends RepositoryTestCase {
public void testSingleSubtree() throws Exception { public void testSingleSubtree() throws Exception {
final DirCache dc = db.readDirCache(); final DirCache dc = db.readDirCache();
final String[] paths = { "a.", "a/b", "a/c", "a/d", "a0b" }; final String[] paths = { "a-", "a/b", "a/c", "a/d", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; 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] = new DirCacheEntry(paths[i]);
@ -130,7 +130,7 @@ public class DirCacheTreeTest extends RepositoryTestCase {
public void testTwoLevelSubtree() throws Exception { public void testTwoLevelSubtree() throws Exception {
final DirCache dc = db.readDirCache(); final DirCache dc = db.readDirCache();
final String[] paths = { "a.", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" }; final String[] paths = { "a-", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; 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] = new DirCacheEntry(paths[i]);
@ -190,7 +190,7 @@ public class DirCacheTreeTest extends RepositoryTestCase {
final String A = String.format("a%2000s", "a"); final String A = String.format("a%2000s", "a");
final String B = String.format("b%2000s", "b"); final String B = String.format("b%2000s", "b");
final String[] paths = { A + ".", A + "." + B, A + "/" + B, A + "0" + B }; final String[] paths = { A + "-", A + "-" + B, A + "/" + B, A + "0" + B };
final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; 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] = new DirCacheEntry(paths[i]);

10
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java

@ -186,10 +186,7 @@ public class DirCacheCheckoutMaliciousPathTest extends RepositoryTestCase {
@Test @Test
public void testMaliciousGitPathEndSpaceUnixOk() throws Exception { public void testMaliciousGitPathEndSpaceUnixOk() throws Exception {
if (File.separatorChar == '\\') testMaliciousPathBadFirstCheckout(".git ", "konfig");
return; // cannot emulate Unix on Windows for this test
((MockSystemReader) SystemReader.getInstance()).setUnix();
testMaliciousPathGoodFirstCheckout(".git ", "konfig");
} }
@Test @Test
@ -212,10 +209,7 @@ public class DirCacheCheckoutMaliciousPathTest extends RepositoryTestCase {
@Test @Test
public void testMaliciousGitPathEndDotUnixOk() throws Exception { public void testMaliciousGitPathEndDotUnixOk() throws Exception {
if (File.separatorChar == '\\') testMaliciousPathBadFirstCheckout(".git.", "konfig");
return; // cannot emulate Unix on Windows for this test
((MockSystemReader) SystemReader.getInstance()).setUnix();
testMaliciousPathGoodFirstCheckout(".git.", "konfig");
} }
@Test @Test

247
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java

@ -1295,12 +1295,11 @@ public class ObjectCheckerTest {
} }
@Test @Test
public void testInvalidTreeNameIsMixedCaseGitWindows() { public void testInvalidTreeNameIsMixedCaseGit() {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
entry(b, "100644 .GiT"); entry(b, "100644 .GiT");
byte[] data = Constants.encodeASCII(b.toString()); byte[] data = Constants.encodeASCII(b.toString());
try { try {
checker.setSafeForWindows(true);
checker.checkTree(data); checker.checkTree(data);
fail("incorrectly accepted an invalid tree"); fail("incorrectly accepted an invalid tree");
} catch (CorruptObjectException e) { } catch (CorruptObjectException e) {
@ -1309,19 +1308,255 @@ public class ObjectCheckerTest {
} }
@Test @Test
public void testInvalidTreeNameIsMixedCaseGitMacOS() { public void testInvalidTreeNameIsMacHFSGit() {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
entry(b, "100644 .GiT"); entry(b, "100644 .gi\u200Ct");
byte[] data = Constants.encodeASCII(b.toString()); byte[] data = Constants.encode(b.toString());
try { try {
checker.setSafeForMacOS(true); checker.setSafeForMacOS(true);
checker.checkTree(data); checker.checkTree(data);
fail("incorrectly accepted an invalid tree"); fail("incorrectly accepted an invalid tree");
} catch (CorruptObjectException e) { } catch (CorruptObjectException e) {
assertEquals("invalid name '.GiT'", e.getMessage()); assertEquals(
"invalid name '.gi\u200Ct' contains ignorable Unicode characters",
e.getMessage());
}
}
@Test
public void testInvalidTreeNameIsMacHFSGit2() {
StringBuilder b = new StringBuilder();
entry(b, "100644 \u206B.git");
byte[] data = Constants.encode(b.toString());
try {
checker.setSafeForMacOS(true);
checker.checkTree(data);
fail("incorrectly accepted an invalid tree");
} catch (CorruptObjectException e) {
assertEquals(
"invalid name '\u206B.git' contains ignorable Unicode characters",
e.getMessage());
}
}
@Test
public void testInvalidTreeNameIsMacHFSGit3() {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git\uFEFF");
byte[] data = Constants.encode(b.toString());
try {
checker.setSafeForMacOS(true);
checker.checkTree(data);
fail("incorrectly accepted an invalid tree");
} catch (CorruptObjectException e) {
assertEquals(
"invalid name '.git\uFEFF' contains ignorable Unicode characters",
e.getMessage());
}
}
private static byte[] concat(byte[] b1, byte[] b2) {
byte[] data = new byte[b1.length + b2.length];
System.arraycopy(b1, 0, data, 0, b1.length);
System.arraycopy(b2, 0, data, b1.length, b2.length);
return data;
}
@Test
public void testInvalidTreeNameIsMacHFSGitCorruptUTF8AtEnd() {
byte[] data = concat(Constants.encode("100644 .git"),
new byte[] { (byte) 0xef });
StringBuilder b = new StringBuilder();
entry(b, "");
data = concat(data, Constants.encode(b.toString()));
try {
checker.setSafeForMacOS(true);
checker.checkTree(data);
fail("incorrectly accepted an invalid tree");
} catch (CorruptObjectException e) {
assertEquals(
"invalid name contains byte sequence '0xef' which is not a valid UTF-8 character",
e.getMessage());
}
}
@Test
public void testInvalidTreeNameIsMacHFSGitCorruptUTF8AtEnd2() {
byte[] data = concat(Constants.encode("100644 .git"), new byte[] {
(byte) 0xe2, (byte) 0xab });
StringBuilder b = new StringBuilder();
entry(b, "");
data = concat(data, Constants.encode(b.toString()));
try {
checker.setSafeForMacOS(true);
checker.checkTree(data);
fail("incorrectly accepted an invalid tree");
} catch (CorruptObjectException e) {
assertEquals(
"invalid name contains byte sequence '0xe2ab' which is not a valid UTF-8 character",
e.getMessage());
}
}
@Test
public void testInvalidTreeNameIsNotMacHFSGit()
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git\u200Cx");
byte[] data = Constants.encode(b.toString());
checker.setSafeForMacOS(true);
checker.checkTree(data);
}
@Test
public void testInvalidTreeNameIsNotMacHFSGit2()
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .kit\u200C");
byte[] data = Constants.encode(b.toString());
checker.setSafeForMacOS(true);
checker.checkTree(data);
}
@Test
public void testInvalidTreeNameIsNotMacHFSGitOtherPlatform()
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git\u200C");
byte[] data = Constants.encode(b.toString());
checker.checkTree(data);
}
@Test
public void testInvalidTreeNameIsDotGitDot() {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git.");
byte[] data = Constants.encodeASCII(b.toString());
try {
checker.checkTree(data);
fail("incorrectly accepted an invalid tree");
} catch (CorruptObjectException e) {
assertEquals("invalid name '.git.'", e.getMessage());
}
}
@Test
public void testValidTreeNameIsDotGitDotDot()
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git..");
checker.checkTree(Constants.encodeASCII(b.toString()));
}
@Test
public void testInvalidTreeNameIsDotGitSpace() {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git ");
byte[] data = Constants.encodeASCII(b.toString());
try {
checker.checkTree(data);
fail("incorrectly accepted an invalid tree");
} catch (CorruptObjectException e) {
assertEquals("invalid name '.git '", e.getMessage());
} }
} }
@Test
public void testInvalidTreeNameIsDotGitSomething()
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .gitfoobar");
byte[] data = Constants.encodeASCII(b.toString());
checker.checkTree(data);
}
@Test
public void testInvalidTreeNameIsDotGitSomethingSpaceSomething()
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .gitfoo bar");
byte[] data = Constants.encodeASCII(b.toString());
checker.checkTree(data);
}
@Test
public void testInvalidTreeNameIsDotGitSomethingDot()
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .gitfoobar.");
byte[] data = Constants.encodeASCII(b.toString());
checker.checkTree(data);
}
@Test
public void testInvalidTreeNameIsDotGitSomethingDotDot()
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .gitfoobar..");
byte[] data = Constants.encodeASCII(b.toString());
checker.checkTree(data);
}
@Test
public void testInvalidTreeNameIsDotGitDotSpace() {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git. ");
byte[] data = Constants.encodeASCII(b.toString());
try {
checker.checkTree(data);
fail("incorrectly accepted an invalid tree");
} catch (CorruptObjectException e) {
assertEquals("invalid name '.git. '", e.getMessage());
}
}
@Test
public void testInvalidTreeNameIsDotGitSpaceDot() {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git . ");
byte[] data = Constants.encodeASCII(b.toString());
try {
checker.checkTree(data);
fail("incorrectly accepted an invalid tree");
} catch (CorruptObjectException e) {
assertEquals("invalid name '.git . '", e.getMessage());
}
}
@Test
public void testInvalidTreeNameIsGITTilde1() {
StringBuilder b = new StringBuilder();
entry(b, "100644 GIT~1");
byte[] data = Constants.encodeASCII(b.toString());
try {
checker.checkTree(data);
fail("incorrectly accepted an invalid tree");
} catch (CorruptObjectException e) {
assertEquals("invalid name 'GIT~1'", e.getMessage());
}
}
@Test
public void testInvalidTreeNameIsGiTTilde1() {
StringBuilder b = new StringBuilder();
entry(b, "100644 GiT~1");
byte[] data = Constants.encodeASCII(b.toString());
try {
checker.checkTree(data);
fail("incorrectly accepted an invalid tree");
} catch (CorruptObjectException e) {
assertEquals("invalid name 'GiT~1'", e.getMessage());
}
}
@Test
public void testValidTreeNameIsGitTilde11() throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 GIT~11");
byte[] data = Constants.encodeASCII(b.toString());
checker.checkTree(data);
}
@Test @Test
public void testInvalidTreeTruncatedInName() { public void testInvalidTreeTruncatedInName() {
final StringBuilder b = new StringBuilder(); final StringBuilder b = new StringBuilder();

2
org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java

@ -169,7 +169,7 @@ public class PathFilterGroupTest {
} }
// less obvious due to git sorting order // less obvious due to git sorting order
filter.include(fakeWalk("d.")); filter.include(fakeWalk("d-"));
// less obvious due to git sorting order // less obvious due to git sorting order
try { try {

24
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TemporaryBufferTest.java

@ -59,7 +59,7 @@ import org.junit.Test;
public class TemporaryBufferTest { public class TemporaryBufferTest {
@Test @Test
public void testEmpty() throws IOException { public void testEmpty() throws IOException {
final TemporaryBuffer b = new TemporaryBuffer.LocalFile(); final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
try { try {
b.close(); b.close();
assertEquals(0, b.length()); assertEquals(0, b.length());
@ -73,7 +73,7 @@ public class TemporaryBufferTest {
@Test @Test
public void testOneByte() throws IOException { public void testOneByte() throws IOException {
final TemporaryBuffer b = new TemporaryBuffer.LocalFile(); final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
final byte test = (byte) new TestRng(getName()).nextInt(); final byte test = (byte) new TestRng(getName()).nextInt();
try { try {
b.write(test); b.write(test);
@ -100,7 +100,7 @@ public class TemporaryBufferTest {
@Test @Test
public void testOneBlock_BulkWrite() throws IOException { public void testOneBlock_BulkWrite() throws IOException {
final TemporaryBuffer b = new TemporaryBuffer.LocalFile(); final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
final byte[] test = new TestRng(getName()) final byte[] test = new TestRng(getName())
.nextBytes(TemporaryBuffer.Block.SZ); .nextBytes(TemporaryBuffer.Block.SZ);
try { try {
@ -131,7 +131,7 @@ public class TemporaryBufferTest {
@Test @Test
public void testOneBlockAndHalf_BulkWrite() throws IOException { public void testOneBlockAndHalf_BulkWrite() throws IOException {
final TemporaryBuffer b = new TemporaryBuffer.LocalFile(); final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
final byte[] test = new TestRng(getName()) final byte[] test = new TestRng(getName())
.nextBytes(TemporaryBuffer.Block.SZ * 3 / 2); .nextBytes(TemporaryBuffer.Block.SZ * 3 / 2);
try { try {
@ -162,7 +162,7 @@ public class TemporaryBufferTest {
@Test @Test
public void testOneBlockAndHalf_SingleWrite() throws IOException { public void testOneBlockAndHalf_SingleWrite() throws IOException {
final TemporaryBuffer b = new TemporaryBuffer.LocalFile(); final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
final byte[] test = new TestRng(getName()) final byte[] test = new TestRng(getName())
.nextBytes(TemporaryBuffer.Block.SZ * 3 / 2); .nextBytes(TemporaryBuffer.Block.SZ * 3 / 2);
try { try {
@ -191,7 +191,7 @@ public class TemporaryBufferTest {
@Test @Test
public void testOneBlockAndHalf_Copy() throws IOException { public void testOneBlockAndHalf_Copy() throws IOException {
final TemporaryBuffer b = new TemporaryBuffer.LocalFile(); final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
final byte[] test = new TestRng(getName()) final byte[] test = new TestRng(getName())
.nextBytes(TemporaryBuffer.Block.SZ * 3 / 2); .nextBytes(TemporaryBuffer.Block.SZ * 3 / 2);
try { try {
@ -221,7 +221,7 @@ public class TemporaryBufferTest {
@Test @Test
public void testLarge_SingleWrite() throws IOException { public void testLarge_SingleWrite() throws IOException {
final TemporaryBuffer b = new TemporaryBuffer.LocalFile(); final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
final byte[] test = new TestRng(getName()) final byte[] test = new TestRng(getName())
.nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 3); .nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 3);
try { try {
@ -263,7 +263,7 @@ public class TemporaryBufferTest {
@Test @Test
public void testInCoreLimit_SwitchOnAppendByte() throws IOException { public void testInCoreLimit_SwitchOnAppendByte() throws IOException {
final TemporaryBuffer b = new TemporaryBuffer.LocalFile(); final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
final byte[] test = new TestRng(getName()) final byte[] test = new TestRng(getName())
.nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT + 1); .nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT + 1);
try { try {
@ -292,7 +292,7 @@ public class TemporaryBufferTest {
@Test @Test
public void testInCoreLimit_SwitchBeforeAppendByte() throws IOException { public void testInCoreLimit_SwitchBeforeAppendByte() throws IOException {
final TemporaryBuffer b = new TemporaryBuffer.LocalFile(); final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
final byte[] test = new TestRng(getName()) final byte[] test = new TestRng(getName())
.nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 3); .nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 3);
try { try {
@ -321,7 +321,7 @@ public class TemporaryBufferTest {
@Test @Test
public void testInCoreLimit_SwitchOnCopy() throws IOException { public void testInCoreLimit_SwitchOnCopy() throws IOException {
final TemporaryBuffer b = new TemporaryBuffer.LocalFile(); final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
final byte[] test = new TestRng(getName()) final byte[] test = new TestRng(getName())
.nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2); .nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2);
try { try {
@ -354,7 +354,7 @@ public class TemporaryBufferTest {
@Test @Test
public void testDestroyWhileOpen() throws IOException { public void testDestroyWhileOpen() throws IOException {
@SuppressWarnings("resource" /* java 7 */) @SuppressWarnings("resource" /* java 7 */)
final TemporaryBuffer b = new TemporaryBuffer.LocalFile(); final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
try { try {
b.write(new TestRng(getName()) b.write(new TestRng(getName())
.nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2)); .nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2));
@ -365,7 +365,7 @@ public class TemporaryBufferTest {
@Test @Test
public void testRandomWrites() throws IOException { public void testRandomWrites() throws IOException {
final TemporaryBuffer b = new TemporaryBuffer.LocalFile(); final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null);
final TestRng rng = new TestRng(getName()); final TestRng rng = new TestRng(getName());
final int max = TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2; final int max = TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2;
final byte[] expect = new byte[max]; final byte[] expect = new byte[max];

25
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java vendored

@ -607,7 +607,8 @@ public class DirCache {
final LockFile tmp = myLock; final LockFile tmp = myLock;
requireLocked(tmp); requireLocked(tmp);
try { try {
writeTo(new SafeBufferedOutputStream(tmp.getOutputStream())); writeTo(liveFile.getParentFile(),
new SafeBufferedOutputStream(tmp.getOutputStream()));
} catch (IOException err) { } catch (IOException err) {
tmp.unlock(); tmp.unlock();
throw err; throw err;
@ -620,7 +621,7 @@ public class DirCache {
} }
} }
void writeTo(final OutputStream os) throws IOException { void writeTo(File dir, final OutputStream os) throws IOException {
final MessageDigest foot = Constants.newMessageDigest(); final MessageDigest foot = Constants.newMessageDigest();
final DigestOutputStream dos = new DigestOutputStream(os, foot); final DigestOutputStream dos = new DigestOutputStream(os, foot);
@ -670,14 +671,18 @@ public class DirCache {
} }
if (writeTree) { if (writeTree) {
final TemporaryBuffer bb = new TemporaryBuffer.LocalFile(); TemporaryBuffer bb = new TemporaryBuffer.LocalFile(dir, 5 << 20);
tree.write(tmp, bb); try {
bb.close(); tree.write(tmp, bb);
bb.close();
NB.encodeInt32(tmp, 0, EXT_TREE);
NB.encodeInt32(tmp, 4, (int) bb.length()); NB.encodeInt32(tmp, 0, EXT_TREE);
dos.write(tmp, 0, 8); NB.encodeInt32(tmp, 4, (int) bb.length());
bb.writeTo(dos, null); dos.write(tmp, 0, 8);
bb.writeTo(dos, null);
} finally {
bb.destroy();
}
} }
writeIndexChecksum = foot.digest(); writeIndexChecksum = foot.digest();
os.write(writeIndexChecksum); os.write(writeIndexChecksum);

4
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java vendored

@ -1291,7 +1291,9 @@ public class DirCacheCheckout {
try { try {
SystemReader.getInstance().checkPath(path); SystemReader.getInstance().checkPath(path);
} catch (CorruptObjectException e) { } catch (CorruptObjectException e) {
throw new InvalidPathException(path); InvalidPathException p = new InvalidPathException(path);
p.initCause(e);
throw p;
} }
} }

53
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java vendored

@ -56,6 +56,7 @@ import java.security.MessageDigest;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Arrays; import java.util.Arrays;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
@ -64,7 +65,6 @@ import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.MutableInteger; import org.eclipse.jgit.util.MutableInteger;
import org.eclipse.jgit.util.NB; import org.eclipse.jgit.util.NB;
import org.eclipse.jgit.util.SystemReader;
/** /**
* A single file (or stage of a file) in a {@link DirCache}. * A single file (or stage of a file) in a {@link DirCache}.
@ -190,6 +190,16 @@ public class DirCacheEntry {
md.update((byte) 0); md.update((byte) 0);
} }
try {
DirCacheCheckout.checkValidPath(toString(path));
} catch (InvalidPathException e) {
CorruptObjectException p =
new CorruptObjectException(e.getMessage());
if (e.getCause() != null)
p.initCause(e.getCause());
throw p;
}
// Index records are padded out to the next 8 byte alignment // Index records are padded out to the next 8 byte alignment
// for historical reasons related to how C Git read the files. // for historical reasons related to how C Git read the files.
// //
@ -203,7 +213,6 @@ public class DirCacheEntry {
if (mightBeRacilyClean(smudge_s, smudge_ns)) if (mightBeRacilyClean(smudge_s, smudge_ns))
smudgeRacilyClean(); smudgeRacilyClean();
} }
/** /**
@ -217,7 +226,7 @@ public class DirCacheEntry {
* or DirCache file. * or DirCache file.
*/ */
public DirCacheEntry(final String newPath) { public DirCacheEntry(final String newPath) {
this(Constants.encode(newPath)); this(Constants.encode(newPath), STAGE_0);
} }
/** /**
@ -266,11 +275,11 @@ public class DirCacheEntry {
*/ */
@SuppressWarnings("boxing") @SuppressWarnings("boxing")
public DirCacheEntry(final byte[] newPath, final int stage) { public DirCacheEntry(final byte[] newPath, final int stage) {
if (!isValidPath(newPath)) DirCacheCheckout.checkValidPath(toString(newPath));
throw new InvalidPathException(toString(newPath));
if (stage < 0 || 3 < stage) if (stage < 0 || 3 < stage)
throw new IllegalArgumentException(MessageFormat.format(JGitText.get().invalidStageForPath throw new IllegalArgumentException(MessageFormat.format(
, stage, toString(newPath))); JGitText.get().invalidStageForPath,
stage, toString(newPath)));
info = new byte[INFO_LEN]; info = new byte[INFO_LEN];
infoOffset = 0; infoOffset = 0;
@ -725,36 +734,6 @@ public class DirCacheEntry {
return Constants.CHARSET.decode(ByteBuffer.wrap(path)).toString(); return Constants.CHARSET.decode(ByteBuffer.wrap(path)).toString();
} }
static boolean isValidPath(final byte[] path) {
if (path.length == 0)
return false; // empty path is not permitted.
boolean componentHasChars = false;
for (final byte c : path) {
switch (c) {
case 0:
return false; // NUL is never allowed within the path.
case '/':
if (componentHasChars)
componentHasChars = false;
else
return false;
break;
case '\\':
case ':':
// Tree's never have a backslash in them, not even on Windows
// but even there we regard it as an invalid path
if (SystemReader.getInstance().isWindows())
return false;
//$FALL-THROUGH$
default:
componentHasChars = true;
}
}
return componentHasChars;
}
static int getMaximumInfoLength(boolean extended) { static int getMaximumInfoLength(boolean extended) {
return extended ? INFO_LEN_EXTENDED : INFO_LEN; return extended ? INFO_LEN_EXTENDED : INFO_LEN;
} }

134
org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java

@ -492,13 +492,27 @@ public class ObjectChecker {
throw new CorruptObjectException("invalid name '..'"); throw new CorruptObjectException("invalid name '..'");
break; break;
case 4: case 4:
if (isDotGit(raw, ptr + 1)) if (isGit(raw, ptr + 1))
throw new CorruptObjectException(String.format(
"invalid name '%s'",
RawParseUtils.decode(raw, ptr, end)));
break;
default:
if (end - ptr > 4 && isNormalizedGit(raw, ptr + 1, end))
throw new CorruptObjectException(String.format( throw new CorruptObjectException(String.format(
"invalid name '%s'", "invalid name '%s'",
RawParseUtils.decode(raw, ptr, end))); RawParseUtils.decode(raw, ptr, end)));
} }
} else if (isGitTilde1(raw, ptr, end)) {
throw new CorruptObjectException(String.format("invalid name '%s'",
RawParseUtils.decode(raw, ptr, end)));
} }
if (macosx && isMacHFSGit(raw, ptr, end))
throw new CorruptObjectException(String.format(
"invalid name '%s' contains ignorable Unicode characters",
RawParseUtils.decode(raw, ptr, end)));
if (windows) { if (windows) {
// Windows ignores space and dot at end of file name. // Windows ignores space and dot at end of file name.
if (raw[end - 1] == ' ' || raw[end - 1] == '.') if (raw[end - 1] == ' ' || raw[end - 1] == '.')
@ -509,6 +523,88 @@ public class ObjectChecker {
} }
} }
// Mac's HFS+ folds permutations of ".git" and Unicode ignorable characters
// to ".git" therefore we should prevent such names
private static boolean isMacHFSGit(byte[] raw, int ptr, int end)
throws CorruptObjectException {
boolean ignorable = false;
byte[] git = new byte[] { '.', 'g', 'i', 't' };
int g = 0;
while (ptr < end) {
switch (raw[ptr]) {
case (byte) 0xe2: // http://www.utf8-chartable.de/unicode-utf8-table.pl?start=8192
checkTruncatedIgnorableUTF8(raw, ptr, end);
switch (raw[ptr + 1]) {
case (byte) 0x80:
switch (raw[ptr + 2]) {
case (byte) 0x8c: // U+200C 0xe2808c ZERO WIDTH NON-JOINER
case (byte) 0x8d: // U+200D 0xe2808d ZERO WIDTH JOINER
case (byte) 0x8e: // U+200E 0xe2808e LEFT-TO-RIGHT MARK
case (byte) 0x8f: // U+200F 0xe2808f RIGHT-TO-LEFT MARK
case (byte) 0xaa: // U+202A 0xe280aa LEFT-TO-RIGHT EMBEDDING
case (byte) 0xab: // U+202B 0xe280ab RIGHT-TO-LEFT EMBEDDING
case (byte) 0xac: // U+202C 0xe280ac POP DIRECTIONAL FORMATTING
case (byte) 0xad: // U+202D 0xe280ad LEFT-TO-RIGHT OVERRIDE
case (byte) 0xae: // U+202E 0xe280ae RIGHT-TO-LEFT OVERRIDE
ignorable = true;
ptr += 3;
continue;
default:
return false;
}
case (byte) 0x81:
switch (raw[ptr + 2]) {
case (byte) 0xaa: // U+206A 0xe281aa INHIBIT SYMMETRIC SWAPPING
case (byte) 0xab: // U+206B 0xe281ab ACTIVATE SYMMETRIC SWAPPING
case (byte) 0xac: // U+206C 0xe281ac INHIBIT ARABIC FORM SHAPING
case (byte) 0xad: // U+206D 0xe281ad ACTIVATE ARABIC FORM SHAPING
case (byte) 0xae: // U+206E 0xe281ae NATIONAL DIGIT SHAPES
case (byte) 0xaf: // U+206F 0xe281af NOMINAL DIGIT SHAPES
ignorable = true;
ptr += 3;
continue;
default:
return false;
}
}
break;
case (byte) 0xef: // http://www.utf8-chartable.de/unicode-utf8-table.pl?start=65024
checkTruncatedIgnorableUTF8(raw, ptr, end);
// U+FEFF 0xefbbbf ZERO WIDTH NO-BREAK SPACE
if ((raw[ptr + 1] == (byte) 0xbb)
&& (raw[ptr + 2] == (byte) 0xbf)) {
ignorable = true;
ptr += 3;
continue;
}
return false;
default:
if (g == 4)
return false;
if (raw[ptr++] != git[g++])
return false;
}
}
if (g == 4 && ignorable)
return true;
return false;
}
private static void checkTruncatedIgnorableUTF8(byte[] raw, int ptr, int end)
throws CorruptObjectException {
if ((ptr + 2) >= end)
throw new CorruptObjectException(MessageFormat.format(
"invalid name contains byte sequence ''{0}'' which is not a valid UTF-8 character",
toHexString(raw, ptr, end)));
}
private static String toHexString(byte[] raw, int ptr, int end) {
StringBuilder b = new StringBuilder("0x"); //$NON-NLS-1$
for (int i = ptr; i < end; i++)
b.append(String.format("%02x", Byte.valueOf(raw[i]))); //$NON-NLS-1$
return b.toString();
}
private static void checkNotWindowsDevice(byte[] raw, int ptr, int end) private static void checkNotWindowsDevice(byte[] raw, int ptr, int end)
throws CorruptObjectException { throws CorruptObjectException {
switch (toLower(raw[ptr])) { switch (toLower(raw[ptr])) {
@ -579,12 +675,36 @@ public class ObjectChecker {
return 1 <= c && c <= 31; return 1 <= c && c <= 31;
} }
private boolean isDotGit(byte[] buf, int p) { private static boolean isGit(byte[] buf, int p) {
if (windows || macosx) return toLower(buf[p]) == 'g'
return toLower(buf[p]) == 'g' && toLower(buf[p + 1]) == 'i'
&& toLower(buf[p + 1]) == 'i' && toLower(buf[p + 2]) == 't';
&& toLower(buf[p + 2]) == 't'; }
return buf[p] == 'g' && buf[p + 1] == 'i' && buf[p + 2] == 't';
private static boolean isGitTilde1(byte[] buf, int p, int end) {
if (end - p != 5)
return false;
return toLower(buf[p]) == 'g' && toLower(buf[p + 1]) == 'i'
&& toLower(buf[p + 2]) == 't' && buf[p + 3] == '~'
&& buf[p + 4] == '1';
}
private static boolean isNormalizedGit(byte[] raw, int ptr, int end) {
if (isGit(raw, ptr)) {
int dots = 0;
boolean space = false;
int p = end - 1;
for (; (ptr + 2) < p; p--) {
if (raw[p] == '.')
dots++;
else if (raw[p] == ' ')
space = true;
else
break;
}
return p == ptr + 2 && (dots == 1 || space);
}
return false;
} }
private static char toLower(byte b) { private static char toLower(byte b) {

13
org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java

@ -43,17 +43,17 @@
package org.eclipse.jgit.lib; package org.eclipse.jgit.lib;
import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStreamWriter; import java.io.OutputStream;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import org.eclipse.jgit.lib.RebaseTodoLine.Action; import org.eclipse.jgit.lib.RebaseTodoLine.Action;
import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils; import org.eclipse.jgit.util.RawParseUtils;
import org.eclipse.jgit.util.io.SafeBufferedOutputStream;
/** /**
* Offers methods to read and write files formatted like the git-rebase-todo * Offers methods to read and write files formatted like the git-rebase-todo
@ -216,9 +216,8 @@ public class RebaseTodoFile {
*/ */
public void writeRebaseTodoFile(String path, List<RebaseTodoLine> steps, public void writeRebaseTodoFile(String path, List<RebaseTodoLine> steps,
boolean append) throws IOException { boolean append) throws IOException {
BufferedWriter fw = new BufferedWriter(new OutputStreamWriter( OutputStream fw = new SafeBufferedOutputStream(new FileOutputStream(
new FileOutputStream(new File(repo.getDirectory(), path), new File(repo.getDirectory(), path), append));
append), Constants.CHARACTER_ENCODING));
try { try {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (RebaseTodoLine step : steps) { for (RebaseTodoLine step : steps) {
@ -232,8 +231,8 @@ public class RebaseTodoFile {
sb.append(" "); //$NON-NLS-1$ sb.append(" "); //$NON-NLS-1$
sb.append(step.getShortMessage().trim()); sb.append(step.getShortMessage().trim());
} }
fw.write(sb.toString()); sb.append('\n');
fw.newLine(); fw.write(Constants.encode(sb.toString()));
} }
} finally { } finally {
fw.close(); fw.close();

7
org.eclipse.jgit/src/org/eclipse/jgit/patch/FileHeader.java

@ -267,7 +267,7 @@ public class FileHeader extends DiffEntry {
final TemporaryBuffer[] tmp = new TemporaryBuffer[getParentCount() + 1]; final TemporaryBuffer[] tmp = new TemporaryBuffer[getParentCount() + 1];
try { try {
for (int i = 0; i < tmp.length; i++) for (int i = 0; i < tmp.length; i++)
tmp[i] = new TemporaryBuffer.LocalFile(); tmp[i] = new TemporaryBuffer.Heap(Integer.MAX_VALUE);
for (final HunkHeader h : getHunks()) for (final HunkHeader h : getHunks())
h.extractFileLines(tmp); h.extractFileLines(tmp);
@ -281,11 +281,6 @@ public class FileHeader extends DiffEntry {
return r; return r;
} catch (IOException ioe) { } catch (IOException ioe) {
throw new RuntimeException(JGitText.get().cannotConvertScriptToText, ioe); throw new RuntimeException(JGitText.get().cannotConvertScriptToText, ioe);
} finally {
for (final TemporaryBuffer b : tmp) {
if (b != null)
b.destroy();
}
} }
} }

12
org.eclipse.jgit/src/org/eclipse/jgit/patch/Patch.java

@ -139,14 +139,10 @@ public class Patch {
} }
private static byte[] readFully(final InputStream is) throws IOException { private static byte[] readFully(final InputStream is) throws IOException {
final TemporaryBuffer b = new TemporaryBuffer.LocalFile(); TemporaryBuffer b = new TemporaryBuffer.Heap(Integer.MAX_VALUE);
try { b.copy(is);
b.copy(is); b.close();
b.close(); return b.toByteArray();
return b.toByteArray();
} finally {
b.destroy();
}
} }
/** /**

8
org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java

@ -182,6 +182,9 @@ public class AmazonS3 {
/** Encryption algorithm, may be a null instance that provides pass-through. */ /** Encryption algorithm, may be a null instance that provides pass-through. */
private final WalkEncryption encryption; private final WalkEncryption encryption;
/** Directory for locally buffered content. */
private final File tmpDir;
/** /**
* Create a new S3 client for the supplied user information. * Create a new S3 client for the supplied user information.
* <p> * <p>
@ -251,6 +254,9 @@ public class AmazonS3 {
maxAttempts = Integer.parseInt(props.getProperty( maxAttempts = Integer.parseInt(props.getProperty(
"httpclient.retry-max", "3")); //$NON-NLS-1$ //$NON-NLS-2$ "httpclient.retry-max", "3")); //$NON-NLS-1$ //$NON-NLS-2$
proxySelector = ProxySelector.getDefault(); proxySelector = ProxySelector.getDefault();
String tmp = props.getProperty("tmpdir"); //$NON-NLS-1$
tmpDir = tmp != null && tmp.length() > 0 ? new File(tmp) : null;
} }
/** /**
@ -452,7 +458,7 @@ public class AmazonS3 {
final ProgressMonitor monitor, final String monitorTask) final ProgressMonitor monitor, final String monitorTask)
throws IOException { throws IOException {
final MessageDigest md5 = newMD5(); final MessageDigest md5 = newMD5();
final TemporaryBuffer buffer = new TemporaryBuffer.LocalFile() { final TemporaryBuffer buffer = new TemporaryBuffer.LocalFile(tmpDir) {
@Override @Override
public void close() throws IOException { public void close() throws IOException {
super.close(); super.close();

6
org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java

@ -147,7 +147,11 @@ public class TransportAmazonS3 extends HttpTransport implements WalkTransport {
throws NotSupportedException { throws NotSupportedException {
super(local, uri); super(local, uri);
s3 = new AmazonS3(loadProperties()); Properties props = loadProperties();
if (!props.contains("tmpdir") && local.getDirectory() != null) //$NON-NLS-1$
props.put("tmpdir", local.getDirectory().getPath()); //$NON-NLS-1$
s3 = new AmazonS3(props);
bucket = uri.getHost(); bucket = uri.getHost();
String p = uri.getPath(); String p = uri.getPath();

9
org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java

@ -361,7 +361,12 @@ public abstract class TemporaryBuffer extends OutputStream {
*/ */
private File onDiskFile; private File onDiskFile;
/** Create a new temporary buffer. */ /**
* Create a new temporary buffer.
*
* @deprecated Use the {@code File} overload to supply a directory.
*/
@Deprecated
public LocalFile() { public LocalFile() {
this(null, DEFAULT_IN_CORE_LIMIT); this(null, DEFAULT_IN_CORE_LIMIT);
} }
@ -372,7 +377,9 @@ public abstract class TemporaryBuffer extends OutputStream {
* @param inCoreLimit * @param inCoreLimit
* maximum number of bytes to store in memory. Storage beyond * maximum number of bytes to store in memory. Storage beyond
* this limit will use the local file. * this limit will use the local file.
* @deprecated Use the {@code File,int} overload to supply a directory.
*/ */
@Deprecated
public LocalFile(final int inCoreLimit) { public LocalFile(final int inCoreLimit) {
this(null, inCoreLimit); this(null, inCoreLimit);
} }

Loading…
Cancel
Save