Performs the first pass over the packfile data for index construction. This will index all non-delta objects, queue delta objects for further processing, and return the pack checksum (which is part of the index format).
fn indexPackFirstPass(
allocator: Allocator,
format: Oid.Format,
pack: *Io.File.Reader,
index_entries: *std.AutoHashMapUnmanaged(Oid, IndexEntry),
pending_deltas: *std.ArrayList(IndexEntry),
) !Oid
fn indexPackFirstPass(
allocator: Allocator,
format: Oid.Format,
pack: *Io.File.Reader,
index_entries: *std.AutoHashMapUnmanaged(Oid, IndexEntry),
pending_deltas: *std.ArrayList(IndexEntry),
) !Oid {
var flate_buffer: [std.compress.flate.max_window_len]u8 = undefined;
var pack_buffer: [2048]u8 = undefined; // Reasonably large buffer for file system.
var pack_hashed = pack.interface.hashed(Oid.Hasher.init(format), &pack_buffer);
const pack_header = try PackHeader.read(&pack_hashed.reader);
for (0..pack_header.total_objects) |_| {
const entry_offset = pack.logicalPos() - pack_hashed.reader.bufferedLen();
const entry_header = try EntryHeader.read(format, &pack_hashed.reader);
switch (entry_header) {
.commit, .tree, .blob, .tag => |object| {
var entry_decompress: std.compress.flate.Decompress = .init(&pack_hashed.reader, .zlib, &.{});
var oid_hasher: Oid.Hashing = .init(format, &flate_buffer);
const oid_hasher_w = oid_hasher.writer();
// The object header is not included in the pack data but is
// part of the object's ID
try oid_hasher_w.print("{t} {d}\x00", .{ entry_header, object.uncompressed_length });
const n = try entry_decompress.reader.streamRemaining(oid_hasher_w);
if (n != object.uncompressed_length) return error.InvalidObject;
const oid = oid_hasher.final();
if (!skip_checksums) @compileError("TODO");
try index_entries.put(allocator, oid, .{
.offset = entry_offset,
.crc32 = 0,
});
},
inline .ofs_delta, .ref_delta => |delta| {
var entry_decompress: std.compress.flate.Decompress = .init(&pack_hashed.reader, .zlib, &flate_buffer);
const n = try entry_decompress.reader.discardRemaining();
if (n != delta.uncompressed_length) return error.InvalidObject;
if (!skip_checksums) @compileError("TODO");
try pending_deltas.append(allocator, .{
.offset = entry_offset,
.crc32 = 0,
});
},
}
}
if (!skip_checksums) @compileError("TODO");
return pack_hashed.hasher.finalResult();
}