From 82cc7bdec502e75c2a48cbdaae4c97939846e71d Mon Sep 17 00:00:00 2001 From: bnuuydev Date: Thu, 16 Oct 2025 21:22:08 +0100 Subject: [PATCH 1/6] wip: upgrade to zig-master the main breakage here is caused by writergate. there's some weirdness going on to do with file paths and the build system too though, so that should be dealt with before merging. also the new writer and reader don't provide any error specificity, so we don't know why a read or a write failed now. this should also be considered: perhaps creating a custom interface is warranted? --- build.zig.zon | 10 +- src/BuildInterface.zig | 47 +++---- src/Parser.zig | 36 ++--- src/Tokenizer.zig | 4 +- src/components/FillData.zig | 6 +- src/components/fs/FatFileSystem.zig | 47 ++++--- src/components/fs/common.zig | 64 +++++---- src/components/part/GptPartitionTable.zig | 10 +- src/components/part/MbrPartitionTable.zig | 2 +- src/dim.zig | 157 +++++++++++----------- 10 files changed, 200 insertions(+), 183 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 3ceb020..56e0973 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -4,14 +4,14 @@ .fingerprint = 0x9947018c924eecb2, .dependencies = .{ .zfat = .{ - .url = "https://github.com/ZigEmbeddedGroup/zfat/archive/3ce06d43a4e04d387034dcae2f486b050701f321.tar.gz", - .hash = "zfat-0.0.0-AAAAAMYlcABdh06Mn9CNk8Ccy_3bBFgJr8wo4jKza1q-", + .url = "https://github.com/CascadeOS/zfat/archive/refs/heads/0.15.zip", + .hash = "zfat-0.16.0-SNNK9fKtTgASssfmCblZwRMLU4pndVtwxTNhYCegBOyA", }, .args = .{ - .url = "git+https://github.com/ikskuh/zig-args.git#9425b94c103a031777fdd272c555ce93a7dea581", - .hash = "args-0.0.0-CiLiqv_NAAC97fGpk9hS2K681jkiqPsWP6w3ucb_ctGH", + .url = "git+https://github.com/ikskuh/zig-args.git#8ae26b44a884ff20dca98ee84c098e8f8e94902f", + .hash = "args-0.0.0-CiLiqojRAACGzDRO7A9dw7kWSchNk29caJZkXuMCb0Cn", }, - }, + }, .paths = .{ "build.zig", "build.zig.zon", diff --git a/src/BuildInterface.zig b/src/BuildInterface.zig index 4d9ebda..10d559d 100644 --- a/src/BuildInterface.zig +++ b/src/BuildInterface.zig @@ -63,13 +63,13 @@ pub fn createDisk(dimmer: Interface, size: u64, content: Content) std.Build.Lazy } fn renderContent(wfs: *std.Build.Step.WriteFile, allocator: std.mem.Allocator, content: Content) struct { []const u8, ContentWriter.VariableMap } { - var code: std.ArrayList(u8) = .init(allocator); + var code = std.Io.Writer.Allocating.init(allocator); defer code.deinit(); var variables: ContentWriter.VariableMap = .init(allocator); var cw: ContentWriter = .{ - .code = code.writer(), + .code = &code.writer, .wfs = wfs, .vars = &variables, }; @@ -99,7 +99,7 @@ const ContentWriter = struct { pub const VariableMap = std.StringArrayHashMap(struct { std.Build.LazyPath, ContentWriter.UsageHint }); wfs: *std.Build.Step.WriteFile, - code: std.ArrayList(u8).Writer, + code: *std.Io.Writer, vars: *VariableMap, fn render(cw: ContentWriter, content: Content) !void { @@ -117,7 +117,7 @@ const ContentWriter = struct { }, .paste_file => |data| { - try cw.code.print("paste-file {}", .{cw.fmtLazyPath(data, .file)}); + try cw.code.print("paste-file {f}", .{cw.fmtLazyPath(data, .file)}); }, .mbr_part_table => |data| { @@ -176,7 +176,7 @@ const ContentWriter = struct { try cw.code.writeByte('\n'); if (part.name) |name| { - try cw.code.print(" name \"{}\"\n", .{std.zig.fmtEscapes(name)}); + try cw.code.print(" name \"{f}\"\n", .{std.zig.fmtString(name)}); } if (part.offset) |offset| { try cw.code.print(" offset {d}\n", .{offset}); @@ -198,7 +198,7 @@ const ContentWriter = struct { @tagName(data.format), }); if (data.label) |label| { - try cw.code.print(" label {}\n", .{ + try cw.code.print(" label {f}\n", .{ fmtPath(label), }); } @@ -213,29 +213,29 @@ const ContentWriter = struct { fn renderFileSystemTree(cw: ContentWriter, fs: FileSystem) !void { for (fs.items) |item| { switch (item) { - .empty_dir => |dir| try cw.code.print("mkdir {}\n", .{ + .empty_dir => |dir| try cw.code.print("mkdir {f}\n", .{ fmtPath(dir), }), - .copy_dir => |copy| try cw.code.print("copy-dir {} {}\n", .{ + .copy_dir => |copy| try cw.code.print("copy-dir {f} {f}\n", .{ fmtPath(copy.destination), cw.fmtLazyPath(copy.source, .directory), }), - .copy_file => |copy| try cw.code.print("copy-file {} {}\n", .{ + .copy_file => |copy| try cw.code.print("copy-file {f} {f}\n", .{ fmtPath(copy.destination), cw.fmtLazyPath(copy.source, .file), }), - .include_script => |script| try cw.code.print("!include {}\n", .{ + .include_script => |script| try cw.code.print("!include {f}\n", .{ cw.fmtLazyPath(script, .file), }), } } } - const PathFormatter = std.fmt.Formatter(formatPath); - const LazyPathFormatter = std.fmt.Formatter(formatLazyPath); + const PathFormatter = std.fmt.Alt([]const u8, formatPath); + const LazyPathFormatter = std.fmt.Alt(struct { ContentWriter, std.Build.LazyPath, UsageHint }, formatLazyPath); const UsageHint = enum { file, directory }; fn fmtLazyPath(cw: ContentWriter, path: std.Build.LazyPath, hint: UsageHint) LazyPathFormatter { @@ -248,13 +248,9 @@ const ContentWriter = struct { fn formatLazyPath( data: struct { ContentWriter, std.Build.LazyPath, UsageHint }, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + writer: *std.Io.Writer, + ) error{WriteFailed}!void { const cw, const path, const hint = data; - _ = fmt; - _ = options; switch (path) { .cwd_relative, @@ -267,7 +263,7 @@ const ContentWriter = struct { std.debug.assert(std.fs.path.isAbsolute(full_path)); - try writer.print("{}", .{ + try writer.print("{f}", .{ fmtPath(full_path), }); }, @@ -278,7 +274,7 @@ const ContentWriter = struct { const var_id = cw.vars.count() + 1; const var_name = cw.wfs.step.owner.fmt("PATH{}", .{var_id}); - try cw.vars.put(var_name, .{ path, hint }); + cw.vars.put(var_name, .{ path, hint }) catch return error.WriteFailed; try writer.print("${s}", .{var_name}); }, @@ -287,13 +283,8 @@ const ContentWriter = struct { fn formatPath( path: []const u8, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, + writer: *std.Io.Writer, ) !void { - _ = fmt; - _ = options; - const is_safe_word = for (path) |char| { switch (char) { 'A'...'Z', @@ -318,7 +309,7 @@ const ContentWriter = struct { if (c == '\\') { try writer.writeAll("/"); } else { - try writer.print("{}", .{std.zig.fmtEscapes(&[_]u8{c})}); + try writer.print("{f}", .{std.zig.fmtString(&[_]u8{c})}); } } @@ -419,7 +410,7 @@ pub const FatFs = struct { pub const FileSystemBuilder = struct { b: *std.Build, - list: std.ArrayListUnmanaged(FileSystem.Item), + list: std.ArrayList(FileSystem.Item), pub fn init(b: *std.Build) FileSystemBuilder { return FileSystemBuilder{ diff --git a/src/Parser.zig b/src/Parser.zig index ff7c179..64609b7 100644 --- a/src/Parser.zig +++ b/src/Parser.zig @@ -103,10 +103,12 @@ pub fn get_include_path(parser: Parser, allocator: std.mem.Allocator, rel_includ if (parser.file_stack.len == parser.max_include_depth) return error.MaxIncludeDepthReached; - const top_path = if (parser.file_stack.len > 0) - parser.file_stack[parser.file_stack.len - 1].path - else - ""; + // const top_path = if (parser.file_stack.len > 0) + // parser.file_stack[parser.file_stack.len - 1].path + // else + // ""; + + const top_path = ""; // TODO what the fuck, the actual issue here needs to be triaged. this workaround fixes things for me for now though. const abs_include_path = try std.fs.path.resolvePosix( allocator, @@ -208,10 +210,12 @@ fn resolve_value(parser: *Parser, token_type: TokenType, text: []const u8) ![]co if (!has_includes) return content_slice; - var unescaped: std.ArrayList(u8) = .init(parser.arena.allocator()); - defer unescaped.deinit(); + const allocator = parser.arena.allocator(); + + var unescaped = std.ArrayList(u8).empty; + defer unescaped.deinit(allocator); - try unescaped.ensureTotalCapacityPrecise(content_slice.len); + try unescaped.ensureTotalCapacityPrecise(allocator, content_slice.len); { var i: usize = 0; @@ -220,7 +224,7 @@ fn resolve_value(parser: *Parser, token_type: TokenType, text: []const u8) ![]co i += 1; if (c != '\\') { - try unescaped.append(c); + try unescaped.append(allocator, c); continue; } @@ -233,20 +237,20 @@ fn resolve_value(parser: *Parser, token_type: TokenType, text: []const u8) ![]co errdefer std.log.err("invalid escape sequence: \\{s}", .{[_]u8{esc_code}}); switch (esc_code) { - 'r' => try unescaped.append('\r'), - 'n' => try unescaped.append('\n'), - 't' => try unescaped.append('\t'), - '\\' => try unescaped.append('\\'), - '\"' => try unescaped.append('\"'), - '\'' => try unescaped.append('\''), - 'e' => try unescaped.append('\x1B'), + 'r' => try unescaped.append(allocator, '\r'), + 'n' => try unescaped.append(allocator, '\n'), + 't' => try unescaped.append(allocator, '\t'), + '\\' => try unescaped.append(allocator, '\\'), + '\"' => try unescaped.append(allocator, '\"'), + '\'' => try unescaped.append(allocator, '\''), + 'e' => try unescaped.append(allocator, '\x1B'), else => return error.InvalidEscapeSequence, } } } - return try unescaped.toOwnedSlice(); + return try unescaped.toOwnedSlice(allocator); }, .comment, .directive, .whitespace => unreachable, diff --git a/src/Tokenizer.zig b/src/Tokenizer.zig index cdac717..c8a0ab5 100644 --- a/src/Tokenizer.zig +++ b/src/Tokenizer.zig @@ -186,9 +186,9 @@ test Tokenizer { var offset: u32 = 0; for (seq) |expected| { const actual = (try tokenizer.next()) orelse return error.Unexpected; - errdefer std.debug.print("unexpected token: .{} \"{}\"\n", .{ + errdefer std.debug.print("unexpected token: .{f} \"{f}\"\n", .{ std.zig.fmtId(@tagName(actual.type)), - std.zig.fmtEscapes(tokenizer.source[actual.offset..][0..actual.len]), + std.zig.fmtString(tokenizer.source[actual.offset..][0..actual.len]), }); try std.testing.expectEqualStrings(expected.@"1", tokenizer.get_text(actual)); try std.testing.expectEqual(offset, actual.offset); diff --git a/src/components/FillData.zig b/src/components/FillData.zig index 82b8cb4..e5f0458 100644 --- a/src/components/FillData.zig +++ b/src/components/FillData.zig @@ -20,8 +20,10 @@ pub fn parse(ctx: dim.Context) !dim.Content { } fn render(self: *FillData, stream: *dim.BinaryStream) dim.Content.RenderError!void { - try stream.writer().writeByteNTimes( + var writer = stream.writer(); + writer.interface.splatByteAll( self.fill_value, stream.length, - ); + ) catch return error.Overflow; // TODO FIX we don't know actually why this failed. + // std.Io.Writer only returns error.WriteFailed. } diff --git a/src/components/fs/FatFileSystem.zig b/src/components/fs/FatFileSystem.zig index 5b5de50..872b1d7 100644 --- a/src/components/fs/FatFileSystem.zig +++ b/src/components/fs/FatFileSystem.zig @@ -14,7 +14,7 @@ format_as: FatType, label: ?[]const u8 = null, fats: ?fatfs.FatTables = null, rootdir_size: ?c_uint = null, -ops: std.ArrayList(common.FsOperation), +ops: std.array_list.Managed(common.FsOperation), sector_align: ?c_uint = null, cluster_size: ?u32 = null, @@ -88,7 +88,7 @@ fn render(self: *FAT, stream: *dim.BinaryStream) dim.Content.RenderError!void { if (stream.length < min_size) { // TODO(fqu): Report fatal erro! - std.log.err("cannot format {} bytes with {s}: min required size is {}", .{ + std.log.err("cannot format {f} bytes with {s}: min required size is {f}", .{ @as(dim.DiskSize, @enumFromInt(stream.length)), @tagName(self.format_as), @as(dim.DiskSize, @enumFromInt(min_size)), @@ -98,7 +98,7 @@ fn render(self: *FAT, stream: *dim.BinaryStream) dim.Content.RenderError!void { if (stream.length > max_size) { // TODO(fqu): Report warning - std.log.warn("will not use all available space: available space is {}, but maximum size for {s} is {}", .{ + std.log.warn("will not use all available space: available space is {f}, but maximum size for {s} is {f}", .{ @as(dim.DiskSize, @enumFromInt(stream.length)), @tagName(self.format_as), @as(dim.DiskSize, @enumFromInt(min_size)), @@ -147,8 +147,8 @@ fn render(self: *FAT, stream: *dim.BinaryStream) dim.Content.RenderError!void { return error.IoError; } } else { - std.log.err("label \"{}\" is {} characters long, but only up to {} are permitted.", .{ - std.zig.fmtEscapes(label), + std.log.err("label \"{f}\" is {} characters long, but only up to {} are permitted.", .{ + std.zig.fmtString(label), label.len, max_label_len, }); @@ -212,7 +212,7 @@ const AtomicOps = struct { }; } - pub fn mkfile(ops: AtomicOps, path: []const u8, reader: anytype) dim.Content.RenderError!void { + pub fn mkfile(ops: AtomicOps, path: []const u8, reader: *std.Io.Reader) dim.Content.RenderError!void { _ = ops; var path_buffer: [max_path_len:0]u8 = undefined; @@ -244,19 +244,28 @@ const AtomicOps = struct { }; defer fs_file.close(); - var fifo: std.fifo.LinearFifo(u8, .{ .Static = 8192 }) = .init(); - fifo.pump( - reader, - fs_file.writer(), - ) catch |err| switch (@as(dim.FileHandle.ReadError || fatfs.File.ReadError.Error, err)) { - error.Overflow => return error.IoError, - error.ReadFileFailed => return error.IoError, - error.Timeout => @panic("implementation bug in fatfs glue"), - error.DiskErr => return error.IoError, - error.IntErr => return error.IoError, - error.Denied => @panic("implementation bug in fatfs glue"), - error.InvalidObject => @panic("implementation bug in fatfs glue"), - }; + var writer_buf: [8192]u8 = undefined; + var writer = fs_file.writer(&writer_buf); + + _ = reader.streamRemaining(&writer.interface) catch return error.IoError; + + writer.interface.flush() catch return error.IoError; + + // TODO we've lost a lot of error specificity due to the use of the new APIs + // See old code: + + // fifo.pump( + // reader, + // fs_file.writer(), + // ) catch |err| switch (@as(dim.FileHandle.ReadError || fatfs.File.ReadError.Error, err)) { + // error.Overflow => return error.IoError, + // error.ReadFileFailed => return error.IoError, + // error.Timeout => @panic("implementation bug in fatfs glue"), + // error.DiskErr => return error.IoError, + // error.IntErr => return error.IoError, + // error.Denied => @panic("implementation bug in fatfs glue"), + // error.InvalidObject => @panic("implementation bug in fatfs glue"), + // }; } }; diff --git a/src/components/fs/common.zig b/src/components/fs/common.zig index a3421e9..d3cb1e6 100644 --- a/src/components/fs/common.zig +++ b/src/components/fs/common.zig @@ -56,7 +56,9 @@ fn Executor(comptime T: type) type { }; defer handle.close(); - try exec.add_file(data.path, handle.reader()); + var reader_buf: [1024]u8 = undefined; + var reader = handle.reader(&reader_buf); + try exec.add_file(data.path, &reader.interface); }, .copy_dir => |data| { var iter_dir = data.source.open_dir() catch |err| switch (err) { @@ -91,7 +93,10 @@ fn Executor(comptime T: type) type { var file = try fname.open(); defer file.close(); - try exec.add_file(path, file.reader()); + var reader_buf: [1024]u8 = undefined; + var reader = file.reader(&reader_buf); + + try exec.add_file(path, &reader.interface); }, .directory => { @@ -117,14 +122,13 @@ fn Executor(comptime T: type) type { try data.contents.render(&bs); - var fbs: std.io.FixedBufferStream([]u8) = .{ .buffer = buffer, .pos = 0 }; - - try exec.add_file(data.path, fbs.reader()); + var reader = std.Io.Reader.fixed(buffer); + try exec.add_file(data.path, &reader); }, } } - fn add_file(exec: Exec, path: [:0]const u8, reader: anytype) !void { + fn add_file(exec: Exec, path: [:0]const u8, reader: *std.Io.Reader) !void { if (std.fs.path.dirnamePosix(path)) |dir| { try exec.recursive_mkdir(dir); } @@ -143,7 +147,7 @@ fn Executor(comptime T: type) type { try exec.inner_mkdir(path); } - fn inner_mkfile(exec: Exec, path: []const u8, reader: anytype) dim.Content.RenderError!void { + fn inner_mkfile(exec: Exec, path: []const u8, reader: *std.Io.Reader) dim.Content.RenderError!void { try exec.inner.mkfile(path, reader); } @@ -153,24 +157,26 @@ fn Executor(comptime T: type) type { fn walk_err(err: (std.fs.Dir.OpenError || std.mem.Allocator.Error)) dim.Content.RenderError { return switch (err) { - error.InvalidUtf8 => error.InvalidPath, - error.InvalidWtf8 => error.InvalidPath, - error.BadPathName => error.InvalidPath, + error.InvalidUtf8, + error.InvalidWtf8, + error.BadPathName, error.NameTooLong => error.InvalidPath, error.OutOfMemory => error.OutOfMemory, error.FileNotFound => error.FileNotFound, - error.DeviceBusy => error.IoError, - error.AccessDenied => error.IoError, - error.SystemResources => error.IoError, - error.NoDevice => error.IoError, - error.Unexpected => error.IoError, - error.NetworkNotFound => error.IoError, - error.SymLinkLoop => error.IoError, - error.ProcessFdQuotaExceeded => error.IoError, - error.SystemFdQuotaExceeded => error.IoError, - error.NotDir => error.IoError, + error.DeviceBusy, + error.AccessDenied, + error.SystemResources, + error.NoDevice, + error.Unexpected, + error.NetworkNotFound, + error.SymLinkLoop, + error.ProcessFdQuotaExceeded, + error.SystemFdQuotaExceeded, + error.NotDir, + error.ProcessNotFound, + error.PermissionDenied, => error.IoError, }; } }; @@ -185,23 +191,23 @@ fn parse_path(ctx: dim.Context) ![:0]const u8 { } if (!std.mem.startsWith(u8, path, "/")) { - try ctx.report_nonfatal_error("Path '{}' did not start with a \"/\"", .{ - std.zig.fmtEscapes(path), + try ctx.report_nonfatal_error("Path '{f}' did not start with a \"/\"", .{ + std.zig.fmtString(path), }); } for (path) |c| { if (c < 0x20 or c == 0x7F or c == '\\') { - try ctx.report_nonfatal_error("Path '{}' contains invalid character 0x{X:0>2}", .{ - std.zig.fmtEscapes(path), + try ctx.report_nonfatal_error("Path '{f}' contains invalid character 0x{X:0>2}", .{ + std.zig.fmtString(path), c, }); } } _ = std.unicode.Utf8View.init(path) catch |err| { - try ctx.report_nonfatal_error("Path '{}' is not a valid UTF-8 string: {s}", .{ - std.zig.fmtEscapes(path), + try ctx.report_nonfatal_error("Path '{f}' is not a valid UTF-8 string: {s}", .{ + std.zig.fmtString(path), @errorName(err), }); }; @@ -249,8 +255,8 @@ pub fn parse_ops(ctx: dim.Context, end_seq: []const u8, handler: anytype) !void } fn normalize(allocator: std.mem.Allocator, src_path: []const u8) ![:0]const u8 { - var list = std.ArrayList([]const u8).init(allocator); - defer list.deinit(); + var list: std.ArrayList([]const u8) = .empty; + defer list.deinit(allocator); var parts = std.mem.tokenizeAny(u8, src_path, "\\/"); @@ -263,7 +269,7 @@ fn normalize(allocator: std.mem.Allocator, src_path: []const u8) ![:0]const u8 { _ = list.pop(); } else { // this is an actual "descend" - try list.append(part); + try list.append(allocator, part); } } diff --git a/src/components/part/GptPartitionTable.zig b/src/components/part/GptPartitionTable.zig index e85007c..249c40f 100644 --- a/src/components/part/GptPartitionTable.zig +++ b/src/components/part/GptPartitionTable.zig @@ -17,7 +17,9 @@ pub fn parse(ctx: dim.Context) !dim.Content { .partitions = undefined, }; - var partitions = std.ArrayList(Partition).init(ctx.get_arena()); + const allocator = ctx.get_arena(); + + var partitions: std.ArrayList(Partition) = .empty; loop: while (true) { const kw = try ctx.parse_enum(enum { guid, @@ -34,7 +36,7 @@ pub fn parse(ctx: dim.Context) !dim.Content { pt.disk_id = Guid.parse(guid_str[0..36].*) catch |err| return ctx.report_fatal_error("Invalid disk GUID: {}", .{err}); }, - .part => (try partitions.addOne()).* = try parsePartition(ctx), + .part => (try partitions.addOne(allocator)).* = try parsePartition(ctx), .@"legacy-bootable" => pt.legacy_bootable = true, .endgpt => break :loop, } @@ -113,7 +115,7 @@ fn parsePartition(ctx: dim.Context) !Partition { const type_guid = known_types.get(type_name) orelse blk: { if (type_name.len == 36) if (Guid.parse(type_name[0..36].*)) |guid| break :blk guid else |_| {}; - return ctx.report_fatal_error("unknown partition type: `{}`", .{std.zig.fmtEscapes(type_name)}); + return ctx.report_fatal_error("unknown partition type: `{f}`", .{std.zig.fmtString(type_name)}); }; try updater.set(.type, type_guid); @@ -167,7 +169,7 @@ pub fn render(table: *PartTable, stream: *dim.BinaryStream) dim.Content.RenderEr for (table.partitions[0..], 0..) |partition, i| { @memset(&pe_block, 0); - const offset = partition.offset orelse 33 * block_size; + const offset = partition.offset orelse 34 * block_size; const size = partition.size orelse if (i == table.partitions.len - 1) ((max_partition_lba + 1) * block_size) - offset else diff --git a/src/components/part/MbrPartitionTable.zig b/src/components/part/MbrPartitionTable.zig index 66ceca8..9d21b69 100644 --- a/src/components/part/MbrPartitionTable.zig +++ b/src/components/part/MbrPartitionTable.zig @@ -115,7 +115,7 @@ fn parse_partition(ctx: dim.Context) !Partition { value else |_| known_partition_types.get(part_name) orelse blk: { - try ctx.report_nonfatal_error("unknown partition type '{}'", .{std.zig.fmtEscapes(part_name)}); + try ctx.report_nonfatal_error("unknown partition type '{f}'", .{std.zig.fmtString(part_name)}); break :blk 0x00; }; diff --git a/src/dim.zig b/src/dim.zig index 01438d8..fe3ae8a 100644 --- a/src/dim.zig +++ b/src/dim.zig @@ -89,8 +89,8 @@ pub fn main() !u8 { const val = pos[idx + 1 ..]; try var_map.put(gpa, key, val); } else { - std.debug.print("unexpected argument positional '{}'\n", .{ - std.zig.fmtEscapes(pos), + std.debug.print("unexpected argument positional '{f}'\n", .{ + std.zig.fmtString(pos), }); bad_args = true; } @@ -106,13 +106,17 @@ pub fn main() !u8 { var current_dir = try std.fs.cwd().openDir(".", .{}); defer current_dir.close(); - const script_source = try current_dir.readFileAlloc(gpa, script_path, max_script_size); + const script_source = try current_dir.readFileAlloc(script_path, gpa, .limited(max_script_size)); defer gpa.free(script_source); if (options.@"deps-file") |deps_file_path| { global_deps_file = try std.fs.cwd().createFile(deps_file_path, .{}); - try global_deps_file.?.writer().print( + var writer = global_deps_file.?.writerStreaming(&.{}); + // TODO would it be better to store the writer and just reuse it? that way we can utilise + // buffering and not have the risk of someone positional writes and breaking things. + + try writer.interface.print( \\{s}: {s} , .{ output_path, @@ -252,7 +256,7 @@ pub const Context = struct { ); if (converted) |ok| return ok; - std.debug.print("detected invalid enum tag for {s}: \"{}\"\n", .{ @typeName(E), std.zig.fmtEscapes(tag_name) }); + std.debug.print("detected invalid enum tag for {s}: \"{f}\"\n", .{ @typeName(E), std.zig.fmtString(tag_name) }); std.debug.print("valid options are:\n", .{}); for (std.enums.values(E)) |val| { @@ -293,8 +297,8 @@ pub const Context = struct { } } - return ctx.report_fatal_error("unknown content type: '{}'", .{ - std.zig.fmtEscapes(content_type_str), + return ctx.report_fatal_error("unknown content type: '{f}'", .{ + std.zig.fmtString(content_type_str), }); } }; @@ -383,14 +387,14 @@ const Environment = struct { fn fetch_file(io: *const Parser.IO, allocator: std.mem.Allocator, path: []const u8) error{ FileNotFound, IoError, OutOfMemory, InvalidPath }![]const u8 { const env: *const Environment = @fieldParentPtr("io", io); - const contents = env.include_base.readFileAlloc(allocator, path, max_script_size) catch |err| switch (err) { + const contents = env.include_base.readFileAlloc(path, allocator, .limited(max_script_size)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.FileNotFound => { const ctx = Context{ .env = @constCast(env) }; var buffer: [std.fs.max_path_bytes]u8 = undefined; - try ctx.report_nonfatal_error("failed to open file: \"{}/{}\"", .{ - std.zig.fmtEscapes(env.include_base.realpath(".", &buffer) catch return error.FileNotFound), - std.zig.fmtEscapes(path), + try ctx.report_nonfatal_error("failed to open file: \"{f}/{f}\"", .{ + std.zig.fmtString(env.include_base.realpath(".", &buffer) catch return error.FileNotFound), + std.zig.fmtString(path), }); return error.FileNotFound; }, @@ -470,9 +474,9 @@ pub const FileName = struct { const file = name.root_dir.openFile(name.rel_path, .{}) catch |err| switch (err) { error.FileNotFound => { var buffer: [std.fs.max_path_bytes]u8 = undefined; - std.log.err("failed to open \"{}/{}\": not found", .{ - std.zig.fmtEscapes(name.root_dir.realpath(".", &buffer) catch |e| @errorName(e)), - std.zig.fmtEscapes(name.rel_path), + std.log.err("failed to open \"{f}/{f}\": not found", .{ + std.zig.fmtString(name.root_dir.realpath(".", &buffer) catch |e| @errorName(e)), + std.zig.fmtString(name.rel_path), }); return error.FileNotFound; }, @@ -503,6 +507,8 @@ pub const FileName = struct { error.NotDir, error.FileLocksNotSupported, error.FileBusy, + error.ProcessNotFound, + error.PermissionDenied, => return error.IoError, }; @@ -515,9 +521,9 @@ pub const FileName = struct { const dir = name.root_dir.openDir(name.rel_path, .{ .iterate = true }) catch |err| switch (err) { error.FileNotFound => { var buffer: [std.fs.max_path_bytes]u8 = undefined; - std.log.err("failed to open \"{}/{}\": not found", .{ - std.zig.fmtEscapes(name.root_dir.realpath(".", &buffer) catch |e| @errorName(e)), - std.zig.fmtEscapes(name.rel_path), + std.log.err("failed to open \"{f}/{f}\": not found", .{ + std.zig.fmtString(name.root_dir.realpath(".", &buffer) catch |e| @errorName(e)), + std.zig.fmtString(name.rel_path), }); return error.FileNotFound; }, @@ -538,6 +544,8 @@ pub const FileName = struct { error.ProcessFdQuotaExceeded, error.SystemFdQuotaExceeded, error.NotDir, + error.ProcessNotFound, + error.PermissionDenied, => return error.IoError, }; @@ -597,19 +605,20 @@ pub const FileName = struct { var handle = try file.open(); defer handle.close(); - var fifo: std.fifo.LinearFifo(u8, .{ .Static = 8192 }) = .init(); + var reader_buf: [8192]u8 = undefined; + var reader = handle.reader(&reader_buf); - try fifo.pump( - handle.reader(), - stream.writer(), - ); + var writer = stream.writer(); + + _ = writer.interface.sendFileAll(&reader, .unlimited) catch |e| return switch (e) { + error.WriteFailed => error.IoError, // TODO this isn't great + else => |err| err, + }; } }; pub const FileHandle = struct { - pub const ReadError = error{ReadFileFailed}; - - pub const Reader = std.io.Reader(std.fs.File, ReadError, read_some); + pub const ReadError = std.Io.Reader.Error; file: std.fs.File, @@ -618,36 +627,15 @@ pub const FileHandle = struct { fd.* = undefined; } - pub fn reader(fd: FileHandle) Reader { - return .{ .context = fd.file }; - } - - fn read_some(file: std.fs.File, data: []u8) ReadError!usize { - return file.read(data) catch |err| switch (err) { - error.InputOutput, - error.AccessDenied, - error.BrokenPipe, - error.SystemResources, - error.OperationAborted, - error.LockViolation, - error.WouldBlock, - error.ConnectionResetByPeer, - error.ProcessNotFound, - error.Unexpected, - error.IsDir, - error.ConnectionTimedOut, - error.NotOpenForReading, - error.SocketNotConnected, - error.Canceled, - => return error.ReadFileFailed, - }; + pub fn reader(fd: FileHandle, buf: []u8) std.fs.File.Reader { + return fd.file.reader(buf); } }; pub const BinaryStream = struct { pub const WriteError = error{ Overflow, IoError }; + pub const WriterError = std.Io.Writer.Error; pub const ReadError = error{ Overflow, IoError }; - pub const Writer = std.io.Writer(*BinaryStream, WriteError, write_some); backing: Backing, @@ -707,26 +695,9 @@ pub const BinaryStream = struct { switch (bs.backing) { .buffer => |ptr| @memcpy(data, ptr[@intCast(offset)..][0..data.len]), .file => |state| { - state.file.seekTo(state.base + offset) catch return error.IoError; - state.file.reader().readNoEof(data) catch |err| switch (err) { - error.InputOutput, - error.AccessDenied, - error.BrokenPipe, - error.SystemResources, - error.OperationAborted, - error.LockViolation, - error.WouldBlock, - error.ConnectionResetByPeer, - error.ProcessNotFound, - error.Unexpected, - error.IsDir, - error.ConnectionTimedOut, - error.NotOpenForReading, - error.SocketNotConnected, - error.Canceled, - error.EndOfStream, - => return error.IoError, - }; + var reader = state.file.reader(&.{}); + reader.seekTo(state.base + offset) catch return error.IoError; + reader.interface.readSliceAll(data) catch return error.IoError; }, } } @@ -757,6 +728,8 @@ pub const BinaryStream = struct { error.ProcessNotFound, error.NoDevice, error.Unexpected, + error.PermissionDenied, + error.MessageTooBig, => return error.IoError, }; }, @@ -770,15 +743,48 @@ pub const BinaryStream = struct { } pub fn writer(bs: *BinaryStream) Writer { - return .{ .context = bs }; + return .{ + .interface = .{ + .vtable = &.{ + .drain = Writer.drain, + }, + .buffer = &.{}, + }, + .stream = bs, + }; } - fn write_some(stream: *BinaryStream, data: []const u8) WriteError!usize { + pub const Writer = struct { + interface: std.Io.Writer, + stream: *BinaryStream, + + pub fn drain(io_w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize { + const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w)); + + var written: usize = 0; + + for (data[0..data.len - 1]) |bytes| { + written += try w.stream.write_some(bytes); + } + + const pattern = data[data.len - 1]; + switch (pattern.len) { + 0 => {}, + else => for (0..splat) |_| { + written += try w.stream.write_some(pattern); + }, + } + + return written; + } + }; + + fn write_some(stream: *BinaryStream, data: []const u8) std.Io.Writer.Error!usize { const remaining_len = stream.length - stream.virtual_offset; const written_len: usize = @intCast(@min(remaining_len, data.len)); - try stream.write(stream.virtual_offset, data[0..written_len]); + stream.write(stream.virtual_offset, data[0..written_len]) catch return error.WriteFailed; stream.virtual_offset += written_len; return written_len; @@ -838,10 +844,7 @@ pub const DiskSize = enum(u64) { return @intFromEnum(ds); } - pub fn format(ds: DiskSize, fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void { - _ = fmt; - _ = opt; - + pub fn format(ds: DiskSize, writer: *std.Io.Writer) std.Io.Writer.Error!void { const size = ds.size_in_bytes(); const div: u64, const unit: []const u8 = if (size > GiB) @@ -861,7 +864,7 @@ pub const DiskSize = enum(u64) { const scaled_value = (1000 * size) / div; var buf: [std.math.log2_int_ceil(u64, std.math.maxInt(u64))]u8 = undefined; - const divided = try std.fmt.bufPrint(&buf, "{d}", .{scaled_value}); + const divided = std.fmt.bufPrint(&buf, "{d}", .{scaled_value}) catch return error.WriteFailed; std.debug.assert(divided.len >= 3); From 963c018a6d4e760377288adf65943250ee82779b Mon Sep 17 00:00:00 2001 From: bnuuydev Date: Sun, 19 Oct 2025 19:22:29 +0100 Subject: [PATCH 2/6] fix build interface we set the cwd of dimmer to the script directory such that the run step passes the correct relative paths. this caused weirdness in zig's dependency file handling - zig expects relative paths to be relative to the project root instead of the cwd of the run step. changing paths to be absolute is a suitable workaround. --- src/BuildInterface.zig | 2 ++ src/Parser.zig | 10 ++++------ src/dim.zig | 14 +++++++++++--- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/BuildInterface.zig b/src/BuildInterface.zig index 10d559d..421f2d3 100644 --- a/src/BuildInterface.zig +++ b/src/BuildInterface.zig @@ -32,6 +32,8 @@ pub fn createDisk(dimmer: Interface, size: u64, content: Content) std.Build.Lazy const compile_script = b.addRunArtifact(dimmer.dimmer_exe); + compile_script.setCwd(script_file.dirname()); + _ = compile_script.addPrefixedDepFileOutputArg("--deps-file=", "image.d"); compile_script.addArg(b.fmt("--size={d}", .{size})); diff --git a/src/Parser.zig b/src/Parser.zig index 64609b7..98720e8 100644 --- a/src/Parser.zig +++ b/src/Parser.zig @@ -103,12 +103,10 @@ pub fn get_include_path(parser: Parser, allocator: std.mem.Allocator, rel_includ if (parser.file_stack.len == parser.max_include_depth) return error.MaxIncludeDepthReached; - // const top_path = if (parser.file_stack.len > 0) - // parser.file_stack[parser.file_stack.len - 1].path - // else - // ""; - - const top_path = ""; // TODO what the fuck, the actual issue here needs to be triaged. this workaround fixes things for me for now though. + const top_path = if (parser.file_stack.len > 0) + parser.file_stack[parser.file_stack.len - 1].path + else + ""; const abs_include_path = try std.fs.path.resolvePosix( allocator, diff --git a/src/dim.zig b/src/dim.zig index fe3ae8a..6a36878 100644 --- a/src/dim.zig +++ b/src/dim.zig @@ -116,11 +116,19 @@ pub fn main() !u8 { // TODO would it be better to store the writer and just reuse it? that way we can utilise // buffering and not have the risk of someone positional writes and breaking things. + // TODO Zig has a bug in dependency file handling: relative paths are taken not to the run + // step cwd, but to the project root. hence, we need to absolute paths until this is fixed. + var buf_output: [std.fs.max_path_bytes]u8 = undefined; + const output_path_abs = try std.fs.cwd().realpath(std.fs.path.dirname(output_path) orelse ".", &buf_output); + var buf_script: [std.fs.max_path_bytes]u8 = undefined; + const script_path_abs = try std.fs.cwd().realpath(script_path, &buf_script); + try writer.interface.print( - \\{s}: {s} + \\{s}/{s}: {s} , .{ - output_path, - script_path, + output_path_abs, + std.fs.path.basename(output_path), + script_path_abs, }); } defer if (global_deps_file) |deps_file| From 6c20cf715a033121933a49c7892dba70b19481eb Mon Sep 17 00:00:00 2001 From: Khitiara Date: Sat, 27 Dec 2025 20:37:55 -0500 Subject: [PATCH 3/6] Compiles on december zig master, untested --- build.zig.zon | 5 +- src/Parser.zig | 7 +-- src/components/EmptyData.zig | 3 +- src/components/FillData.zig | 3 +- src/components/PasteFile.zig | 4 +- src/components/fs/FatFileSystem.zig | 15 +++--- src/components/fs/common.zig | 21 ++++---- src/components/part/GptPartitionTable.zig | 6 +-- src/components/part/MbrPartitionTable.zig | 6 +-- src/dim.zig | 63 ++++++++++++----------- 10 files changed, 71 insertions(+), 62 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 56e0973..28f39bb 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -4,8 +4,9 @@ .fingerprint = 0x9947018c924eecb2, .dependencies = .{ .zfat = .{ - .url = "https://github.com/CascadeOS/zfat/archive/refs/heads/0.15.zip", - .hash = "zfat-0.16.0-SNNK9fKtTgASssfmCblZwRMLU4pndVtwxTNhYCegBOyA", + // .url = "git+https://github.com/CascadeOS/zfat#2806bfd983dd810c9c74b0ea6a63f783208518b5", + // .hash = "zfat-0.16.0-SNNK9fKtTgASssfmCblZwRMLU4pndVtwxTNhYCegBOyA", + .path = "../zfat" }, .args = .{ .url = "git+https://github.com/ikskuh/zig-args.git#8ae26b44a884ff20dca98ee84c098e8f8e94902f", diff --git a/src/Parser.zig b/src/Parser.zig index 98720e8..734333f 100644 --- a/src/Parser.zig +++ b/src/Parser.zig @@ -18,13 +18,14 @@ pub const Error = Tokenizer.Error || error{ UnknownDirective, OutOfMemory, InvalidEscapeSequence, + Canceled, }; pub const IO = struct { - fetch_file_fn: *const fn (io: *const IO, std.mem.Allocator, path: []const u8) error{ FileNotFound, IoError, OutOfMemory, InvalidPath }![]const u8, + fetch_file_fn: *const fn (io: *const IO, std.mem.Allocator, path: []const u8) error{ FileNotFound, IoError, OutOfMemory, InvalidPath, Canceled }![]const u8, resolve_variable_fn: *const fn (io: *const IO, name: []const u8) error{UnknownVariable}![]const u8, - pub fn fetch_file(io: *const IO, allocator: std.mem.Allocator, path: []const u8) error{ FileNotFound, IoError, OutOfMemory, InvalidPath }![]const u8 { + pub fn fetch_file(io: *const IO, allocator: std.mem.Allocator, path: []const u8) error{ FileNotFound, IoError, OutOfMemory, InvalidPath, Canceled }![]const u8 { return io.fetch_file_fn(io, allocator, path); } @@ -106,7 +107,7 @@ pub fn get_include_path(parser: Parser, allocator: std.mem.Allocator, rel_includ const top_path = if (parser.file_stack.len > 0) parser.file_stack[parser.file_stack.len - 1].path else - ""; + ""; const abs_include_path = try std.fs.path.resolvePosix( allocator, diff --git a/src/components/EmptyData.zig b/src/components/EmptyData.zig index da335f0..c5ef15a 100644 --- a/src/components/EmptyData.zig +++ b/src/components/EmptyData.zig @@ -15,7 +15,8 @@ pub fn parse(ctx: dim.Context) !dim.Content { })); } -fn render(self: *EmptyData, stream: *dim.BinaryStream) dim.Content.RenderError!void { +fn render(self: *EmptyData, io: std.Io, stream: *dim.BinaryStream) dim.Content.RenderError!void { _ = self; _ = stream; + _ = io; } diff --git a/src/components/FillData.zig b/src/components/FillData.zig index e5f0458..a087cd7 100644 --- a/src/components/FillData.zig +++ b/src/components/FillData.zig @@ -19,7 +19,8 @@ pub fn parse(ctx: dim.Context) !dim.Content { })); } -fn render(self: *FillData, stream: *dim.BinaryStream) dim.Content.RenderError!void { +fn render(self: *FillData, io: std.Io, stream: *dim.BinaryStream) dim.Content.RenderError!void { + _ = io; var writer = stream.writer(); writer.interface.splatByteAll( self.fill_value, diff --git a/src/components/PasteFile.zig b/src/components/PasteFile.zig index 3cbd9e7..80e8b68 100644 --- a/src/components/PasteFile.zig +++ b/src/components/PasteFile.zig @@ -15,6 +15,6 @@ pub fn parse(ctx: dim.Context) !dim.Content { })); } -fn render(self: *PasteFile, stream: *dim.BinaryStream) dim.Content.RenderError!void { - try self.file_handle.copy_to(stream); +fn render(self: *PasteFile, io: std.Io, stream: *dim.BinaryStream) dim.Content.RenderError!void { + try self.file_handle.copy_to(io, stream); } diff --git a/src/components/fs/FatFileSystem.zig b/src/components/fs/FatFileSystem.zig index 872b1d7..cbff252 100644 --- a/src/components/fs/FatFileSystem.zig +++ b/src/components/fs/FatFileSystem.zig @@ -81,7 +81,8 @@ const Appender = struct { } }; -fn render(self: *FAT, stream: *dim.BinaryStream) dim.Content.RenderError!void { +fn render(self: *FAT, io: std.Io, stream: *dim.BinaryStream) dim.Content.RenderError!void { + fatfs.io = io; var bsd: BinaryStreamDisk = .{ .stream = stream }; const min_size, const max_size = self.format_as.get_size_limits(); @@ -158,7 +159,7 @@ fn render(self: *FAT, stream: *dim.BinaryStream) dim.Content.RenderError!void { const wrapper = AtomicOps{}; for (ops) |op| { - try op.execute(wrapper); + try op.execute(io, wrapper); } } @@ -292,19 +293,21 @@ const BinaryStreamDisk = struct { return disk_getStatus(intf); } - fn disk_read(intf: *fatfs.Disk, buff: [*]u8, sector: fatfs.LBA, count: c_uint) fatfs.Disk.Error!void { + fn disk_read(intf: *fatfs.Disk, io: std.Io, buff: [*]u8, sector: fatfs.LBA, count: c_uint) fatfs.Disk.Error!void { const bsd: *BinaryStreamDisk = @fieldParentPtr("disk", intf); - bsd.stream.read(block_size * sector, buff[0 .. count * block_size]) catch return error.IoError; + bsd.stream.read(io, block_size * sector, buff[0 .. count * block_size]) catch return error.IoError; } - fn disk_write(intf: *fatfs.Disk, buff: [*]const u8, sector: fatfs.LBA, count: c_uint) fatfs.Disk.Error!void { + fn disk_write(intf: *fatfs.Disk, io: std.Io, buff: [*]const u8, sector: fatfs.LBA, count: c_uint) fatfs.Disk.Error!void { + _ = io; const bsd: *BinaryStreamDisk = @fieldParentPtr("disk", intf); bsd.stream.write(block_size * sector, buff[0 .. count * block_size]) catch return error.IoError; } - fn disk_ioctl(intf: *fatfs.Disk, cmd: fatfs.IoCtl, buff: [*]u8) fatfs.Disk.Error!void { + fn disk_ioctl(intf: *fatfs.Disk, io: std.Io, cmd: fatfs.IoCtl, buff: [*]u8) fatfs.Disk.Error!void { + _ = io; const bsd: *BinaryStreamDisk = @fieldParentPtr("disk", intf); switch (cmd) { diff --git a/src/components/fs/common.zig b/src/components/fs/common.zig index d3cb1e6..19f8e62 100644 --- a/src/components/fs/common.zig +++ b/src/components/fs/common.zig @@ -26,10 +26,10 @@ pub const FsOperation = union(enum) { contents: dim.Content, }, - pub fn execute(op: FsOperation, executor: anytype) !void { + pub fn execute(op: FsOperation, io: std.Io, executor: anytype) !void { const exec: Executor(@TypeOf(executor)) = .init(executor); - try exec.execute(op); + try exec.execute(io, op); } }; @@ -43,7 +43,7 @@ fn Executor(comptime T: type) type { return .{ .inner = wrapped }; } - fn execute(exec: Exec, op: FsOperation) dim.Content.RenderError!void { + fn execute(exec: Exec, io: std.Io, op: FsOperation) dim.Content.RenderError!void { switch (op) { .make_dir => |data| { try exec.recursive_mkdir(data.path); @@ -54,10 +54,10 @@ fn Executor(comptime T: type) type { error.FileNotFound => return, // open() already reporeted the error else => |e| return e, }; - defer handle.close(); + defer handle.close(io); var reader_buf: [1024]u8 = undefined; - var reader = handle.reader(&reader_buf); + var reader = handle.reader(io, &reader_buf); try exec.add_file(data.path, &reader.interface); }, .copy_dir => |data| { @@ -91,10 +91,10 @@ fn Executor(comptime T: type) type { }; var file = try fname.open(); - defer file.close(); + defer file.close(io); var reader_buf: [1024]u8 = undefined; - var reader = file.reader(&reader_buf); + var reader = file.reader(io, &reader_buf); try exec.add_file(path, &reader.interface); }, @@ -120,7 +120,7 @@ fn Executor(comptime T: type) type { var bs: dim.BinaryStream = .init_buffer(buffer); - try data.contents.render(&bs); + try data.contents.render(io, &bs); var reader = std.Io.Reader.fixed(buffer); try exec.add_file(data.path, &reader); @@ -157,14 +157,14 @@ fn Executor(comptime T: type) type { fn walk_err(err: (std.fs.Dir.OpenError || std.mem.Allocator.Error)) dim.Content.RenderError { return switch (err) { - error.InvalidUtf8, - error.InvalidWtf8, error.BadPathName, error.NameTooLong => error.InvalidPath, error.OutOfMemory => error.OutOfMemory, error.FileNotFound => error.FileNotFound, + error.Canceled => error.Canceled, + error.DeviceBusy, error.AccessDenied, error.SystemResources, @@ -175,7 +175,6 @@ fn Executor(comptime T: type) type { error.ProcessFdQuotaExceeded, error.SystemFdQuotaExceeded, error.NotDir, - error.ProcessNotFound, error.PermissionDenied, => error.IoError, }; } diff --git a/src/components/part/GptPartitionTable.zig b/src/components/part/GptPartitionTable.zig index 249c40f..7671e1c 100644 --- a/src/components/part/GptPartitionTable.zig +++ b/src/components/part/GptPartitionTable.zig @@ -147,7 +147,7 @@ fn parsePartition(ctx: dim.Context) !Partition { return part; } -pub fn render(table: *PartTable, stream: *dim.BinaryStream) dim.Content.RenderError!void { +pub fn render(table: *PartTable, io: std.Io, stream: *dim.BinaryStream) dim.Content.RenderError!void { const random = std.crypto.random; const lba_len = stream.length / block_size; @@ -210,7 +210,7 @@ pub fn render(table: *PartTable, stream: *dim.BinaryStream) dim.Content.RenderEr try stream.write(block_size * secondary_pe_array_lba + pe_ofs, &pe_block); var sub_view = try stream.slice(offset, size); - try partition.contains.render(&sub_view); + try partition.contains.render(io, &sub_view); pe_ofs += 0x80; } @@ -272,7 +272,7 @@ pub fn render(table: *PartTable, stream: *dim.BinaryStream) dim.Content.RenderEr std.mem.writeInt(u32, backup_gpt_header[0x10..0x14], backup_gpt_header_crc32, .little); // CRC32 of backup header // write everything we generated to disk - try mbr.render(stream); + try mbr.render(io, stream); try stream.write(block_size, &gpt_header_block); try stream.write(block_size * secondary_pth_lba, &backup_gpt_header_block); } diff --git a/src/components/part/MbrPartitionTable.zig b/src/components/part/MbrPartitionTable.zig index 9d21b69..a9bc6d9 100644 --- a/src/components/part/MbrPartitionTable.zig +++ b/src/components/part/MbrPartitionTable.zig @@ -134,7 +134,7 @@ fn parse_partition(ctx: dim.Context) !Partition { return part; } -pub fn render(table: *PartTable, stream: *dim.BinaryStream) dim.Content.RenderError!void { +pub fn render(table: *PartTable, io: std.Io, stream: *dim.BinaryStream) dim.Content.RenderError!void { const last_part_id = blk: { var last: usize = 0; for (table.partitions, 0..) |p, i| { @@ -158,7 +158,7 @@ pub fn render(table: *PartTable, stream: *dim.BinaryStream) dim.Content.RenderEr if (table.bootloader) |bootloader| { var sector: dim.BinaryStream = .init_buffer(&boot_sector); - try bootloader.render(§or); + try bootloader.render(io, §or); const upper_limit: u64 = if (table.disk_id != null) 0x01B8 @@ -244,7 +244,7 @@ pub fn render(table: *PartTable, stream: *dim.BinaryStream) dim.Content.RenderEr var sub_view = try stream.slice(info.offset, info.size); - try part.contains.render(&sub_view); + try part.contains.render(io, &sub_view); } } diff --git a/src/dim.zig b/src/dim.zig index 6a36878..dc009b8 100644 --- a/src/dim.zig +++ b/src/dim.zig @@ -61,6 +61,8 @@ pub fn main() !u8 { const gpa = gpa_impl.allocator(); + var io: std.Io.Threaded = .init(gpa); + const opts = try args.parseForCurrentProcess(Options, gpa, .print); defer opts.deinit(); @@ -179,7 +181,7 @@ pub fn main() !u8 { var stream: BinaryStream = .init_file(output_file, size_limit); - try root_content.render(&stream); + try root_content.render(io.io(), &stream); } if (global_deps_file) |deps_file| { @@ -392,7 +394,7 @@ const Environment = struct { std.log.err("PARSE ERROR: " ++ fmt, params); } - fn fetch_file(io: *const Parser.IO, allocator: std.mem.Allocator, path: []const u8) error{ FileNotFound, IoError, OutOfMemory, InvalidPath }![]const u8 { + fn fetch_file(io: *const Parser.IO, allocator: std.mem.Allocator, path: []const u8) error{ FileNotFound, IoError, OutOfMemory, InvalidPath, Canceled }![]const u8 { const env: *const Environment = @fieldParentPtr("io", io); const contents = env.include_base.readFileAlloc(path, allocator, .limited(max_script_size)) catch |err| switch (err) { @@ -431,6 +433,7 @@ pub const Content = struct { ConfigurationError, OutOfBounds, OutOfMemory, + Canceled, }; pub const GuessError = FileName.GetSizeError; @@ -444,23 +447,24 @@ pub const Content = struct { } /// Emits the content into a binary stream. - pub fn render(content: Content, stream: *BinaryStream) RenderError!void { - try content.vtable.render_fn(content.obj, stream); + pub fn render(content: Content, io: std.Io, stream: *BinaryStream) RenderError!void { + try content.vtable.render_fn(content.obj, io, stream); } pub const VTable = struct { - render_fn: *const fn (*anyopaque, *BinaryStream) RenderError!void, + render_fn: *const fn (*anyopaque, std.Io, *BinaryStream) RenderError!void, pub fn create( comptime Container: type, comptime funcs: struct { - render_fn: *const fn (*Container, *BinaryStream) RenderError!void, + render_fn: *const fn (*Container, std.Io, *BinaryStream) RenderError!void, }, ) *const VTable { const Wrap = struct { - fn render(self: *anyopaque, stream: *BinaryStream) RenderError!void { + fn render(self: *anyopaque, io: std.Io, stream: *BinaryStream) RenderError!void { return funcs.render_fn( @ptrCast(@alignCast(self)), + io, stream, ); } @@ -476,7 +480,7 @@ pub const FileName = struct { root_dir: std.fs.Dir, rel_path: []const u8, - pub const OpenError = error{ FileNotFound, InvalidPath, IoError }; + pub const OpenError = error{ FileNotFound, InvalidPath, IoError, Canceled }; pub fn open(name: FileName) OpenError!FileHandle { const file = name.root_dir.openFile(name.rel_path, .{}) catch |err| switch (err) { @@ -489,10 +493,10 @@ pub const FileName = struct { return error.FileNotFound; }, + error.Canceled => return error.Canceled, + error.NameTooLong, - error.InvalidWtf8, error.BadPathName, - error.InvalidUtf8, => return error.InvalidPath, error.NoSpaceLeft, @@ -536,10 +540,10 @@ pub const FileName = struct { return error.FileNotFound; }, + error.Canceled => return error.Canceled, + error.NameTooLong, - error.InvalidWtf8, error.BadPathName, - error.InvalidUtf8, => return error.InvalidPath, error.DeviceBusy, @@ -552,7 +556,6 @@ pub const FileName = struct { error.ProcessFdQuotaExceeded, error.SystemFdQuotaExceeded, error.NotDir, - error.ProcessNotFound, error.PermissionDenied, => return error.IoError, }; @@ -578,9 +581,7 @@ pub const FileName = struct { error.FileNotFound => return error.FileNotFound, error.NameTooLong, - error.InvalidWtf8, error.BadPathName, - error.InvalidUtf8, => return error.InvalidPath, error.NoSpaceLeft, @@ -609,12 +610,12 @@ pub const FileName = struct { return stat.size; } - pub fn copy_to(file: FileName, stream: *BinaryStream) (OpenError || FileHandle.ReadError || BinaryStream.WriteError)!void { + pub fn copy_to(file: FileName, io: std.Io, stream: *BinaryStream) (OpenError || FileHandle.ReadError || BinaryStream.WriteError)!void { var handle = try file.open(); - defer handle.close(); + defer handle.close(io); var reader_buf: [8192]u8 = undefined; - var reader = handle.reader(&reader_buf); + var reader = handle.reader(io, &reader_buf); var writer = stream.writer(); @@ -630,20 +631,21 @@ pub const FileHandle = struct { file: std.fs.File, - pub fn close(fd: *FileHandle) void { + pub fn close(fd: *FileHandle, io: std.Io) void { + _ = io; fd.file.close(); fd.* = undefined; } - pub fn reader(fd: FileHandle, buf: []u8) std.fs.File.Reader { - return fd.file.reader(buf); + pub fn reader(fd: FileHandle, io: std.Io, buf: []u8) std.fs.File.Reader { + return fd.file.reader(io, buf); } }; pub const BinaryStream = struct { - pub const WriteError = error{ Overflow, IoError }; + pub const WriteError = error{ Overflow, IoError, Canceled }; pub const WriterError = std.Io.Writer.Error; - pub const ReadError = error{ Overflow, IoError }; + pub const ReadError = error{ Overflow, IoError, Canceled }; backing: Backing, @@ -695,7 +697,7 @@ pub const BinaryStream = struct { }; } - pub fn read(bs: *BinaryStream, offset: u64, data: []u8) ReadError!void { + pub fn read(bs: *BinaryStream, io: std.Io, offset: u64, data: []u8) ReadError!void { const end_pos = offset + data.len; if (end_pos > bs.length) return error.Overflow; @@ -703,7 +705,7 @@ pub const BinaryStream = struct { switch (bs.backing) { .buffer => |ptr| @memcpy(data, ptr[@intCast(offset)..][0..data.len]), .file => |state| { - var reader = state.file.reader(&.{}); + var reader = state.file.reader(io, &.{}); reader.seekTo(state.base + offset) catch return error.IoError; reader.interface.readSliceAll(data) catch return error.IoError; }, @@ -722,13 +724,14 @@ pub const BinaryStream = struct { state.file.writeAll(data) catch |err| switch (err) { error.DiskQuota, error.NoSpaceLeft, error.FileTooBig => return error.Overflow, + error.Canceled => return error.Canceled, + error.InputOutput, error.DeviceBusy, error.InvalidArgument, error.AccessDenied, error.BrokenPipe, error.SystemResources, - error.OperationAborted, error.NotOpenForWriting, error.LockViolation, error.WouldBlock, @@ -737,7 +740,7 @@ pub const BinaryStream = struct { error.NoDevice, error.Unexpected, error.PermissionDenied, - error.MessageTooBig, + error.MessageOversize, => return error.IoError, }; }, @@ -765,13 +768,13 @@ pub const BinaryStream = struct { pub const Writer = struct { interface: std.Io.Writer, stream: *BinaryStream, - + pub fn drain(io_w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize { const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w)); var written: usize = 0; - for (data[0..data.len - 1]) |bytes| { + for (data[0 .. data.len - 1]) |bytes| { written += try w.stream.write_some(bytes); } @@ -878,7 +881,7 @@ pub const DiskSize = enum(u64) { const prefix, const suffix = .{ divided[0 .. divided.len - 3], - std.mem.trimRight(u8, divided[divided.len - 3 ..], "0"), + std.mem.trimEnd(u8, divided[divided.len - 3 ..], "0"), }; if (suffix.len > 0) { From 6dc9d3382807bdc34fbbf879a10e347149c20666 Mon Sep 17 00:00:00 2001 From: Khitiara Date: Thu, 8 Jan 2026 12:52:50 -0500 Subject: [PATCH 4/6] Now works on 12/28 master --- build.zig.zon | 9 +- src/Parser.zig | 32 ++-- src/components/EmptyData.zig | 3 +- src/components/FillData.zig | 7 +- src/components/PasteFile.zig | 4 +- src/components/fs/FatFileSystem.zig | 21 ++- src/components/fs/common.zig | 48 +++--- src/components/part/GptPartitionTable.zig | 36 ++--- src/components/part/MbrPartitionTable.zig | 22 +-- src/dim.zig | 177 ++++++++++------------ 10 files changed, 172 insertions(+), 187 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 28f39bb..0a7f9fe 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -6,13 +6,14 @@ .zfat = .{ // .url = "git+https://github.com/CascadeOS/zfat#2806bfd983dd810c9c74b0ea6a63f783208518b5", // .hash = "zfat-0.16.0-SNNK9fKtTgASssfmCblZwRMLU4pndVtwxTNhYCegBOyA", - .path = "../zfat" + .path = "../zfat", }, .args = .{ - .url = "git+https://github.com/ikskuh/zig-args.git#8ae26b44a884ff20dca98ee84c098e8f8e94902f", - .hash = "args-0.0.0-CiLiqojRAACGzDRO7A9dw7kWSchNk29caJZkXuMCb0Cn", + .path = "../zig-args", + // .url = "git+https://github.com/ikskuh/zig-args.git#8ae26b44a884ff20dca98ee84c098e8f8e94902f", + // .hash = "args-0.0.0-CiLiqojRAACGzDRO7A9dw7kWSchNk29caJZkXuMCb0Cn", }, - }, + }, .paths = .{ "build.zig", "build.zig.zon", diff --git a/src/Parser.zig b/src/Parser.zig index 734333f..d656f73 100644 --- a/src/Parser.zig +++ b/src/Parser.zig @@ -22,15 +22,15 @@ pub const Error = Tokenizer.Error || error{ }; pub const IO = struct { - fetch_file_fn: *const fn (io: *const IO, std.mem.Allocator, path: []const u8) error{ FileNotFound, IoError, OutOfMemory, InvalidPath, Canceled }![]const u8, - resolve_variable_fn: *const fn (io: *const IO, name: []const u8) error{UnknownVariable}![]const u8, + fetch_file_fn: *const fn (stdio: std.Io, io: *const IO, std.mem.Allocator, path: []const u8) error{ FileNotFound, IoError, OutOfMemory, InvalidPath, Canceled }![]const u8, + resolve_variable_fn: *const fn (stdio: std.Io, io: *const IO, name: []const u8) error{UnknownVariable}![]const u8, - pub fn fetch_file(io: *const IO, allocator: std.mem.Allocator, path: []const u8) error{ FileNotFound, IoError, OutOfMemory, InvalidPath, Canceled }![]const u8 { - return io.fetch_file_fn(io, allocator, path); + pub fn fetch_file(io: *const IO, stdio: std.Io, allocator: std.mem.Allocator, path: []const u8) error{ FileNotFound, IoError, OutOfMemory, InvalidPath, Canceled }![]const u8 { + return io.fetch_file_fn(stdio,io, allocator, path); } - pub fn resolve_variable(io: *const IO, name: []const u8) error{UnknownVariable}![]const u8 { - return io.resolve_variable_fn(io, name); + pub fn resolve_variable(io: *const IO, stdio: std.Io, name: []const u8) error{UnknownVariable}![]const u8 { + return io.resolve_variable_fn(stdio,io, name); } }; @@ -85,10 +85,10 @@ pub fn push_source(parser: *Parser, options: struct { }; } -pub fn push_file(parser: *Parser, include_path: []const u8) !void { +pub fn push_file(parser: *Parser, stdio: std.Io, include_path: []const u8) !void { const abs_include_path = try parser.get_include_path(parser.arena.allocator(), include_path); - const file_contents = try parser.io.fetch_file(parser.arena.allocator(), abs_include_path); + const file_contents = try parser.io.fetch_file(stdio , parser.arena.allocator(), abs_include_path); const index = parser.file_stack.len; parser.file_stack.len += 1; @@ -121,14 +121,14 @@ pub fn get_include_path(parser: Parser, allocator: std.mem.Allocator, rel_includ return abs_include_path; } -pub fn next(parser: *Parser) (Error || error{UnexpectedEndOfFile})![]const u8 { - return if (try parser.next_or_eof()) |word| +pub fn next(parser: *Parser, stdio: std.Io) (Error || error{UnexpectedEndOfFile})![]const u8 { + return if (try parser.next_or_eof(stdio)) |word| word else error.UnexpectedEndOfFile; } -pub fn next_or_eof(parser: *Parser) Error!?[]const u8 { +pub fn next_or_eof(parser: *Parser, stdio: std.Io) Error!?[]const u8 { fetch_loop: while (parser.file_stack.len > 0) { const top = &parser.file_stack[parser.file_stack.len - 1]; @@ -142,7 +142,7 @@ pub fn next_or_eof(parser: *Parser) Error!?[]const u8 { switch (token.type) { .whitespace, .comment => unreachable, - .word, .variable, .string => return try parser.resolve_value( + .word, .variable, .string => return try parser.resolve_value(stdio, token.type, top.tokenizer.get_text(token), ), @@ -153,14 +153,14 @@ pub fn next_or_eof(parser: *Parser) Error!?[]const u8 { if (std.mem.eql(u8, directive, "!include")) { if (try fetch_token(&top.tokenizer)) |path_token| { const rel_include_path = switch (path_token.type) { - .word, .variable, .string => try parser.resolve_value( + .word, .variable, .string => try parser.resolve_value(stdio, path_token.type, top.tokenizer.get_text(path_token), ), .comment, .directive, .whitespace => return error.BadDirective, }; - try parser.push_file(rel_include_path); + try parser.push_file(stdio, rel_include_path); } else { return error.ExpectedIncludePath; } @@ -190,11 +190,11 @@ fn fetch_token(tok: *Tokenizer) Tokenizer.Error!?Token { } } -fn resolve_value(parser: *Parser, token_type: TokenType, text: []const u8) ![]const u8 { +fn resolve_value(parser: *Parser, stdio: std.Io, token_type: TokenType, text: []const u8) ![]const u8 { return switch (token_type) { .word => text, - .variable => try parser.io.resolve_variable( + .variable => try parser.io.resolve_variable(stdio, text[1..], ), diff --git a/src/components/EmptyData.zig b/src/components/EmptyData.zig index c5ef15a..6393a1f 100644 --- a/src/components/EmptyData.zig +++ b/src/components/EmptyData.zig @@ -8,8 +8,9 @@ const dim = @import("../dim.zig"); const EmptyData = @This(); -pub fn parse(ctx: dim.Context) !dim.Content { +pub fn parse(ctx: dim.Context, stdio: std.Io) !dim.Content { _ = ctx; + _ = stdio; return .create_handle(undefined, .create(@This(), .{ .render_fn = render, })); diff --git a/src/components/FillData.zig b/src/components/FillData.zig index a087cd7..da01ef4 100644 --- a/src/components/FillData.zig +++ b/src/components/FillData.zig @@ -9,10 +9,10 @@ const FillData = @This(); fill_value: u8, -pub fn parse(ctx: dim.Context) !dim.Content { +pub fn parse(ctx: dim.Context, stdio: std.Io) !dim.Content { const pf = try ctx.alloc_object(FillData); pf.* = .{ - .fill_value = try ctx.parse_integer(u8, 0), + .fill_value = try ctx.parse_integer(stdio, u8, 0), }; return .create_handle(pf, .create(@This(), .{ .render_fn = render, @@ -20,8 +20,7 @@ pub fn parse(ctx: dim.Context) !dim.Content { } fn render(self: *FillData, io: std.Io, stream: *dim.BinaryStream) dim.Content.RenderError!void { - _ = io; - var writer = stream.writer(); + var writer = stream.writer(io); writer.interface.splatByteAll( self.fill_value, stream.length, diff --git a/src/components/PasteFile.zig b/src/components/PasteFile.zig index 80e8b68..fec4b8a 100644 --- a/src/components/PasteFile.zig +++ b/src/components/PasteFile.zig @@ -5,10 +5,10 @@ const PasteFile = @This(); file_handle: dim.FileName, -pub fn parse(ctx: dim.Context) !dim.Content { +pub fn parse(ctx: dim.Context, stdio: std.Io) !dim.Content { const pf = try ctx.alloc_object(PasteFile); pf.* = .{ - .file_handle = try ctx.parse_file_name(), + .file_handle = try ctx.parse_file_name(stdio), }; return .create_handle(pf, .create(@This(), .{ .render_fn = render, diff --git a/src/components/fs/FatFileSystem.zig b/src/components/fs/FatFileSystem.zig index cbff252..587c132 100644 --- a/src/components/fs/FatFileSystem.zig +++ b/src/components/fs/FatFileSystem.zig @@ -18,8 +18,8 @@ ops: std.array_list.Managed(common.FsOperation), sector_align: ?c_uint = null, cluster_size: ?u32 = null, -pub fn parse(ctx: dim.Context) !dim.Content { - const fat_type = try ctx.parse_enum(FatType); +pub fn parse(ctx: dim.Context, stdio: std.Io) !dim.Content { + const fat_type = try ctx.parse_enum(stdio,FatType); const pf = try ctx.alloc_object(FAT); pf.* = .{ @@ -32,7 +32,7 @@ pub fn parse(ctx: dim.Context) !dim.Content { .updater = .init(ctx, pf), }; - try common.parse_ops(ctx, "endfat", &appender); + try common.parse_ops(ctx, stdio,"endfat", &appender); try appender.updater.validate(); @@ -59,7 +59,7 @@ const Appender = struct { try self.fat.ops.append(op); } - pub fn parse_custom_op(self: *@This(), ctx: dim.Context, str_op: []const u8) !void { + pub fn parse_custom_op(self: *@This(), stdio: std.Io, ctx: dim.Context, str_op: []const u8) !void { const Op = enum { label, fats, @@ -72,11 +72,11 @@ const Appender = struct { .{str_op}, ); switch (op) { - .label => try self.updater.set(.label, try ctx.parse_string()), - .fats => try self.updater.set(.fats, try ctx.parse_enum(fatfs.FatTables)), - .@"root-size" => try self.updater.set(.rootdir_size, try ctx.parse_integer(c_uint, 0)), - .@"sector-align" => try self.updater.set(.sector_align, try ctx.parse_integer(c_uint, 0)), - .@"cluster-size" => try self.updater.set(.cluster_size, try ctx.parse_integer(u32, 0)), + .label => try self.updater.set(.label, try ctx.parse_string(stdio)), + .fats => try self.updater.set(.fats, try ctx.parse_enum(stdio, fatfs.FatTables)), + .@"root-size" => try self.updater.set(.rootdir_size, try ctx.parse_integer(stdio,c_uint, 0)), + .@"sector-align" => try self.updater.set(.sector_align, try ctx.parse_integer(stdio, c_uint, 0)), + .@"cluster-size" => try self.updater.set(.cluster_size, try ctx.parse_integer(stdio, u32, 0)), } } }; @@ -300,10 +300,9 @@ const BinaryStreamDisk = struct { } fn disk_write(intf: *fatfs.Disk, io: std.Io, buff: [*]const u8, sector: fatfs.LBA, count: c_uint) fatfs.Disk.Error!void { - _ = io; const bsd: *BinaryStreamDisk = @fieldParentPtr("disk", intf); - bsd.stream.write(block_size * sector, buff[0 .. count * block_size]) catch return error.IoError; + bsd.stream.write(io, block_size * sector, buff[0 .. count * block_size]) catch return error.IoError; } fn disk_ioctl(intf: *fatfs.Disk, io: std.Io, cmd: fatfs.IoCtl, buff: [*]u8) fatfs.Disk.Error!void { diff --git a/src/components/fs/common.zig b/src/components/fs/common.zig index 19f8e62..bd6f28a 100644 --- a/src/components/fs/common.zig +++ b/src/components/fs/common.zig @@ -50,7 +50,7 @@ fn Executor(comptime T: type) type { }, .copy_file => |data| { - var handle = data.source.open() catch |err| switch (err) { + var handle = data.source.open(io) catch |err| switch (err) { error.FileNotFound => return, // open() already reporeted the error else => |e| return e, }; @@ -61,11 +61,11 @@ fn Executor(comptime T: type) type { try exec.add_file(data.path, &reader.interface); }, .copy_dir => |data| { - var iter_dir = data.source.open_dir() catch |err| switch (err) { + var iter_dir = data.source.open_dir(io) catch |err| switch (err) { error.FileNotFound => return, // open() already reporeted the error else => |e| return e, }; - defer iter_dir.close(); + defer iter_dir.close(io); var walker_memory: [16384]u8 = undefined; var temp_allocator: std.heap.FixedBufferAllocator = .init(&walker_memory); @@ -75,7 +75,7 @@ fn Executor(comptime T: type) type { var walker = try iter_dir.walk(temp_allocator.allocator()); defer walker.deinit(); - while (walker.next() catch |err| return walk_err(err)) |entry| { + while (walker.next(io) catch |err| return walk_err(err)) |entry| { const path = std.fmt.bufPrintZ(&path_memory, "{s}/{s}", .{ data.path, entry.path, @@ -90,7 +90,7 @@ fn Executor(comptime T: type) type { .rel_path = entry.basename, }; - var file = try fname.open(); + var file = try fname.open(io); defer file.close(io); var reader_buf: [1024]u8 = undefined; @@ -105,8 +105,8 @@ fn Executor(comptime T: type) type { else => { var realpath_buffer: [std.fs.max_path_bytes]u8 = undefined; - std.log.warn("cannot copy file {!s}: {s} is not a supported file type!", .{ - entry.dir.realpath(entry.path, &realpath_buffer), + std.log.warn("cannot copy file {s}: {s} is not a supported file type!", .{ + if (entry.dir.realPathFile(io,entry.path, &realpath_buffer)) |l| realpath_buffer[0..l] else |e| @errorName(e), @tagName(entry.kind), }); }, @@ -155,10 +155,9 @@ fn Executor(comptime T: type) type { try exec.inner.mkdir(path); } - fn walk_err(err: (std.fs.Dir.OpenError || std.mem.Allocator.Error)) dim.Content.RenderError { + fn walk_err(err: (std.Io.Dir.OpenError || std.mem.Allocator.Error)) dim.Content.RenderError { return switch (err) { - error.BadPathName, - error.NameTooLong => error.InvalidPath, + error.BadPathName, error.NameTooLong => error.InvalidPath, error.OutOfMemory => error.OutOfMemory, error.FileNotFound => error.FileNotFound, @@ -175,14 +174,15 @@ fn Executor(comptime T: type) type { error.ProcessFdQuotaExceeded, error.SystemFdQuotaExceeded, error.NotDir, - error.PermissionDenied, => error.IoError, + error.PermissionDenied, + => error.IoError, }; } }; } -fn parse_path(ctx: dim.Context) ![:0]const u8 { - const path = try ctx.parse_string(); +fn parse_path(ctx: dim.Context, stdio: std.Io) ![:0]const u8 { + const path = try ctx.parse_string(stdio); if (path.len == 0) { try ctx.report_nonfatal_error("Path cannot be empty!", .{}); @@ -214,41 +214,41 @@ fn parse_path(ctx: dim.Context) ![:0]const u8 { return try normalize(ctx.get_arena(), path); } -pub fn parse_ops(ctx: dim.Context, end_seq: []const u8, handler: anytype) !void { +pub fn parse_ops(ctx: dim.Context, stdio: std.Io, end_seq: []const u8, handler: anytype) !void { while (true) { - const opsel = try ctx.parse_string(); + const opsel = try ctx.parse_string(stdio); if (std.mem.eql(u8, opsel, end_seq)) return; if (std.mem.eql(u8, opsel, "mkdir")) { - const path = try parse_path(ctx); + const path = try parse_path(ctx, stdio); try handler.append_common_op(FsOperation{ .make_dir = .{ .path = path }, }); } else if (std.mem.eql(u8, opsel, "copy-dir")) { - const path = try parse_path(ctx); - const src = try ctx.parse_file_name(); + const path = try parse_path(ctx, stdio); + const src = try ctx.parse_file_name(stdio); try handler.append_common_op(FsOperation{ .copy_dir = .{ .path = path, .source = src }, }); } else if (std.mem.eql(u8, opsel, "copy-file")) { - const path = try parse_path(ctx); - const src = try ctx.parse_file_name(); + const path = try parse_path(ctx, stdio); + const src = try ctx.parse_file_name(stdio); try handler.append_common_op(FsOperation{ .copy_file = .{ .path = path, .source = src }, }); } else if (std.mem.eql(u8, opsel, "create-file")) { - const path = try parse_path(ctx); - const size = try ctx.parse_mem_size(); - const contents = try ctx.parse_content(); + const path = try parse_path(ctx, stdio); + const size = try ctx.parse_mem_size(stdio); + const contents = try ctx.parse_content(stdio); try handler.append_common_op(FsOperation{ .create_file = .{ .path = path, .size = size, .contents = contents }, }); } else { - try handler.parse_custom_op(ctx, opsel); + try handler.parse_custom_op(stdio, ctx, opsel); } } } diff --git a/src/components/part/GptPartitionTable.zig b/src/components/part/GptPartitionTable.zig index 7671e1c..38cd086 100644 --- a/src/components/part/GptPartitionTable.zig +++ b/src/components/part/GptPartitionTable.zig @@ -10,7 +10,7 @@ disk_id: ?Guid, legacy_bootable: bool = false, partitions: []Partition, -pub fn parse(ctx: dim.Context) !dim.Content { +pub fn parse(ctx: dim.Context, stdio: std.Io) !dim.Content { const pt = try ctx.alloc_object(PartTable); pt.* = PartTable{ .disk_id = null, @@ -21,7 +21,7 @@ pub fn parse(ctx: dim.Context) !dim.Content { var partitions: std.ArrayList(Partition) = .empty; loop: while (true) { - const kw = try ctx.parse_enum(enum { + const kw = try ctx.parse_enum(stdio, enum { guid, part, endgpt, @@ -29,14 +29,14 @@ pub fn parse(ctx: dim.Context) !dim.Content { }); switch (kw) { .guid => { - const guid_str = try ctx.parse_string(); + const guid_str = try ctx.parse_string(stdio); if (guid_str.len != 36) return ctx.report_fatal_error("Invalid disk GUID: wrong length", .{}); pt.disk_id = Guid.parse(guid_str[0..36].*) catch |err| return ctx.report_fatal_error("Invalid disk GUID: {}", .{err}); }, - .part => (try partitions.addOne(allocator)).* = try parsePartition(ctx), + .part => (try partitions.addOne(allocator)).* = try parsePartition(ctx, stdio), .@"legacy-bootable" => pt.legacy_bootable = true, .endgpt => break :loop, } @@ -76,7 +76,7 @@ pub fn parse(ctx: dim.Context) !dim.Content { })); } -fn parsePartition(ctx: dim.Context) !Partition { +fn parsePartition(ctx: dim.Context, stdio: std.Io) !Partition { var part = Partition{ .type = undefined, .part_id = null, @@ -100,7 +100,7 @@ fn parsePartition(ctx: dim.Context) !Partition { }) = .init(ctx, &part); parse_loop: while (true) { - const kw = try ctx.parse_enum(enum { + const kw = try ctx.parse_enum(stdio, enum { type, name, guid, @@ -111,7 +111,7 @@ fn parsePartition(ctx: dim.Context) !Partition { }); switch (kw) { .type => { - const type_name = try ctx.parse_string(); + const type_name = try ctx.parse_string(stdio); const type_guid = known_types.get(type_name) orelse blk: { if (type_name.len == 36) if (Guid.parse(type_name[0..36].*)) |guid| break :blk guid else |_| {}; @@ -121,13 +121,13 @@ fn parsePartition(ctx: dim.Context) !Partition { try updater.set(.type, type_guid); }, .name => { - const string = try ctx.parse_string(); + const string = try ctx.parse_string(stdio); const name = stringToName(string) catch return error.BadStringLiteral; try updater.set(.name, name); }, .guid => { - const string = try ctx.parse_string(); + const string = try ctx.parse_string(stdio); if (string.len != 36) return ctx.report_fatal_error("Invalid partition GUID: wrong length", .{}); @@ -135,9 +135,9 @@ fn parsePartition(ctx: dim.Context) !Partition { return ctx.report_fatal_error("Invalid partition GUID: {}", .{err}); }); }, - .size => try updater.set(.size, try ctx.parse_mem_size()), - .offset => try updater.set(.offset, try ctx.parse_mem_size()), - .contains => try updater.set(.contains, try ctx.parse_content()), + .size => try updater.set(.size, try ctx.parse_mem_size(stdio)), + .offset => try updater.set(.offset, try ctx.parse_mem_size(stdio)), + .contains => try updater.set(.contains, try ctx.parse_content(stdio)), .endpart => break :parse_loop, } } @@ -206,8 +206,8 @@ pub fn render(table: *PartTable, io: std.Io, stream: *dim.BinaryStream) dim.Cont pe_block[0x38..].* = @bitCast(partition.name); pe_crc.update(&pe_block); - try stream.write(block_size * 2 + pe_ofs, &pe_block); - try stream.write(block_size * secondary_pe_array_lba + pe_ofs, &pe_block); + try stream.write(io, block_size * 2 + pe_ofs, &pe_block); + try stream.write(io, block_size * secondary_pe_array_lba + pe_ofs, &pe_block); var sub_view = try stream.slice(offset, size); try partition.contains.render(io, &sub_view); @@ -219,8 +219,8 @@ pub fn render(table: *PartTable, io: std.Io, stream: *dim.BinaryStream) dim.Cont @memset(&pe_block, 0); for (table.partitions.len..0x80) |_| { pe_crc.update(&pe_block); - try stream.write(block_size * 2 + pe_ofs, &pe_block); - try stream.write(block_size * secondary_pe_array_lba + pe_ofs, &pe_block); + try stream.write(io, block_size * 2 + pe_ofs, &pe_block); + try stream.write(io, block_size * secondary_pe_array_lba + pe_ofs, &pe_block); pe_ofs += 0x80; } } @@ -273,8 +273,8 @@ pub fn render(table: *PartTable, io: std.Io, stream: *dim.BinaryStream) dim.Cont // write everything we generated to disk try mbr.render(io, stream); - try stream.write(block_size, &gpt_header_block); - try stream.write(block_size * secondary_pth_lba, &backup_gpt_header_block); + try stream.write(io, block_size, &gpt_header_block); + try stream.write(io, block_size * secondary_pth_lba, &backup_gpt_header_block); } pub const Guid = extern struct { diff --git a/src/components/part/MbrPartitionTable.zig b/src/components/part/MbrPartitionTable.zig index a9bc6d9..35f6833 100644 --- a/src/components/part/MbrPartitionTable.zig +++ b/src/components/part/MbrPartitionTable.zig @@ -13,7 +13,7 @@ bootloader: ?dim.Content, disk_id: ?u32, partitions: [4]?Partition, -pub fn parse(ctx: dim.Context) !dim.Content { +pub fn parse(ctx: dim.Context, stdio: std.Io) !dim.Content { const pf = try ctx.alloc_object(PartTable); pf.* = .{ .bootloader = null, @@ -29,14 +29,14 @@ pub fn parse(ctx: dim.Context) !dim.Content { var next_part_id: usize = 0; var last_part_id: ?usize = null; while (next_part_id < pf.partitions.len) { - const kw = try ctx.parse_enum(enum { + const kw = try ctx.parse_enum(stdio, enum { bootloader, part, ignore, }); switch (kw) { .bootloader => { - const bootloader_content = try ctx.parse_content(); + const bootloader_content = try ctx.parse_content(stdio); if (pf.bootloader != null) { try ctx.report_nonfatal_error("mbr-part.bootloader specified twice!", .{}); } @@ -47,7 +47,7 @@ pub fn parse(ctx: dim.Context) !dim.Content { next_part_id += 1; }, .part => { - pf.partitions[next_part_id] = try parse_partition(ctx); + pf.partitions[next_part_id] = try parse_partition(ctx, stdio); last_part_id = next_part_id; next_part_id += 1; }, @@ -83,7 +83,7 @@ pub fn parse(ctx: dim.Context) !dim.Content { })); } -fn parse_partition(ctx: dim.Context) !Partition { +fn parse_partition(ctx: dim.Context, stdio: std.Io) !Partition { var part: Partition = .{ .offset = null, .size = null, @@ -99,7 +99,7 @@ fn parse_partition(ctx: dim.Context) !Partition { }) = .init(ctx, &part); parse_loop: while (true) { - const kw = try ctx.parse_enum(enum { + const kw = try ctx.parse_enum(stdio, enum { type, bootable, size, @@ -109,7 +109,7 @@ fn parse_partition(ctx: dim.Context) !Partition { }); try switch (kw) { .type => { - const part_name = try ctx.parse_string(); + const part_name = try ctx.parse_string(stdio); const encoded = if (std.fmt.parseInt(u8, part_name, 0)) |value| value @@ -122,9 +122,9 @@ fn parse_partition(ctx: dim.Context) !Partition { try updater.set(.type, encoded); }, .bootable => updater.set(.bootable, true), - .size => updater.set(.size, try ctx.parse_mem_size()), - .offset => updater.set(.offset, try ctx.parse_mem_size()), - .contains => updater.set(.contains, try ctx.parse_content()), + .size => updater.set(.size, try ctx.parse_mem_size(stdio)), + .offset => updater.set(.offset, try ctx.parse_mem_size(stdio)), + .contains => updater.set(.contains, try ctx.parse_content(stdio)), .endpart => break :parse_loop, }; } @@ -235,7 +235,7 @@ pub fn render(table: *PartTable, io: std.Io, stream: *dim.BinaryStream) dim.Cont boot_sector[0x01FE] = 0x55; boot_sector[0x01FF] = 0xAA; - try stream.write(0, &boot_sector); + try stream.write(io,0, &boot_sector); } for (part_infos, table.partitions) |maybe_info, maybe_part| { diff --git a/src/dim.zig b/src/dim.zig index dc009b8..3002b8f 100644 --- a/src/dim.zig +++ b/src/dim.zig @@ -53,7 +53,7 @@ const usage = const VariableMap = std.StringArrayHashMapUnmanaged([]const u8); -var global_deps_file: ?std.fs.File = null; +var global_deps_file: ?std.Io.File = null; pub fn main() !u8 { var gpa_impl: std.heap.DebugAllocator(.{}) = .init; @@ -61,7 +61,8 @@ pub fn main() !u8 { const gpa = gpa_impl.allocator(); - var io: std.Io.Threaded = .init(gpa); + var io: std.Io.Threaded = .init(gpa, .{}); + const io_iface = io.ioBasic(); const opts = try args.parseForCurrentProcess(Options, gpa, .print); defer opts.deinit(); @@ -105,36 +106,36 @@ pub fn main() !u8 { return fatal("--size must be given!"); } - var current_dir = try std.fs.cwd().openDir(".", .{}); - defer current_dir.close(); + var current_dir = try std.Io.Dir.cwd().openDir(io_iface, ".", .{}); + defer current_dir.close(io_iface); - const script_source = try current_dir.readFileAlloc(script_path, gpa, .limited(max_script_size)); + const script_source = try current_dir.readFileAlloc(io_iface, script_path, gpa, .limited(max_script_size)); defer gpa.free(script_source); if (options.@"deps-file") |deps_file_path| { - global_deps_file = try std.fs.cwd().createFile(deps_file_path, .{}); + global_deps_file = try std.Io.Dir.cwd().createFile(io_iface, deps_file_path, .{}); - var writer = global_deps_file.?.writerStreaming(&.{}); + var writer = global_deps_file.?.writerStreaming(io_iface, &.{}); // TODO would it be better to store the writer and just reuse it? that way we can utilise // buffering and not have the risk of someone positional writes and breaking things. // TODO Zig has a bug in dependency file handling: relative paths are taken not to the run // step cwd, but to the project root. hence, we need to absolute paths until this is fixed. var buf_output: [std.fs.max_path_bytes]u8 = undefined; - const output_path_abs = try std.fs.cwd().realpath(std.fs.path.dirname(output_path) orelse ".", &buf_output); + const output_path_abs = try std.Io.Dir.cwd().realPathFile(io_iface, std.fs.path.dirname(output_path) orelse ".", &buf_output); var buf_script: [std.fs.max_path_bytes]u8 = undefined; - const script_path_abs = try std.fs.cwd().realpath(script_path, &buf_script); + const script_path_abs = try std.Io.Dir.cwd().realPathFile(io_iface, script_path, &buf_script); try writer.interface.print( \\{s}/{s}: {s} , .{ - output_path_abs, + buf_output[0..output_path_abs], std.fs.path.basename(output_path), - script_path_abs, + buf_script[0..script_path_abs], }); } defer if (global_deps_file) |deps_file| - deps_file.close(); + deps_file.close(io_iface); var mem_arena: std.heap.ArenaAllocator = .init(gpa); defer mem_arena.deinit(); @@ -163,7 +164,7 @@ pub fn main() !u8 { .contents = script_source, }); - const root_content: Content = env.parse_content() catch |err| switch (err) { + const root_content: Content = env.parse_content(io_iface) catch |err| switch (err) { error.FatalConfigError => return 1, else => |e| return e, @@ -174,33 +175,33 @@ pub fn main() !u8 { } { - var output_file = try current_dir.createFile(output_path, .{ .read = true }); - defer output_file.close(); + var output_file = try current_dir.createFile(io_iface, output_path, .{ .read = true }); + defer output_file.close(io_iface); - try output_file.setEndPos(size_limit); + try output_file.setLength(io_iface, size_limit); var stream: BinaryStream = .init_file(output_file, size_limit); - try root_content.render(io.io(), &stream); + try root_content.render(io_iface, &stream); } if (global_deps_file) |deps_file| { - try deps_file.writeAll("\n"); + try deps_file.writeStreamingAll(io_iface, "\n"); } return 0; } -pub fn declare_file_dependency(path: []const u8) !void { +pub fn declare_file_dependency(stdio: std.Io, path: []const u8) !void { const deps_file = global_deps_file orelse return; - const stat = std.fs.cwd().statFile(path) catch |err| switch (err) { + const stat = std.Io.Dir.cwd().statFile(stdio, path, .{}) catch |err| switch (err) { error.IsDir => return, else => |e| return e, }; if (stat.kind != .directory) { - try deps_file.writeAll(" \\\n "); - try deps_file.writeAll(path); + try deps_file.writeStreamingAll(stdio, " \\\n "); + try deps_file.writeStreamingAll(stdio, path); } } @@ -239,14 +240,14 @@ pub const Context = struct { return error.FatalConfigError; } - pub fn parse_string(ctx: Context) Environment.ParseError![]const u8 { - const str = try ctx.env.parser.next(); + pub fn parse_string(ctx: Context, stdio: std.Io) Environment.ParseError![]const u8 { + const str = try ctx.env.parser.next(stdio); // std.debug.print("token: '{}'\n", .{std.zig.fmtEscapes(str)}); return str; } - pub fn parse_file_name(ctx: Context) Environment.ParseError!FileName { - const rel_path = try ctx.parse_string(); + pub fn parse_file_name(ctx: Context, stdio: std.Io) Environment.ParseError!FileName { + const rel_path = try ctx.parse_string(stdio); const abs_path = try ctx.env.parser.get_include_path(ctx.env.arena, rel_path); @@ -256,10 +257,10 @@ pub const Context = struct { }; } - pub fn parse_enum(ctx: Context, comptime E: type) Environment.ParseError!E { + pub fn parse_enum(ctx: Context, stdio: std.Io, comptime E: type) Environment.ParseError!E { if (@typeInfo(E) != .@"enum") @compileError("get_enum requires an enum type!"); - const tag_name = try ctx.parse_string(); + const tag_name = try ctx.parse_string(stdio); const converted = std.meta.stringToEnum( E, tag_name, @@ -276,32 +277,32 @@ pub const Context = struct { return error.InvalidEnumTag; } - pub fn parse_integer(ctx: Context, comptime I: type, base: u8) Environment.ParseError!I { + pub fn parse_integer(ctx: Context, stdio: std.Io, comptime I: type, base: u8) Environment.ParseError!I { if (@typeInfo(I) != .int) @compileError("get_integer requires an integer type!"); return std.fmt.parseInt( I, - try ctx.parse_string(), + try ctx.parse_string(stdio), base, ) catch return error.InvalidNumber; } - pub fn parse_mem_size(ctx: Context) Environment.ParseError!u64 { - const str = try ctx.parse_string(); + pub fn parse_mem_size(ctx: Context, stdio: std.Io) Environment.ParseError!u64 { + const str = try ctx.parse_string(stdio); const ds: DiskSize = try .parse(str); return ds.size_in_bytes(); } - pub fn parse_content(ctx: Context) Environment.ParseError!Content { - const content_type_str = try ctx.env.parser.next(); + pub fn parse_content(ctx: Context, stdio: std.Io) Environment.ParseError!Content { + const content_type_str = try ctx.env.parser.next(stdio); inline for (content_types) |tn| { const name, const impl = tn; if (std.mem.eql(u8, name, content_type_str)) { - const content: Content = try impl.parse(ctx); + const content: Content = try impl.parse(ctx, stdio); return content; } @@ -374,7 +375,7 @@ const Environment = struct { arena: std.mem.Allocator, allocator: std.mem.Allocator, parser: *Parser, - include_base: std.fs.Dir, + include_base: std.Io.Dir, vars: *const VariableMap, error_flag: bool = false, @@ -383,10 +384,10 @@ const Environment = struct { .resolve_variable_fn = resolve_var, }, - fn parse_content(env: *Environment) ParseError!Content { + fn parse_content(env: *Environment, stdio: std.Io) ParseError!Content { var ctx = Context{ .env = env }; - return try ctx.parse_content(); + return try ctx.parse_content(stdio); } fn report_error(env: *Environment, comptime fmt: []const u8, params: anytype) error{OutOfMemory}!void { @@ -394,16 +395,16 @@ const Environment = struct { std.log.err("PARSE ERROR: " ++ fmt, params); } - fn fetch_file(io: *const Parser.IO, allocator: std.mem.Allocator, path: []const u8) error{ FileNotFound, IoError, OutOfMemory, InvalidPath, Canceled }![]const u8 { + fn fetch_file(stdio: std.Io, io: *const Parser.IO, allocator: std.mem.Allocator, path: []const u8) error{ FileNotFound, IoError, OutOfMemory, InvalidPath, Canceled }![]const u8 { const env: *const Environment = @fieldParentPtr("io", io); - const contents = env.include_base.readFileAlloc(path, allocator, .limited(max_script_size)) catch |err| switch (err) { + const contents = env.include_base.readFileAlloc(stdio, path, allocator, .limited(max_script_size)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.FileNotFound => { const ctx = Context{ .env = @constCast(env) }; var buffer: [std.fs.max_path_bytes]u8 = undefined; try ctx.report_nonfatal_error("failed to open file: \"{f}/{f}\"", .{ - std.zig.fmtString(env.include_base.realpath(".", &buffer) catch return error.FileNotFound), + std.zig.fmtString(buffer[0 .. env.include_base.realPath(stdio, &buffer) catch return error.FileNotFound]), std.zig.fmtString(path), }); return error.FileNotFound; @@ -413,12 +414,13 @@ const Environment = struct { errdefer allocator.free(contents); const name: FileName = .{ .root_dir = env.include_base, .rel_path = path }; - try name.declare_dependency(); + try name.declare_dependency(stdio); return contents; } - fn resolve_var(io: *const Parser.IO, name: []const u8) error{UnknownVariable}![]const u8 { + fn resolve_var(stdio: std.Io, io: *const Parser.IO, name: []const u8) error{UnknownVariable}![]const u8 { + _ = stdio; const env: *const Environment = @fieldParentPtr("io", io); return env.vars.get(name) orelse return error.UnknownVariable; } @@ -440,7 +442,7 @@ pub const Content = struct { obj: *anyopaque, vtable: *const VTable, - pub const empty: Content = @import("components/EmptyData.zig").parse(undefined) catch unreachable; + pub const empty: Content = @import("components/EmptyData.zig").parse(undefined, undefined) catch unreachable; pub fn create_handle(obj: *anyopaque, vtable: *const VTable) Content { return .{ .obj = obj, .vtable = vtable }; @@ -477,17 +479,17 @@ pub const Content = struct { }; pub const FileName = struct { - root_dir: std.fs.Dir, + root_dir: std.Io.Dir, rel_path: []const u8, pub const OpenError = error{ FileNotFound, InvalidPath, IoError, Canceled }; - pub fn open(name: FileName) OpenError!FileHandle { - const file = name.root_dir.openFile(name.rel_path, .{}) catch |err| switch (err) { + pub fn open(name: FileName, stdio: std.Io) OpenError!FileHandle { + const file = name.root_dir.openFile(stdio, name.rel_path, .{}) catch |err| switch (err) { error.FileNotFound => { var buffer: [std.fs.max_path_bytes]u8 = undefined; std.log.err("failed to open \"{f}/{f}\": not found", .{ - std.zig.fmtString(name.root_dir.realpath(".", &buffer) catch |e| @errorName(e)), + std.zig.fmtString(if (name.root_dir.realPath(stdio, &buffer)) |l| buffer[0..l] else |e| @errorName(e)), std.zig.fmtString(name.rel_path), }); return error.FileNotFound; @@ -499,6 +501,7 @@ pub const FileName = struct { error.BadPathName, => return error.InvalidPath, + // error.DiskQuota, error.NoSpaceLeft, error.FileTooBig, error.DeviceBusy, @@ -517,24 +520,23 @@ pub const FileName = struct { error.SystemFdQuotaExceeded, error.IsDir, error.NotDir, - error.FileLocksNotSupported, + error.FileLocksUnsupported, error.FileBusy, - error.ProcessNotFound, error.PermissionDenied, => return error.IoError, }; - try name.declare_dependency(); + try name.declare_dependency(stdio); return .{ .file = file }; } - pub fn open_dir(name: FileName) OpenError!std.fs.Dir { - const dir = name.root_dir.openDir(name.rel_path, .{ .iterate = true }) catch |err| switch (err) { + pub fn open_dir(name: FileName, stdio: std.Io) OpenError!std.Io.Dir { + const dir = name.root_dir.openDir(stdio, name.rel_path, .{ .iterate = true }) catch |err| switch (err) { error.FileNotFound => { var buffer: [std.fs.max_path_bytes]u8 = undefined; std.log.err("failed to open \"{f}/{f}\": not found", .{ - std.zig.fmtString(name.root_dir.realpath(".", &buffer) catch |e| @errorName(e)), + std.zig.fmtString(if (name.root_dir.realPath(stdio, &buffer)) |l| buffer[0..l] else |e| @errorName(e)), std.zig.fmtString(name.rel_path), }); return error.FileNotFound; @@ -560,19 +562,20 @@ pub const FileName = struct { => return error.IoError, }; - try name.declare_dependency(); + try name.declare_dependency(stdio); return dir; } - pub fn declare_dependency(name: FileName) OpenError!void { + pub fn declare_dependency(name: FileName, stdio: std.Io) OpenError!void { var buffer: [std.fs.max_path_bytes]u8 = undefined; - const realpath = name.root_dir.realpath( + const realpath = name.root_dir.realPathFile( + stdio, name.rel_path, &buffer, ) catch |e| std.debug.panic("failed to determine real path for dependency file: {s}", .{@errorName(e)}); - declare_file_dependency(realpath) catch |e| std.debug.panic("Failed to write to deps file: {s}", .{@errorName(e)}); + declare_file_dependency(stdio, buffer[0..realpath]) catch |e| std.debug.panic("Failed to write to deps file: {s}", .{@errorName(e)}); } pub const GetSizeError = error{ FileNotFound, InvalidPath, IoError }; @@ -611,13 +614,13 @@ pub const FileName = struct { } pub fn copy_to(file: FileName, io: std.Io, stream: *BinaryStream) (OpenError || FileHandle.ReadError || BinaryStream.WriteError)!void { - var handle = try file.open(); + var handle = try file.open(io); defer handle.close(io); var reader_buf: [8192]u8 = undefined; var reader = handle.reader(io, &reader_buf); - var writer = stream.writer(); + var writer = stream.writer(io); _ = writer.interface.sendFileAll(&reader, .unlimited) catch |e| return switch (e) { error.WriteFailed => error.IoError, // TODO this isn't great @@ -629,21 +632,20 @@ pub const FileName = struct { pub const FileHandle = struct { pub const ReadError = std.Io.Reader.Error; - file: std.fs.File, + file: std.Io.File, pub fn close(fd: *FileHandle, io: std.Io) void { - _ = io; - fd.file.close(); + fd.file.close(io); fd.* = undefined; } - pub fn reader(fd: FileHandle, io: std.Io, buf: []u8) std.fs.File.Reader { + pub fn reader(fd: FileHandle, io: std.Io, buf: []u8) std.Io.File.Reader { return fd.file.reader(io, buf); } }; pub const BinaryStream = struct { - pub const WriteError = error{ Overflow, IoError, Canceled }; + pub const WriteError = error{ Overflow, IoError }; pub const WriterError = std.Io.Writer.Error; pub const ReadError = error{ Overflow, IoError, Canceled }; @@ -663,7 +665,7 @@ pub const BinaryStream = struct { } /// Constructs a BinaryStream from a file. - pub fn init_file(file: std.fs.File, max_len: u64) BinaryStream { + pub fn init_file(file: std.Io.File, max_len: u64) BinaryStream { return .{ .backing = .{ .file = .{ @@ -712,7 +714,7 @@ pub const BinaryStream = struct { } } - pub fn write(bs: *BinaryStream, offset: u64, data: []const u8) WriteError!void { + pub fn write(bs: *BinaryStream, io: std.Io, offset: u64, data: []const u8) WriteError!void { const end_pos = offset + data.len; if (end_pos > bs.length) return error.Overflow; @@ -720,29 +722,10 @@ pub const BinaryStream = struct { switch (bs.backing) { .buffer => |ptr| @memcpy(ptr[@intCast(offset)..][0..data.len], data), .file => |state| { - state.file.seekTo(state.base + offset) catch return error.IoError; - state.file.writeAll(data) catch |err| switch (err) { - error.DiskQuota, error.NoSpaceLeft, error.FileTooBig => return error.Overflow, - - error.Canceled => return error.Canceled, - - error.InputOutput, - error.DeviceBusy, - error.InvalidArgument, - error.AccessDenied, - error.BrokenPipe, - error.SystemResources, - error.NotOpenForWriting, - error.LockViolation, - error.WouldBlock, - error.ConnectionResetByPeer, - error.ProcessNotFound, - error.NoDevice, - error.Unexpected, - error.PermissionDenied, - error.MessageOversize, - => return error.IoError, - }; + var w = state.file.writer(io, &.{}); + w.seekTo(state.base + offset) catch return error.IoError; + w.interface.writeAll(data) catch return error.IoError; + w.interface.flush() catch return error.IoError; }, } } @@ -753,7 +736,7 @@ pub const BinaryStream = struct { bs.virtual_offset = offset; } - pub fn writer(bs: *BinaryStream) Writer { + pub fn writer(bs: *BinaryStream, stdio: std.Io) Writer { return .{ .interface = .{ .vtable = &.{ @@ -762,12 +745,14 @@ pub const BinaryStream = struct { .buffer = &.{}, }, .stream = bs, + .stdio = stdio, }; } pub const Writer = struct { interface: std.Io.Writer, stream: *BinaryStream, + stdio: std.Io, pub fn drain(io_w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize { const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w)); @@ -775,14 +760,14 @@ pub const BinaryStream = struct { var written: usize = 0; for (data[0 .. data.len - 1]) |bytes| { - written += try w.stream.write_some(bytes); + written += try w.stream.write_some(w.stdio, bytes); } const pattern = data[data.len - 1]; switch (pattern.len) { 0 => {}, else => for (0..splat) |_| { - written += try w.stream.write_some(pattern); + written += try w.stream.write_some(w.stdio, pattern); }, } @@ -790,12 +775,12 @@ pub const BinaryStream = struct { } }; - fn write_some(stream: *BinaryStream, data: []const u8) std.Io.Writer.Error!usize { + fn write_some(stream: *BinaryStream, stdio: std.Io, data: []const u8) std.Io.Writer.Error!usize { const remaining_len = stream.length - stream.virtual_offset; const written_len: usize = @intCast(@min(remaining_len, data.len)); - stream.write(stream.virtual_offset, data[0..written_len]) catch return error.WriteFailed; + stream.write(stdio, stream.virtual_offset, data[0..written_len]) catch return error.WriteFailed; stream.virtual_offset += written_len; return written_len; @@ -803,7 +788,7 @@ pub const BinaryStream = struct { pub const Backing = union(enum) { file: struct { - file: std.fs.File, + file: std.Io.File, base: u64, }, buffer: [*]u8, From 7ffe00aad2c1fda564215b76c78c6b08bc56a2ed Mon Sep 17 00:00:00 2001 From: Khitiara Date: Fri, 9 Jan 2026 18:56:25 -0500 Subject: [PATCH 5/6] rich main and IoSource rng --- src/components/fs/common.zig | 2 +- src/components/part/GptPartitionTable.zig | 3 ++- src/dim.zig | 12 +++++------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/components/fs/common.zig b/src/components/fs/common.zig index bd6f28a..68ba7f1 100644 --- a/src/components/fs/common.zig +++ b/src/components/fs/common.zig @@ -164,7 +164,7 @@ fn Executor(comptime T: type) type { error.Canceled => error.Canceled, - error.DeviceBusy, + // error.DeviceBusy, error.AccessDenied, error.SystemResources, error.NoDevice, diff --git a/src/components/part/GptPartitionTable.zig b/src/components/part/GptPartitionTable.zig index 38cd086..01b9547 100644 --- a/src/components/part/GptPartitionTable.zig +++ b/src/components/part/GptPartitionTable.zig @@ -148,7 +148,8 @@ fn parsePartition(ctx: dim.Context, stdio: std.Io) !Partition { } pub fn render(table: *PartTable, io: std.Io, stream: *dim.BinaryStream) dim.Content.RenderError!void { - const random = std.crypto.random; + var r: std.Random.IoSource = .{ .io = io }; + const random = r.interface(); const lba_len = stream.length / block_size; const secondary_pth_lba = lba_len - 1; diff --git a/src/dim.zig b/src/dim.zig index 3002b8f..a384b3d 100644 --- a/src/dim.zig +++ b/src/dim.zig @@ -55,16 +55,15 @@ const VariableMap = std.StringArrayHashMapUnmanaged([]const u8); var global_deps_file: ?std.Io.File = null; -pub fn main() !u8 { +pub fn main(init: std.process.Init) !u8 { var gpa_impl: std.heap.DebugAllocator(.{}) = .init; defer _ = gpa_impl.deinit(); const gpa = gpa_impl.allocator(); - var io: std.Io.Threaded = .init(gpa, .{}); - const io_iface = io.ioBasic(); + const io_iface = init.io; - const opts = try args.parseForCurrentProcess(Options, gpa, .print); + const opts = try args.parseForCurrentProcess(Options, gpa, init.minimal.args, .print); defer opts.deinit(); const options = opts.options; @@ -75,8 +74,7 @@ pub fn main() !u8 { var var_map: VariableMap = .empty; defer var_map.deinit(gpa); - var env_map = try std.process.getEnvMap(gpa); - defer env_map.deinit(); + var env_map = init.environ_map; if (options.@"import-env") { var iter = env_map.iterator(); @@ -548,7 +546,7 @@ pub const FileName = struct { error.BadPathName, => return error.InvalidPath, - error.DeviceBusy, + // error.DeviceBusy, error.AccessDenied, error.SystemResources, error.NoDevice, From b869e366813343cb44dee0ef8069b2715f739e2e Mon Sep 17 00:00:00 2001 From: Khitiara Date: Mon, 19 Jan 2026 16:40:19 -0500 Subject: [PATCH 6/6] support setting part GUID --- src/BuildInterface.zig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/BuildInterface.zig b/src/BuildInterface.zig index 421f2d3..4f5aea6 100644 --- a/src/BuildInterface.zig +++ b/src/BuildInterface.zig @@ -160,7 +160,7 @@ const ContentWriter = struct { .gpt_part_table => |data| { try cw.code.writeAll("gpt-part\n"); - if(data.legacy_bootable) { + if (data.legacy_bootable) { try cw.code.writeAll(" legacy-bootable\n"); } @@ -180,6 +180,9 @@ const ContentWriter = struct { if (part.name) |name| { try cw.code.print(" name \"{f}\"\n", .{std.zig.fmtString(name)}); } + if (part.part_guid) |pg| { + try cw.code.print(" guid \"{s}\"", .{&pg}); + } if (part.offset) |offset| { try cw.code.print(" offset {d}\n", .{offset}); } @@ -378,7 +381,7 @@ pub const GptPartTable = struct { @"microsoft-basic-data", @"microsoft-reserved", @"windows-recovery", - @"plan9", + plan9, @"linux-swap", @"linux-fs", @"linux-reserved", @@ -387,6 +390,7 @@ pub const GptPartTable = struct { guid: [36]u8, }, name: ?[]const u8 = null, + part_guid: ?[36]u8 = null, size: ?u64 = null, offset: ?u64 = null, data: Content,