From 053d64a95427f24d5bf951738773a0d82e4efa54 Mon Sep 17 00:00:00 2001 From: "Caleb J. Gardner" Date: Sat, 7 Feb 2026 16:59:23 -0600 Subject: [PATCH] Some cleanup to build zon. Minor start on threaded extraction --- build.zig | 2 +- build.zig.zon | 43 ++++++------------------------------------ src/bin/unsquashfs.zig | 7 ++++--- src/file.zig | 3 +-- src/inode.zig | 31 ++++++++++++++++++++---------- 5 files changed, 33 insertions(+), 53 deletions(-) diff --git a/build.zig b/build.zig index 342648c..427763d 100644 --- a/build.zig +++ b/build.zig @@ -20,7 +20,7 @@ pub fn build(b: *std.Build) !void { mod.linkSystemLibrary("zstd", .{}); const unsquashfs_options = b.addOptions(); - unsquashfs_options.addOption(std.SemanticVersion, "version_string", try std.SemanticVersion.parse(version_string_option orelse "0.0.0-testing")); + unsquashfs_options.addOption(std.SemanticVersion, "version", try std.SemanticVersion.parse(version_string_option orelse "0.0.0-testing")); var exe_mod = b.createModule(.{ .root_source_file = b.path("src/bin/unsquashfs.zig"), diff --git a/build.zig.zon b/build.zig.zon index ac82177..00d1bdd 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,30 +1,7 @@ .{ - // This is the default name used by packages depending on this one. For - // example, when a user runs `zig fetch --save `, this field is used - // as the key in the `dependencies` table. Although the user can choose a - // different name, most users will stick with this provided value. - // - // It is redundant to include "zig" in this name because it is already - // within the Zig package namespace. - .name = .zig_squashfs, - // This is a [Semantic Version](https://semver.org/). - // In a future version of Zig it will be used for package deduplication. - .version = "0.0.0", - // Together with name, this represents a globally unique package - // identifier. This field is generated by the Zig toolchain when the - // package is first created, and then *never changes*. This allows - // unambiguous detection of one package being an updated version of - // another. - // - // When forking a Zig project, this id should be regenerated (delete the - // field and run `zig build`) if the upstream project is still maintained. - // Otherwise, the fork is *hostile*, attempting to take control over the - // original project's identity. Thus it is recommended to leave the comment - // on the following line intact, so that it shows up in code reviews that - // modify the field. - .fingerprint = 0x527960c74dddb509, // Changing this has security and trust implications. - // Tracks the earliest Zig version that the package considers to be a - // supported use case. + .name = .squashfs, + .version = "0.0.1", + .fingerprint = 0x37ba29474b87f145, // Changing this has security and trust implications. .minimum_zig_version = "0.15.2", // This field is optional. // Each dependency must either provide a `url` and `hash`, or a `path`. @@ -62,20 +39,12 @@ // .lazy = false, //}, }, - // Specifies the set of files and directories that are included in this package. - // Only files and directories listed here are included in the `hash` that - // is computed for this package. Only files listed here will remain on disk - // when using the zig package manager. As a rule of thumb, one should list - // files required for compilation plus any license(s). - // Paths are relative to the build root. Use the empty string (`""`) to refer to - // the build root itself. - // A directory listed here means that all files within, recursively, are included. .paths = .{ "build.zig", "build.zig.zon", "src", - // For example... - //"LICENSE", - //"README.md", + + "LICENSE", + "README.md", }, } diff --git a/src/bin/unsquashfs.zig b/src/bin/unsquashfs.zig index 41b844f..4a64213 100644 --- a/src/bin/unsquashfs.zig +++ b/src/bin/unsquashfs.zig @@ -1,5 +1,6 @@ const std = @import("std"); const Writer = std.Io.Writer; +const builtin = @import("builtin"); const config = @import("config"); const squashfs = @import("zig_squashfs"); @@ -64,9 +65,9 @@ fn handleArgs(alloc: std.mem.Allocator, out: *Writer) !void { extLoc = nxt.?; continue; } else if (std.mem.eql(u8, arg, "--version")) { - _ = try out.write("v"); - try config.version_string.format(out); - _ = try out.write("\n"); + _ = try out.write("unsquashfs version"); + try config.version.format(out); + try out.print("\nBuilt using Zig {s} with {} backend in {} mode.\n", .{ builtin.zig_version_string, builtin.zig_backend, builtin.mode }); std.process.cleanExit(); return; } diff --git a/src/file.zig b/src/file.zig index 0049692..6963244 100644 --- a/src/file.zig +++ b/src/file.zig @@ -198,8 +198,7 @@ pub fn extract(self: *SfsFile, path: []const u8, options: ExtractionOptions) !vo } } defer if (ext_path.len > path.len) alloc.free(ext_path); - //TODO: switch to threaded version. - return self.inode.extractTo(self.archive, path, options); + return self.inode.extractToThreaded(self.archive, path, options, self.archive.thread_count); } /// Utility function. diff --git a/src/inode.zig b/src/inode.zig index 0468e88..47fdd8c 100644 --- a/src/inode.zig +++ b/src/inode.zig @@ -133,6 +133,7 @@ fn entriesFromData(archive: *Archive, data: anytype) ![]DirEntry { return DirEntry.readDir(alloc, &meta.interface, data.size); } +/// Extract the inode to the given path. Single threaded. pub fn extractTo(self: Inode, archive: *Archive, path: []const u8, options: ExtractionOptions) !void { switch (self.hdr.inode_type) { .dir, .ext_dir => { @@ -175,20 +176,30 @@ const Perms = struct { mod_time: u32, }; -pub fn extractToThreaded(inode: Inode, archive: *Archive, path: []const u8, options: ExtractionOptions, threads: usize) !void { - _ = archive; - _ = path; - _ = options; - _ = threads; - switch (inode.hdr.inode_type) {} +/// Extract the inode to the given path. Multi-threaded. +/// Functions identically to extractTo on all but regular files and directories. +/// +/// If threads <= 1, then this just calls extractTo. +pub fn extractToThreaded(self: Inode, archive: *Archive, path: []const u8, options: ExtractionOptions, threads: usize) !void { + if (threads <= 1) return self.extractTo(archive, path, options); + std.debug.print("{}\n", .{threads}); + @constCast(&threads).* = try std.Thread.getCpuCount(); + std.debug.print("{}\n", .{threads}); + switch (self.hdr.inode_type) { + .dir, .ext_dir => {}, + .file, .ext_file => {}, + .symlink, .ext_symlink => try self.extractSymlink(path), + else => try self.extractDevice(archive, path, options), + } + return error.TODO; } /// Extract threadedly the inode to the path. -fn extractThread(inode: Inode, archive: *Archive, path: []const u8, options: ExtractionOptions, wg: *WaitGroup, pool: *Pool, perms: ?*std.ArrayList(Perms)) !void { +fn extractThread(self: Inode, archive: *Archive, path: []const u8, options: ExtractionOptions, wg: *WaitGroup, pool: *Pool, perms: ?*std.ArrayList(Perms)) !void { _ = pool; _ = perms; _ = archive; - switch (inode.hdr.inode_type) { + switch (self.hdr.inode_type) { .dir, .ext_dir => { //TOOD return error.TODO; @@ -199,11 +210,11 @@ fn extractThread(inode: Inode, archive: *Archive, path: []const u8, options: Ext }, .symlink, .ext_symlink => { defer wg.finish(); - try inode.extractSymlink(path); + try self.extractSymlink(path); }, else => { defer wg.finish(); - try inode.extractDevice(path, options.ignore_permissions); + try self.extractDevice(path, options.ignore_permissions); }, } }