Browse Source
If ensureProvidedObjectsVisible is enabled we expected any trees or blobs directly reachable from an advertised reference to be marked with UNINTERESTING. Unfortunately ObjectWalk doesn't bother setting this until the traversal is complete. Even then it won't necessarily set it on every tree if the corresponding commit wasn't popped. When we are going to check the base objects for the received pack, ensure the UNINTERESTING flag gets carried into every immediately reachable tree or blob, because these are the ones that the client might try to use as delta bases in a thin pack. Change-Id: I5d5fdcf07e25ac9fc360e79a25dff491925e4101 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>stable-0.8
Shawn O. Pearce
15 years ago
3 changed files with 510 additions and 5 deletions
@ -0,0 +1,477 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2010, Google Inc. |
||||||
|
* and other copyright owners as documented in the project's IP log. |
||||||
|
* |
||||||
|
* This program and the accompanying materials are made available |
||||||
|
* under the terms of the Eclipse Distribution License v1.0 which |
||||||
|
* accompanies this distribution, is reproduced below, and is |
||||||
|
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||||
|
* |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or |
||||||
|
* without modification, are permitted provided that the following |
||||||
|
* conditions are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above |
||||||
|
* copyright notice, this list of conditions and the following |
||||||
|
* disclaimer in the documentation and/or other materials provided |
||||||
|
* with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||||
|
* names of its contributors may be used to endorse or promote |
||||||
|
* products derived from this software without specific prior |
||||||
|
* written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.eclipse.jgit.transport; |
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream; |
||||||
|
import java.io.IOException; |
||||||
|
import java.net.URISyntaxException; |
||||||
|
import java.security.MessageDigest; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.zip.Deflater; |
||||||
|
|
||||||
|
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; |
||||||
|
import org.eclipse.jgit.junit.TestRepository; |
||||||
|
import org.eclipse.jgit.lib.Constants; |
||||||
|
import org.eclipse.jgit.lib.NullProgressMonitor; |
||||||
|
import org.eclipse.jgit.lib.ObjectDirectory; |
||||||
|
import org.eclipse.jgit.lib.ObjectId; |
||||||
|
import org.eclipse.jgit.lib.ObjectLoader; |
||||||
|
import org.eclipse.jgit.lib.Ref; |
||||||
|
import org.eclipse.jgit.lib.Repository; |
||||||
|
import org.eclipse.jgit.revwalk.RevBlob; |
||||||
|
import org.eclipse.jgit.revwalk.RevCommit; |
||||||
|
import org.eclipse.jgit.revwalk.RevTree; |
||||||
|
import org.eclipse.jgit.util.NB; |
||||||
|
import org.eclipse.jgit.util.TemporaryBuffer; |
||||||
|
|
||||||
|
public class ReceivePackRefFilterTest extends LocalDiskRepositoryTestCase { |
||||||
|
private static final NullProgressMonitor PM = NullProgressMonitor.INSTANCE; |
||||||
|
|
||||||
|
private static final String R_MASTER = Constants.R_HEADS + Constants.MASTER; |
||||||
|
|
||||||
|
private static final String R_PRIVATE = Constants.R_HEADS + "private"; |
||||||
|
|
||||||
|
private Repository src; |
||||||
|
|
||||||
|
private Repository dst; |
||||||
|
|
||||||
|
private RevCommit A, B, P; |
||||||
|
|
||||||
|
private RevBlob a, b; |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void setUp() throws Exception { |
||||||
|
super.setUp(); |
||||||
|
|
||||||
|
src = createBareRepository(); |
||||||
|
dst = createBareRepository(); |
||||||
|
|
||||||
|
// Fill dst with a some common history.
|
||||||
|
//
|
||||||
|
TestRepository d = new TestRepository(dst); |
||||||
|
a = d.blob("a"); |
||||||
|
A = d.commit(d.tree(d.file("a", a))); |
||||||
|
B = d.commit().parent(A).create(); |
||||||
|
d.update(R_MASTER, B); |
||||||
|
|
||||||
|
// Clone from dst into src
|
||||||
|
//
|
||||||
|
Transport t = Transport.open(src, uriOf(dst)); |
||||||
|
try { |
||||||
|
t.fetch(PM, Collections.singleton(new RefSpec("+refs/*:refs/*"))); |
||||||
|
assertEquals(B.copy(), src.resolve(R_MASTER)); |
||||||
|
} finally { |
||||||
|
t.close(); |
||||||
|
} |
||||||
|
|
||||||
|
// Now put private stuff into dst.
|
||||||
|
//
|
||||||
|
b = d.blob("b"); |
||||||
|
P = d.commit(d.tree(d.file("b", b)), A); |
||||||
|
d.update(R_PRIVATE, P); |
||||||
|
} |
||||||
|
|
||||||
|
public void testFilterHidesPrivate() throws Exception { |
||||||
|
Map<String, Ref> refs; |
||||||
|
TransportLocal t = new TransportLocal(src, uriOf(dst)) { |
||||||
|
@Override |
||||||
|
ReceivePack createReceivePack(final Repository db) { |
||||||
|
db.close(); |
||||||
|
dst.incrementOpen(); |
||||||
|
|
||||||
|
final ReceivePack rp = super.createReceivePack(dst); |
||||||
|
rp.setRefFilter(new HidePrivateFilter()); |
||||||
|
return rp; |
||||||
|
} |
||||||
|
}; |
||||||
|
try { |
||||||
|
PushConnection c = t.openPush(); |
||||||
|
try { |
||||||
|
refs = c.getRefsMap(); |
||||||
|
} finally { |
||||||
|
c.close(); |
||||||
|
} |
||||||
|
} finally { |
||||||
|
t.close(); |
||||||
|
} |
||||||
|
|
||||||
|
assertNotNull(refs); |
||||||
|
assertNull("no private", refs.get(R_PRIVATE)); |
||||||
|
assertNull("no HEAD", refs.get(Constants.HEAD)); |
||||||
|
assertEquals(1, refs.size()); |
||||||
|
|
||||||
|
Ref master = refs.get(R_MASTER); |
||||||
|
assertNotNull("has master", master); |
||||||
|
assertEquals(B.copy(), master.getObjectId()); |
||||||
|
} |
||||||
|
|
||||||
|
public void testSuccess() throws Exception { |
||||||
|
// Manually force a delta of an object so we reuse it later.
|
||||||
|
//
|
||||||
|
TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024); |
||||||
|
|
||||||
|
packHeader(pack, 2); |
||||||
|
pack.write((Constants.OBJ_BLOB) << 4 | 1); |
||||||
|
deflate(pack, new byte[] { 'a' }); |
||||||
|
|
||||||
|
pack.write((Constants.OBJ_REF_DELTA) << 4 | 4); |
||||||
|
a.copyRawTo(pack); |
||||||
|
deflate(pack, new byte[] { 0x1, 0x1, 0x1, 'b' }); |
||||||
|
|
||||||
|
digest(pack); |
||||||
|
openPack(pack); |
||||||
|
|
||||||
|
// Verify the only storage of b is our packed delta above.
|
||||||
|
//
|
||||||
|
ObjectDirectory od = (ObjectDirectory) src.getObjectDatabase(); |
||||||
|
assertTrue("has b", od.hasObject(b)); |
||||||
|
assertFalse("b not loose", od.fileFor(b).exists()); |
||||||
|
|
||||||
|
// Now use b but in a different commit than what is hidden.
|
||||||
|
//
|
||||||
|
TestRepository s = new TestRepository(src); |
||||||
|
RevCommit N = s.commit().parent(B).add("q", b).create(); |
||||||
|
s.update(R_MASTER, N); |
||||||
|
|
||||||
|
// Push this new content to the remote, doing strict validation.
|
||||||
|
//
|
||||||
|
TransportLocal t = new TransportLocal(src, uriOf(dst)) { |
||||||
|
@Override |
||||||
|
ReceivePack createReceivePack(final Repository db) { |
||||||
|
db.close(); |
||||||
|
dst.incrementOpen(); |
||||||
|
|
||||||
|
final ReceivePack rp = super.createReceivePack(dst); |
||||||
|
rp.setCheckReceivedObjects(true); |
||||||
|
rp.setEnsureProvidedObjectsVisible(true); |
||||||
|
rp.setRefFilter(new HidePrivateFilter()); |
||||||
|
return rp; |
||||||
|
} |
||||||
|
}; |
||||||
|
RemoteRefUpdate u = new RemoteRefUpdate( //
|
||||||
|
src, //
|
||||||
|
R_MASTER, // src name
|
||||||
|
R_MASTER, // dst name
|
||||||
|
false, // do not force update
|
||||||
|
null, // local tracking branch
|
||||||
|
null // expected id
|
||||||
|
); |
||||||
|
PushResult r; |
||||||
|
try { |
||||||
|
t.setPushThin(true); |
||||||
|
r = t.push(PM, Collections.singleton(u)); |
||||||
|
} finally { |
||||||
|
t.close(); |
||||||
|
} |
||||||
|
|
||||||
|
assertNotNull("have result", r); |
||||||
|
assertNull("private not advertised", r.getAdvertisedRef(R_PRIVATE)); |
||||||
|
assertSame("master updated", RemoteRefUpdate.Status.OK, u.getStatus()); |
||||||
|
assertEquals(N.copy(), dst.resolve(R_MASTER)); |
||||||
|
} |
||||||
|
|
||||||
|
public void testCreateBranchAtHiddenCommitFails() throws Exception { |
||||||
|
final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(64); |
||||||
|
packHeader(pack, 0); |
||||||
|
digest(pack); |
||||||
|
|
||||||
|
final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(256); |
||||||
|
final PacketLineOut inPckLine = new PacketLineOut(inBuf); |
||||||
|
inPckLine.writeString(ObjectId.zeroId().name() + ' ' + P.name() + ' ' |
||||||
|
+ "refs/heads/s" + '\0' |
||||||
|
+ BasePackPushConnection.CAPABILITY_REPORT_STATUS); |
||||||
|
inPckLine.end(); |
||||||
|
pack.writeTo(inBuf, PM); |
||||||
|
|
||||||
|
final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024); |
||||||
|
final ReceivePack rp = new ReceivePack(dst); |
||||||
|
rp.setCheckReceivedObjects(true); |
||||||
|
rp.setEnsureProvidedObjectsVisible(true); |
||||||
|
rp.setRefFilter(new HidePrivateFilter()); |
||||||
|
rp.receive(new ByteArrayInputStream(inBuf.toByteArray()), outBuf, null); |
||||||
|
|
||||||
|
final PacketLineIn r = asPacketLineIn(outBuf); |
||||||
|
String master = r.readString(); |
||||||
|
int nul = master.indexOf('\0'); |
||||||
|
assertTrue("has capability list", nul > 0); |
||||||
|
assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul)); |
||||||
|
assertSame(PacketLineIn.END, r.readString()); |
||||||
|
|
||||||
|
assertEquals("unpack error Missing commit " + P.name(), r.readString()); |
||||||
|
assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString()); |
||||||
|
assertSame(PacketLineIn.END, r.readString()); |
||||||
|
} |
||||||
|
|
||||||
|
public void testUsingHiddenDeltaBaseFails() throws Exception { |
||||||
|
final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(64); |
||||||
|
packHeader(pack, 1); |
||||||
|
pack.write((Constants.OBJ_REF_DELTA) << 4 | 4); |
||||||
|
b.copyRawTo(pack); |
||||||
|
deflate(pack, new byte[] { 0x1, 0x1, 0x1, 'b' }); |
||||||
|
digest(pack); |
||||||
|
|
||||||
|
final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(256); |
||||||
|
final PacketLineOut inPckLine = new PacketLineOut(inBuf); |
||||||
|
inPckLine.writeString(ObjectId.zeroId().name() + ' ' + P.name() + ' ' |
||||||
|
+ "refs/heads/s" + '\0' |
||||||
|
+ BasePackPushConnection.CAPABILITY_REPORT_STATUS); |
||||||
|
inPckLine.end(); |
||||||
|
pack.writeTo(inBuf, PM); |
||||||
|
|
||||||
|
final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024); |
||||||
|
final ReceivePack rp = new ReceivePack(dst); |
||||||
|
rp.setCheckReceivedObjects(true); |
||||||
|
rp.setEnsureProvidedObjectsVisible(true); |
||||||
|
rp.setRefFilter(new HidePrivateFilter()); |
||||||
|
rp.receive(new ByteArrayInputStream(inBuf.toByteArray()), outBuf, null); |
||||||
|
|
||||||
|
final PacketLineIn r = asPacketLineIn(outBuf); |
||||||
|
String master = r.readString(); |
||||||
|
int nul = master.indexOf('\0'); |
||||||
|
assertTrue("has capability list", nul > 0); |
||||||
|
assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul)); |
||||||
|
assertSame(PacketLineIn.END, r.readString()); |
||||||
|
|
||||||
|
assertEquals("unpack error Missing blob " + b.name(), r.readString()); |
||||||
|
assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString()); |
||||||
|
assertSame(PacketLineIn.END, r.readString()); |
||||||
|
} |
||||||
|
|
||||||
|
public void testUsingHiddenCommonBlobFails() throws Exception { |
||||||
|
// Try to use the 'b' blob that is hidden.
|
||||||
|
//
|
||||||
|
TestRepository s = new TestRepository(src); |
||||||
|
RevCommit N = s.commit().parent(B).add("q", s.blob("b")).create(); |
||||||
|
|
||||||
|
// But don't include it in the pack.
|
||||||
|
//
|
||||||
|
final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(64); |
||||||
|
packHeader(pack, 2); |
||||||
|
copy(pack, src.openObject(N)); |
||||||
|
copy(pack,src.openObject(s.parseBody(N).getTree())); |
||||||
|
digest(pack); |
||||||
|
|
||||||
|
final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(256); |
||||||
|
final PacketLineOut inPckLine = new PacketLineOut(inBuf); |
||||||
|
inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' ' |
||||||
|
+ "refs/heads/s" + '\0' |
||||||
|
+ BasePackPushConnection.CAPABILITY_REPORT_STATUS); |
||||||
|
inPckLine.end(); |
||||||
|
pack.writeTo(inBuf, PM); |
||||||
|
|
||||||
|
final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024); |
||||||
|
final ReceivePack rp = new ReceivePack(dst); |
||||||
|
rp.setCheckReceivedObjects(true); |
||||||
|
rp.setEnsureProvidedObjectsVisible(true); |
||||||
|
rp.setRefFilter(new HidePrivateFilter()); |
||||||
|
rp.receive(new ByteArrayInputStream(inBuf.toByteArray()), outBuf, null); |
||||||
|
|
||||||
|
final PacketLineIn r = asPacketLineIn(outBuf); |
||||||
|
String master = r.readString(); |
||||||
|
int nul = master.indexOf('\0'); |
||||||
|
assertTrue("has capability list", nul > 0); |
||||||
|
assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul)); |
||||||
|
assertSame(PacketLineIn.END, r.readString()); |
||||||
|
|
||||||
|
assertEquals("unpack error Missing blob " + b.name(), r.readString()); |
||||||
|
assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString()); |
||||||
|
assertSame(PacketLineIn.END, r.readString()); |
||||||
|
} |
||||||
|
|
||||||
|
public void testUsingUnknownBlobFails() throws Exception { |
||||||
|
// Try to use the 'n' blob that is not on the server.
|
||||||
|
//
|
||||||
|
TestRepository s = new TestRepository(src); |
||||||
|
RevBlob n = s.blob("n"); |
||||||
|
RevCommit N = s.commit().parent(B).add("q", n).create(); |
||||||
|
|
||||||
|
// But don't include it in the pack.
|
||||||
|
//
|
||||||
|
final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(64); |
||||||
|
packHeader(pack, 2); |
||||||
|
copy(pack, src.openObject(N)); |
||||||
|
copy(pack,src.openObject(s.parseBody(N).getTree())); |
||||||
|
digest(pack); |
||||||
|
|
||||||
|
final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(256); |
||||||
|
final PacketLineOut inPckLine = new PacketLineOut(inBuf); |
||||||
|
inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' ' |
||||||
|
+ "refs/heads/s" + '\0' |
||||||
|
+ BasePackPushConnection.CAPABILITY_REPORT_STATUS); |
||||||
|
inPckLine.end(); |
||||||
|
pack.writeTo(inBuf, PM); |
||||||
|
|
||||||
|
final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024); |
||||||
|
final ReceivePack rp = new ReceivePack(dst); |
||||||
|
rp.setCheckReceivedObjects(true); |
||||||
|
rp.setEnsureProvidedObjectsVisible(true); |
||||||
|
rp.setRefFilter(new HidePrivateFilter()); |
||||||
|
rp.receive(new ByteArrayInputStream(inBuf.toByteArray()), outBuf, null); |
||||||
|
|
||||||
|
final PacketLineIn r = asPacketLineIn(outBuf); |
||||||
|
String master = r.readString(); |
||||||
|
int nul = master.indexOf('\0'); |
||||||
|
assertTrue("has capability list", nul > 0); |
||||||
|
assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul)); |
||||||
|
assertSame(PacketLineIn.END, r.readString()); |
||||||
|
|
||||||
|
assertEquals("unpack error Missing blob " + n.name(), r.readString()); |
||||||
|
assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString()); |
||||||
|
assertSame(PacketLineIn.END, r.readString()); |
||||||
|
} |
||||||
|
|
||||||
|
public void testUsingUnknownTreeFails() throws Exception { |
||||||
|
TestRepository s = new TestRepository(src); |
||||||
|
RevCommit N = s.commit().parent(B).add("q", s.blob("a")).create(); |
||||||
|
RevTree t = s.parseBody(N).getTree(); |
||||||
|
|
||||||
|
// Don't include the tree in the pack.
|
||||||
|
//
|
||||||
|
final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(64); |
||||||
|
packHeader(pack, 1); |
||||||
|
copy(pack, src.openObject(N)); |
||||||
|
digest(pack); |
||||||
|
|
||||||
|
final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(256); |
||||||
|
final PacketLineOut inPckLine = new PacketLineOut(inBuf); |
||||||
|
inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' ' |
||||||
|
+ "refs/heads/s" + '\0' |
||||||
|
+ BasePackPushConnection.CAPABILITY_REPORT_STATUS); |
||||||
|
inPckLine.end(); |
||||||
|
pack.writeTo(inBuf, PM); |
||||||
|
|
||||||
|
final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024); |
||||||
|
final ReceivePack rp = new ReceivePack(dst); |
||||||
|
rp.setCheckReceivedObjects(true); |
||||||
|
rp.setEnsureProvidedObjectsVisible(true); |
||||||
|
rp.setRefFilter(new HidePrivateFilter()); |
||||||
|
rp.receive(new ByteArrayInputStream(inBuf.toByteArray()), outBuf, null); |
||||||
|
|
||||||
|
final PacketLineIn r = asPacketLineIn(outBuf); |
||||||
|
String master = r.readString(); |
||||||
|
int nul = master.indexOf('\0'); |
||||||
|
assertTrue("has capability list", nul > 0); |
||||||
|
assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul)); |
||||||
|
assertSame(PacketLineIn.END, r.readString()); |
||||||
|
|
||||||
|
assertEquals("unpack error Missing tree " + t.name(), r.readString()); |
||||||
|
assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString()); |
||||||
|
assertSame(PacketLineIn.END, r.readString()); |
||||||
|
} |
||||||
|
|
||||||
|
private void packHeader(TemporaryBuffer.Heap tinyPack, int cnt) |
||||||
|
throws IOException { |
||||||
|
final byte[] hdr = new byte[8]; |
||||||
|
NB.encodeInt32(hdr, 0, 2); |
||||||
|
NB.encodeInt32(hdr, 4, cnt); |
||||||
|
|
||||||
|
tinyPack.write(Constants.PACK_SIGNATURE); |
||||||
|
tinyPack.write(hdr, 0, 8); |
||||||
|
} |
||||||
|
|
||||||
|
private void copy(TemporaryBuffer.Heap tinyPack, ObjectLoader ldr) |
||||||
|
throws IOException { |
||||||
|
final byte[] buf = new byte[64]; |
||||||
|
final byte[] content = ldr.getCachedBytes(); |
||||||
|
int dataLength = content.length; |
||||||
|
int nextLength = dataLength >>> 4; |
||||||
|
int size = 0; |
||||||
|
buf[size++] = (byte) ((nextLength > 0 ? 0x80 : 0x00) |
||||||
|
| (ldr.getType() << 4) | (dataLength & 0x0F)); |
||||||
|
dataLength = nextLength; |
||||||
|
while (dataLength > 0) { |
||||||
|
nextLength >>>= 7; |
||||||
|
buf[size++] = (byte) ((nextLength > 0 ? 0x80 : 0x00) | (dataLength & 0x7F)); |
||||||
|
dataLength = nextLength; |
||||||
|
} |
||||||
|
tinyPack.write(buf, 0, size); |
||||||
|
deflate(tinyPack, content); |
||||||
|
} |
||||||
|
|
||||||
|
private void deflate(TemporaryBuffer.Heap tinyPack, final byte[] content) |
||||||
|
throws IOException { |
||||||
|
final Deflater deflater = new Deflater(); |
||||||
|
final byte[] buf = new byte[128]; |
||||||
|
deflater.setInput(content, 0, content.length); |
||||||
|
deflater.finish(); |
||||||
|
do { |
||||||
|
final int n = deflater.deflate(buf, 0, buf.length); |
||||||
|
if (n > 0) |
||||||
|
tinyPack.write(buf, 0, n); |
||||||
|
} while (!deflater.finished()); |
||||||
|
} |
||||||
|
|
||||||
|
private void digest(TemporaryBuffer.Heap buf) throws IOException { |
||||||
|
MessageDigest md = Constants.newMessageDigest(); |
||||||
|
md.update(buf.toByteArray()); |
||||||
|
buf.write(md.digest()); |
||||||
|
} |
||||||
|
|
||||||
|
private void openPack(TemporaryBuffer.Heap buf) throws IOException { |
||||||
|
final byte[] raw = buf.toByteArray(); |
||||||
|
IndexPack ip = IndexPack.create(src, new ByteArrayInputStream(raw)); |
||||||
|
ip.setFixThin(true); |
||||||
|
ip.index(PM); |
||||||
|
ip.renameAndOpenPack(); |
||||||
|
} |
||||||
|
|
||||||
|
private static PacketLineIn asPacketLineIn(TemporaryBuffer.Heap buf) |
||||||
|
throws IOException { |
||||||
|
return new PacketLineIn(new ByteArrayInputStream(buf.toByteArray())); |
||||||
|
} |
||||||
|
|
||||||
|
private static final class HidePrivateFilter implements RefFilter { |
||||||
|
public Map<String, Ref> filter(Map<String, Ref> refs) { |
||||||
|
Map<String, Ref> r = new HashMap<String, Ref>(refs); |
||||||
|
assertNotNull(r.remove(R_PRIVATE)); |
||||||
|
return r; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static URIish uriOf(Repository r) throws URISyntaxException { |
||||||
|
return new URIish(r.getDirectory().getAbsolutePath()); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue