From bcfd983f8d8dd3b1813e4abbc8712faa846e97f8 Mon Sep 17 00:00:00 2001 From: "Caleb J. Gardner" Date: Sat, 7 Feb 2026 06:28:27 -0600 Subject: [PATCH] Fixed a handful of errors when extracting. Fixed issues with unsquashfs --- src/bin/unsquashfs.zig | 3 +++ src/decomp.zig | 14 +++++++++----- src/dir_entry.zig | 10 +++------- src/file.zig | 2 +- src/inode.zig | 5 ++++- src/test.zig | 4 ++-- src/util/data.zig | 1 + 7 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/bin/unsquashfs.zig b/src/bin/unsquashfs.zig index 4ff213e..0eb90d3 100644 --- a/src/bin/unsquashfs.zig +++ b/src/bin/unsquashfs.zig @@ -34,6 +34,7 @@ pub fn main() !void { fn handleArgs(alloc: std.mem.Allocator, out: *Writer) !void { var args = try std.process.argsWithAllocator(alloc); defer args.deinit(); + _ = args.next(); // args[0] is the application launch command. while (args.next()) |arg| { if (std.mem.eql(u8, arg, "-o")) { const nxt = args.next(); @@ -45,6 +46,7 @@ fn handleArgs(alloc: std.mem.Allocator, out: *Writer) !void { try out.print("-o must be followed by a number\n", .{}); return errors.InvalidArguments; }; + continue; } else if (std.mem.eql(u8, arg, "-d")) { const nxt = args.next(); if (nxt == null or nxt.?.len == 0) { @@ -52,6 +54,7 @@ fn handleArgs(alloc: std.mem.Allocator, out: *Writer) !void { return errors.InvalidArguments; } extLoc = nxt.?; + continue; } if (archive.len > 0) { try out.print("you can only provide one file at a time\n", .{}); diff --git a/src/decomp.zig b/src/decomp.zig index 97f7064..5e432da 100644 --- a/src/decomp.zig +++ b/src/decomp.zig @@ -18,9 +18,10 @@ pub const DecompFn = *const fn (alloc: std.mem.Allocator, in: []u8, out: []u8) a // }; pub fn gzipDecompress(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { - _ = alloc; var rdr: Reader = .fixed(in); - var decomp = std.compress.flate.Decompress.init(&rdr, .zlib, &[0]u8{}); + const buf = try alloc.alloc(u8, out.len); + defer alloc.free(buf); + var decomp = std.compress.flate.Decompress.init(&rdr, .zlib, buf); return decomp.reader.readSliceShort(out); } @@ -37,8 +38,11 @@ pub fn xzDecompress(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usiz } pub fn zstdDecompress(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { - _ = alloc; var rdr: Reader = .fixed(in); - var decomp = std.compress.zstd.Decompress.init(&rdr, &[0]u8{}, .{}); - return decomp.reader.readSliceShort(out); + const buf = try alloc.alloc(u8, std.compress.zstd.default_window_len + std.compress.zstd.block_size_max); + defer alloc.free(buf); + var decomp = std.compress.zstd.Decompress.init(&rdr, buf, .{}); + return decomp.reader.readSliceShort(out) catch |err| { + return decomp.err orelse err; + }; } diff --git a/src/dir_entry.zig b/src/dir_entry.zig index 4909f82..191da47 100644 --- a/src/dir_entry.zig +++ b/src/dir_entry.zig @@ -30,17 +30,13 @@ pub fn readDir(alloc: std.mem.Allocator, rdr: *Reader, size: u32) ![]Entry { var cur_red: u32 = 3; // start at 3 due to "." & ".." being counted in the dir size. var hdr: Header = undefined; var raw: RawEntry = undefined; - var out: std.ArrayList(Entry) = try .initCapacity(alloc, 25); // Start out with capacity instead of needing to allocate per header. + var out: std.ArrayList(Entry) = try .initCapacity(alloc, 100); // Start out with a decent capacity instead of needing to allocate per header. errdefer out.deinit(alloc); while (cur_red < size) { try rdr.readSliceEndian(Header, @ptrCast(&hdr), .little); cur_red += @sizeOf(Header); - const count = hdr.count + 1; - if (out.capacity < count) { - // Make sure we have at least 25 capacity past current count. - try out.ensureUnusedCapacity(alloc, ((count % 25) + 2) * 25); - } - for (0..count) |_| { + try out.ensureUnusedCapacity(alloc, hdr.count + 1); + for (0..hdr.count + 1) |_| { try rdr.readSliceEndian(RawEntry, @ptrCast(&raw), .little); const name = try alloc.alloc(u8, raw.name_size + 1); errdefer alloc.free(name); diff --git a/src/file.zig b/src/file.zig index c051533..0049692 100644 --- a/src/file.zig +++ b/src/file.zig @@ -42,7 +42,7 @@ pub fn init(archive: *Archive, inode: Inode, name: []const u8) !SfsFile { } pub fn fromEntry(archive: *Archive, entry: DirEntry) !SfsFile { var rdr = try archive.fil.readerAt(entry.block_start + archive.super.inode_start, &[0]u8{}); - var meta: MetadataReader = .init(archive.allocator(), &rdr.interface, &archive.decomp); + var meta: MetadataReader = .init(archive.allocator(), &rdr.interface, archive.decomp); try meta.interface.discardAll(entry.block_offset); const inode: Inode = try .read(archive.allocator(), &meta.interface, archive.super.block_size); errdefer inode.deinit(archive.allocator()); diff --git a/src/inode.zig b/src/inode.zig index 1b2a92d..1c11534 100644 --- a/src/inode.zig +++ b/src/inode.zig @@ -138,6 +138,9 @@ pub fn extractTo(self: Inode, archive: *Archive, path: []const u8, options: Extr .dir, .ext_dir => { // Removing any trailing separators since that's the easiest path forward. if (path[path.len - 1] == '/') return self.extractTo(archive, path[0 .. path.len - 1], options); + std.fs.cwd().makeDir(path) catch |err| { + if (err != std.fs.Dir.MakeError.PathAlreadyExists) return err; + }; var alloc = archive.allocator(); const entries = try self.dirEntries(archive); defer { @@ -218,7 +221,7 @@ fn extractRegFile(self: Inode, archive: *Archive, path: []const u8, options: Ext _ = try dat_rdr.interface.streamRemaining(&wrt.interface); try wrt.interface.flush(); // updateTime is in nanoseconds (a billionth of a second). mod_time is in seconds. - try fil.updateTimes(self.hdr.mod_time * (10 ^ 9), self.hdr.mod_time * (10 ^ 9)); + try fil.updateTimes(self.hdr.mod_time, self.hdr.mod_time); if (!options.ignore_permissions) { try fil.chmod(self.hdr.permissions); try fil.chown(try archive.id(self.hdr.uid_idx), try archive.id(self.hdr.gid_idx)); diff --git a/src/test.zig b/src/test.zig index fc99fbd..4bb58cb 100644 --- a/src/test.zig +++ b/src/test.zig @@ -28,7 +28,7 @@ test "ExtractSingleFile" { defer sfs.deinit(); var test_fil = try sfs.open(TestFile); defer test_fil.deinit(); - try test_fil.extract(TestFileExtractLocation, .VerboseDefault); + try test_fil.extract(TestFileExtractLocation, .Default); //TODO: validate extracted file. } @@ -40,7 +40,7 @@ test "ExtractCompleteArchive" { defer fil.close(); var sfs: Archive = try .init(std.testing.allocator, fil); defer sfs.deinit(); - try sfs.extract(TestFullExtractLocation, .VerboseDefault); + try sfs.extract(TestFullExtractLocation, .Default); } const LinuxPATestCorrectSuperblock: Superblock = .{ diff --git a/src/util/data.zig b/src/util/data.zig index ae7c424..aea7310 100644 --- a/src/util/data.zig +++ b/src/util/data.zig @@ -111,6 +111,7 @@ fn advance(self: *DataReader) !void { } const tmp_buf = try self.alloc.alloc(u8, block.size); defer self.alloc.free(tmp_buf); + try rdr.interface.readSliceAll(tmp_buf); _ = try self.decomp(self.alloc, tmp_buf, self.interface.buffer); } /// Does not guarentee that data currently in the buffer is retained.