aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit/src
diff options
context:
space:
mode:
authorMatthias Sohn <matthias.sohn@sap.com>2024-11-26 14:17:25 +0100
committerMatthias Sohn <matthias.sohn@sap.com>2024-11-26 14:17:25 +0100
commite3eabe5d5cc9bd4f43f18014cac70e80b55cb45b (patch)
treeb97646c8541cccc3e85ac4c673a2986fda88a5db /org.eclipse.jgit/src
parent8445d6449dc80ce562ea0c34180bf527aabbd21f (diff)
parentf27ea5102641818ad3505fbb5cae3fee28c3b056 (diff)
downloadjgit-e3eabe5d5cc9bd4f43f18014cac70e80b55cb45b.tar.gz
jgit-e3eabe5d5cc9bd4f43f18014cac70e80b55cb45b.zip
Merge branch 'stable-6.10' into stable-7.0
* stable-6.10: PackDirectory: Filter out tmp GC pack files Test advertised capabilities with protocol V0 and allow*Sha1InWant Align request policies with CGit Pack.java: Recover more often in Pack.copyAsIs2() Change-Id: Ib301efa54aaf2196d764a0fc1f91f652b4d68396
Diffstat (limited to 'org.eclipse.jgit/src')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java295
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java38
4 files changed, 187 insertions, 156 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
index be457644d9..3518342f97 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
@@ -416,185 +416,196 @@ public class Pack implements Iterable<PackIndex.MutableEntry> {
final CRC32 crc2 = validate ? new CRC32() : null;
final byte[] buf = out.getCopyBuffer();
+ boolean isHeaderWritten = false;
// Rip apart the header so we can discover the size.
//
- readFully(src.offset, buf, 0, 20, curs);
- int c = buf[0] & 0xff;
- final int typeCode = (c >> 4) & 7;
- long inflatedLength = c & 15;
- int shift = 4;
- int headerCnt = 1;
- while ((c & 0x80) != 0) {
- c = buf[headerCnt++] & 0xff;
- inflatedLength += ((long) (c & 0x7f)) << shift;
- shift += 7;
- }
-
- if (typeCode == Constants.OBJ_OFS_DELTA) {
- do {
+ try {
+ readFully(src.offset, buf, 0, 20, curs);
+
+ int c = buf[0] & 0xff;
+ final int typeCode = (c >> 4) & 7;
+ long inflatedLength = c & 15;
+ int shift = 4;
+ int headerCnt = 1;
+ while ((c & 0x80) != 0) {
c = buf[headerCnt++] & 0xff;
- } while ((c & 128) != 0);
- if (validate) {
- assert(crc1 != null && crc2 != null);
- crc1.update(buf, 0, headerCnt);
- crc2.update(buf, 0, headerCnt);
+ inflatedLength += ((long) (c & 0x7f)) << shift;
+ shift += 7;
}
- } else if (typeCode == Constants.OBJ_REF_DELTA) {
- if (validate) {
+
+ if (typeCode == Constants.OBJ_OFS_DELTA) {
+ do {
+ c = buf[headerCnt++] & 0xff;
+ } while ((c & 128) != 0);
+ if (validate) {
+ assert(crc1 != null && crc2 != null);
+ crc1.update(buf, 0, headerCnt);
+ crc2.update(buf, 0, headerCnt);
+ }
+ } else if (typeCode == Constants.OBJ_REF_DELTA) {
+ if (validate) {
+ assert(crc1 != null && crc2 != null);
+ crc1.update(buf, 0, headerCnt);
+ crc2.update(buf, 0, headerCnt);
+ }
+
+ readFully(src.offset + headerCnt, buf, 0, 20, curs);
+ if (validate) {
+ assert(crc1 != null && crc2 != null);
+ crc1.update(buf, 0, 20);
+ crc2.update(buf, 0, 20);
+ }
+ headerCnt += 20;
+ } else if (validate) {
assert(crc1 != null && crc2 != null);
crc1.update(buf, 0, headerCnt);
crc2.update(buf, 0, headerCnt);
}
- readFully(src.offset + headerCnt, buf, 0, 20, curs);
- if (validate) {
- assert(crc1 != null && crc2 != null);
- crc1.update(buf, 0, 20);
- crc2.update(buf, 0, 20);
- }
- headerCnt += 20;
- } else if (validate) {
- assert(crc1 != null && crc2 != null);
- crc1.update(buf, 0, headerCnt);
- crc2.update(buf, 0, headerCnt);
- }
+ final long dataOffset = src.offset + headerCnt;
+ final long dataLength = src.length;
+ final long expectedCRC;
+ final ByteArrayWindow quickCopy;
- final long dataOffset = src.offset + headerCnt;
- final long dataLength = src.length;
- final long expectedCRC;
- final ByteArrayWindow quickCopy;
-
- // Verify the object isn't corrupt before sending. If it is,
- // we report it missing instead.
- //
- try {
- quickCopy = curs.quickCopy(this, dataOffset, dataLength);
+ // Verify the object isn't corrupt before sending. If it is,
+ // we report it missing instead.
+ //
+ try {
+ quickCopy = curs.quickCopy(this, dataOffset, dataLength);
- if (validate && idx().hasCRC32Support()) {
- assert(crc1 != null);
- // Index has the CRC32 code cached, validate the object.
- //
- expectedCRC = idx().findCRC32(src);
- if (quickCopy != null) {
- quickCopy.crc32(crc1, dataOffset, (int) dataLength);
- } else {
- long pos = dataOffset;
- long cnt = dataLength;
- while (cnt > 0) {
- final int n = (int) Math.min(cnt, buf.length);
- readFully(pos, buf, 0, n, curs);
- crc1.update(buf, 0, n);
- pos += n;
- cnt -= n;
+ if (validate && idx().hasCRC32Support()) {
+ assert(crc1 != null);
+ // Index has the CRC32 code cached, validate the object.
+ //
+ expectedCRC = idx().findCRC32(src);
+ if (quickCopy != null) {
+ quickCopy.crc32(crc1, dataOffset, (int) dataLength);
+ } else {
+ long pos = dataOffset;
+ long cnt = dataLength;
+ while (cnt > 0) {
+ final int n = (int) Math.min(cnt, buf.length);
+ readFully(pos, buf, 0, n, curs);
+ crc1.update(buf, 0, n);
+ pos += n;
+ cnt -= n;
+ }
}
+ if (crc1.getValue() != expectedCRC) {
+ setCorrupt(src.offset);
+ throw new CorruptObjectException(MessageFormat.format(
+ JGitText.get().objectAtHasBadZlibStream,
+ Long.valueOf(src.offset), getPackFile()));
+ }
+ } else if (validate) {
+ // We don't have a CRC32 code in the index, so compute it
+ // now while inflating the raw data to get zlib to tell us
+ // whether or not the data is safe.
+ //
+ Inflater inf = curs.inflater();
+ byte[] tmp = new byte[1024];
+ if (quickCopy != null) {
+ quickCopy.check(inf, tmp, dataOffset, (int) dataLength);
+ } else {
+ assert(crc1 != null);
+ long pos = dataOffset;
+ long cnt = dataLength;
+ while (cnt > 0) {
+ final int n = (int) Math.min(cnt, buf.length);
+ readFully(pos, buf, 0, n, curs);
+ crc1.update(buf, 0, n);
+ inf.setInput(buf, 0, n);
+ while (inf.inflate(tmp, 0, tmp.length) > 0)
+ continue;
+ pos += n;
+ cnt -= n;
+ }
+ }
+ if (!inf.finished() || inf.getBytesRead() != dataLength) {
+ setCorrupt(src.offset);
+ throw new EOFException(MessageFormat.format(
+ JGitText.get().shortCompressedStreamAt,
+ Long.valueOf(src.offset)));
+ }
+ assert(crc1 != null);
+ expectedCRC = crc1.getValue();
+ } else {
+ expectedCRC = -1;
}
- if (crc1.getValue() != expectedCRC) {
- setCorrupt(src.offset);
- throw new CorruptObjectException(MessageFormat.format(
- JGitText.get().objectAtHasBadZlibStream,
- Long.valueOf(src.offset), getPackFile()));
- }
- } else if (validate) {
- // We don't have a CRC32 code in the index, so compute it
- // now while inflating the raw data to get zlib to tell us
- // whether or not the data is safe.
+ } catch (DataFormatException dataFormat) {
+ setCorrupt(src.offset);
+
+ CorruptObjectException corruptObject = new CorruptObjectException(
+ MessageFormat.format(
+ JGitText.get().objectAtHasBadZlibStream,
+ Long.valueOf(src.offset), getPackFile()),
+ dataFormat);
+
+ throw new StoredObjectRepresentationNotAvailableException(
+ corruptObject);
+ }
+
+ if (quickCopy != null) {
+ // The entire object fits into a single byte array window slice,
+ // and we have it pinned. Write this out without copying.
//
- Inflater inf = curs.inflater();
- byte[] tmp = new byte[1024];
- if (quickCopy != null) {
- quickCopy.check(inf, tmp, dataOffset, (int) dataLength);
- } else {
- assert(crc1 != null);
+ out.writeHeader(src, inflatedLength);
+ isHeaderWritten = true;
+ quickCopy.write(out, dataOffset, (int) dataLength);
+
+ } else if (dataLength <= buf.length) {
+ // Tiny optimization: Lots of objects are very small deltas or
+ // deflated commits that are likely to fit in the copy buffer.
+ //
+ if (!validate) {
long pos = dataOffset;
long cnt = dataLength;
while (cnt > 0) {
final int n = (int) Math.min(cnt, buf.length);
readFully(pos, buf, 0, n, curs);
- crc1.update(buf, 0, n);
- inf.setInput(buf, 0, n);
- while (inf.inflate(tmp, 0, tmp.length) > 0)
- continue;
pos += n;
cnt -= n;
}
}
- if (!inf.finished() || inf.getBytesRead() != dataLength) {
- setCorrupt(src.offset);
- throw new EOFException(MessageFormat.format(
- JGitText.get().shortCompressedStreamAt,
- Long.valueOf(src.offset)));
- }
- assert(crc1 != null);
- expectedCRC = crc1.getValue();
+ out.writeHeader(src, inflatedLength);
+ isHeaderWritten = true;
+ out.write(buf, 0, (int) dataLength);
} else {
- expectedCRC = -1;
- }
- } catch (DataFormatException dataFormat) {
- setCorrupt(src.offset);
-
- CorruptObjectException corruptObject = new CorruptObjectException(
- MessageFormat.format(
- JGitText.get().objectAtHasBadZlibStream,
- Long.valueOf(src.offset), getPackFile()),
- dataFormat);
-
- throw new StoredObjectRepresentationNotAvailableException(
- corruptObject);
-
- } catch (IOException ioError) {
- throw new StoredObjectRepresentationNotAvailableException(ioError);
- }
-
- if (quickCopy != null) {
- // The entire object fits into a single byte array window slice,
- // and we have it pinned. Write this out without copying.
- //
- out.writeHeader(src, inflatedLength);
- quickCopy.write(out, dataOffset, (int) dataLength);
-
- } else if (dataLength <= buf.length) {
- // Tiny optimization: Lots of objects are very small deltas or
- // deflated commits that are likely to fit in the copy buffer.
- //
- if (!validate) {
+ // Now we are committed to sending the object. As we spool it out,
+ // check its CRC32 code to make sure there wasn't corruption between
+ // the verification we did above, and us actually outputting it.
+ //
long pos = dataOffset;
long cnt = dataLength;
while (cnt > 0) {
final int n = (int) Math.min(cnt, buf.length);
readFully(pos, buf, 0, n, curs);
+ if (validate) {
+ assert(crc2 != null);
+ crc2.update(buf, 0, n);
+ }
+ if (!isHeaderWritten) {
+ out.writeHeader(src, inflatedLength);
+ isHeaderWritten = true;
+ }
+ out.write(buf, 0, n);
pos += n;
cnt -= n;
}
- }
- out.writeHeader(src, inflatedLength);
- out.write(buf, 0, (int) dataLength);
- } else {
- // Now we are committed to sending the object. As we spool it out,
- // check its CRC32 code to make sure there wasn't corruption between
- // the verification we did above, and us actually outputting it.
- //
- out.writeHeader(src, inflatedLength);
- long pos = dataOffset;
- long cnt = dataLength;
- while (cnt > 0) {
- final int n = (int) Math.min(cnt, buf.length);
- readFully(pos, buf, 0, n, curs);
if (validate) {
assert(crc2 != null);
- crc2.update(buf, 0, n);
+ if (crc2.getValue() != expectedCRC) {
+ throw new CorruptObjectException(MessageFormat.format(
+ JGitText.get().objectAtHasBadZlibStream,
+ Long.valueOf(src.offset), getPackFile()));
+ }
}
- out.write(buf, 0, n);
- pos += n;
- cnt -= n;
}
- if (validate) {
- assert(crc2 != null);
- if (crc2.getValue() != expectedCRC) {
- throw new CorruptObjectException(MessageFormat.format(
- JGitText.get().objectAtHasBadZlibStream,
- Long.valueOf(src.offset), getPackFile()));
- }
+ } catch (IOException ioError) {
+ if (!isHeaderWritten) {
+ throw new StoredObjectRepresentationNotAvailableException(ioError);
}
+ throw ioError;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
index 8221cff442..51a8148838 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
@@ -545,7 +545,7 @@ class PackDirectory {
for (String name : nameList) {
try {
PackFile pack = new PackFile(directory, name);
- if (pack.getPackExt() != null) {
+ if (pack.getPackExt() != null && !pack.isTmpGCFile()) {
Map<PackExt, PackFile> packByExt = packFilesByExtById
.get(pack.getId());
if (packByExt == null) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
index 19979d0ed5..c9b05ad025 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
@@ -27,6 +27,7 @@ public class PackFile extends File {
private static final long serialVersionUID = 1L;
private static final String PREFIX = "pack-"; //$NON-NLS-1$
+ private static final String TMP_GC_PREFIX = ".tmp-"; //$NON-NLS-1$
private final String base; // PREFIX + id i.e.
// pack-0123456789012345678901234567890123456789
@@ -126,6 +127,13 @@ public class PackFile extends File {
}
/**
+ * @return whether the file is a temporary GC file
+ */
+ public boolean isTmpGCFile() {
+ return id.startsWith(TMP_GC_PREFIX);
+ }
+
+ /**
* Create a new similar PackFile with the given extension instead.
*
* @param ext
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 3772c00819..62da98b95b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -117,13 +117,13 @@ public class UploadPack implements Closeable {
/** Policy the server uses to validate client requests */
public enum RequestPolicy {
/** Client may only ask for objects the server advertised a reference for. */
- ADVERTISED,
+ ADVERTISED(0x08),
/**
* Client may ask for any commit reachable from a reference advertised by
* the server.
*/
- REACHABLE_COMMIT,
+ REACHABLE_COMMIT(0x02),
/**
* Client may ask for objects that are the tip of any reference, even if not
@@ -133,18 +133,34 @@ public class UploadPack implements Closeable {
*
* @since 3.1
*/
- TIP,
+ TIP(0x01),
/**
* Client may ask for any commit reachable from any reference, even if that
- * reference wasn't advertised.
+ * reference wasn't advertised, implies REACHABLE_COMMIT and TIP.
*
* @since 3.1
*/
- REACHABLE_COMMIT_TIP,
+ REACHABLE_COMMIT_TIP(0x03),
- /** Client may ask for any SHA-1 in the repository. */
- ANY;
+ /** Client may ask for any SHA-1 in the repository, implies REACHABLE_COMMIT_TIP. */
+ ANY(0x07);
+
+ private final int bitmask;
+
+ RequestPolicy(int bitmask) {
+ this.bitmask = bitmask;
+ }
+
+ /**
+ * Check if the current policy implies another, based on its bitmask.
+ *
+ * @param implied the implied policy based on its bitmask.
+ * @return true if the policy is implied.
+ */
+ public boolean implies(RequestPolicy implied) {
+ return (bitmask & implied.bitmask) != 0;
+ }
}
/**
@@ -1582,13 +1598,9 @@ public class UploadPack implements Closeable {
if (!biDirectionalPipe)
adv.advertiseCapability(OPTION_NO_DONE);
RequestPolicy policy = getRequestPolicy();
- if (policy == RequestPolicy.TIP
- || policy == RequestPolicy.REACHABLE_COMMIT_TIP
- || policy == null)
+ if (policy == null || policy.implies(RequestPolicy.TIP))
adv.advertiseCapability(OPTION_ALLOW_TIP_SHA1_IN_WANT);
- if (policy == RequestPolicy.REACHABLE_COMMIT
- || policy == RequestPolicy.REACHABLE_COMMIT_TIP
- || policy == null)
+ if (policy == null || policy.implies(RequestPolicy.REACHABLE_COMMIT))
adv.advertiseCapability(OPTION_ALLOW_REACHABLE_SHA1_IN_WANT);
adv.advertiseCapability(OPTION_AGENT, UserAgent.get());
if (transferConfig.isAllowFilter()) {