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 {
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", .{});
+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 {
_ = 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;
};
}
+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 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);
+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 {
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());
+4 -1
View File
@@ -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));
+2 -2
View File
@@ -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 = .{
+1
View File
@@ -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.