/* * Copyright (C) 2024, GerritForge Inc. and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at * https://www.eclipse.org/org/documents/edl-v10.php. * * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.internal.storage.midx; import static java.nio.charset.StandardCharsets.UTF_8; import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.CHUNK_LOOKUP_WIDTH; import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_BITMAPPEDPACKS; import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_LARGEOFFSETS; import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_OBJECTOFFSETS; import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_OIDFANOUT; import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_OIDLOOKUP; import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_PACKNAMES; import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_REVINDEX; import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_SIGNATURE; import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.NB; import org.eclipse.jgit.util.io.SilentFileInputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The loader returns the representation of the MultiPackIndex file content. */ public class MultiPackIndexLoader { private final static Logger LOG = LoggerFactory .getLogger(MultiPackIndexLoader.class); /** * Open an existing MultiPackIndex file for reading. *
* The format of the file will be automatically detected and a proper access * implementation for that format will be constructed and returned to the * caller. The file may or may not be held open by the returned instance. * * @param midxFile * existing multi-pack-index to read. * @return a copy of the multi-pack-index file in memory * @throws FileNotFoundException * the file does not exist. * @throws MultiPackIndexFormatException * MultiPackIndex file's format is different from we expected. * @throws java.io.IOException * the file exists but could not be read due to security errors * or unexpected data corruption. */ public static MultiPackIndex open(File midxFile) throws FileNotFoundException, MultiPackIndexFormatException, IOException { try (SilentFileInputStream fd = new SilentFileInputStream(midxFile)) { try { return read(fd); } catch (MultiPackIndexFormatException fe) { throw fe; } catch (IOException ioe) { throw new IOException( MessageFormat.format(JGitText.get().unreadableMIDX, midxFile.getAbsolutePath()), ioe); } } } /** * Read an existing MultiPackIndex file from a buffered stream. *
* The format of the file will be automatically detected and a proper access
* implementation for that format will be constructed and returned to the
* caller. The file may or may not be held open by the returned instance.
*
* @param fd
* stream to read the multipack-index file from. The stream must be
* buffered as some small IOs are performed against the stream.
* The caller is responsible for closing the stream.
* @return a copy of the MultiPackIndex file in memory
* @throws MultiPackIndexFormatException
* the MultiPackIndex file's format is different from we
* expected.
* @throws java.io.IOException
* the stream cannot be read.
*/
public static MultiPackIndex read(InputStream fd)
throws MultiPackIndexFormatException, IOException {
byte[] hdr = new byte[12];
IO.readFully(fd, hdr, 0, hdr.length);
int magic = NB.decodeInt32(hdr, 0);
if (magic != MIDX_SIGNATURE) {
throw new MultiPackIndexFormatException(JGitText.get().notAMIDX);
}
// Check MultiPackIndex version
int v = hdr[4];
if (v != 1) {
throw new MultiPackIndexFormatException(MessageFormat
.format(JGitText.get().unsupportedMIDXVersion, v));
}
// Read the object Id version (1 byte)
// 1 => SHA-1
// 2 => SHA-256
// TODO: If the hash type does not match the repository's hash
// algorithm,
// the multi-pack-index file should be ignored with a warning
// presented to the user.
int commitIdVersion = hdr[5];
if (commitIdVersion != 1) {
throw new MultiPackIndexFormatException(
JGitText.get().incorrectOBJECT_ID_LENGTH);
}
// Read the number of "chunkOffsets" (1 byte)
int chunkCount = hdr[6];
// Read the number of multi-pack-index files (1 byte)
// This value is currently always zero.
// TODO populate this
// int numberOfMultiPackIndexFiles = hdr[7];
// Number of packfiles (4 bytes)
int packCount = NB.decodeInt32(hdr, 8);
byte[] lookupBuffer = new byte[CHUNK_LOOKUP_WIDTH * (chunkCount + 1)];
IO.readFully(fd, lookupBuffer, 0, lookupBuffer.length);
List