diff options
author | Shawn O. Pearce <spearce@spearce.org> | 2011-05-31 09:14:50 -0700 |
---|---|---|
committer | Shawn O. Pearce <spearce@spearce.org> | 2011-05-31 09:15:11 -0700 |
commit | 690c268c793bfc218982130fbfc25870f292295e (patch) | |
tree | 2566abc3eb7c591ce2591129e90c8219615348a7 | |
parent | b04be9334494640a693ef5e515af1be4a6983eb5 (diff) | |
parent | 50f236aff861ab2a6851eb96cff6fe07b775bb5b (diff) | |
download | jgit-690c268c793bfc218982130fbfc25870f292295e.tar.gz jgit-690c268c793bfc218982130fbfc25870f292295e.zip |
Merge branch 'stable-1.0'
* stable-1.0:
DHT: Support removing a repository name
DHT: Fix thread-safety issue in AbstractWriteBuffer
jgit.sh: Implement pager support
Change EditList to extend ArrayList
Ensure the HTTP request is fully consumed
Make sure test repositories are closed
Fix CloneCommand not to fetch into remote tracking branches when bare
Update Eclipse IP log for 1.0
Change-Id: I6340d551482e1dda01f82496296d2038b07fa68b
17 files changed, 295 insertions, 73 deletions
diff --git a/.eclipse_iplog b/.eclipse_iplog index 8707214f73..2f518e1235 100644 --- a/.eclipse_iplog +++ b/.eclipse_iplog @@ -120,9 +120,3 @@ license = Apache License, 2.0 use = unmodified source & binary state = approved - -[CQ "5135"] - description = Protocol Buffers Version: 2.4.0a (ATO CQ4876) - license = New BSD license - use = unmodified source & binary - state = approved 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 30d437540f..8ed51fb908 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 @@ -303,6 +303,17 @@ public abstract class LocalDiskRepositoryTestCase { } /** + * Adds a repository to the list of repositories which is closed at the end + * of the tests + * + * @param r + * the repository to be closed + */ + public void addRepoToClose(Repository r) { + toClose.add(r); + } + + /** * Creates a new unique directory for a test repository * * @param bare diff --git a/org.eclipse.jgit.pgm/jgit.sh b/org.eclipse.jgit.pgm/jgit.sh index e6a2119ef1..9ff59d6122 100644 --- a/org.eclipse.jgit.pgm/jgit.sh +++ b/org.eclipse.jgit.pgm/jgit.sh @@ -41,6 +41,20 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +cmd= +for a in "$@" +do + case "$a" in + -*) continue ;; + *) cmd=$a; break; ;; + esac +done + +use_pager= +case "$cmd" in +diff) use_pager=1 ;; +log) use_pager=1 ;; +esac this_script=`which "$0" 2>/dev/null` [ $? -gt 0 -a -f "$0" ] && this_script="$0" @@ -58,7 +72,7 @@ CYGWIN*) cp=`cygpath --windows --mixed --path "$cp"` ;; Darwin) - if test -e /System/Library/Frameworks/JavaVM.framework + if [ -e /System/Library/Frameworks/JavaVM.framework ] then java_args=' -Dcom.apple.mrj.application.apple.menu.about.name=JGit @@ -74,10 +88,25 @@ CLASSPATH="$cp" export CLASSPATH java=java -if test -n "$JAVA_HOME" +if [ -n "$JAVA_HOME" ] then java="$JAVA_HOME/bin/java" fi -exec "$java" $java_args org.eclipse.jgit.pgm.Main "$@" -exit 1 +if [ -n "$use_pager" ] +then + use_pager=${GIT_PAGER:-${PAGER:-less}} + [ cat = "$use_pager" ] && use_pager= +fi + +if [ -n "$use_pager" ] +then + LESS=${LESS:-FSRX} + export LESS + + "$java" $java_args org.eclipse.jgit.pgm.Main "$@" | $use_pager + exit +else + exec "$java" $java_args org.eclipse.jgit.pgm.Main "$@" + exit 1 +fi diff --git a/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/spi/RepositoryIndexTable.java b/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/spi/RepositoryIndexTable.java index 794db6e5e2..36afd13229 100644 --- a/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/spi/RepositoryIndexTable.java +++ b/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/spi/RepositoryIndexTable.java @@ -87,4 +87,21 @@ public interface RepositoryIndexTable { */ public void putUnique(RepositoryName name, RepositoryKey key) throws DhtException, TimeoutException; + + /** + * Remove the association of a name to an identifier. + * <p> + * This method must use some sort of transaction system to ensure the name + * is removed only if it currently references {@code key}. This may require + * running some sort of lock management service in parallel to the database. + * + * @param name + * name of the repository. + * @param key + * internal key defining the repository. + * @throws DhtException + * @throws TimeoutException + */ + public void remove(RepositoryName name, RepositoryKey key) + throws DhtException, TimeoutException; } diff --git a/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/spi/cache/CacheRepositoryIndexTable.java b/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/spi/cache/CacheRepositoryIndexTable.java index 5ff43910f3..b50092c6d1 100644 --- a/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/spi/cache/CacheRepositoryIndexTable.java +++ b/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/spi/cache/CacheRepositoryIndexTable.java @@ -128,4 +128,18 @@ public class CacheRepositoryIndexTable implements RepositoryIndexTable { throw new TimeoutException(); } } + + public void remove(RepositoryName name, RepositoryKey key) + throws DhtException, TimeoutException { + db.remove(name, key); + + Sync<Void> sync = Sync.create(); + CacheKey memKey = ns.key(name); + client.modify(singleton(Change.remove(memKey)), sync); + try { + sync.get(options.getTimeout()); + } catch (InterruptedException e) { + throw new TimeoutException(); + } + } } diff --git a/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/spi/memory/MemRepositoryIndexTable.java b/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/spi/memory/MemRepositoryIndexTable.java index 46a1fd619a..000ff77327 100644 --- a/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/spi/memory/MemRepositoryIndexTable.java +++ b/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/spi/memory/MemRepositoryIndexTable.java @@ -78,4 +78,16 @@ final class MemRepositoryIndexTable implements RepositoryIndexTable { throw new DhtException(MessageFormat.format( DhtText.get().repositoryAlreadyExists, name.asString())); } + + public void remove(RepositoryName name, RepositoryKey key) + throws DhtException, TimeoutException { + boolean ok = table.compareAndSet( + name.asBytes(), + colId.name(), + key.asBytes(), + null); + if (!ok) + throw new DhtException(MessageFormat.format( + DhtText.get().repositoryAlreadyExists, name.asString())); + } } diff --git a/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/spi/util/AbstractWriteBuffer.java b/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/spi/util/AbstractWriteBuffer.java index d40cbe31ad..ad55206fe7 100644 --- a/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/spi/util/AbstractWriteBuffer.java +++ b/org.eclipse.jgit.storage.dht/src/org/eclipse/jgit/storage/dht/spi/util/AbstractWriteBuffer.java @@ -82,6 +82,8 @@ public abstract class AbstractWriteBuffer implements WriteBuffer { private final List<Future<?>> running; + private final Object runningLock; + private final Semaphore spaceAvailable; private int queuedCount; @@ -102,6 +104,7 @@ public abstract class AbstractWriteBuffer implements WriteBuffer { this.executor = executor; this.bufferSize = bufferSize; this.running = new LinkedList<Future<?>>(); + this.runningLock = new Object(); this.spaceAvailable = new Semaphore(bufferSize); } @@ -189,14 +192,18 @@ public abstract class AbstractWriteBuffer implements WriteBuffer { } } - checkRunningTasks(true); + synchronized (runningLock) { + checkRunningTasks(true); + } } finally { flushing = false; } } public void abort() throws DhtException { - checkRunningTasks(true); + synchronized (runningLock) { + checkRunningTasks(true); + } } private void acquireSpace(int sz) throws DhtException { @@ -259,9 +266,11 @@ public abstract class AbstractWriteBuffer implements WriteBuffer { return; } - if (!flushing) - checkRunningTasks(false); - running.add(executor.submit(op)); + synchronized (runningLock) { + if (!flushing) + checkRunningTasks(false); + running.add(executor.submit(op)); + } } /** @@ -284,8 +293,10 @@ public abstract class AbstractWriteBuffer implements WriteBuffer { int size) throws DhtException { int permits = permitsForSize(size); WrappedCallback<T> op = new WrappedCallback<T>(callback, permits); - checkRunningTasks(false); - running.add(op); + synchronized (runningLock) { + checkRunningTasks(false); + running.add(op); + } return op; } 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 f21dc4a0be..2e3345756d 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 @@ -49,12 +49,14 @@ import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; import java.util.Collections; +import java.util.List; import org.eclipse.jgit.api.ListBranchCommand.ListMode; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryTestCase; @@ -99,6 +101,7 @@ public class CloneCommandTest extends RepositoryTestCase { command.setURI("file://" + git.getRepository().getWorkTree().getPath()); Git git2 = command.call(); + addRepoToClose(git2.getRepository()); assertNotNull(git2); ObjectId id = git2.getRepository().resolve("tag-for-blob"); assertNotNull(id); @@ -133,9 +136,51 @@ public class CloneCommandTest extends RepositoryTestCase { command.setURI("file://" + git.getRepository().getWorkTree().getPath()); Git git2 = command.call(); + addRepoToClose(git2.getRepository()); + + assertNotNull(git2); + assertEquals(git2.getRepository().getFullBranch(), + "refs/heads/master"); + assertEquals( + "refs/heads/master, refs/remotes/origin/master, refs/remotes/origin/test", + allRefNames(git2.branchList().setListMode(ListMode.ALL) + .call())); + + // Same thing, but now without checkout + directory = createTempDirectory("testCloneRepositoryWithBranch_bare"); + command = Git.cloneRepository(); + command.setBranch("refs/heads/master"); + command.setDirectory(directory); + command.setURI("file://" + + git.getRepository().getWorkTree().getPath()); + command.setNoCheckout(true); + git2 = command.call(); + addRepoToClose(git2.getRepository()); + assertNotNull(git2); assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master"); + assertEquals( + "refs/remotes/origin/master, refs/remotes/origin/test", + allRefNames(git2.branchList().setListMode(ListMode.ALL) + .call())); + + // Same thing, but now test with bare repo + directory = createTempDirectory("testCloneRepositoryWithBranch_bare"); + command = Git.cloneRepository(); + command.setBranch("refs/heads/master"); + command.setDirectory(directory); + command.setURI("file://" + + git.getRepository().getWorkTree().getPath()); + command.setBare(true); + git2 = command.call(); + addRepoToClose(git2.getRepository()); + + assertNotNull(git2); + assertEquals(git2.getRepository().getFullBranch(), + "refs/heads/master"); + assertEquals("refs/heads/master, refs/heads/test", allRefNames(git2 + .branchList().setListMode(ListMode.ALL).call())); } catch (Exception e) { fail(e.getMessage()); } @@ -153,16 +198,46 @@ public class CloneCommandTest extends RepositoryTestCase { command.setURI("file://" + git.getRepository().getWorkTree().getPath()); Git git2 = command.call(); + addRepoToClose(git2.getRepository()); assertNotNull(git2); assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master"); - assertEquals(1, git2.branchList().setListMode(ListMode.REMOTE) - .call().size()); + assertEquals("refs/remotes/origin/master", + allRefNames(git2.branchList() + .setListMode(ListMode.REMOTE).call())); + + // Same thing, but now test with bare repo + directory = createTempDirectory("testCloneRepositoryWithBranch_bare"); + command = Git.cloneRepository(); + command.setBranch("refs/heads/master"); + command.setBranchesToClone(Collections + .singletonList("refs/heads/master")); + command.setDirectory(directory); + command.setURI("file://" + + git.getRepository().getWorkTree().getPath()); + command.setBare(true); + git2 = command.call(); + addRepoToClose(git2.getRepository()); + assertNotNull(git2); + assertEquals(git2.getRepository().getFullBranch(), + "refs/heads/master"); + assertEquals("refs/heads/master", allRefNames(git2 + .branchList().setListMode(ListMode.ALL).call())); } catch (Exception e) { fail(e.getMessage()); } } + public static String allRefNames(List<Ref> refs) { + StringBuilder sb = new StringBuilder(); + for (Ref f : refs) { + if (sb.length() > 0) + sb.append(", "); + sb.append(f.getName()); + } + return sb.toString(); + } + public static File createTempDirectory(String name) throws IOException { final File temp; temp = File.createTempFile(name, Long.toString(System.nanoTime())); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java index 8aacbb063c..8031769204 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java @@ -72,6 +72,7 @@ public class GitConstructionTest extends RepositoryTestCase { .setURI(db.getDirectory().toURI().toString()) .setDirectory(createUniqueTestGitDir(true)).call() .getRepository(); + addRepoToClose(bareRepo); } @Override @@ -88,7 +89,7 @@ public class GitConstructionTest extends RepositoryTestCase { assertEquals(1, git.branchList().call().size()); git = Git.wrap(bareRepo); - assertEquals(2, git.branchList().setListMode(ListMode.ALL).call() + assertEquals(1, git.branchList().setListMode(ListMode.ALL).call() .size()); try { @@ -105,7 +106,7 @@ public class GitConstructionTest extends RepositoryTestCase { assertEquals(1, git.branchList().call().size()); git = Git.open(bareRepo.getDirectory()); - assertEquals(2, git.branchList().setListMode(ListMode.ALL).call() + assertEquals(1, git.branchList().setListMode(ListMode.ALL).call() .size()); git = Git.open(db.getWorkTree()); 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 15aafc9060..28c54c269f 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 @@ -70,6 +70,7 @@ public class InitCommandTest extends RepositoryTestCase { InitCommand command = new InitCommand(); command.setDirectory(directory); Repository repository = command.call().getRepository(); + addRepoToClose(repository); assertNotNull(repository); } catch (Exception e) { fail(e.getMessage()); @@ -84,6 +85,7 @@ public class InitCommandTest extends RepositoryTestCase { command.setDirectory(directory); command.setBare(true); Repository repository = command.call().getRepository(); + addRepoToClose(repository); assertNotNull(repository); assertTrue(repository.isBare()); } catch (Exception e) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LsRemoteCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LsRemoteCommandTest.java index 81aa25f981..a4a5a2671b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LsRemoteCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LsRemoteCommandTest.java @@ -89,6 +89,8 @@ public class LsRemoteCommandTest extends RepositoryTestCase { + git.getRepository().getWorkTree().getPath()); command.setCloneAllBranches(true); Git git2 = command.call(); + addRepoToClose(git2.getRepository()); + LsRemoteCommand lsRemoteCommand = git2.lsRemote(); Collection<Ref> refs = lsRemoteCommand.call(); @@ -109,6 +111,7 @@ public class LsRemoteCommandTest extends RepositoryTestCase { + git.getRepository().getWorkTree().getPath()); command.setCloneAllBranches(true); Git git2 = command.call(); + addRepoToClose(git2.getRepository()); LsRemoteCommand lsRemoteCommand = git2.lsRemote(); lsRemoteCommand.setTags(true); @@ -130,6 +133,7 @@ public class LsRemoteCommandTest extends RepositoryTestCase { + git.getRepository().getWorkTree().getPath()); command.setCloneAllBranches(true); Git git2 = command.call(); + addRepoToClose(git2.getRepository()); LsRemoteCommand lsRemoteCommand = git2.lsRemote(); lsRemoteCommand.setHeads(true); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java index df89674e6f..719cc66671 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java @@ -46,7 +46,9 @@ package org.eclipse.jgit.transport; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.File; @@ -54,8 +56,10 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; +import java.text.MessageFormat; import java.util.zip.Deflater; +import org.eclipse.jgit.JGitText; import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.lib.Constants; @@ -69,6 +73,7 @@ import org.eclipse.jgit.storage.file.ObjectDirectoryPackParser; import org.eclipse.jgit.storage.file.PackFile; import org.eclipse.jgit.util.NB; import org.eclipse.jgit.util.TemporaryBuffer; +import org.eclipse.jgit.util.io.UnionInputStream; import org.junit.After; import org.junit.Test; @@ -177,6 +182,33 @@ public class PackParserTest extends RepositoryTestCase { p.parse(NullProgressMonitor.INSTANCE); } + @Test + public void testPackWithTrailingGarbage() throws Exception { + TestRepository d = new TestRepository(db); + RevBlob a = d.blob("a"); + + TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024); + packHeader(pack, 1); + pack.write((Constants.OBJ_REF_DELTA) << 4 | 4); + a.copyRawTo(pack); + deflate(pack, new byte[] { 0x1, 0x1, 0x1, 'b' }); + digest(pack); + + PackParser p = index(new UnionInputStream( + new ByteArrayInputStream(pack.toByteArray()), + new ByteArrayInputStream(new byte[] { 0x7e }))); + p.setAllowThin(true); + p.setCheckEofAfterPackFooter(true); + try { + p.parse(NullProgressMonitor.INSTANCE); + fail("Pack with trailing garbage was accepted"); + } catch (IOException err) { + assertEquals( + MessageFormat.format(JGitText.get().expectedEOFReceived, "\\x73"), + err.getMessage()); + } + } + private void packHeader(TemporaryBuffer.Heap tinyPack, int cnt) throws IOException { final byte[] hdr = new byte[8]; 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 39652306b0..aa8cf6e30a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java @@ -98,6 +98,8 @@ public class CloneCommand implements Callable<Git> { private boolean cloneAllBranches; + private boolean noCheckout; + private Collection<String> branchesToClone; /** @@ -112,7 +114,8 @@ public class CloneCommand implements Callable<Git> { URIish u = new URIish(uri); Repository repository = init(u); FetchResult result = fetch(repository, u); - checkout(repository, result); + if (!noCheckout) + checkout(repository, result); return new Git(repository); } catch (IOException ioe) { throw new JGitInternalException(ioe.getMessage(), ioe); @@ -140,7 +143,8 @@ public class CloneCommand implements Callable<Git> { RemoteConfig config = new RemoteConfig(repo.getConfig(), remote); config.addURI(u); - final String dst = Constants.R_REMOTES + config.getName(); + final String dst = bare ? Constants.R_HEADS : Constants.R_REMOTES + + config.getName(); RefSpec refSpec = new RefSpec(); refSpec = refSpec.setForceUpdate(true); refSpec = refSpec.setSourceDestination(Constants.R_HEADS + "*", dst + "/*"); //$NON-NLS-1$ //$NON-NLS-2$ @@ -368,4 +372,16 @@ public class CloneCommand implements Callable<Git> { return this; } + /** + * @param noCheckout + * if set to <code>true</code> no branch will be checked out + * after the clone. This enhances performance of the clone + * command when there is no need for a checked out branch. + * @return {@code this} + */ + public CloneCommand setNoCheckout(boolean noCheckout) { + this.noCheckout = noCheckout; + return this; + } + } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/EditList.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/EditList.java index 445ff7afe2..be753bee8c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/EditList.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/EditList.java @@ -43,12 +43,12 @@ package org.eclipse.jgit.diff; -import java.util.AbstractList; import java.util.ArrayList; -import java.util.Collection; /** Specialized list of {@link Edit}s in a document. */ -public class EditList extends AbstractList<Edit> { +public class EditList extends ArrayList<Edit> { + private static final long serialVersionUID = 1L; + /** * Construct an edit list containing a single edit. * @@ -62,11 +62,9 @@ public class EditList extends AbstractList<Edit> { return res; } - private final ArrayList<Edit> container; - /** Create a new, empty edit list. */ public EditList() { - container = new ArrayList<Edit>(); + super(16); } /** @@ -77,53 +75,11 @@ public class EditList extends AbstractList<Edit> { * added to the list, it will be grown to support them. */ public EditList(int capacity) { - container = new ArrayList<Edit>(capacity); - } - - @Override - public int size() { - return container.size(); - } - - @Override - public Edit get(final int index) { - return container.get(index); - } - - @Override - public Edit set(final int index, final Edit element) { - return container.set(index, element); - } - - @Override - public void add(final int index, final Edit element) { - container.add(index, element); - } - - @Override - public boolean addAll(Collection<? extends Edit> c) { - return container.addAll(c); - } - - @Override - public Edit remove(final int index) { - return container.remove(index); - } - - @Override - public int hashCode() { - return container.hashCode(); - } - - @Override - public boolean equals(final Object o) { - if (o instanceof EditList) - return container.equals(((EditList) o).container); - return false; + super(capacity); } @Override public String toString() { - return "EditList" + container.toString(); + return "EditList" + super.toString(); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java index 6f0c6c3b36..4bbe3a0048 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java @@ -136,6 +136,8 @@ public abstract class PackParser { private boolean needBaseObjectIds; + private boolean checkEofAfterPackFooter; + private long objectCount; private PackedObjectInfo[] entries; @@ -282,6 +284,21 @@ public abstract class PackParser { this.needBaseObjectIds = b; } + /** @return true if the EOF should be read from the input after the footer. */ + public boolean isCheckEofAfterPackFooter() { + return checkEofAfterPackFooter; + } + + /** + * Ensure EOF is read from the input stream after the footer. + * + * @param b + * true if the EOF should be read; false if it is not checked. + */ + public void setCheckEofAfterPackFooter(boolean b) { + checkEofAfterPackFooter = b; + } + /** @return the new objects that were sent by the user */ public ObjectIdSubclassMap<ObjectId> getNewObjectIds() { if (newObjectIds != null) @@ -782,6 +799,25 @@ public abstract class PackParser { System.arraycopy(buf, c, srcHash, 0, 20); use(20); + // The input stream should be at EOF at this point. We do not support + // yielding back any remaining buffered data after the pack footer, so + // protocols that embed a pack stream are required to either end their + // stream with the pack, or embed the pack with a framing system like + // the SideBandInputStream does. + + if (bAvail != 0) + throw new CorruptObjectException(MessageFormat.format( + JGitText.get().expectedEOFReceived, + "\\x" + Integer.toHexString(buf[bOffset] & 0xff))); + + if (isCheckEofAfterPackFooter()) { + int eof = in.read(); + if (0 <= eof) + throw new CorruptObjectException(MessageFormat.format( + JGitText.get().expectedEOFReceived, + "\\x" + Integer.toHexString(eof))); + } + if (!Arrays.equals(actHash, srcHash)) throw new CorruptObjectException( JGitText.get().corruptObjectPackfileChecksumIncorrect); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java index e2ab5f6780..f1f9b0f44d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java @@ -825,6 +825,7 @@ public class ReceivePack { parser.setAllowThin(true); parser.setNeedNewObjectIds(checkReferencedIsReachable); parser.setNeedBaseObjectIds(checkReferencedIsReachable); + parser.setCheckEofAfterPackFooter(!biDirectionalPipe); parser.setObjectChecking(isCheckReceivedObjects()); parser.setLockMessage(lockMsg); packLock = parser.parse(receiving, resolving); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java index 50f57130c3..0e50b937b6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java @@ -55,6 +55,7 @@ import java.util.Map; import java.util.Set; import org.eclipse.jgit.JGitText; +import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.PackProtocolException; import org.eclipse.jgit.lib.Constants; @@ -757,6 +758,16 @@ public class UploadPack { final boolean sideband = options.contains(OPTION_SIDE_BAND) || options.contains(OPTION_SIDE_BAND_64K); + if (!biDirectionalPipe) { + // Ensure the request was fully consumed. Any remaining input must + // be a protocol error. If we aren't at EOF the implementation is broken. + int eof = rawIn.read(); + if (0 <= eof) + throw new CorruptObjectException(MessageFormat.format( + JGitText.get().expectedEOFReceived, + "\\x" + Integer.toHexString(eof))); + } + ProgressMonitor pm = NullProgressMonitor.INSTANCE; OutputStream packOut = rawOut; SideBandOutputStream msgOut = null; |