If your goal is simply to get the hash of a file, you don’t need to use std.Io.Reader/Writer at all. You can just mmap the file and compute the hash in a single hash() call. This is tested with 0.16.0-dev.2349+204fa8959:
const std = @import("std");
const Io = std.Io;
pub fn main(init: std.process.Init) !void {
const io = init.io;
const args = try init.minimal.args.toSlice(init.arena.allocator());
const dir = std.Io.Dir.cwd();
const path = args[1];
const file = try dir.openFile(io, path, .{ .allow_directory = false, .mode = .read_write });
defer file.close(io);
var file_map = try file.createMemoryMap(io, .{ .len = try file.length(io) });
defer file_map.destroy(io);
// Ensure the contents of the map are populated
try file_map.read(io);
var src_hash: [std.crypto.hash.Blake3.digest_length]u8 = undefined;
std.crypto.hash.Blake3.hash(file_map.memory, &src_hash, .{});
std.debug.print("hash: {x}\n", .{&src_hash});
}
Output:
$ zig build run -- ./src/main.zig
hash: bd0a0de9738517f4c062ad0f6d781bcb3e3a7d1285581ab2bc6c7f539f1e0438
$ zig build run -- ./build.zig
hash: 50c65a7c4efe3d9ad0a478bc106db3a42dfd92b1ce627b88101ec05542c6ba0b
It’s probably possible to open the file as read only too, but I couldn’t get it to work. If I tried:
const file = try dir.openFile(io, path, .{ .allow_directory = false }); // Default is read only
defer file.close(io);
var file_map = try file.createMemoryMap(io, .{ .len = try file.length(io) });
defer file_map.destroy(io);
I got:
error: AccessDenied
/home/robby/downloads/zig-x86_64-linux-0.16.0-dev.2349+204fa8959/lib/std/Io/Threaded.zig:16548:27: 0x1088635 in createFileMap (std.zig)
.ACCES => return error.AccessDenied,
^
/home/robby/downloads/zig-x86_64-linux-0.16.0-dev.2349+204fa8959/lib/std/Io/Threaded.zig:16389:73: 0x106c3aa in fileMemoryMapCreate (std.zig)
error.Unseekable, error.Canceled, error.AccessDenied => |e| return e,
^
/home/robby/downloads/zig-x86_64-linux-0.16.0-dev.2349+204fa8959/lib/std/Io/File/MemoryMap.zig:67:5: 0x11d4942 in create (std.zig)
return io.vtable.fileMemoryMapCreate(io.userdata, file, options);
^
/home/robby/downloads/zig-x86_64-linux-0.16.0-dev.2349+204fa8959/lib/std/Io/File.zig:819:5: 0x11c52df in createMemoryMap (std.zig)
return .create(io, file, options);
^
/tmp/hash-test/src/main.zig:12:20: 0x11c215b in main (main.zig)
var file_map = try file.createMemoryMap(io, .{ .len = try file.length(io) });
^
run
└─ run exe hash_test failure
error: process exited with error code 1
failed command: /tmp/hash-test/zig-out/bin/hash_test ./build.zig
Build Summary: 3/5 steps succeeded (1 failed)
run transitive failure
└─ run exe hash_test failure
error: the following build command failed with exit code 1:
.zig-cache/o/8e4d2a7c1391bbc16b86b37a4ffe20f1/build /home/robby/downloads/zig-x86_64-linux-0.16.0-dev.2349+204fa8959/zig /home/robby/downloads/zig-x86_64-linux-0.16.0-dev.2349+204fa8959/lib /tmp/hash-test .zig-cache /home/robby/.cache/zig --seed 0x9757c8af -Z4ce972384ce331ee run -- ./build.zig
Because it’s trying to create the memory map with read / write access, but if I try:
const file = try dir.openFile(io, path, .{ .allow_directory = false });
defer file.close(io);
var file_map = try file.createMemoryMap(io, .{ .len = try file.length(io), .protection = .{ .write = false } });
defer file_map.destroy(io);
I get:
Segmentation fault at address 0x7f4c3e568000
/home/robby/downloads/zig-x86_64-linux-0.16.0-dev.2349+204fa8959/lib/compiler_rt/memcpy.zig:170:17: 0x12599b3 in copyFixedLength (compiler_rt)
d[i] = s[i];
^
/home/robby/downloads/zig-x86_64-linux-0.16.0-dev.2349+204fa8959/lib/std/crypto/blake3.zig:870:57: 0x11eb57e in fillBuf (std.zig)
@memcpy(self.buf[self.buf_len..][0..take], input[0..take]);
^
/home/robby/downloads/zig-x86_64-linux-0.16.0-dev.2349+204fa8959/lib/std/crypto/blake3.zig:890:38: 0x11e0189 in update (std.zig)
const take = self.fillBuf(inp);
^
/home/robby/downloads/zig-x86_64-linux-0.16.0-dev.2349+204fa8959/lib/std/crypto/blake3.zig:1154:30: 0x11d576e in update (std.zig)
self.chunk.update(inp);
^
/home/robby/downloads/zig-x86_64-linux-0.16.0-dev.2349+204fa8959/lib/std/crypto/blake3.zig:989:17: 0x11c5562 in hash (std.zig)
d.update(b);
^
/tmp/hash-test/src/main.zig:19:32: 0x11c22f3 in main (main.zig)
std.crypto.hash.Blake3.hash(file_map.memory, &src_hash, .{});
^
/home/robby/downloads/zig-x86_64-linux-0.16.0-dev.2349+204fa8959/lib/std/start.zig:718:30: 0x11c2ea0 in callMain (std.zig)
return wrapMain(root.main(.{
^
/home/robby/downloads/zig-x86_64-linux-0.16.0-dev.2349+204fa8959/lib/std/start.zig:190:5: 0x11c1cf1 in _start (std.zig)
asm volatile (switch (native_arch) {
^
run
└─ run exe hash_test failure
error: process terminated with signal ABRT
failed command: /tmp/hash-test/zig-out/bin/hash_test ./src/main.zig
Build Summary: 3/5 steps succeeded (1 failed)
run transitive failure
└─ run exe hash_test failure
error: the following build command failed with exit code 1:
.zig-cache/o/8e4d2a7c1391bbc16b86b37a4ffe20f1/build /home/robby/downloads/zig-x86_64-linux-0.16.0-dev.2349+204fa8959/zig /home/robby/downloads/zig-x86_64-linux-0.16.0-dev.2349+204fa8959/lib /tmp/hash-test .zig-cache /home/robby/.cache/zig --seed 0x815dc2f5 -Zd28f190fd79a4981 run -- ./src/main.zig
which… seems like it might be a bug? It seems like using @memcpy to copy out of a read only memory region is triggering a segfault, and I don’t think that should happen. Either way, if you’re fine opening with .read_write access then the above code should work fine.