From 8123dcd6993457622fc5df08c58c776286cc427a Mon Sep 17 00:00:00 2001 From: Anna Papitto Date: Fri, 14 Jul 2023 12:19:27 -0700 Subject: [PATCH 1/3] PackReverseIndex: verify checksums The new version 1 file-based reverse index has a footer with the checksum of the corresponding pack file and a checksum of its own contents. The initial implementation doesn't enforce that the pack checksum matches the checksum found in the forward index nor that the self checksum matches the contents of the file just read in. Offer a method for reverse index users to verify the checksums in a way appropriate to the version being used. For the pre-existing computed version, always succeed since it is not based on a file so there is no possibility of corruption. Check for corruption of the file itself during parsing the checksum footer, by comparing the self checksum with the digest of the file contents read. Change-Id: I87ff3933cf1afa76663350400b616695e4966cb6 Signed-off-by: Anna Papitto --- .../file/PackReverseIndexComputedTest.java | 7 +++ .../storage/file/PackReverseIndexV1Test.java | 43 +++++++++++++++++++ .../eclipse/jgit/internal/JGitText.properties | 3 +- .../org/eclipse/jgit/internal/JGitText.java | 1 + .../jgit/internal/storage/file/Pack.java | 20 +++++---- .../storage/file/PackReverseIndex.java | 12 ++++++ .../file/PackReverseIndexComputed.java | 7 +++ .../storage/file/PackReverseIndexV1.java | 30 ++++++++++++- 8 files changed, 111 insertions(+), 12 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackReverseIndexComputedTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackReverseIndexComputedTest.java index 4facd6e00..ea5aaf5dd 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackReverseIndexComputedTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackReverseIndexComputedTest.java @@ -17,6 +17,7 @@ import static org.junit.Assert.fail; import org.eclipse.jgit.errors.CorruptObjectException; +import org.eclipse.jgit.errors.PackMismatchException; import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry; import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.RepositoryTestCase; @@ -92,6 +93,12 @@ public void testFindNextOffsetWrongOffset() { } } + @Test + public void testVerifyChecksum() throws PackMismatchException { + // ComputedReverseIndex doesn't have a file containing a checksum. + reverseIdx.verifyPackChecksum(null); + } + private long findFirstOffset() { long min = Long.MAX_VALUE; for (MutableEntry me : idx) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackReverseIndexV1Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackReverseIndexV1Test.java index b4849f99f..38b28b501 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackReverseIndexV1Test.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackReverseIndexV1Test.java @@ -15,11 +15,14 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; import java.io.IOException; import org.eclipse.jgit.errors.CorruptObjectException; +import org.eclipse.jgit.errors.PackMismatchException; import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.transport.PackedObjectInfo; @@ -146,6 +149,26 @@ public void read_objectCountTooLarge() { () -> null)); } + @Test + public void read_incorrectChecksum() { + byte[] badChecksum = new byte[] { 'R', 'I', 'D', 'X', // magic + 0x00, 0x00, 0x00, 0x01, // file version + 0x00, 0x00, 0x00, 0x01, // oid version + // pack checksum to copy into at byte 12 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // checksum + (byte) 0xf2, 0x1a, 0x1a, (byte) 0xaa, 0x32, 0x2d, (byte) 0xb9, + (byte) 0xfd, 0x0f, (byte) 0xa5, 0x4c, (byte) 0xea, (byte) 0xcf, + (byte) 0xbb, (byte) 0x99, (byte) 0xde, (byte) 0xd3, 0x4e, + (byte) 0xb1, (byte) 0xee, // would be 0x74 if correct + }; + System.arraycopy(FAKE_PACK_CHECKSUM, 0, badChecksum, 12, + FAKE_PACK_CHECKSUM.length); + ByteArrayInputStream in = new ByteArrayInputStream(badChecksum); + assertThrows(CorruptObjectException.class, + () -> PackReverseIndexFactory.readFromFile(in, 0, () -> null)); + } + @Test public void findObject_noObjects() { assertNull(emptyReverseIndex.findObject(0)); @@ -235,6 +258,26 @@ public void findObjectByPosition_badOffset() { () -> smallReverseIndex.findObjectByPosition(10)); } + @Test + public void verifyChecksum_match() throws IOException { + smallReverseIndex.verifyPackChecksum("smallPackFilePath"); + } + + @Test + public void verifyChecksum_mismatch() throws IOException { + ByteArrayInputStream in = new ByteArrayInputStream(NO_OBJECTS); + PackIndex mockForwardIndex = mock(PackIndex.class); + when(mockForwardIndex.getChecksum()).thenReturn( + new byte[] { 'D', 'I', 'F', 'F', 'P', 'A', 'C', 'K', 'C', 'H', + 'E', 'C', 'K', 'S', 'U', 'M', '7', '8', '9', '0', }); + PackReverseIndex reverseIndex = PackReverseIndexFactory.readFromFile(in, + 0, + () -> mockForwardIndex); + + assertThrows(PackMismatchException.class, + () -> reverseIndex.verifyPackChecksum("packFilePath")); + } + private static PackedObjectInfo objectInfo(String objectId, int type, long offset) { PackedObjectInfo objectInfo = new PackedObjectInfo( 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 bf8a1ef5d..c73d85f07 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -223,6 +223,7 @@ corruptObjectTruncatedInMode=truncated in mode corruptObjectTruncatedInName=truncated in name corruptObjectTruncatedInObjectId=truncated in object id corruptObjectZeroId=entry points to null SHA-1 +corruptReverseIndexChecksumIncorrect=Reverse index checksum incorrect: written as {0} but digest was {1} corruptUseCnt=close() called when useCnt is already zero for {0} couldNotGetAdvertisedRef=Remote {0} did not advertise Ref for branch {1}. This Ref may not exist in the remote or may be hidden by permission settings. couldNotGetRepoStatistics=Could not get repository statistics @@ -566,7 +567,7 @@ openingConnection=Opening connection operationCanceled=Operation {0} was canceled outputHasAlreadyBeenStarted=Output has already been started. overflowedReftableBlock=Overflowed reftable block -packChecksumMismatch=Pack checksum mismatch detected for pack file {0}: .pack has {1} whilst .idx has {2} +packChecksumMismatch=Pack checksum mismatch detected for pack file {0}: {1} has {2} whilst {3} has {4} packCorruptedWhileWritingToFilesystem=Pack corrupted while writing to filesystem packedRefsHandleIsStale=packed-refs handle is stale, {0}. retry packetSizeMustBeAtLeast=packet size {0} must be >= {1} 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 a032d24c7..91d53220a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -252,6 +252,7 @@ public static JGitText get() { /***/ public String corruptObjectTruncatedInName; /***/ public String corruptObjectTruncatedInObjectId; /***/ public String corruptObjectZeroId; + /***/ public String corruptReverseIndexChecksumIncorrect; /***/ public String corruptPack; /***/ public String corruptUseCnt; /***/ public String couldNotFindTabInLine; 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 782cbea05..8d9fe23ae 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 @@ -50,12 +50,14 @@ import org.eclipse.jgit.errors.UnsupportedPackVersionException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.pack.BinaryDelta; +import org.eclipse.jgit.internal.storage.pack.PackExt; import org.eclipse.jgit.internal.storage.pack.PackOutputStream; import org.eclipse.jgit.lib.AbbreviatedObjectId; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectLoader; +import org.eclipse.jgit.util.Hex; import org.eclipse.jgit.util.LongList; import org.eclipse.jgit.util.NB; import org.eclipse.jgit.util.RawParseUtils; @@ -177,10 +179,10 @@ private PackIndex idx() throws IOException { throw new PackMismatchException(MessageFormat .format(JGitText.get().packChecksumMismatch, packFile.getPath(), - ObjectId.fromRaw(packChecksum) - .name(), - ObjectId.fromRaw(idx.packChecksum) - .name())); + PackExt.PACK.getExtension(), + Hex.toHexString(packChecksum), + PackExt.INDEX.getExtension(), + Hex.toHexString(idx.packChecksum))); } loadedIdx = idx; } catch (InterruptedIOException e) { @@ -765,11 +767,11 @@ private void onOpenPack() throws IOException { fd.seek(length - 20); fd.readFully(buf, 0, 20); if (!Arrays.equals(buf, packChecksum)) { - throw new PackMismatchException(MessageFormat.format( - JGitText.get().packChecksumMismatch, - getPackFile(), - ObjectId.fromRaw(buf).name(), - ObjectId.fromRaw(idx.packChecksum).name())); + throw new PackMismatchException( + MessageFormat.format(JGitText.get().packChecksumMismatch, + getPackFile(), PackExt.PACK.getExtension(), + Hex.toHexString(buf), PackExt.INDEX.getExtension(), + Hex.toHexString(idx.packChecksum))); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java index 74ea89025..ef9753cd7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java @@ -11,6 +11,7 @@ package org.eclipse.jgit.internal.storage.file; import org.eclipse.jgit.errors.CorruptObjectException; +import org.eclipse.jgit.errors.PackMismatchException; import org.eclipse.jgit.lib.ObjectId; /** @@ -34,6 +35,17 @@ public interface PackReverseIndex { */ int VERSION_1 = 1; + /** + * Verify that the pack checksum found in the reverse index matches that + * from the pack file. + * + * @param packFilePath + * the path to display in event of a mismatch + * @throws PackMismatchException + * if the checksums do not match + */ + void verifyPackChecksum(String packFilePath) throws PackMismatchException; + /** * Search for object id with the specified start offset in this pack * (reverse) index. diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexComputed.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexComputed.java index d6eaa965d..0b487a281 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexComputed.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexComputed.java @@ -12,6 +12,7 @@ import java.text.MessageFormat; import org.eclipse.jgit.errors.CorruptObjectException; +import org.eclipse.jgit.errors.PackMismatchException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry; import org.eclipse.jgit.lib.ObjectId; @@ -143,6 +144,12 @@ final class PackReverseIndexComputed implements PackReverseIndex { } } + @Override + public void verifyPackChecksum(String packFilePath) + throws PackMismatchException { + // There is no file with a checksum. + } + @Override public ObjectId findObject(long offset) { final int ith = binarySearch(offset); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexV1.java index 76f0793cc..c77a8eb76 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexV1.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexV1.java @@ -16,10 +16,14 @@ import java.io.UncheckedIOException; import java.security.DigestInputStream; import java.text.MessageFormat; +import java.util.Arrays; import org.eclipse.jgit.errors.CorruptObjectException; +import org.eclipse.jgit.errors.PackMismatchException; import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.internal.storage.pack.PackExt; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.util.Hex; import org.eclipse.jgit.util.IO; /** @@ -89,7 +93,20 @@ final class PackReverseIndexV1 implements PackReverseIndex { parseChecksums(); } - private void parseBody() throws IOException { + @Override + public void verifyPackChecksum(String packFilePath) + throws PackMismatchException { + if (!Arrays.equals(packChecksum, getPackIndex().getChecksum())) { + throw new PackMismatchException( + MessageFormat.format(JGitText.get().packChecksumMismatch, + packFilePath, PackExt.INDEX.getExtension(), + Hex.toHexString(getPackIndex().getChecksum()), + PackExt.REVERSE_INDEX.getExtension(), + Hex.toHexString(packChecksum))); + } + } + + private void parseBody() throws IOException { for (int i = 0; i < objectCount; i++) { indexPositionsSortedByOffset[i] = dataIn.readInt(); } @@ -98,10 +115,19 @@ private void parseBody() throws IOException { private void parseChecksums() throws IOException { packChecksum = new byte[SHA1_BYTES]; IO.readFully(inputStream, packChecksum); - // TODO: verify checksum + + // Take digest before reading the self checksum changes it. + byte[] observedSelfChecksum = inputStream.getMessageDigest().digest(); byte[] readSelfChecksum = new byte[SHA1_BYTES]; IO.readFully(inputStream, readSelfChecksum); + + if (!Arrays.equals(readSelfChecksum, observedSelfChecksum)) { + throw new CorruptObjectException(MessageFormat.format( + JGitText.get().corruptReverseIndexChecksumIncorrect, + Hex.toHexString(readSelfChecksum), + Hex.toHexString(observedSelfChecksum))); + } } @Override From 2eba4e5b41c299d82e5aa0b974a1f039997ecf6e Mon Sep 17 00:00:00 2001 From: Anna Papitto Date: Fri, 14 Jul 2023 12:19:27 -0700 Subject: [PATCH 2/3] PackReverseIndex: open file if present otherwise compute The existing #read and #computeFromIndex static builder methods require the caller to choose whether to supply an input stream of a reverse index file or a forward index to compute the reverse index from, which is slower. Allow a caller to provide a file path where the pack's reverse index might be and the pack's forward index index and simply get some reverse index instance back. Prefer opening and parsing the file if it is present, to save computation time. Otherwise, fall back onto computing the reverse index from the pack's forward index. Change-Id: I09bdd4b813ad62c86add586417b2ab86e9331aec Signed-off-by: Anna Papitto --- ...9ae0e6e789088ea0f51f164f489d14.corrupt.rev | Bin 0 -> 76 bytes ...deda40019ae0e6e789088ea0f51f164f489d14.rev | Bin 0 -> 76 bytes .../storage/file/PackReverseIndexTest.java | 44 ++++++++++++++++++ .../storage/file/PackReverseIndexFactory.java | 33 +++++++++++++ 4 files changed, 77 insertions(+) create mode 100644 org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.corrupt.rev create mode 100644 org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.rev diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.corrupt.rev b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.corrupt.rev new file mode 100644 index 0000000000000000000000000000000000000000..74283a2f9aa54045e24d9fb4e21131e4b70cb703 GIT binary patch literal 76 zcmWIYbctYKU|@t|79h<8#LQ4WE0AW`EvssK`2$Dk36=}_#V;9}ZgZXx{*cRjJ%9c| QGqpXZOU)LlWxWFe0OW-g=l}o! literal 0 HcmV?d00001 diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.rev b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.rev new file mode 100644 index 0000000000000000000000000000000000000000..6ac7d65f674cb2a4317149c01f29d0e641201d73 GIT binary patch literal 76 zcmWIYbctYKU|@t|79h<8#LQ4WE0AW`EvssK`2$Dk36=}_#V;9}ZgZXx{*cRjJ%9c| SGqpXZOU)LlWofsFH3I PackIndex.open( + getResourceFileFor(noRevFilePrefix, PackExt.INDEX))); + + assertTrue(computed instanceof PackReverseIndexComputed); + } + + @Test + public void open_readGoodFile() throws IOException { + String hasRevFilePrefix = "pack-cbdeda40019ae0e6e789088ea0f51f164f489d14."; + PackReverseIndex version1 = PackReverseIndexFactory.openOrCompute( + getResourceFileFor(hasRevFilePrefix, PackExt.REVERSE_INDEX), 6, + () -> PackIndex.open( + getResourceFileFor(hasRevFilePrefix, PackExt.INDEX))); + + assertTrue(version1 instanceof PackReverseIndexV1); + } + + @Test + public void open_readCorruptFile() { + String hasRevFilePrefix = "pack-cbdeda40019ae0e6e789088ea0f51f164f489d14."; + + assertThrows(IOException.class, + () -> PackReverseIndexFactory.openOrCompute( + getResourceFileFor(hasRevFilePrefix + "corrupt.", + PackExt.REVERSE_INDEX), + 6, () -> PackIndex.open(getResourceFileFor( + hasRevFilePrefix, PackExt.INDEX)))); + } + @Test public void read_badMagic() { byte[] badMagic = new byte[] { 'R', 'B', 'A', 'D', // magic @@ -53,4 +92,9 @@ public void read_unsupportedVersion2() { assertThrows(IOException.class, () -> PackReverseIndexFactory.readFromFile(in, 0, () -> null)); } + + private File getResourceFileFor(String packFilePrefix, PackExt ext) { + return JGitTestUtil + .getTestResourceFile(packFilePrefix + ext.getExtension()); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexFactory.java index b16da5ae8..32830c3cf 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexFactory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndexFactory.java @@ -14,6 +14,8 @@ import static org.eclipse.jgit.internal.storage.file.PackReverseIndex.VERSION_1; import java.io.DataInput; +import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.security.DigestInputStream; @@ -23,11 +25,42 @@ import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.util.IO; +import org.eclipse.jgit.util.io.SilentFileInputStream; /** * Factory for creating instances of {@link PackReverseIndex}. */ public final class PackReverseIndexFactory { + /** + * Create an in-memory pack reverse index by reading it from the given file + * if the file exists, or computing it from the given pack index if the file + * doesn't exist. + * + * @param idxFile + * the file to read the pack file from, if it exists + * @param objectCount + * the number of objects in the corresponding pack + * @param packIndexSupplier + * a function to lazily get the corresponding forward index + * @return the reverse index instance + * @throws IOException + * if reading from the file fails + */ + static PackReverseIndex openOrCompute(File idxFile, long objectCount, + PackBitmapIndex.SupplierWithIOException packIndexSupplier) + throws IOException { + try (SilentFileInputStream fd = new SilentFileInputStream(idxFile)) { + return readFromFile(fd, objectCount, packIndexSupplier); + } catch (FileNotFoundException e) { + return computeFromIndex(packIndexSupplier.get()); + } catch (IOException e) { + throw new IOException( + MessageFormat.format(JGitText.get().unreadablePackIndex, + idxFile.getAbsolutePath()), + e); + } + } + /** * Compute an in-memory pack reverse index from the in-memory pack forward * index. This computation uses insertion sort, which has a quadratic From f196c7a0e838becff12d9a3ea922398cf8c9d3be Mon Sep 17 00:00:00 2001 From: Anna Papitto Date: Fri, 14 Jul 2023 12:19:27 -0700 Subject: [PATCH 3/3] Pack: open reverse index from file if present The reverse index for a pack is still always computed if needed, which is slower than parsing it from a file. Supply the file path where the reverse index file might be so that it parsed instead of computed if the file is present. Change-Id: I8c60d970fd587341dfb2763fb87f1c586279f2a5 Signed-off-by: Anna Papitto --- .../org/eclipse/jgit/internal/storage/file/Pack.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 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 8d9fe23ae..2b5586a2c 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 @@ -14,6 +14,7 @@ import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.KEEP; +import static org.eclipse.jgit.internal.storage.pack.PackExt.REVERSE_INDEX; import java.io.EOFException; import java.io.File; @@ -1150,8 +1151,15 @@ synchronized PackBitmapIndex getBitmapIndex() throws IOException { } private synchronized PackReverseIndex getReverseIdx() throws IOException { - if (reverseIdx == null) - reverseIdx = PackReverseIndexFactory.computeFromIndex(idx()); + if (invalid) { + throw new PackInvalidException(packFile, invalidatingCause); + } + if (reverseIdx == null) { + PackFile reverseIndexFile = packFile.create(REVERSE_INDEX); + reverseIdx = PackReverseIndexFactory.openOrCompute(reverseIndexFile, + getObjectCount(), () -> getIndex()); + reverseIdx.verifyPackChecksum(getPackFile().getPath()); + } return reverseIdx; }