Fixed a handful of errors when extracting.

Fixed issues with unsquashfs
This commit is contained in:
Caleb J. Gardner
2026-02-07 06:28:27 -06:00
parent 75502da1d0
commit bcfd983f8d
7 changed files with 23 additions and 16 deletions
+3
View File
@@ -34,6 +34,7 @@ pub fn main() !void {
fn handleArgs(alloc: std.mem.Allocator, out: *Writer) !void { fn handleArgs(alloc: std.mem.Allocator, out: *Writer) !void {
var args = try std.process.argsWithAllocator(alloc); var args = try std.process.argsWithAllocator(alloc);
defer args.deinit(); defer args.deinit();
_ = args.next(); // args[0] is the application launch command.
while (args.next()) |arg| { while (args.next()) |arg| {
if (std.mem.eql(u8, arg, "-o")) { if (std.mem.eql(u8, arg, "-o")) {
const nxt = args.next(); 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", .{}); try out.print("-o must be followed by a number\n", .{});
return errors.InvalidArguments; return errors.InvalidArguments;
}; };
continue;
} else if (std.mem.eql(u8, arg, "-d")) { } else if (std.mem.eql(u8, arg, "-d")) {
const nxt = args.next(); const nxt = args.next();
if (nxt == null or nxt.?.len == 0) { if (nxt == null or nxt.?.len == 0) {
@@ -52,6 +54,7 @@ fn handleArgs(alloc: std.mem.Allocator, out: *Writer) !void {
return errors.InvalidArguments; return errors.InvalidArguments;
} }
extLoc = nxt.?; extLoc = nxt.?;
continue;
} }
if (archive.len > 0) { if (archive.len > 0) {
try out.print("you can only provide one file at a time\n", .{}); try out.print("you can only provide one file at a time\n", .{});
+9 -5
View File
@@ -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 { pub fn gzipDecompress(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize {
_ = alloc;
var rdr: Reader = .fixed(in); 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); 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 { pub fn zstdDecompress(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize {
_ = alloc;
var rdr: Reader = .fixed(in); var rdr: Reader = .fixed(in);
var decomp = std.compress.zstd.Decompress.init(&rdr, &[0]u8{}, .{}); const buf = try alloc.alloc(u8, std.compress.zstd.default_window_len + std.compress.zstd.block_size_max);
return decomp.reader.readSliceShort(out); 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;
};
} }
+3 -7
View File
@@ -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 cur_red: u32 = 3; // start at 3 due to "." & ".." being counted in the dir size.
var hdr: Header = undefined; var hdr: Header = undefined;
var raw: RawEntry = 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); errdefer out.deinit(alloc);
while (cur_red < size) { while (cur_red < size) {
try rdr.readSliceEndian(Header, @ptrCast(&hdr), .little); try rdr.readSliceEndian(Header, @ptrCast(&hdr), .little);
cur_red += @sizeOf(Header); cur_red += @sizeOf(Header);
const count = hdr.count + 1; try out.ensureUnusedCapacity(alloc, hdr.count + 1);
if (out.capacity < count) { for (0..hdr.count + 1) |_| {
// Make sure we have at least 25 capacity past current count.
try out.ensureUnusedCapacity(alloc, ((count % 25) + 2) * 25);
}
for (0..count) |_| {
try rdr.readSliceEndian(RawEntry, @ptrCast(&raw), .little); try rdr.readSliceEndian(RawEntry, @ptrCast(&raw), .little);
const name = try alloc.alloc(u8, raw.name_size + 1); const name = try alloc.alloc(u8, raw.name_size + 1);
errdefer alloc.free(name); errdefer alloc.free(name);
+1 -1
View File
@@ -42,7 +42,7 @@ pub fn init(archive: *Archive, inode: Inode, name: []const u8) !SfsFile {
} }
pub fn fromEntry(archive: *Archive, entry: DirEntry) !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 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); try meta.interface.discardAll(entry.block_offset);
const inode: Inode = try .read(archive.allocator(), &meta.interface, archive.super.block_size); const inode: Inode = try .read(archive.allocator(), &meta.interface, archive.super.block_size);
errdefer inode.deinit(archive.allocator()); errdefer inode.deinit(archive.allocator());
+4 -1
View File
@@ -138,6 +138,9 @@ pub fn extractTo(self: Inode, archive: *Archive, path: []const u8, options: Extr
.dir, .ext_dir => { .dir, .ext_dir => {
// Removing any trailing separators since that's the easiest path forward. // 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); 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(); var alloc = archive.allocator();
const entries = try self.dirEntries(archive); const entries = try self.dirEntries(archive);
defer { defer {
@@ -218,7 +221,7 @@ fn extractRegFile(self: Inode, archive: *Archive, path: []const u8, options: Ext
_ = try dat_rdr.interface.streamRemaining(&wrt.interface); _ = try dat_rdr.interface.streamRemaining(&wrt.interface);
try wrt.interface.flush(); try wrt.interface.flush();
// updateTime is in nanoseconds (a billionth of a second). mod_time is in seconds. // 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) { if (!options.ignore_permissions) {
try fil.chmod(self.hdr.permissions); try fil.chmod(self.hdr.permissions);
try fil.chown(try archive.id(self.hdr.uid_idx), try archive.id(self.hdr.gid_idx)); try fil.chown(try archive.id(self.hdr.uid_idx), try archive.id(self.hdr.gid_idx));
+2 -2
View File
@@ -28,7 +28,7 @@ test "ExtractSingleFile" {
defer sfs.deinit(); defer sfs.deinit();
var test_fil = try sfs.open(TestFile); var test_fil = try sfs.open(TestFile);
defer test_fil.deinit(); defer test_fil.deinit();
try test_fil.extract(TestFileExtractLocation, .VerboseDefault); try test_fil.extract(TestFileExtractLocation, .Default);
//TODO: validate extracted file. //TODO: validate extracted file.
} }
@@ -40,7 +40,7 @@ test "ExtractCompleteArchive" {
defer fil.close(); defer fil.close();
var sfs: Archive = try .init(std.testing.allocator, fil); var sfs: Archive = try .init(std.testing.allocator, fil);
defer sfs.deinit(); defer sfs.deinit();
try sfs.extract(TestFullExtractLocation, .VerboseDefault); try sfs.extract(TestFullExtractLocation, .Default);
} }
const LinuxPATestCorrectSuperblock: Superblock = .{ const LinuxPATestCorrectSuperblock: Superblock = .{
+1
View File
@@ -111,6 +111,7 @@ fn advance(self: *DataReader) !void {
} }
const tmp_buf = try self.alloc.alloc(u8, block.size); const tmp_buf = try self.alloc.alloc(u8, block.size);
defer self.alloc.free(tmp_buf); defer self.alloc.free(tmp_buf);
try rdr.interface.readSliceAll(tmp_buf);
_ = try self.decomp(self.alloc, tmp_buf, self.interface.buffer); _ = try self.decomp(self.alloc, tmp_buf, self.interface.buffer);
} }
/// Does not guarentee that data currently in the buffer is retained. /// Does not guarentee that data currently in the buffer is retained.