diff options
author | Shawn Pearce <spearce@spearce.org> | 2014-12-19 07:57:55 -0800 |
---|---|---|
committer | Shawn Pearce <spearce@spearce.org> | 2014-12-19 07:59:22 -0800 |
commit | 90cccb96d2e215c633efa2b06cdd73fca9951489 (patch) | |
tree | 8dcdc28c16667ac52c7bd20f6c2cb58d99404970 | |
parent | 3f27b9135b59c7c95cdfc854cc728329e9ca4987 (diff) | |
parent | 75272ccdfc705a2e7c42cd5c27c4665c398b1b5d (diff) | |
download | jgit-90cccb96d2e215c633efa2b06cdd73fca9951489.tar.gz jgit-90cccb96d2e215c633efa2b06cdd73fca9951489.zip |
Merge branch 'stable-3.6'
* stable-3.6: (26 commits)
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
Support the new repository layout for submodules
Allow explicit configuration of git directory in CloneCommand
Allow explicit configuration of git directory in InitCommand
Fix tests on windows by closing repos
RepoCommand should close opened repos
Fix LocalDiskRepositoryTestCase to create correct type of repos
Prevent NPE if ref can't be resolved when executing ReflogCommand
Fix DirCacheCheckout to set correct file length if core.autocrlf=true
CheckoutCommand: Fix checking out ours/theirs when no base stage exists
Make sure modifications to config-param trustFolderStat are detected
Apache HttpClientConnection: replace calls to deprecated LocalFile()
...
Change-Id: Ife6f21d64a148dbb0d0d9055356b1568188806fe
51 files changed, 1288 insertions, 433 deletions
diff --git a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java index b776119e23..d42d6f29ee 100644 --- a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java +++ b/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) { if (entity != null) throw new IllegalArgumentException(); - entity = new TemporaryBufferEntity(new LocalFile()); + entity = new TemporaryBufferEntity(new LocalFile(null)); entity.setContentLength(contentLength); } public OutputStream getOutputStream() throws IOException { if (entity == null) - entity = new TemporaryBufferEntity(new LocalFile()); + entity = new TemporaryBufferEntity(new LocalFile(null)); return entity.getBuffer(); } public void setChunkedStreamingMode(int chunklen) { if (entity == null) - entity = new TemporaryBufferEntity(new LocalFile()); + entity = new TemporaryBufferEntity(new LocalFile(null)); entity.setChunked(true); } diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java index bb612b1a68..4e75a56321 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java @@ -84,6 +84,7 @@ import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.junit.TestRng; import org.eclipse.jgit.junit.http.AccessEvent; import org.eclipse.jgit.junit.http.HttpTestCase; +import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; @@ -143,6 +144,10 @@ public class SmartClientSmartServerTest extends HttpTestCase { final TestRepository<Repository> src = createTestRepository(); final String srcName = src.getRepository().getDirectory().getName(); + src.getRepository() + .getConfig() + .setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true); ServletContextHandler app = server.addContext("/git"); GitServlet gs = new GitServlet(); diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java index 053751f8ab..b98db7d187 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java @@ -265,7 +265,7 @@ public abstract class LocalDiskRepositoryTestCase { File gitdir = createUniqueTestGitDir(bare); FileRepository db = new FileRepository(gitdir); assertFalse(gitdir.exists()); - db.create(); + db.create(bare); toClose.add(db); return db; } diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java index deca341067..3d21f9f8ad 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java @@ -90,6 +90,7 @@ public class MockSystemReader extends SystemReader { init(Constants.GIT_AUTHOR_EMAIL_KEY); init(Constants.GIT_COMMITTER_NAME_KEY); init(Constants.GIT_COMMITTER_EMAIL_KEY); + setProperty(Constants.OS_USER_DIR, "."); userGitConfig = new MockConfig(null, null); systemGitConfig = new MockConfig(null, null); setCurrentPlatform(); diff --git a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java index dc5821b5cc..76930f2b86 100644 --- a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java +++ b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java @@ -216,7 +216,7 @@ public class EGitPatchHistoryTest { buf.destroy(); } commitId = line.substring("commit ".length()); - buf = new TemporaryBuffer.LocalFile(); + buf = new TemporaryBuffer.LocalFile(null); } else if (buf != null) { buf.write(line.getBytes("ISO-8859-1")); buf.write('\n'); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java index f13fb20261..f7a50dffcb 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java @@ -43,8 +43,8 @@ */ package org.eclipse.jgit.api; -import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -78,6 +78,7 @@ import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.URIish; @@ -508,4 +509,49 @@ public class CheckoutCommandTest extends RepositoryTestCase { } } + // TODO: write a faster test which depends less on characteristics of + // underlying filesystem/OS. + @Test + public void testCheckoutAutoCrlfTrue() throws Exception { + int nrOfAutoCrlfTestFiles = 200; + + FileBasedConfig c = db.getConfig(); + c.setString("core", null, "autocrlf", "true"); + c.save(); + + AddCommand add = git.add(); + for (int i = 100; i < 100 + nrOfAutoCrlfTestFiles; i++) { + writeTrashFile("Test_" + i + ".txt", "Hello " + i + + " world\nX\nYU\nJK\n"); + add.addFilepattern("Test_" + i + ".txt"); + } + fsTick(null); + add.call(); + RevCommit c1 = git.commit().setMessage("add some lines").call(); + + add = git.add(); + for (int i = 100; i < 100 + nrOfAutoCrlfTestFiles; i++) { + writeTrashFile("Test_" + i + ".txt", "Hello " + i + + " world\nX\nY\n"); + add.addFilepattern("Test_" + i + ".txt"); + } + fsTick(null); + add.call(); + git.commit().setMessage("add more").call(); + + git.checkout().setName(c1.getName()).call(); + + boolean foundUnsmudged = false; + DirCache dc = db.readDirCache(); + for (int i = 100; i < 100 + nrOfAutoCrlfTestFiles; i++) { + DirCacheEntry entry = dc.getEntry( + "Test_" + i + ".txt"); + if (!entry.isSmudged()) { + foundUnsmudged = true; + assertEquals("unexpected file length in git index", 28, + entry.getLength()); + } + } + org.junit.Assume.assumeTrue(foundUnsmudged); + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java index 56c1201760..ece1b324b0 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java @@ -45,6 +45,7 @@ package org.eclipse.jgit.api; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -58,6 +59,7 @@ import java.util.Map; import org.eclipse.jgit.api.ListBranchCommand.ListMode; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.JGitInternalException; +import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.lib.ConfigConstants; @@ -136,6 +138,54 @@ public class CloneCommandTest extends RepositoryTestCase { } @Test + public void testCloneRepositoryExplicitGitDir() throws IOException, + JGitInternalException, GitAPIException { + File directory = createTempDirectory("testCloneRepository"); + CloneCommand command = Git.cloneRepository(); + command.setDirectory(directory); + command.setGitDir(new File(directory, ".git")); + command.setURI(fileUri()); + Git git2 = command.call(); + assertEquals(directory, git2.getRepository().getWorkTree()); + assertEquals(new File(directory, ".git"), git2.getRepository() + .getDirectory()); + } + + @Test + public void testCloneRepositoryExplicitGitDirNonStd() throws IOException, + JGitInternalException, GitAPIException { + File directory = createTempDirectory("testCloneRepository"); + File gDir = createTempDirectory("testCloneRepository.git"); + CloneCommand command = Git.cloneRepository(); + command.setDirectory(directory); + command.setGitDir(gDir); + command.setURI(fileUri()); + Git git2 = command.call(); + assertEquals(directory, git2.getRepository().getWorkTree()); + assertEquals(gDir, git2.getRepository() + .getDirectory()); + assertTrue(new File(directory, ".git").isFile()); + assertFalse(new File(gDir, ".git").exists()); + } + + @Test + public void testCloneRepositoryExplicitGitDirBare() throws IOException, + JGitInternalException, GitAPIException { + File gDir = createTempDirectory("testCloneRepository.git"); + CloneCommand command = Git.cloneRepository(); + command.setBare(true); + command.setGitDir(gDir); + command.setURI(fileUri()); + Git git2 = command.call(); + try { + assertNull(null, git2.getRepository().getWorkTree()); + fail("Expected NoWorkTreeException"); + } catch (NoWorkTreeException e) { + assertEquals(gDir, git2.getRepository().getDirectory()); + } + } + + @Test public void testBareCloneRepository() throws IOException, JGitInternalException, GitAPIException, URISyntaxException { File directory = createTempDirectory("testCloneRepository_bare"); @@ -360,6 +410,18 @@ public class CloneCommandTest extends RepositoryTestCase { assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType()); assertEquals(commit, pathStatus.getHeadId()); assertEquals(commit, pathStatus.getIndexId()); + + SubmoduleWalk walk = SubmoduleWalk.forIndex(git2.getRepository()); + assertTrue(walk.next()); + Repository clonedSub1 = walk.getRepository(); + addRepoToClose(clonedSub1); + assertNotNull(clonedSub1); + assertEquals( + new File(git2.getRepository().getWorkTree(), walk.getPath()), + clonedSub1.getWorkTree()); + assertEquals(new File(new File(git2.getRepository().getDirectory(), + "modules"), walk.getPath()), clonedSub1.getDirectory()); + walk.release(); } @Test @@ -441,10 +503,16 @@ public class CloneCommandTest extends RepositoryTestCase { SubmoduleWalk walk = SubmoduleWalk.forIndex(git2.getRepository()); assertTrue(walk.next()); Repository clonedSub1 = walk.getRepository(); - addRepoToClose(clonedSub1); assertNotNull(clonedSub1); + assertEquals( + new File(git2.getRepository().getWorkTree(), walk.getPath()), + clonedSub1.getWorkTree()); + assertEquals(new File(new File(git2.getRepository().getDirectory(), + "modules"), walk.getPath()), + clonedSub1.getDirectory()); status = new SubmoduleStatusCommand(clonedSub1); statuses = status.call(); + clonedSub1.close(); pathStatus = statuses.get(path); assertNotNull(pathStatus); assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java index 0b523f4f3c..1f71402879 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java @@ -205,8 +205,8 @@ public class CommitCommandTest extends RepositoryTestCase { assertEquals(path, generator.getModulesPath()); assertEquals(uri, generator.getConfigUrl()); Repository subModRepo = generator.getRepository(); - addRepoToClose(subModRepo); assertNotNull(subModRepo); + subModRepo.close(); assertEquals(commit, repo.resolve(Constants.HEAD)); RevCommit submoduleCommit = git.commit().setMessage("submodule add") @@ -253,8 +253,8 @@ public class CommitCommandTest extends RepositoryTestCase { assertEquals(path, generator.getModulesPath()); assertEquals(uri, generator.getConfigUrl()); Repository subModRepo = generator.getRepository(); - addRepoToClose(subModRepo); assertNotNull(subModRepo); + subModRepo.close(); assertEquals(commit2, repo.resolve(Constants.HEAD)); RevCommit submoduleAddCommit = git.commit().setMessage("submodule add") diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/InitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/InitCommandTest.java index 3296717c0e..e850223762 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/InitCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/InitCommandTest.java @@ -43,6 +43,7 @@ package org.eclipse.jgit.api; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.File; @@ -50,8 +51,12 @@ import java.io.IOException; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.JGitInternalException; +import org.eclipse.jgit.errors.NoWorkTreeException; +import org.eclipse.jgit.junit.MockSystemReader; import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.util.SystemReader; import org.junit.Before; import org.junit.Test; @@ -101,4 +106,109 @@ public class InitCommandTest extends RepositoryTestCase { assertNotNull(repository); assertTrue(repository.isBare()); } + + // non-bare repos where gitDir and directory is set. Same as + // "git init --separate-git-dir /tmp/a /tmp/b" + @Test + public void testInitWithExplicitGitDir() throws IOException, + JGitInternalException, GitAPIException { + File wt = createTempDirectory("testInitRepositoryWT"); + File gitDir = createTempDirectory("testInitRepositoryGIT"); + InitCommand command = new InitCommand(); + command.setDirectory(wt); + command.setGitDir(gitDir); + Repository repository = command.call().getRepository(); + addRepoToClose(repository); + assertNotNull(repository); + assertEqualsFile(wt, repository.getWorkTree()); + assertEqualsFile(gitDir, repository.getDirectory()); + } + + // non-bare repos where only gitDir is set. Same as + // "git init --separate-git-dir /tmp/a" + @Test + public void testInitWithOnlyExplicitGitDir() throws IOException, + JGitInternalException, GitAPIException { + MockSystemReader reader = (MockSystemReader) SystemReader.getInstance(); + reader.setProperty(Constants.OS_USER_DIR, getTemporaryDirectory() + .getAbsolutePath()); + File gitDir = createTempDirectory("testInitRepository/.git"); + InitCommand command = new InitCommand(); + command.setGitDir(gitDir); + Repository repository = command.call().getRepository(); + addRepoToClose(repository); + assertNotNull(repository); + assertEqualsFile(gitDir, repository.getDirectory()); + assertEqualsFile(new File(reader.getProperty("user.dir")), + repository.getWorkTree()); + } + + // Bare repos where gitDir and directory is set will only work if gitDir and + // directory is pointing to same dir. Same as + // "git init --bare --separate-git-dir /tmp/a /tmp/b" + // (works in native git but I guess that's more a bug) + @Test(expected = IllegalStateException.class) + public void testInitBare_DirAndGitDirMustBeEqual() throws IOException, + JGitInternalException, GitAPIException { + File gitDir = createTempDirectory("testInitRepository.git"); + InitCommand command = new InitCommand(); + command.setBare(true); + command.setDirectory(gitDir); + command.setGitDir(new File(gitDir, "..")); + command.call(); + } + + // If neither directory nor gitDir is set in a non-bare repo make sure + // worktree and gitDir are set correctly. Standard case. Same as + // "git init" + @Test + public void testInitWithDefaultsNonBare() throws JGitInternalException, + GitAPIException, IOException { + MockSystemReader reader = (MockSystemReader) SystemReader.getInstance(); + reader.setProperty(Constants.OS_USER_DIR, getTemporaryDirectory() + .getAbsolutePath()); + InitCommand command = new InitCommand(); + command.setBare(false); + Repository repository = command.call().getRepository(); + addRepoToClose(repository); + assertNotNull(repository); + assertEqualsFile(new File(reader.getProperty("user.dir"), ".git"), + repository.getDirectory()); + assertEqualsFile(new File(reader.getProperty("user.dir")), + repository.getWorkTree()); + } + + // If neither directory nor gitDir is set in a bare repo make sure + // worktree and gitDir are set correctly. Standard case. Same as + // "git init --bare" + @Test(expected = NoWorkTreeException.class) + public void testInitWithDefaultsBare() throws JGitInternalException, + GitAPIException, IOException { + MockSystemReader reader = (MockSystemReader) SystemReader.getInstance(); + reader.setProperty(Constants.OS_USER_DIR, getTemporaryDirectory() + .getAbsolutePath()); + InitCommand command = new InitCommand(); + command.setBare(true); + Repository repository = command.call().getRepository(); + addRepoToClose(repository); + assertNotNull(repository); + assertEqualsFile(new File(reader.getProperty("user.dir")), + repository.getDirectory()); + assertNull(repository.getWorkTree()); + } + + // In a non-bare repo when directory and gitDir is set then they shouldn't + // point to the same dir. Same as + // "git init --separate-git-dir /tmp/a /tmp/a" + // (works in native git but I guess that's more a bug) + @Test(expected = IllegalStateException.class) + public void testInitNonBare_GitdirAndDirShouldntBeSame() + throws JGitInternalException, GitAPIException, IOException { + File gitDir = createTempDirectory("testInitRepository.git"); + InitCommand command = new InitCommand(); + command.setBare(false); + command.setGitDir(gitDir); + command.setDirectory(gitDir); + command.call().getRepository(); + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java index dbda852850..eb092ad6c8 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java @@ -43,6 +43,7 @@ package org.eclipse.jgit.api; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; @@ -276,6 +277,39 @@ public class PathCheckoutCommandTest extends RepositoryTestCase { assertStageOneToThree(FILE1); } + @Test + public void testCheckoutOursWhenNoBase() throws Exception { + String file = "added.txt"; + + git.checkout().setCreateBranch(true).setName("side") + .setStartPoint(initialCommit).call(); + writeTrashFile(file, "Added on side"); + git.add().addFilepattern(file).call(); + RevCommit side = git.commit().setMessage("Commit on side").call(); + + git.checkout().setName("master").call(); + writeTrashFile(file, "Added on master"); + git.add().addFilepattern(file).call(); + git.commit().setMessage("Commit on master").call(); + + git.merge().include(side).call(); + assertEquals(RepositoryState.MERGING, db.getRepositoryState()); + + DirCache cache = DirCache.read(db.getIndexFile(), db.getFS()); + assertEquals("Expected add/add file to not have base stage", + DirCacheEntry.STAGE_2, cache.getEntry(file).getStage()); + + assertTrue(read(file).startsWith("<<<<<<< HEAD")); + + git.checkout().setStage(Stage.OURS).addPath(file).call(); + + assertEquals("Added on master", read(file)); + + cache = DirCache.read(db.getIndexFile(), db.getFS()); + assertEquals("Expected conflict stages to still exist after checkout", + DirCacheEntry.STAGE_2, cache.getEntry(file).getStage()); + } + @Test(expected = IllegalStateException.class) public void testStageNotPossibleWithBranch() throws Exception { git.checkout().setStage(Stage.OURS).setStartPoint("master").call(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java index 6ac718ec5b..0c1baab2b8 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java @@ -47,12 +47,19 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; 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.lib.Constants; import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.ObjectInserter; +import org.eclipse.jgit.util.SystemReader; import org.junit.Test; public class DirCacheBasicTest extends RepositoryTestCase { @@ -190,7 +197,7 @@ public class DirCacheBasicTest extends RepositoryTestCase { public void testBuildThenClear() throws Exception { 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]; for (int i = 0; i < paths.length; i++) { ents[i] = new DirCacheEntry(paths[i]); @@ -234,4 +241,41 @@ public class DirCacheBasicTest extends RepositoryTestCase { final byte[] path = Constants.encode("a"); 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()); + } + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java index 254431f74b..8561fdf35b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java @@ -63,7 +63,7 @@ public class DirCacheBuilderIteratorTest extends RepositoryTestCase { final DirCache dc = db.readDirCache(); 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]; for (int i = 0; i < paths.length; i++) { ents[i] = new DirCacheEntry(paths[i]); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java index a502db3ac1..5408f761dc 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java @@ -290,7 +290,7 @@ public class DirCacheBuilderTest extends RepositoryTestCase { public void testAdd_InGitSortOrder() throws Exception { 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]; for (int i = 0; i < paths.length; i++) { ents[i] = new DirCacheEntry(paths[i]); @@ -315,7 +315,7 @@ public class DirCacheBuilderTest extends RepositoryTestCase { public void testAdd_ReverseGitSortOrder() throws Exception { 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]; for (int i = 0; i < paths.length; i++) { ents[i] = new DirCacheEntry(paths[i]); @@ -340,7 +340,7 @@ public class DirCacheBuilderTest extends RepositoryTestCase { public void testBuilderClear() throws Exception { 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]; for (int i = 0; i < paths.length; i++) { ents[i] = new DirCacheEntry(paths[i]); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java index 53d672d7f3..7f58a1cbed 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java @@ -213,7 +213,7 @@ public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase { assertV3TreeEntry(9, "newfile.txt", false, true, dc); final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - dc.writeTo(bos); + dc.writeTo(null, bos); final byte[] indexBytes = bos.toByteArray(); final byte[] expectedBytes = IO.readFully(file); assertArrayEquals(expectedBytes, indexBytes); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java index 225ce2a907..e159ed939e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java @@ -49,7 +49,6 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.junit.Test; @@ -71,7 +70,12 @@ public class DirCacheEntryTest { } 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 diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheFindTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheFindTest.java index 0b43b2311a..3b8c6ee7b4 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheFindTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheFindTest.java @@ -56,7 +56,7 @@ public class DirCacheFindTest extends RepositoryTestCase { public void testEntriesWithin() throws Exception { 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]; for (int i = 0; i < paths.length; i++) { ents[i] = new DirCacheEntry(paths[i]); @@ -96,13 +96,13 @@ public class DirCacheFindTest extends RepositoryTestCase { assertSame(ents[i], aContents[i]); } - assertNotNull(dc.getEntriesWithin("a.")); - assertEquals(0, dc.getEntriesWithin("a.").length); + assertNotNull(dc.getEntriesWithin("a-")); + assertEquals(0, dc.getEntriesWithin("a-").length); assertNotNull(dc.getEntriesWithin("a0b")); - assertEquals(0, dc.getEntriesWithin("a0b.").length); + assertEquals(0, dc.getEntriesWithin("a0b-").length); assertNotNull(dc.getEntriesWithin("zoo")); - assertEquals(0, dc.getEntriesWithin("zoo.").length); + assertEquals(0, dc.getEntriesWithin("zoo-").length); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java index 8d29a73188..af1c8a3567 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java @@ -85,7 +85,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase { public void testNoSubtree_NoTreeWalk() throws Exception { final DirCache dc = DirCache.newInCore(); - final String[] paths = { "a.", "a0b" }; + final String[] paths = { "a-", "a0b" }; final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; for (int i = 0; i < paths.length; i++) { ents[i] = new DirCacheEntry(paths[i]); @@ -111,7 +111,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase { public void testNoSubtree_WithTreeWalk() throws Exception { final DirCache dc = DirCache.newInCore(); - final String[] paths = { "a.", "a0b" }; + final String[] paths = { "a-", "a0b" }; final FileMode[] modes = { FileMode.EXECUTABLE_FILE, FileMode.GITLINK }; final DirCacheEntry[] ents = new DirCacheEntry[paths.length]; for (int i = 0; i < paths.length; i++) { @@ -144,7 +144,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase { public void testSingleSubtree_NoRecursion() throws Exception { 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]; for (int i = 0; i < paths.length; i++) { ents[i] = new DirCacheEntry(paths[i]); @@ -156,7 +156,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase { b.add(ents[i]); b.finish(); - final String[] expPaths = { "a.", "a", "a0b" }; + final String[] expPaths = { "a-", "a", "a0b" }; final FileMode[] expModes = { FileMode.REGULAR_FILE, FileMode.TREE, FileMode.REGULAR_FILE }; final int expPos[] = { 0, -1, 4 }; @@ -189,7 +189,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase { final DirCache dc = DirCache.newInCore(); 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]; for (int i = 0; i < paths.length; i++) { ents[i] = new DirCacheEntry(paths[i]); @@ -224,7 +224,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase { final DirCache dc = DirCache.newInCore(); 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]; for (int i = 0; i < paths.length; i++) { ents[i] = new DirCacheEntry(paths[i]); @@ -258,7 +258,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase { final DirCache dc = DirCache.newInCore(); 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]; for (int i = 0; i < paths.length; i++) { ents[i] = new DirCacheEntry(paths[i]); @@ -272,7 +272,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase { DirCacheIterator dci = new DirCacheIterator(dc); assertFalse(dci.eof()); - assertEquals("a.", dci.getEntryPathString()); + assertEquals("a-", dci.getEntryPathString()); dci.next(1); assertFalse(dci.eof()); assertEquals("a", dci.getEntryPathString()); @@ -285,7 +285,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase { // same entries the second time dci.reset(); assertFalse(dci.eof()); - assertEquals("a.", dci.getEntryPathString()); + assertEquals("a-", dci.getEntryPathString()); dci.next(1); assertFalse(dci.eof()); assertEquals("a", dci.getEntryPathString()); @@ -304,12 +304,12 @@ public class DirCacheIteratorTest extends RepositoryTestCase { assertEquals("a", dci.getEntryPathString()); dci.back(1); assertFalse(dci.eof()); - assertEquals("a.", dci.getEntryPathString()); + assertEquals("a-", dci.getEntryPathString()); assertTrue(dci.first()); // forward assertFalse(dci.eof()); - assertEquals("a.", dci.getEntryPathString()); + assertEquals("a-", dci.getEntryPathString()); dci.next(1); assertFalse(dci.eof()); assertEquals("a", dci.getEntryPathString()); @@ -385,7 +385,7 @@ public class DirCacheIteratorTest extends RepositoryTestCase { final DirCache dc = DirCache.newInCore(); 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]; for (int i = 0; i < paths.length; i++) { ents[i] = new DirCacheEntry(paths[i]); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java index 28140f330e..63ec85861d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java @@ -113,21 +113,23 @@ public class DirCachePathEditTest { DirCache dc = DirCache.newInCore(); DirCacheEditor editor = dc.editor(); editor.add(new AddEdit("a/b")); - editor.add(new AddEdit("a.")); + editor.add(new AddEdit("a-")); editor.add(new AddEdit("ab")); editor.finish(); assertEquals(3, dc.getEntryCount()); + // Validate sort order - assertEquals("a.", dc.getEntry(0).getPathString()); + assertEquals("a-", dc.getEntry(0).getPathString()); assertEquals("a/b", dc.getEntry(1).getPathString()); assertEquals("ab", dc.getEntry(2).getPathString()); editor = dc.editor(); + // Sort order should not confuse DeleteTree editor.add(new DirCacheEditor.DeleteTree("a")); editor.finish(); assertEquals(2, dc.getEntryCount()); - assertEquals("a.", dc.getEntry(0).getPathString()); + assertEquals("a-", dc.getEntry(0).getPathString()); assertEquals("ab", dc.getEntry(1).getPathString()); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheTreeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheTreeTest.java index 89d7bed8b7..f662e2660c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheTreeTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheTreeTest.java @@ -92,7 +92,7 @@ public class DirCacheTreeTest extends RepositoryTestCase { public void testSingleSubtree() throws Exception { 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]; for (int i = 0; i < paths.length; i++) { ents[i] = new DirCacheEntry(paths[i]); @@ -130,7 +130,7 @@ public class DirCacheTreeTest extends RepositoryTestCase { public void testTwoLevelSubtree() throws Exception { 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]; for (int i = 0; i < paths.length; 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 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]; for (int i = 0; i < paths.length; i++) { ents[i] = new DirCacheEntry(paths[i]); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java index d24d375cbc..3d86cfd5bb 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java @@ -90,24 +90,28 @@ public class RepoCommandTest extends RepositoryTestCase { JGitTestUtil.writeTrashFile(defaultDb, "hello.txt", "master world"); git.add().addFilepattern("hello.txt").call(); git.commit().setMessage("Second commit").call(); + addRepoToClose(defaultDb); notDefaultDb = createWorkRepository(); git = new Git(notDefaultDb); JGitTestUtil.writeTrashFile(notDefaultDb, "world.txt", "hello"); git.add().addFilepattern("world.txt").call(); git.commit().setMessage("Initial commit").call(); + addRepoToClose(notDefaultDb); groupADb = createWorkRepository(); git = new Git(groupADb); JGitTestUtil.writeTrashFile(groupADb, "a.txt", "world"); git.add().addFilepattern("a.txt").call(); git.commit().setMessage("Initial commit").call(); + addRepoToClose(groupADb); groupBDb = createWorkRepository(); git = new Git(groupBDb); JGitTestUtil.writeTrashFile(groupBDb, "b.txt", "world"); git.add().addFilepattern("b.txt").call(); git.commit().setMessage("Initial commit").call(); + addRepoToClose(groupBDb); resolveRelativeUris(); } @@ -239,45 +243,47 @@ public class RepoCommandTest extends RepositoryTestCase { public void testBareRepo() throws Exception { Repository remoteDb = createBareRepository(); Repository tempDb = createWorkRepository(); - StringBuilder xmlContent = new StringBuilder(); - xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") - .append("<manifest>") - .append("<remote name=\"remote1\" fetch=\".\" />") - .append("<default revision=\"master\" remote=\"remote1\" />") - .append("<project path=\"foo\" name=\"") - .append(defaultUri) - .append("\" />") - .append("</manifest>"); - JGitTestUtil.writeTrashFile( - tempDb, "manifest.xml", xmlContent.toString()); - RepoCommand command = new RepoCommand(remoteDb); - command - .setPath(tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") - .setURI(rootUri) - .call(); - // Clone it - File directory = createTempDirectory("testBareRepo"); - Repository localDb = Git - .cloneRepository() - .setDirectory(directory) - .setURI(remoteDb.getDirectory().toURI().toString()) - .call() - .getRepository(); - // The .gitmodules file should exist - File gitmodules = new File(localDb.getWorkTree(), ".gitmodules"); - assertTrue("The .gitmodules file should exist", gitmodules.exists()); - // The first line of .gitmodules file should be expected - BufferedReader reader = new BufferedReader(new FileReader(gitmodules)); - String content = reader.readLine(); - reader.close(); - assertEquals( - "The first line of .gitmodules file should be as expected", - "[submodule \"foo\"]", content); - // The gitlink should be the same as remote head sha1 - String gitlink = localDb.resolve(Constants.HEAD + ":foo").name(); - String remote = defaultDb.resolve(Constants.HEAD).name(); - assertEquals("The gitlink should be the same as remote head", - remote, gitlink); + try { + StringBuilder xmlContent = new StringBuilder(); + xmlContent + .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + .append("<manifest>") + .append("<remote name=\"remote1\" fetch=\".\" />") + .append("<default revision=\"master\" remote=\"remote1\" />") + .append("<project path=\"foo\" name=\"").append(defaultUri) + .append("\" />").append("</manifest>"); + JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", + xmlContent.toString()); + RepoCommand command = new RepoCommand(remoteDb); + command.setPath( + tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") + .setURI(rootUri).call(); + // Clone it + File directory = createTempDirectory("testBareRepo"); + Repository localDb = Git.cloneRepository().setDirectory(directory) + .setURI(remoteDb.getDirectory().toURI().toString()).call() + .getRepository(); + // The .gitmodules file should exist + File gitmodules = new File(localDb.getWorkTree(), ".gitmodules"); + assertTrue("The .gitmodules file should exist", gitmodules.exists()); + // The first line of .gitmodules file should be expected + BufferedReader reader = new BufferedReader(new FileReader( + gitmodules)); + String content = reader.readLine(); + reader.close(); + assertEquals( + "The first line of .gitmodules file should be as expected", + "[submodule \"foo\"]", content); + // The gitlink should be the same as remote head sha1 + String gitlink = localDb.resolve(Constants.HEAD + ":foo").name(); + localDb.close(); + String remote = defaultDb.resolve(Constants.HEAD).name(); + assertEquals("The gitlink should be the same as remote head", + remote, gitlink); + } finally { + tempDb.close(); + remoteDb.close(); + } } @Test @@ -362,213 +368,213 @@ public class RepoCommandTest extends RepositoryTestCase { public void testRevisionBare() throws Exception { Repository remoteDb = createBareRepository(); Repository tempDb = createWorkRepository(); - StringBuilder xmlContent = new StringBuilder(); - xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") - .append("<manifest>") - .append("<remote name=\"remote1\" fetch=\".\" />") - .append("<default revision=\"") - .append(BRANCH) - .append("\" remote=\"remote1\" />") - .append("<project path=\"foo\" name=\"") - .append(defaultUri) - .append("\" />") - .append("</manifest>"); - JGitTestUtil.writeTrashFile( - tempDb, "manifest.xml", xmlContent.toString()); - RepoCommand command = new RepoCommand(remoteDb); - command - .setPath(tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") - .setURI(rootUri) - .call(); - // Clone it - File directory = createTempDirectory("testRevisionBare"); - Repository localDb = Git - .cloneRepository() - .setDirectory(directory) - .setURI(remoteDb.getDirectory().toURI().toString()) - .call() - .getRepository(); - // The gitlink should be the same as oldCommitId - String gitlink = localDb.resolve(Constants.HEAD + ":foo").name(); - assertEquals("The gitlink is same as remote head", - oldCommitId.name(), gitlink); + try { + StringBuilder xmlContent = new StringBuilder(); + xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + .append("<manifest>") + .append("<remote name=\"remote1\" fetch=\".\" />") + .append("<default revision=\"").append(BRANCH) + .append("\" remote=\"remote1\" />") + .append("<project path=\"foo\" name=\"").append(defaultUri) + .append("\" />").append("</manifest>"); + JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", + xmlContent.toString()); + RepoCommand command = new RepoCommand(remoteDb); + command.setPath( + tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") + .setURI(rootUri).call(); + // Clone it + File directory = createTempDirectory("testRevisionBare"); + Repository localDb = Git.cloneRepository().setDirectory(directory) + .setURI(remoteDb.getDirectory().toURI().toString()).call() + .getRepository(); + // The gitlink should be the same as oldCommitId + String gitlink = localDb.resolve(Constants.HEAD + ":foo").name(); + localDb.close(); + assertEquals("The gitlink is same as remote head", + oldCommitId.name(), gitlink); + } finally { + tempDb.close(); + remoteDb.close(); + } } @Test public void testCopyFileBare() throws Exception { Repository remoteDb = createBareRepository(); Repository tempDb = createWorkRepository(); - StringBuilder xmlContent = new StringBuilder(); - xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") - .append("<manifest>") - .append("<remote name=\"remote1\" fetch=\".\" />") - .append("<default revision=\"master\" remote=\"remote1\" />") - .append("<project path=\"foo\" name=\"") - .append(defaultUri) - .append("\" revision=\"") - .append(BRANCH) - .append("\" >") - .append("<copyfile src=\"hello.txt\" dest=\"Hello\" />") - .append("</project>") - .append("</manifest>"); - JGitTestUtil.writeTrashFile( - tempDb, "manifest.xml", xmlContent.toString()); - RepoCommand command = new RepoCommand(remoteDb); - command - .setPath(tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") - .setURI(rootUri) - .call(); - // Clone it - File directory = createTempDirectory("testCopyFileBare"); - Repository localDb = Git - .cloneRepository() - .setDirectory(directory) - .setURI(remoteDb.getDirectory().toURI().toString()) - .call() - .getRepository(); - // The Hello file should exist - File hello = new File(localDb.getWorkTree(), "Hello"); - assertTrue("The Hello file should exist", hello.exists()); - // The content of Hello file should be expected - BufferedReader reader = new BufferedReader(new FileReader(hello)); - String content = reader.readLine(); - reader.close(); - assertEquals("The Hello file should have expected content", - "branch world", content); + try { + StringBuilder xmlContent = new StringBuilder(); + xmlContent + .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + .append("<manifest>") + .append("<remote name=\"remote1\" fetch=\".\" />") + .append("<default revision=\"master\" remote=\"remote1\" />") + .append("<project path=\"foo\" name=\"").append(defaultUri) + .append("\" revision=\"").append(BRANCH).append("\" >") + .append("<copyfile src=\"hello.txt\" dest=\"Hello\" />") + .append("</project>").append("</manifest>"); + JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", + xmlContent.toString()); + RepoCommand command = new RepoCommand(remoteDb); + command.setPath( + tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") + .setURI(rootUri).call(); + // Clone it + File directory = createTempDirectory("testCopyFileBare"); + Repository localDb = Git.cloneRepository().setDirectory(directory) + .setURI(remoteDb.getDirectory().toURI().toString()).call() + .getRepository(); + // The Hello file should exist + File hello = new File(localDb.getWorkTree(), "Hello"); + localDb.close(); + assertTrue("The Hello file should exist", hello.exists()); + // The content of Hello file should be expected + BufferedReader reader = new BufferedReader(new FileReader(hello)); + String content = reader.readLine(); + reader.close(); + assertEquals("The Hello file should have expected content", + "branch world", content); + } finally { + tempDb.close(); + remoteDb.close(); + } } @Test public void testReplaceManifestBare() throws Exception { Repository remoteDb = createBareRepository(); Repository tempDb = createWorkRepository(); - StringBuilder xmlContent = new StringBuilder(); - xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") - .append("<manifest>") - .append("<remote name=\"remote1\" fetch=\".\" />") - .append("<default revision=\"master\" remote=\"remote1\" />") - .append("<project path=\"foo\" name=\"") - .append(defaultUri) - .append("\" revision=\"") - .append(BRANCH) - .append("\" >") - .append("<copyfile src=\"hello.txt\" dest=\"Hello\" />") - .append("</project>") - .append("</manifest>"); - JGitTestUtil.writeTrashFile(tempDb, "old.xml", xmlContent.toString()); - RepoCommand command = new RepoCommand(remoteDb); - command.setPath(tempDb.getWorkTree().getAbsolutePath() + "/old.xml") - .setURI(rootUri) - .call(); - xmlContent = new StringBuilder(); - xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") - .append("<manifest>") - .append("<remote name=\"remote1\" fetch=\".\" />") - .append("<default revision=\"master\" remote=\"remote1\" />") - .append("<project path=\"bar\" name=\"") - .append(defaultUri) - .append("\" revision=\"") - .append(BRANCH) - .append("\" >") - .append("<copyfile src=\"hello.txt\" dest=\"Hello.txt\" />") - .append("</project>") - .append("</manifest>"); - JGitTestUtil.writeTrashFile(tempDb, "new.xml", xmlContent.toString()); - command = new RepoCommand(remoteDb); - command.setPath(tempDb.getWorkTree().getAbsolutePath() + "/new.xml") - .setURI(rootUri) - .call(); - // Clone it - File directory = createTempDirectory("testReplaceManifestBare"); - Repository localDb = Git - .cloneRepository() - .setDirectory(directory) - .setURI(remoteDb.getDirectory().toURI().toString()) - .call() - .getRepository(); - // The Hello file should not exist - File hello = new File(localDb.getWorkTree(), "Hello"); - assertFalse("The Hello file shouldn't exist", hello.exists()); - // The Hello.txt file should exist - File hellotxt = new File(localDb.getWorkTree(), "Hello.txt"); - assertTrue("The Hello.txt file should exist", hellotxt.exists()); - // The .gitmodules file should have 'submodule "bar"' and shouldn't have - // 'submodule "foo"' lines. - File dotmodules = new File(localDb.getWorkTree(), - Constants.DOT_GIT_MODULES); - BufferedReader reader = new BufferedReader(new FileReader(dotmodules)); - boolean foo = false; - boolean bar = false; - while (true) { - String line = reader.readLine(); - if (line == null) - break; - if (line.contains("submodule \"foo\"")) - foo = true; - if (line.contains("submodule \"bar\"")) - bar = true; + try { + StringBuilder xmlContent = new StringBuilder(); + xmlContent + .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + .append("<manifest>") + .append("<remote name=\"remote1\" fetch=\".\" />") + .append("<default revision=\"master\" remote=\"remote1\" />") + .append("<project path=\"foo\" name=\"").append(defaultUri) + .append("\" revision=\"").append(BRANCH).append("\" >") + .append("<copyfile src=\"hello.txt\" dest=\"Hello\" />") + .append("</project>").append("</manifest>"); + JGitTestUtil.writeTrashFile(tempDb, "old.xml", + xmlContent.toString()); + RepoCommand command = new RepoCommand(remoteDb); + command.setPath(tempDb.getWorkTree().getAbsolutePath() + "/old.xml") + .setURI(rootUri).call(); + xmlContent = new StringBuilder(); + xmlContent + .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + .append("<manifest>") + .append("<remote name=\"remote1\" fetch=\".\" />") + .append("<default revision=\"master\" remote=\"remote1\" />") + .append("<project path=\"bar\" name=\"") + .append(defaultUri) + .append("\" revision=\"") + .append(BRANCH) + .append("\" >") + .append("<copyfile src=\"hello.txt\" dest=\"Hello.txt\" />") + .append("</project>").append("</manifest>"); + JGitTestUtil.writeTrashFile(tempDb, "new.xml", + xmlContent.toString()); + command = new RepoCommand(remoteDb); + command.setPath(tempDb.getWorkTree().getAbsolutePath() + "/new.xml") + .setURI(rootUri).call(); + // Clone it + File directory = createTempDirectory("testReplaceManifestBare"); + Repository localDb = Git.cloneRepository().setDirectory(directory) + .setURI(remoteDb.getDirectory().toURI().toString()).call() + .getRepository(); + // The Hello file should not exist + File hello = new File(localDb.getWorkTree(), "Hello"); + assertFalse("The Hello file shouldn't exist", hello.exists()); + // The Hello.txt file should exist + File hellotxt = new File(localDb.getWorkTree(), "Hello.txt"); + assertTrue("The Hello.txt file should exist", hellotxt.exists()); + // The .gitmodules file should have 'submodule "bar"' and shouldn't + // have + // 'submodule "foo"' lines. + File dotmodules = new File(localDb.getWorkTree(), + Constants.DOT_GIT_MODULES); + localDb.close(); + BufferedReader reader = new BufferedReader(new FileReader( + dotmodules)); + boolean foo = false; + boolean bar = false; + while (true) { + String line = reader.readLine(); + if (line == null) + break; + if (line.contains("submodule \"foo\"")) + foo = true; + if (line.contains("submodule \"bar\"")) + bar = true; + } + reader.close(); + assertTrue("The bar submodule should exist", bar); + assertFalse("The foo submodule shouldn't exist", foo); + } finally { + tempDb.close(); + remoteDb.close(); } - reader.close(); - assertTrue("The bar submodule should exist", bar); - assertFalse("The foo submodule shouldn't exist", foo); } @Test public void testRemoveOverlappingBare() throws Exception { Repository remoteDb = createBareRepository(); Repository tempDb = createWorkRepository(); - StringBuilder xmlContent = new StringBuilder(); - xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") - .append("<manifest>") - .append("<remote name=\"remote1\" fetch=\".\" />") - .append("<default revision=\"master\" remote=\"remote1\" />") - .append("<project path=\"foo/bar\" name=\"") - .append(groupBUri) - .append("\" />") - .append("<project path=\"a\" name=\"") - .append(groupAUri) - .append("\" />") - .append("<project path=\"foo\" name=\"") - .append(defaultUri) - .append("\" />") - .append("</manifest>"); - JGitTestUtil.writeTrashFile( - tempDb, "manifest.xml", xmlContent.toString()); - RepoCommand command = new RepoCommand(remoteDb); - command - .setPath(tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") - .setURI(rootUri) - .call(); - // Clone it - File directory = createTempDirectory("testRemoveOverlappingBare"); - Repository localDb = Git - .cloneRepository() - .setDirectory(directory) - .setURI(remoteDb.getDirectory().toURI().toString()) - .call() - .getRepository(); - // The .gitmodules file should have 'submodule "foo"' and shouldn't have - // 'submodule "foo/bar"' lines. - File dotmodules = new File(localDb.getWorkTree(), - Constants.DOT_GIT_MODULES); - BufferedReader reader = new BufferedReader(new FileReader(dotmodules)); - boolean foo = false; - boolean foobar = false; - boolean a = false; - while (true) { - String line = reader.readLine(); - if (line == null) - break; - if (line.contains("submodule \"foo\"")) - foo = true; - if (line.contains("submodule \"foo/bar\"")) - foobar = true; - if (line.contains("submodule \"a\"")) - a = true; + try { + StringBuilder xmlContent = new StringBuilder(); + xmlContent + .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + .append("<manifest>") + .append("<remote name=\"remote1\" fetch=\".\" />") + .append("<default revision=\"master\" remote=\"remote1\" />") + .append("<project path=\"foo/bar\" name=\"") + .append(groupBUri).append("\" />") + .append("<project path=\"a\" name=\"").append(groupAUri) + .append("\" />").append("<project path=\"foo\" name=\"") + .append(defaultUri).append("\" />").append("</manifest>"); + JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", + xmlContent.toString()); + RepoCommand command = new RepoCommand(remoteDb); + command.setPath( + tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") + .setURI(rootUri).call(); + // Clone it + File directory = createTempDirectory("testRemoveOverlappingBare"); + Repository localDb = Git.cloneRepository().setDirectory(directory) + .setURI(remoteDb.getDirectory().toURI().toString()).call() + .getRepository(); + // The .gitmodules file should have 'submodule "foo"' and shouldn't + // have + // 'submodule "foo/bar"' lines. + File dotmodules = new File(localDb.getWorkTree(), + Constants.DOT_GIT_MODULES); + localDb.close(); + BufferedReader reader = new BufferedReader(new FileReader( + dotmodules)); + boolean foo = false; + boolean foobar = false; + boolean a = false; + while (true) { + String line = reader.readLine(); + if (line == null) + break; + if (line.contains("submodule \"foo\"")) + foo = true; + if (line.contains("submodule \"foo/bar\"")) + foobar = true; + if (line.contains("submodule \"a\"")) + a = true; + } + reader.close(); + assertTrue("The foo submodule should exist", foo); + assertFalse("The foo/bar submodule shouldn't exist", foobar); + assertTrue("The a submodule should exist", a); + } finally { + tempDb.close(); + remoteDb.close(); } - reader.close(); - assertTrue("The foo submodule should exist", foo); - assertFalse("The foo/bar submodule shouldn't exist", foobar); - assertTrue("The a submodule should exist", a); } @Test diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java index d29a75ef71..ca3e0666ea 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java @@ -186,10 +186,7 @@ public class DirCacheCheckoutMaliciousPathTest extends RepositoryTestCase { @Test public void testMaliciousGitPathEndSpaceUnixOk() throws Exception { - if (File.separatorChar == '\\') - return; // cannot emulate Unix on Windows for this test - ((MockSystemReader) SystemReader.getInstance()).setUnix(); - testMaliciousPathGoodFirstCheckout(".git ", "konfig"); + testMaliciousPathBadFirstCheckout(".git ", "konfig"); } @Test @@ -212,10 +209,7 @@ public class DirCacheCheckoutMaliciousPathTest extends RepositoryTestCase { @Test public void testMaliciousGitPathEndDotUnixOk() throws Exception { - if (File.separatorChar == '\\') - return; // cannot emulate Unix on Windows for this test - ((MockSystemReader) SystemReader.getInstance()).setUnix(); - testMaliciousPathGoodFirstCheckout(".git.", "konfig"); + testMaliciousPathBadFirstCheckout(".git.", "konfig"); } @Test diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java index 8003824d4e..863d79ddee 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java @@ -90,7 +90,9 @@ public class IndexDiffSubmoduleTest extends RepositoryTestCase { .setPath("submodule") .setURI(submoduleStandalone.getDirectory().toURI().toString()) .call(); + submoduleStandalone.close(); submodule_trash = submodule_db.getWorkTree(); + addRepoToClose(submodule_db); writeTrashFile("fileInRoot", "root"); Git rootGit = Git.wrap(db); rootGit.add().addFilepattern("fileInRoot").call(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java index 9fc7fca987..c6578ccfae 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java @@ -1295,12 +1295,11 @@ public class ObjectCheckerTest { } @Test - public void testInvalidTreeNameIsMixedCaseGitWindows() { + public void testInvalidTreeNameIsMixedCaseGit() { StringBuilder b = new StringBuilder(); entry(b, "100644 .GiT"); byte[] data = Constants.encodeASCII(b.toString()); try { - checker.setSafeForWindows(true); checker.checkTree(data); fail("incorrectly accepted an invalid tree"); } catch (CorruptObjectException e) { @@ -1309,20 +1308,256 @@ public class ObjectCheckerTest { } @Test - public void testInvalidTreeNameIsMixedCaseGitMacOS() { + public void testInvalidTreeNameIsMacHFSGit() { StringBuilder b = new StringBuilder(); - entry(b, "100644 .GiT"); - byte[] data = Constants.encodeASCII(b.toString()); + entry(b, "100644 .gi\u200Ct"); + 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'", 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 public void testInvalidTreeTruncatedInName() { final StringBuilder b = new StringBuilder(); b.append("100644 b"); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java index b17b991add..b13c4cd801 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java @@ -131,7 +131,8 @@ public class SubmoduleAddTest extends RepositoryTestCase { command.setURI(uri); Repository repo = command.call(); assertNotNull(repo); - addRepoToClose(repo); + ObjectId subCommit = repo.resolve(Constants.HEAD); + repo.close(); SubmoduleWalk generator = SubmoduleWalk.forIndex(db); assertTrue(generator.next()); @@ -141,9 +142,9 @@ public class SubmoduleAddTest extends RepositoryTestCase { assertEquals(path, generator.getModulesPath()); assertEquals(uri, generator.getConfigUrl()); Repository subModRepo = generator.getRepository(); - addRepoToClose(subModRepo); assertNotNull(subModRepo); - assertEquals(commit, repo.resolve(Constants.HEAD)); + assertEquals(subCommit, commit); + subModRepo.close(); Status status = Git.wrap(db).status().call(); assertTrue(status.getAdded().contains(Constants.DOT_GIT_MODULES)); @@ -206,7 +207,6 @@ public class SubmoduleAddTest extends RepositoryTestCase { fullUri = fullUri.replace('\\', '/'); assertEquals(fullUri, generator.getConfigUrl()); Repository subModRepo = generator.getRepository(); - addRepoToClose(subModRepo); assertNotNull(subModRepo); assertEquals( fullUri, @@ -215,6 +215,7 @@ public class SubmoduleAddTest extends RepositoryTestCase { .getString(ConfigConstants.CONFIG_REMOTE_SECTION, Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL)); + subModRepo.close(); assertEquals(commit, repo.resolve(Constants.HEAD)); Status status = Git.wrap(db).status().call(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java index b00d452875..54a6f77b45 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java @@ -135,8 +135,8 @@ public class SubmoduleSyncTest extends RepositoryTestCase { assertTrue(generator.next()); assertEquals(url, generator.getConfigUrl()); Repository subModRepository = generator.getRepository(); - addRepoToClose(subModRepository); StoredConfig submoduleConfig = subModRepository.getConfig(); + subModRepository.close(); assertEquals(url, submoduleConfig.getString( ConfigConstants.CONFIG_REMOTE_SECTION, Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL)); @@ -207,8 +207,8 @@ public class SubmoduleSyncTest extends RepositoryTestCase { assertTrue(generator.next()); assertEquals("git://server/sub.git", generator.getConfigUrl()); Repository subModRepository1 = generator.getRepository(); - addRepoToClose(subModRepository1); StoredConfig submoduleConfig = subModRepository1.getConfig(); + subModRepository1.close(); assertEquals("git://server/sub.git", submoduleConfig.getString( ConfigConstants.CONFIG_REMOTE_SECTION, Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL)); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java index eac4c873fb..bcdd5e21b6 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java @@ -121,9 +121,9 @@ public class SubmoduleUpdateTest extends RepositoryTestCase { SubmoduleWalk generator = SubmoduleWalk.forIndex(db); assertTrue(generator.next()); Repository subRepo = generator.getRepository(); - addRepoToClose(subRepo); assertNotNull(subRepo); assertEquals(commit, subRepo.resolve(Constants.HEAD)); + subRepo.close(); } @Test diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java index 251938fece..f7acaa7880 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java @@ -175,12 +175,12 @@ public class SubmoduleWalkTest extends RepositoryTestCase { assertNull(gen.getModulesUpdate()); assertNull(gen.getModulesUrl()); Repository subRepo = gen.getRepository(); - addRepoToClose(subRepo); assertNotNull(subRepo); assertEquals(modulesGitDir.getAbsolutePath(), subRepo.getDirectory().getAbsolutePath()); assertEquals(new File(db.getWorkTree(), path).getAbsolutePath(), subRepo.getWorkTree().getAbsolutePath()); + subRepo.close(); assertFalse(gen.next()); } @@ -227,11 +227,11 @@ public class SubmoduleWalkTest extends RepositoryTestCase { assertNull(gen.getModulesUpdate()); assertNull(gen.getModulesUrl()); Repository subRepo = gen.getRepository(); - addRepoToClose(subRepo); assertNotNull(subRepo); assertEqualsFile(modulesGitDir, subRepo.getDirectory()); assertEqualsFile(new File(db.getWorkTree(), path), subRepo.getWorkTree()); + subRepo.close(); assertFalse(gen.next()); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java index 4c329cb191..d0062e1990 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java +++ b/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 - filter.include(fakeWalk("d.")); + filter.include(fakeWalk("d-")); // less obvious due to git sorting order try { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TemporaryBufferTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TemporaryBufferTest.java index 5f5968dbcf..9817cdc0a1 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TemporaryBufferTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TemporaryBufferTest.java @@ -59,7 +59,7 @@ import org.junit.Test; public class TemporaryBufferTest { @Test public void testEmpty() throws IOException { - final TemporaryBuffer b = new TemporaryBuffer.LocalFile(); + final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null); try { b.close(); assertEquals(0, b.length()); @@ -73,7 +73,7 @@ public class TemporaryBufferTest { @Test 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(); try { b.write(test); @@ -100,7 +100,7 @@ public class TemporaryBufferTest { @Test 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()) .nextBytes(TemporaryBuffer.Block.SZ); try { @@ -131,7 +131,7 @@ public class TemporaryBufferTest { @Test 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()) .nextBytes(TemporaryBuffer.Block.SZ * 3 / 2); try { @@ -162,7 +162,7 @@ public class TemporaryBufferTest { @Test 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()) .nextBytes(TemporaryBuffer.Block.SZ * 3 / 2); try { @@ -191,7 +191,7 @@ public class TemporaryBufferTest { @Test 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()) .nextBytes(TemporaryBuffer.Block.SZ * 3 / 2); try { @@ -221,7 +221,7 @@ public class TemporaryBufferTest { @Test 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()) .nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 3); try { @@ -263,7 +263,7 @@ public class TemporaryBufferTest { @Test 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()) .nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT + 1); try { @@ -292,7 +292,7 @@ public class TemporaryBufferTest { @Test 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()) .nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 3); try { @@ -321,7 +321,7 @@ public class TemporaryBufferTest { @Test 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()) .nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2); try { @@ -354,7 +354,7 @@ public class TemporaryBufferTest { @Test public void testDestroyWhileOpen() throws IOException { @SuppressWarnings("resource" /* java 7 */) - final TemporaryBuffer b = new TemporaryBuffer.LocalFile(); + final TemporaryBuffer b = new TemporaryBuffer.LocalFile(null); try { b.write(new TestRng(getName()) .nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2)); @@ -365,7 +365,7 @@ public class TemporaryBufferTest { @Test 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 int max = TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2; final byte[] expect = new byte[max]; diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index 76c709422e..a753188e88 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -249,6 +249,8 @@ indexFileIsInUse=Index file is in use indexFileIsTooLargeForJgit=Index file is too large for jgit indexSignatureIsInvalid=Index signature is invalid: {0} indexWriteException=Modified index could not be written +initFailedBareRepoDifferentDirs=When initializing a bare repo with directory {0} and separate git-dir {1} specified both folders must point to the same location +initFailedNonBareRepoSameDirs=When initializing a non-bare repo with directory {0} and separate git-dir {1} specified both folders should not point to the same location inMemoryBufferLimitExceeded=In-memory buffer limit exceeded inputStreamMustSupportMark=InputStream must support mark() integerValueOutOfRange=Integer value {0}.{1} out of range diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java index 1820932286..3787ac5117 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java @@ -405,14 +405,17 @@ public class CheckoutCommand extends GitCommand<Ref> { DirCacheIterator dci = new DirCacheIterator(dc); treeWalk.addTree(dci); + String previousPath = null; + final ObjectReader r = treeWalk.getObjectReader(); DirCacheEditor editor = dc.editor(); while (treeWalk.next()) { - DirCacheEntry entry = dci.getDirCacheEntry(); + String path = treeWalk.getPathString(); // Only add one edit per path - if (entry != null && entry.getStage() > DirCacheEntry.STAGE_1) + if (path.equals(previousPath)) continue; - editor.add(new PathEdit(treeWalk.getPathString()) { + + editor.add(new PathEdit(path) { public void apply(DirCacheEntry ent) { int stage = ent.getStage(); if (stage > DirCacheEntry.STAGE_0) { @@ -429,6 +432,8 @@ public class CheckoutCommand extends GitCommand<Ref> { } } }); + + previousPath = path; } editor.commit(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java index 645d3e7815..de24dadff6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java @@ -86,6 +86,8 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { private File directory; + private File gitDir; + private boolean bare; private String remote = Constants.DEFAULT_REMOTE_NAME; @@ -137,12 +139,19 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { private Repository init(URIish u) throws GitAPIException { InitCommand command = Git.init(); command.setBare(bare); - if (directory == null) + if (directory == null && gitDir == null) directory = new File(u.getHumanishName(), Constants.DOT_GIT); - if (directory.exists() && directory.listFiles().length != 0) + if (directory != null && directory.exists() + && directory.listFiles().length != 0) throw new JGitInternalException(MessageFormat.format( JGitText.get().cloneNonEmptyDirectory, directory.getName())); - command.setDirectory(directory); + if (gitDir != null && gitDir.exists() && gitDir.listFiles().length != 0) + throw new JGitInternalException(MessageFormat.format( + JGitText.get().cloneNonEmptyDirectory, gitDir.getName())); + if (directory != null) + command.setDirectory(directory); + if (gitDir != null) + command.setGitDir(gitDir); return command.call().getRepository(); } @@ -336,18 +345,47 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { * @param directory * the directory to clone to * @return this instance + * @throws IllegalStateException + * if the combination of directory, gitDir and bare is illegal. + * E.g. if for a non-bare repository directory and gitDir point + * to the same directory of if for a bare repository both + * directory and gitDir are specified */ public CloneCommand setDirectory(File directory) { + validateDirs(directory, gitDir, bare); this.directory = directory; return this; } /** + * @param gitDir + * the repository meta directory + * @return this instance + * @throws IllegalStateException + * if the combination of directory, gitDir and bare is illegal. + * E.g. if for a non-bare repository directory and gitDir point + * to the same directory of if for a bare repository both + * directory and gitDir are specified + * @since 3.6 + */ + public CloneCommand setGitDir(File gitDir) { + validateDirs(directory, gitDir, bare); + this.gitDir = gitDir; + return this; + } + + /** * @param bare * whether the cloned repository is bare or not * @return this instance + * @throws IllegalStateException + * if the combination of directory, gitDir and bare is illegal. + * E.g. if for a non-bare repository directory and gitDir point + * to the same directory of if for a bare repository both + * directory and gitDir are specified */ - public CloneCommand setBare(boolean bare) { + public CloneCommand setBare(boolean bare) throws IllegalStateException { + validateDirs(directory, gitDir, bare); this.bare = bare; return this; } @@ -438,4 +476,21 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { this.noCheckout = noCheckout; return this; } + + private static void validateDirs(File directory, File gitDir, boolean bare) + throws IllegalStateException { + if (directory != null) { + if (bare) { + if (gitDir != null && !gitDir.equals(directory)) + throw new IllegalStateException(MessageFormat.format( + JGitText.get().initFailedBareRepoDifferentDirs, + gitDir, directory)); + } else { + if (gitDir != null && gitDir.equals(directory)) + throw new IllegalStateException(MessageFormat.format( + JGitText.get().initFailedNonBareRepoSameDirs, + gitDir, directory)); + } + } + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java index bf43e90d42..37a788e85c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java @@ -44,13 +44,16 @@ package org.eclipse.jgit.api; import java.io.File; import java.io.IOException; +import java.text.MessageFormat; import java.util.concurrent.Callable; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.JGitInternalException; +import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryBuilder; +import org.eclipse.jgit.util.SystemReader; /** * Create an empty git repository or reinitalize an existing one @@ -61,6 +64,8 @@ import org.eclipse.jgit.lib.RepositoryBuilder; public class InitCommand implements Callable<Git> { private File directory; + private File gitDir; + private boolean bare; /** @@ -74,18 +79,36 @@ public class InitCommand implements Callable<Git> { if (bare) builder.setBare(); builder.readEnvironment(); + if (gitDir != null) + builder.setGitDir(gitDir); + else + gitDir = builder.getGitDir(); if (directory != null) { - File d = directory; - if (!bare) - d = new File(d, Constants.DOT_GIT); - builder.setGitDir(d); + if (bare) + builder.setGitDir(directory); + else { + builder.setWorkTree(directory); + if (gitDir == null) + builder.setGitDir(new File(directory, Constants.DOT_GIT)); + } } else if (builder.getGitDir() == null) { - File d = new File("."); //$NON-NLS-1$ - if (d.getParentFile() != null) - d = d.getParentFile(); + String dStr = SystemReader.getInstance() + .getProperty("user.dir"); //$NON-NLS-1$ + if (dStr == null) + dStr = "."; //$NON-NLS-1$ + File d = new File(dStr); if (!bare) d = new File(d, Constants.DOT_GIT); builder.setGitDir(d); + } else { + // directory was not set but gitDir was set + if (!bare) { + String dStr = SystemReader.getInstance().getProperty( + "user.dir"); //$NON-NLS-1$ + if (dStr == null) + dStr = "."; //$NON-NLS-1$ + builder.setWorkTree(new File(dStr)); + } } Repository repository = builder.build(); if (!repository.getObjectDatabase().exists()) @@ -103,20 +126,67 @@ public class InitCommand implements Callable<Git> { * @param directory * the directory to init to * @return this instance + * @throws IllegalStateException + * if the combination of directory, gitDir and bare is illegal. + * E.g. if for a non-bare repository directory and gitDir point + * to the same directory of if for a bare repository both + * directory and gitDir are specified */ - public InitCommand setDirectory(File directory) { + public InitCommand setDirectory(File directory) + throws IllegalStateException { + validateDirs(directory, gitDir, bare); this.directory = directory; return this; } /** + * @param gitDir + * the repository meta directory + * @return this instance + * @throws IllegalStateException + * if the combination of directory, gitDir and bare is illegal. + * E.g. if for a non-bare repository directory and gitDir point + * to the same directory of if for a bare repository both + * directory and gitDir are specified + * @since 3.6 + */ + public InitCommand setGitDir(File gitDir) + throws IllegalStateException { + validateDirs(directory, gitDir, bare); + this.gitDir = gitDir; + return this; + } + + private static void validateDirs(File directory, File gitDir, boolean bare) + throws IllegalStateException { + if (directory != null) { + if (bare) { + if (gitDir != null && !gitDir.equals(directory)) + throw new IllegalStateException(MessageFormat.format( + JGitText.get().initFailedBareRepoDifferentDirs, + gitDir, directory)); + } else { + if (gitDir != null && gitDir.equals(directory)) + throw new IllegalStateException(MessageFormat.format( + JGitText.get().initFailedNonBareRepoSameDirs, + gitDir, directory)); + } + } + } + + /** * @param bare * whether the repository is bare or not + * @throws IllegalStateException + * if the combination of directory, gitDir and bare is illegal. + * E.g. if for a non-bare repository directory and gitDir point + * to the same directory of if for a bare repository both + * directory and gitDir are specified * @return this instance */ public InitCommand setBare(boolean bare) { + validateDirs(directory, gitDir, bare); this.bare = bare; return this; } - } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ReflogCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ReflogCommand.java index 8cd78aebe1..4536af1be0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ReflogCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ReflogCommand.java @@ -48,6 +48,7 @@ import java.util.Collection; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.InvalidRefNameException; +import org.eclipse.jgit.api.errors.RefNotFoundException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ReflogEntry; @@ -97,6 +98,9 @@ public class ReflogCommand extends GitCommand<Collection<ReflogEntry>> { try { ReflogReader reader = repo.getReflogReader(ref); + if (reader == null) + throw new RefNotFoundException(MessageFormat.format( + JGitText.get().refNotResolved, ref)); return reader.getReverseEntries(); } catch (IOException e) { throw new InvalidRefNameException(MessageFormat.format( diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java index de1a3e9fd0..81a30156a6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java @@ -42,6 +42,7 @@ */ package org.eclipse.jgit.api; +import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; @@ -163,6 +164,8 @@ public class SubmoduleUpdateCommand extends configure(clone); clone.setURI(url); clone.setDirectory(generator.getDirectory()); + clone.setGitDir(new File(new File(repo.getDirectory(), + Constants.MODULES), generator.getPath())); if (monitor != null) clone.setProgressMonitor(monitor); submoduleRepo = clone.call().getRepository(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java index 645de2704e..98a1c8ca4b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java @@ -607,7 +607,8 @@ public class DirCache { final LockFile tmp = myLock; requireLocked(tmp); try { - writeTo(new SafeBufferedOutputStream(tmp.getOutputStream())); + writeTo(liveFile.getParentFile(), + new SafeBufferedOutputStream(tmp.getOutputStream())); } catch (IOException err) { tmp.unlock(); 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 DigestOutputStream dos = new DigestOutputStream(os, foot); @@ -670,14 +671,18 @@ public class DirCache { } if (writeTree) { - final TemporaryBuffer bb = new TemporaryBuffer.LocalFile(); - tree.write(tmp, bb); - bb.close(); - - NB.encodeInt32(tmp, 0, EXT_TREE); - NB.encodeInt32(tmp, 4, (int) bb.length()); - dos.write(tmp, 0, 8); - bb.writeTo(dos, null); + TemporaryBuffer bb = new TemporaryBuffer.LocalFile(dir, 5 << 20); + try { + tree.write(tmp, bb); + bb.close(); + + NB.encodeInt32(tmp, 0, EXT_TREE); + NB.encodeInt32(tmp, 4, (int) bb.length()); + dos.write(tmp, 0, 8); + bb.writeTo(dos, null); + } finally { + bb.destroy(); + } } writeIndexChecksum = foot.digest(); os.write(writeIndexChecksum); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java index c7dd03dd46..015d9d6a85 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java @@ -1245,9 +1245,9 @@ public class DirCacheCheckout { } finally { channel.close(); } - entry.setLength(opt.getAutoCRLF() == AutoCRLF.TRUE - ? f.length() // AutoCRLF wants on-disk-size - : (int) ol.getSize()); + entry.setLength(opt.getAutoCRLF() == AutoCRLF.TRUE ? // + tmpFile.length() // AutoCRLF wants on-disk-size + : (int) ol.getSize()); if (opt.isFileMode() && fs.supportsExecute()) { if (FileMode.EXECUTABLE_FILE.equals(entry.getRawMode())) { @@ -1291,7 +1291,9 @@ public class DirCacheCheckout { try { SystemReader.getInstance().checkPath(path); } catch (CorruptObjectException e) { - throw new InvalidPathException(path); + InvalidPathException p = new InvalidPathException(path); + p.initCause(e); + throw p; } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java index 65188c8f43..eef2e6d3c3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java @@ -56,6 +56,7 @@ import java.security.MessageDigest; import java.text.MessageFormat; import java.util.Arrays; +import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.AnyObjectId; 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.MutableInteger; import org.eclipse.jgit.util.NB; -import org.eclipse.jgit.util.SystemReader; /** * A single file (or stage of a file) in a {@link DirCache}. @@ -190,6 +190,16 @@ public class DirCacheEntry { 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 // for historical reasons related to how C Git read the files. // @@ -203,7 +213,6 @@ public class DirCacheEntry { if (mightBeRacilyClean(smudge_s, smudge_ns)) smudgeRacilyClean(); - } /** @@ -217,7 +226,7 @@ public class DirCacheEntry { * or DirCache file. */ public DirCacheEntry(final String newPath) { - this(Constants.encode(newPath)); + this(Constants.encode(newPath), STAGE_0); } /** @@ -266,11 +275,11 @@ public class DirCacheEntry { */ @SuppressWarnings("boxing") public DirCacheEntry(final byte[] newPath, final int stage) { - if (!isValidPath(newPath)) - throw new InvalidPathException(toString(newPath)); + DirCacheCheckout.checkValidPath(toString(newPath)); if (stage < 0 || 3 < stage) - throw new IllegalArgumentException(MessageFormat.format(JGitText.get().invalidStageForPath - , stage, toString(newPath))); + throw new IllegalArgumentException(MessageFormat.format( + JGitText.get().invalidStageForPath, + stage, toString(newPath))); info = new byte[INFO_LEN]; infoOffset = 0; @@ -725,36 +734,6 @@ public class DirCacheEntry { 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) { return extended ? INFO_LEN_EXTENDED : INFO_LEN; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java index 1c4c3db0d3..4207513e70 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java @@ -193,6 +193,7 @@ public class RepoCommand extends GitCommand<RevCommit> { try { return readFileFromRepo(repo, ref, path); } finally { + repo.close(); FileUtils.delete(dir, FileUtils.RECURSIVE); } } @@ -860,6 +861,7 @@ public class RepoCommand extends GitCommand<RevCommit> { if (revision != null) { Git sub = new Git(subRepo); sub.checkout().setName(findRef(revision, subRepo)).call(); + subRepo.close(); git.add().addFilepattern(name).call(); } for (CopyFile copyfile : copyfiles) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index d1f0deec9d..65272fb0bd 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -308,6 +308,8 @@ public class JGitText extends TranslationBundle { /***/ public String indexFileIsTooLargeForJgit; /***/ public String indexSignatureIsInvalid; /***/ public String indexWriteException; + /***/ public String initFailedBareRepoDifferentDirs; + /***/ public String initFailedNonBareRepoSameDirs; /***/ public String inMemoryBufferLimitExceeded; /***/ public String inputStreamMustSupportMark; /***/ public String integerValueOutOfRange; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java index 9670bf10a2..995621ee3e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java @@ -273,7 +273,8 @@ public class FileRepository extends Repository { ConfigConstants.CONFIG_CORE_SECTION, null, ConfigConstants.CONFIG_KEY_HIDEDOTFILES, HideDotFiles.DOTGITONLY); - if (hideDotFiles != HideDotFiles.FALSE && !isBare()) + if (hideDotFiles != HideDotFiles.FALSE && !isBare() + && getDirectory().getName().startsWith(".")) //$NON-NLS-1$ getFS().setHidden(getDirectory(), true); refs.create(); objectDatabase.create(); @@ -329,6 +330,25 @@ public class FileRepository extends Repository { // Java has no other way cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, ConfigConstants.CONFIG_KEY_PRECOMPOSEUNICODE, true); + if (!bare) { + File workTree = getWorkTree(); + if (!getDirectory().getParentFile().equals(workTree)) { + cfg.setString(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_WORKTREE, getWorkTree() + .getAbsolutePath()); + LockFile dotGitLockFile = new LockFile(new File(workTree, + Constants.DOT_GIT), getFS()); + try { + if (dotGitLockFile.lock()) { + dotGitLockFile.write(Constants.encode(Constants.GITDIR + + getDirectory().getAbsolutePath())); + dotGitLockFile.commit(); + } + } finally { + dotGitLockFile.unlock(); + } + } + } cfg.save(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java index 48a6b9d677..58276051ea 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java @@ -131,14 +131,6 @@ public class ObjectDirectory extends FileObjectDatabase { private Set<ObjectId> shallowCommitsIds; - // Whether to trust the pack folder's modification time. If set - // to false we will always scan the .git/objects/pack folder to - // check for new pack files. If set to true (default) we use the - // lastmodified attribute of the folder and assume that no new - // pack files can be in this folder if his modification time has - // not changed. - private boolean trustFolderStat = true; - /** * Initialize a reference to an on-disk object directory. * @@ -161,9 +153,6 @@ public class ObjectDirectory extends FileObjectDatabase { File[] alternatePaths, FS fs, File shallowFile) throws IOException { config = cfg; objects = dir; - trustFolderStat = config.getBoolean( - ConfigConstants.CONFIG_CORE_SECTION, - ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true); infoDirectory = new File(objects, "info"); //$NON-NLS-1$ packDirectory = new File(objects, "pack"); //$NON-NLS-1$ alternatesFile = new File(infoDirectory, "alternates"); //$NON-NLS-1$ @@ -618,6 +607,16 @@ public class ObjectDirectory extends FileObjectDatabase { } private boolean searchPacksAgain(PackList old) { + // Whether to trust the pack folder's modification time. If set + // to false we will always scan the .git/objects/pack folder to + // check for new pack files. If set to true (default) we use the + // lastmodified attribute of the folder and assume that no new + // pack files can be in this folder if his modification time has + // not changed. + boolean trustFolderStat = config.getBoolean( + ConfigConstants.CONFIG_CORE_SECTION, + ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true); + return ((!trustFolderStat) || old.snapshot.isModified(packDirectory)) && old != scanPacks(old); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java index d14614dc38..f149749843 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java @@ -272,7 +272,14 @@ public final class Constants { */ public static final String INFO_EXCLUDE = "info/exclude"; - /** The environment variable that contains the system user name */ + /** + * The system property that contains the system user name + * + * @since 3.6 + */ + public static final String OS_USER_DIR = "user.dir"; + + /** The system property that contains the system user name */ public static final String OS_USER_NAME_KEY = "user.name"; /** The environment variable that contains the author's name */ @@ -359,6 +366,20 @@ public final class Constants { public static final String SHALLOW = "shallow"; /** + * Prefix of the first line in a ".git" file + * + * @since 3.6 + */ + public static final String GITDIR = "gitdir: "; + + /** + * Name of the folder (inside gitDir) where submodules are stored + * + * @since 3.6 + */ + public static final String MODULES = "modules"; + + /** * Create a new digest function for objects. * * @return a new digest object. diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java index d62b1f58a0..1b049f6155 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java @@ -533,28 +533,35 @@ public class IndexDiff { } Repository subRepo = smw.getRepository(); if (subRepo != null) { - ObjectId subHead = subRepo.resolve("HEAD"); //$NON-NLS-1$ - if (subHead != null && !subHead.equals(smw.getObjectId())) - modified.add(smw.getPath()); - else if (ignoreSubmoduleMode != IgnoreSubmoduleMode.DIRTY) { - IndexDiff smid = submoduleIndexDiffs.get(smw.getPath()); - if (smid == null) { - smid = new IndexDiff(subRepo, smw.getObjectId(), - wTreeIt.getWorkingTreeIterator(subRepo)); - submoduleIndexDiffs.put(smw.getPath(), smid); - } - if (smid.diff()) { - if (ignoreSubmoduleMode == IgnoreSubmoduleMode.UNTRACKED - && smid.getAdded().isEmpty() - && smid.getChanged().isEmpty() - && smid.getConflicting().isEmpty() - && smid.getMissing().isEmpty() - && smid.getModified().isEmpty() - && smid.getRemoved().isEmpty()) { - continue; - } + try { + ObjectId subHead = subRepo.resolve("HEAD"); //$NON-NLS-1$ + if (subHead != null + && !subHead.equals(smw.getObjectId())) modified.add(smw.getPath()); + else if (ignoreSubmoduleMode != IgnoreSubmoduleMode.DIRTY) { + IndexDiff smid = submoduleIndexDiffs.get(smw + .getPath()); + if (smid == null) { + smid = new IndexDiff(subRepo, + smw.getObjectId(), + wTreeIt.getWorkingTreeIterator(subRepo)); + submoduleIndexDiffs.put(smw.getPath(), smid); + } + if (smid.diff()) { + if (ignoreSubmoduleMode == IgnoreSubmoduleMode.UNTRACKED + && smid.getAdded().isEmpty() + && smid.getChanged().isEmpty() + && smid.getConflicting().isEmpty() + && smid.getMissing().isEmpty() + && smid.getModified().isEmpty() + && smid.getRemoved().isEmpty()) { + continue; + } + modified.add(smw.getPath()); + } } + } finally { + subRepo.close(); } } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java index 9fe54b0c5c..8435c9a64b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java @@ -492,13 +492,27 @@ public class ObjectChecker { throw new CorruptObjectException("invalid name '..'"); break; 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( "invalid name '%s'", 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) { // Windows ignores space and dot at end of file name. 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) throws CorruptObjectException { switch (toLower(raw[ptr])) { @@ -579,12 +675,36 @@ public class ObjectChecker { return 1 <= c && c <= 31; } - private boolean isDotGit(byte[] buf, int p) { - if (windows || macosx) - return toLower(buf[p]) == 'g' - && toLower(buf[p + 1]) == 'i' - && toLower(buf[p + 2]) == 't'; - return buf[p] == 'g' && buf[p + 1] == 'i' && buf[p + 2] == 't'; + private static boolean isGit(byte[] buf, int p) { + return toLower(buf[p]) == 'g' + && toLower(buf[p + 1]) == 'i' + && toLower(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) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java index ef61e22032..4ebe5fedf3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java @@ -43,17 +43,17 @@ package org.eclipse.jgit.lib; -import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.io.OutputStreamWriter; +import java.io.OutputStream; import java.util.LinkedList; import java.util.List; import org.eclipse.jgit.lib.RebaseTodoLine.Action; import org.eclipse.jgit.util.IO; 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 @@ -216,9 +216,8 @@ public class RebaseTodoFile { */ public void writeRebaseTodoFile(String path, List<RebaseTodoLine> steps, boolean append) throws IOException { - BufferedWriter fw = new BufferedWriter(new OutputStreamWriter( - new FileOutputStream(new File(repo.getDirectory(), path), - append), Constants.CHARACTER_ENCODING)); + OutputStream fw = new SafeBufferedOutputStream(new FileOutputStream( + new File(repo.getDirectory(), path), append)); try { StringBuilder sb = new StringBuilder(); for (RebaseTodoLine step : steps) { @@ -232,8 +231,8 @@ public class RebaseTodoFile { sb.append(" "); //$NON-NLS-1$ sb.append(step.getShortMessage().trim()); } - fw.write(sb.toString()); - fw.newLine(); + sb.append('\n'); + fw.write(Constants.encode(sb.toString())); } } finally { fw.close(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/patch/FileHeader.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/FileHeader.java index 8171669bc8..534c827314 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/FileHeader.java +++ b/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]; try { 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()) h.extractFileLines(tmp); @@ -281,11 +281,6 @@ public class FileHeader extends DiffEntry { return r; } catch (IOException ioe) { throw new RuntimeException(JGitText.get().cannotConvertScriptToText, ioe); - } finally { - for (final TemporaryBuffer b : tmp) { - if (b != null) - b.destroy(); - } } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/patch/Patch.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/Patch.java index 7b48473523..383c1f8fef 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/Patch.java +++ b/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 { - final TemporaryBuffer b = new TemporaryBuffer.LocalFile(); - try { - b.copy(is); - b.close(); - return b.toByteArray(); - } finally { - b.destroy(); - } + TemporaryBuffer b = new TemporaryBuffer.Heap(Integer.MAX_VALUE); + b.copy(is); + b.close(); + return b.toByteArray(); } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java index 99d8b09d87..722bfc489d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java +++ b/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. */ private final WalkEncryption encryption; + /** Directory for locally buffered content. */ + private final File tmpDir; + /** * Create a new S3 client for the supplied user information. * <p> @@ -251,6 +254,9 @@ public class AmazonS3 { maxAttempts = Integer.parseInt(props.getProperty( "httpclient.retry-max", "3")); //$NON-NLS-1$ //$NON-NLS-2$ 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) throws IOException { final MessageDigest md5 = newMD5(); - final TemporaryBuffer buffer = new TemporaryBuffer.LocalFile() { + final TemporaryBuffer buffer = new TemporaryBuffer.LocalFile(tmpDir) { @Override public void close() throws IOException { super.close(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java index b3a55a581b..afaaa69a43 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java @@ -147,7 +147,11 @@ public class TransportAmazonS3 extends HttpTransport implements WalkTransport { throws NotSupportedException { 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(); String p = uri.getPath(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java index 88c32d2f53..10aade4e11 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java @@ -361,7 +361,12 @@ public abstract class TemporaryBuffer extends OutputStream { */ 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() { this(null, DEFAULT_IN_CORE_LIMIT); } @@ -372,7 +377,9 @@ public abstract class TemporaryBuffer extends OutputStream { * @param inCoreLimit * maximum number of bytes to store in memory. Storage beyond * this limit will use the local file. + * @deprecated Use the {@code File,int} overload to supply a directory. */ + @Deprecated public LocalFile(final int inCoreLimit) { this(null, inCoreLimit); } |