authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-31 16:04:53-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-31 22:10:11-07:00
log95273337c507917e28a6be7dbd89a5c13fea9401
treed46761047937a32f53e104bd29fad1d01ae04ee9
parentc9ff068391b18b0c6fe90a46c39e6e2956512660

fetch: remove checksum logic and fix new I/O API bugs

Thanks Ian Johnson for finding these

1 files changed, 20 insertions(+), 16 deletions(-)

src/Package/Fetch/git.zig+20-16
...@@ -1355,21 +1355,18 @@ fn indexPackFirstPass(...@@ -1355,21 +1355,18 @@ fn indexPackFirstPass(
1355 pending_deltas: *std.ArrayListUnmanaged(IndexEntry),1355 pending_deltas: *std.ArrayListUnmanaged(IndexEntry),
1356) !Oid {1356) !Oid {
1357 var flate_buffer: [std.compress.flate.max_window_len]u8 = undefined;1357 var flate_buffer: [std.compress.flate.max_window_len]u8 = undefined;
1358 var entry_buffer: [1024]u8 = undefined; // Input buffer to flate.
1359 var pack_buffer: [2048]u8 = undefined; // Reasonably large buffer for file system.1358 var pack_buffer: [2048]u8 = undefined; // Reasonably large buffer for file system.
1360 var hasher_buffer: [64]u8 = undefined;
1361 var pack_hashed = pack.interface.hashed(Oid.Hasher.init(format), &pack_buffer);1359 var pack_hashed = pack.interface.hashed(Oid.Hasher.init(format), &pack_buffer);
13621360
1363 const pack_header = try PackHeader.read(&pack_hashed.reader);1361 const pack_header = try PackHeader.read(&pack_hashed.reader);
13641362
1365 for (0..pack_header.total_objects) |_| {1363 for (0..pack_header.total_objects) |_| {
1366 const entry_offset = pack.logicalPos();1364 const entry_offset = pack.logicalPos() - pack_hashed.reader.bufferedLen();
1367 var entry_crc32_stream = pack_hashed.reader.hashed(std.hash.Crc32.init(), &entry_buffer);1365 const entry_header = try EntryHeader.read(format, &pack_hashed.reader);
1368 const entry_header = try EntryHeader.read(format, &entry_crc32_stream.reader);
1369 var entry_decompress: std.compress.flate.Decompress = .init(&entry_crc32_stream.reader, .zlib, &flate_buffer);
1370 switch (entry_header) {1366 switch (entry_header) {
1371 .commit, .tree, .blob, .tag => |object| {1367 .commit, .tree, .blob, .tag => |object| {
1372 var oid_hasher: Oid.Hashing = .init(format, &hasher_buffer);1368 var entry_decompress: std.compress.flate.Decompress = .init(&pack_hashed.reader, .zlib, &.{});
1369 var oid_hasher: Oid.Hashing = .init(format, &flate_buffer);
1373 const oid_hasher_w = oid_hasher.writer();1370 const oid_hasher_w = oid_hasher.writer();
1374 // The object header is not included in the pack data but is1371 // The object header is not included in the pack data but is
1375 // part of the object's ID1372 // part of the object's ID
...@@ -1377,28 +1374,27 @@ fn indexPackFirstPass(...@@ -1377,28 +1374,27 @@ fn indexPackFirstPass(
1377 const n = try entry_decompress.reader.streamRemaining(oid_hasher_w);1374 const n = try entry_decompress.reader.streamRemaining(oid_hasher_w);
1378 if (n != object.uncompressed_length) return error.InvalidObject;1375 if (n != object.uncompressed_length) return error.InvalidObject;
1379 const oid = oid_hasher.final();1376 const oid = oid_hasher.final();
1377 if (!skip_checksums) @compileError("TODO");
1380 try index_entries.put(allocator, oid, .{1378 try index_entries.put(allocator, oid, .{
1381 .offset = entry_offset,1379 .offset = entry_offset,
1382 .crc32 = entry_crc32_stream.hasher.final(),1380 .crc32 = 0,
1383 });1381 });
1384 },1382 },
1385 inline .ofs_delta, .ref_delta => |delta| {1383 inline .ofs_delta, .ref_delta => |delta| {
1384 var entry_decompress: std.compress.flate.Decompress = .init(&pack_hashed.reader, .zlib, &flate_buffer);
1386 const n = try entry_decompress.reader.discardRemaining();1385 const n = try entry_decompress.reader.discardRemaining();
1387 if (n != delta.uncompressed_length) return error.InvalidObject;1386 if (n != delta.uncompressed_length) return error.InvalidObject;
1387 if (!skip_checksums) @compileError("TODO");
1388 try pending_deltas.append(allocator, .{1388 try pending_deltas.append(allocator, .{
1389 .offset = entry_offset,1389 .offset = entry_offset,
1390 .crc32 = entry_crc32_stream.hasher.final(),1390 .crc32 = 0,
1391 });1391 });
1392 },1392 },
1393 }1393 }
1394 }1394 }
13951395
1396 const pack_checksum = pack_hashed.hasher.finalResult();1396 if (!skip_checksums) @compileError("TODO");
1397 const recorded_checksum = try Oid.readBytes(format, &pack.interface);1397 return pack_hashed.hasher.finalResult();
1398 if (!mem.eql(u8, pack_checksum.slice(), recorded_checksum.slice())) {
1399 return error.CorruptedPack;
1400 }
1401 return pack_checksum;
1402}1398}
14031399
1404/// Attempts to determine the final object ID of the given deltified object.1400/// Attempts to determine the final object ID of the given deltified object.
...@@ -1497,7 +1493,7 @@ fn resolveDeltaChain(...@@ -1497,7 +1493,7 @@ fn resolveDeltaChain(
1497fn readObjectRaw(allocator: Allocator, reader: *std.Io.Reader, size: u64) ![]u8 {1493fn readObjectRaw(allocator: Allocator, reader: *std.Io.Reader, size: u64) ![]u8 {
1498 const alloc_size = std.math.cast(usize, size) orelse return error.ObjectTooLarge;1494 const alloc_size = std.math.cast(usize, size) orelse return error.ObjectTooLarge;
1499 var aw: std.Io.Writer.Allocating = .init(allocator);1495 var aw: std.Io.Writer.Allocating = .init(allocator);
1500 try aw.ensureTotalCapacity(alloc_size);1496 try aw.ensureTotalCapacity(alloc_size + std.compress.flate.max_window_len);
1501 defer aw.deinit();1497 defer aw.deinit();
1502 var decompress: std.compress.flate.Decompress = .init(reader, .zlib, &.{});1498 var decompress: std.compress.flate.Decompress = .init(reader, .zlib, &.{});
1503 try decompress.reader.streamExact(&aw.writer, alloc_size);1499 try decompress.reader.streamExact(&aw.writer, alloc_size);
...@@ -1666,11 +1662,19 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void...@@ -1666,11 +1662,19 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void
1666 try testing.expectEqualStrings(expected_file_contents, actual_file_contents);1662 try testing.expectEqualStrings(expected_file_contents, actual_file_contents);
1667}1663}
16681664
1665/// Checksum calculation is useful for troubleshooting and debugging, but it's
1666/// redundant since the package manager already does content hashing at the
1667/// end. Let's save time by not doing that work, but, I left a cookie crumb
1668/// trail here if you want to restore the functionality for tinkering purposes.
1669const skip_checksums = true;
1670
1669test "SHA-1 packfile indexing and checkout" {1671test "SHA-1 packfile indexing and checkout" {
1672 if (skip_checksums) return error.SkipZigTest;
1670 try runRepositoryTest(.sha1, "dd582c0720819ab7130b103635bd7271b9fd4feb");1673 try runRepositoryTest(.sha1, "dd582c0720819ab7130b103635bd7271b9fd4feb");
1671}1674}
16721675
1673test "SHA-256 packfile indexing and checkout" {1676test "SHA-256 packfile indexing and checkout" {
1677 if (skip_checksums) return error.SkipZigTest;
1674 try runRepositoryTest(.sha256, "7f444a92bd4572ee4a28b2c63059924a9ca1829138553ef3e7c41ee159afae7a");1678 try runRepositoryTest(.sha256, "7f444a92bd4572ee4a28b2c63059924a9ca1829138553ef3e7c41ee159afae7a");
1675}1679}
16761680