authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-25 13:50:42-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-25 23:22:17-05:00
logee6df50678d985947bfb85cf7bfefb25ab68cdfc
treec74711a6e1b5671e98fbfca05042c0ef66f2b4d0
parent81a47dc874d8468db7120e1733acd122f90d8eab

fix package hashes on Windows

closes #14602

1 files changed, 32 insertions(+), 6 deletions(-)

src/Package.zig+32-6
......@@ -493,6 +493,11 @@ fn fetchAndUnpack(
493493 // apply those rules directly to the filesystem right here. This ensures that files
494494 // not protected by the hash are not present on the file system.
495495
496 // TODO: raise an error for files that have illegal paths on some operating systems.
497 // For example, on Linux a path with a backslash should raise an error here.
498 // Of course, if the ignore rules above omit the file from the package, then everything
499 // is fine and no error should be raised.
500
496501 break :a try computePackageHash(thread_pool, .{ .dir = tmp_directory.handle });
497502 };
498503
......@@ -546,7 +551,8 @@ fn unpackTarball(
546551}
547552
548553const HashedFile = struct {
549 path: []const u8,
554 fs_path: []const u8,
555 normalized_path: []const u8,
550556 hash: [Manifest.Hash.digest_length]u8,
551557 failure: Error!void,
552558
......@@ -554,7 +560,7 @@ const HashedFile = struct {
554560
555561 fn lessThan(context: void, lhs: *const HashedFile, rhs: *const HashedFile) bool {
556562 _ = context;
557 return mem.lessThan(u8, lhs.path, rhs.path);
563 return mem.lessThan(u8, lhs.normalized_path, rhs.normalized_path);
558564 }
559565};
560566
......@@ -590,8 +596,10 @@ fn computePackageHash(
590596 else => return error.IllegalFileTypeInPackage,
591597 }
592598 const hashed_file = try arena.create(HashedFile);
599 const fs_path = try arena.dupe(u8, entry.path);
593600 hashed_file.* = .{
594 .path = try arena.dupe(u8, entry.path),
601 .fs_path = fs_path,
602 .normalized_path = try normalizePath(arena, fs_path),
595603 .hash = undefined, // to be populated by the worker
596604 .failure = undefined, // to be populated by the worker
597605 };
......@@ -609,7 +617,7 @@ fn computePackageHash(
609617 for (all_files.items) |hashed_file| {
610618 hashed_file.failure catch |err| {
611619 any_failures = true;
612 std.log.err("unable to hash '{s}': {s}", .{ hashed_file.path, @errorName(err) });
620 std.log.err("unable to hash '{s}': {s}", .{ hashed_file.fs_path, @errorName(err) });
613621 };
614622 hasher.update(&hashed_file.hash);
615623 }
......@@ -617,6 +625,24 @@ fn computePackageHash(
617625 return hasher.finalResult();
618626}
619627
628/// Make a file system path identical independently of operating system path inconsistencies.
629/// This converts backslashes into forward slashes.
630fn normalizePath(arena: Allocator, fs_path: []const u8) ![]const u8 {
631 const canonical_sep = '/';
632
633 if (fs.path.sep == canonical_sep)
634 return fs_path;
635
636 const normalized = try arena.dupe(u8, fs_path);
637 for (normalized) |*byte| {
638 switch (byte.*) {
639 fs.path.sep => byte.* = canonical_sep,
640 else => continue,
641 }
642 }
643 return normalized;
644}
645
620646fn workerHashFile(dir: fs.Dir, hashed_file: *HashedFile, wg: *WaitGroup) void {
621647 defer wg.finish();
622648 hashed_file.failure = hashFileFallible(dir, hashed_file);
......@@ -624,10 +650,10 @@ fn workerHashFile(dir: fs.Dir, hashed_file: *HashedFile, wg: *WaitGroup) void {
624650
625651fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void {
626652 var buf: [8000]u8 = undefined;
627 var file = try dir.openFile(hashed_file.path, .{});
653 var file = try dir.openFile(hashed_file.fs_path, .{});
628654 defer file.close();
629655 var hasher = Manifest.Hash.init(.{});
630 hasher.update(hashed_file.path);
656 hasher.update(hashed_file.normalized_path);
631657 hasher.update(&.{ 0, @boolToInt(try isExecutable(file)) });
632658 while (true) {
633659 const bytes_read = try file.read(&buf);