Finished (?) extraction

Fixed missing zlib_compat (updated library)
This commit is contained in:
Caleb J. Gardner
2026-06-02 18:31:00 -05:00
parent 01d87f6948
commit c51cc34f17
8 changed files with 70 additions and 36 deletions
+2 -5
View File
@@ -68,10 +68,7 @@ pub fn build(b: *std.Build) !void {
.target = target, .target = target,
.root_source_file = b.path("src/bin/unsquashfs.zig"), .root_source_file = b.path("src/bin/unsquashfs.zig"),
.valgrind = debug, .valgrind = debug,
.imports = &.{ .imports = &.{ .{ .name = "config", .module = exe_config.createModule() }, .{ .name = "squashfs", .module = lib.root_module } },
.{ .name = "config", .module = exe_config.createModule() },
.{ .name = "squashfs", .module = lib.root_module }
},
}), }),
}); });
@@ -104,7 +101,7 @@ fn getDependencies(b: *Build, optimize: std.builtin.OptimizeMode, target: Build.
var list: std.ArrayList(*Build.Step.Compile) = .empty; var list: std.ArrayList(*Build.Step.Compile) = .empty;
const zlib_ng = b.dependency("zlib_ng", .{ .optimize = optimize, .target = target }); const zlib_ng = b.dependency("zlib_ng", .{ .optimize = optimize, .target = target, .zlib_compat = true });
try list.append(alloc, zlib_ng.artifact("zng")); try list.append(alloc, zlib_ng.artifact("zng"));
const xz = b.dependency("xz", .{ .optimize = optimize, .target = target }); const xz = b.dependency("xz", .{ .optimize = optimize, .target = target });
+2 -2
View File
@@ -5,8 +5,8 @@
.minimum_zig_version = "0.16.0", .minimum_zig_version = "0.16.0",
.dependencies = .{ .dependencies = .{
.zlib_ng = .{ .zlib_ng = .{
.url = "git+https://github.com/CalebQ42/zig-zlib-ng#5f2f02dfb28acca2517dacbbd09e9b987f57b133", .url = "git+https://github.com/CalebQ42/zig-zlib-ng#915db2dbd4a540d8a933336d67520b786f168f01",
.hash = "zlib_ng-2.3.3-pre1-2HYS4ClFAABW8KlHMyBHtlNKE3V7kCS8wqfxawG7xeaa", .hash = "zlib_ng-2.3.3-pre1-2HYS4MlFAADc-eSZv4_xjkxZRCdGUVOYZKdtqhybstgk",
}, },
.zstd = .{ .zstd = .{
.url = "git+https://github.com/allyourcodebase/zstd.git?ref=1.5.7-1#e1a501be57f42c541e8a5597e4b59a074dfd09a3", .url = "git+https://github.com/allyourcodebase/zstd.git?ref=1.5.7-1#e1a501be57f42c541e8a5597e4b59a074dfd09a3",
+8 -7
View File
@@ -33,7 +33,7 @@ pub fn addFragment(self: *Extractor, data: []u8, offset: u32) void {
} }
pub fn asyncExtract(self: Extractor, io: Io, fil: Io.File) Error!void { pub fn asyncExtract(self: Extractor, io: Io, fil: Io.File) Error!void {
try fil.writePositionalAll(io, &.{&.{0}}, self.size - 1); try fil.writePositionalAll(io, &.{0}, self.size - 1);
var map = try fil.createMemoryMap(io, .{ .len = self.size, .protection = .{ .write = true } }); var map = try fil.createMemoryMap(io, .{ .len = self.size, .protection = .{ .write = true } });
defer map.destroy(io); defer map.destroy(io);
@@ -59,7 +59,7 @@ pub fn asyncExtract(self: Extractor, io: Io, fil: Io.File) Error!void {
fn blockThread(self: Extractor, io: Io, map: Io.File.MemoryMap, read_offset: u64, idx: usize, ret_err: *?Error) error{Canceled}!void { fn blockThread(self: Extractor, io: Io, map: Io.File.MemoryMap, read_offset: u64, idx: usize, ret_err: *?Error) error{Canceled}!void {
const write_pos = idx * self.block_size; const write_pos = idx * self.block_size;
const size = if (self.frag_data == null and idx == self.block_size.len - 1) const size = if (self.frag_data == null and idx == self.blocks.len - 1)
self.size % self.block_size self.size % self.block_size
else else
self.block_size; self.block_size;
@@ -70,10 +70,10 @@ fn blockThread(self: Extractor, io: Io, map: Io.File.MemoryMap, read_offset: u64
return; return;
} }
if (block.uncompressed) { if (block.uncompressed) {
@memcpy(map[write_pos..][0..size], self.cache.map.memory[read_offset..][0..size]); @memcpy(map.memory[write_pos..][0..size], self.cache.map.memory[read_offset..][0..size]);
return; return;
} }
const data = self.cache.get(io, read_offset, block.size, size) catch |err| switch (err) { const data = self.cache.get(io, read_offset, block.size, @truncate(size)) catch |err| switch (err) {
error.Canceled => { error.Canceled => {
io.recancel(); io.recancel();
return error.Canceled; return error.Canceled;
@@ -86,9 +86,10 @@ fn blockThread(self: Extractor, io: Io, map: Io.File.MemoryMap, read_offset: u64
defer self.cache.finished(io, read_offset); defer self.cache.finished(io, read_offset);
if (data.len != size) { if (data.len != size) {
std.debug.print("Size of decompression at {} is {} and should be {}\n", .{ read_offset, data.len, size }); std.debug.print("Size of decompression at {} is {} and should be {}\n", .{ read_offset, data.len, size });
return Error.BadDecompressionSize; ret_err.* = Error.BadDecompressionSize;
return error.Canceled;
} }
@memcpy(map[write_pos..][0..size], data); @memcpy(map.memory[write_pos..][0..size], data);
} }
fn fragThread(self: Extractor, map: Io.File.MemoryMap) error{Canceled}!void { fn fragThread(self: Extractor, map: Io.File.MemoryMap) error{Canceled}!void {
const write_pos = self.blocks.len * self.block_size; const write_pos = self.blocks.len * self.block_size;
@@ -99,4 +100,4 @@ fn fragThread(self: Extractor, map: Io.File.MemoryMap) error{Canceled}!void {
// Types // Types
pub const Error = error{BadDecompressionSize} || Io.File.WritePositionalError || Io.File.MemoryMap.CreateError; pub const Error = error{BadDecompressionSize} || Io.File.WritePositionalError || Io.File.MemoryMap.CreateError || DecompCache.Error;
+3 -1
View File
@@ -39,7 +39,7 @@ pub fn deinit(self: *DecompCache, io: Io) void {
self.cache.deinit(); self.cache.deinit();
} }
pub fn get(self: *DecompCache, io: Io, offset: u64, compressed_size: u32, max_size: u32) ![]u8 { pub fn get(self: *DecompCache, io: Io, offset: u64, compressed_size: u32, max_size: u32) Error![]u8 {
{ {
try self.mut.lockShared(io); try self.mut.lockShared(io);
defer self.mut.unlockShared(io); defer self.mut.unlockShared(io);
@@ -110,6 +110,8 @@ fn ensureSpace(self: *DecompCache, io: Io, size: u64) !void {
// Types // Types
pub const Error = error{ Canceled, OutOfMemory, ReadFailed };
const Cache = struct { const Cache = struct {
data: []u8, data: []u8,
usage: Atomic(u32), usage: Atomic(u32),
+41 -6
View File
@@ -11,6 +11,7 @@ const Directory = @import("directory.zig");
const DataExtractor = @import("data/extractor.zig"); const DataExtractor = @import("data/extractor.zig");
const DataReader = @import("data/reader.zig"); const DataReader = @import("data/reader.zig");
const Lookup = @import("lookup.zig"); const Lookup = @import("lookup.zig");
const XattrTable = @import("xattr.zig");
pub fn extract(alloc: std.mem.Allocator, io: Io, inode: Inode, cache: *DecompCache, super: Superblock, ext_loc: []const u8, options: ExtractionOptions) !void { pub fn extract(alloc: std.mem.Allocator, io: Io, inode: Inode, cache: *DecompCache, super: Superblock, ext_loc: []const u8, options: ExtractionOptions) !void {
const path = std.mem.trim(u8, ext_loc, "/"); const path = std.mem.trim(u8, ext_loc, "/");
@@ -34,11 +35,17 @@ pub fn extract(alloc: std.mem.Allocator, io: Io, inode: Inode, cache: *DecompCac
} }
} }
var id_table: Lookup.Table(u16) = .init(alloc, cache, super.id_start, super.id_count);
defer id_table.deinit();
var xattr_table: XattrTable = try .init(alloc, cache, super.xattr_start);
defer xattr_table.deinit();
var ret_loop = io.async(returnLoop, .{ alloc, io, &id_table, &xattr_table, &sel, options });
var frag_table: Lookup.Table(Lookup.FragmentEntry) = .init(alloc, cache, super.frag_start, super.frag_count); var frag_table: Lookup.Table(Lookup.FragmentEntry) = .init(alloc, cache, super.frag_start, super.frag_count);
defer frag_table.deinit(); defer frag_table.deinit();
var ret_loop = io.async(returnLoop, .{ alloc, io, &sel, options });
try extractReal(alloc, io, cache, super, &sel, &frag_table, path, inode, null, false); try extractReal(alloc, io, cache, super, &sel, &frag_table, path, inode, null, false);
try ret_loop.await(io); try ret_loop.await(io);
@@ -311,7 +318,7 @@ fn extractNod(alloc: std.mem.Allocator, path: []const u8, inode: Inode, parent:
// Loop // Loop
fn returnLoop(alloc: std.mem.Allocator, io: Io, id_table: Lookup.Table(u16), xattr_table: Lookup.Table(Lookup.XattrEntry), sel: *Io.Select(ReturnUnion), options: ExtractionOptions) !void { fn returnLoop(alloc: std.mem.Allocator, io: Io, id_table: *Lookup.Table(u16), xattr_table: *XattrTable, sel: *Io.Select(ReturnUnion), options: ExtractionOptions) !void {
while (true) { while (true) {
const finished = try sel.await(); const finished = try sel.await();
@@ -339,15 +346,43 @@ fn returnLoop(alloc: std.mem.Allocator, io: Io, id_table: Lookup.Table(u16), xat
try file.setPermissions(io, @enumFromInt(ret.permissions)); try file.setPermissions(io, @enumFromInt(ret.permissions));
try file.setOwner(io, try id_table.get(io, ret.uid_idx), try id_table.get(io, ret.gid_idx)); try file.setOwner(io, try id_table.get(io, ret.uid_idx), try id_table.get(io, ret.gid_idx));
} }
if (!options.ignore_xattr and ret.xattr_idx != null) {} if (!options.ignore_xattr and ret.xattr_idx != null) {
const xattrs = try xattr_table.get(alloc, io, ret.xattr_idx.?);
defer xattrs.deinit(alloc);
for (xattrs.xattrs) |x| {
const res = std.os.linux.fsetxattr(file.handle, x.key, x.value.ptr, x.value.len, 0);
if (res != 0)
return error.SetXattrFailed;
}
}
} }
}, },
.file_ret => |f| { .file_ret => |f| {
const ret = try f; const ret = try f;
if (!ret.origin) alloc.free(ret.path); if (!ret.origin) alloc.free(ret.path);
if (!options.ignore_permissions and !options.ignore_xattr) { if (!options.ignore_permissions and (!options.ignore_xattr and ret.xattr_idx != null)) {
// TODO: set permissions & xattr. const file = try Io.Dir.cwd().openFile(io, ret.path, .{});
defer file.close(io);
if (!options.ignore_permissions) {
try file.setTimestamps(io, .{
.modify_timestamp = .init(.{ .nanoseconds = @as(i96, @intCast(ret.mod_time)) * std.time.ns_per_s }),
});
try file.setPermissions(io, @enumFromInt(ret.permissions));
try file.setOwner(io, try id_table.get(io, ret.uid_idx), try id_table.get(io, ret.gid_idx));
}
if (!options.ignore_xattr and ret.xattr_idx != null) {
const xattrs = try xattr_table.get(alloc, io, ret.xattr_idx.?);
defer xattrs.deinit(alloc);
for (xattrs.xattrs) |x| {
const res = std.os.linux.fsetxattr(file.handle, x.key, x.value.ptr, x.value.len, 0);
if (res != 0)
return error.SetXattrFailed;
}
}
} }
}, },
.void_ret => |v| try v, .void_ret => |v| try v,
+5 -9
View File
@@ -64,7 +64,7 @@ pub fn deinit(self: SfsFile) void {
/// Attempts to open the filepath if the SfsFile is a directory. /// Attempts to open the filepath if the SfsFile is a directory.
/// If the given path refers to itself (such as "" or "."), a copied SfsFile is returned. /// If the given path refers to itself (such as "" or "."), a copied SfsFile is returned.
pub fn open(self: SfsFile, alloc: std.mem.Allocator, io: Io, filepath: []const u8) !SfsFile { pub fn open(self: *SfsFile, alloc: std.mem.Allocator, io: Io, filepath: []const u8) !SfsFile {
const path = std.mem.trim(u8, filepath, "/"); const path = std.mem.trim(u8, filepath, "/");
const first_element: []const u8 = std.mem.sliceTo(path, '/'); const first_element: []const u8 = std.mem.sliceTo(path, '/');
@@ -86,17 +86,13 @@ pub fn open(self: SfsFile, alloc: std.mem.Allocator, io: Io, filepath: []const u
} }
if (first_element.len == path.len) return .initDirEntry(alloc, io, self.archive, cur_slice[idx]); if (first_element.len == path.len) return .initDirEntry(alloc, io, self.archive, cur_slice[idx]);
if (cur_slice[idx].type != .dir) return error.NotFound; if (cur_slice[idx].type != .dir) return error.NotFound;
const tmp_file: SfsFile = try .initDirEntry(alloc, io, self.archive, cur_slice[idx]); var tmp_file: SfsFile = try .initDirEntry(alloc, io, self.archive, cur_slice[idx]);
defer tmp_file.deinit(); defer tmp_file.deinit();
return tmp_file.open(alloc, io, path[first_element.len..]); return tmp_file.open(alloc, io, path[first_element.len..]);
} }
pub fn extract(self: SfsFile, alloc: std.mem.Allocator, io: Io, ext_dir: []const u8, options: ExtractionOptions) !void { const Extract = @import("extract.zig");
_ = self; pub fn extract(self: *SfsFile, alloc: std.mem.Allocator, io: Io, ext_dir: []const u8, options: ExtractionOptions) !void {
_ = alloc; return Extract.extract(alloc, io, self.inode, &self.archive.cache, self.archive.super, ext_dir, options);
_ = io;
_ = ext_dir;
_ = options;
return error.TODO;
} }
+4 -4
View File
@@ -52,7 +52,7 @@ pub fn Table(comptime T: anytype) type {
pub fn deinit(self: *LookupTable) void { pub fn deinit(self: *LookupTable) void {
var iter = self.values.valueIterator(); var iter = self.values.valueIterator();
while (iter.next()) |v| while (iter.next()) |v|
self.alloc.free(v); self.alloc.free(v.*);
self.values.deinit(); self.values.deinit();
} }
@@ -64,7 +64,7 @@ pub fn Table(comptime T: anytype) type {
defer self.mut.unlockShared(io); defer self.mut.unlockShared(io);
const val = self.values.get(block); const val = self.values.get(block);
if (val != null) return val.*[block_idx]; if (val != null) return val.?[block_idx];
} }
try self.mut.lock(io); try self.mut.lock(io);
defer self.mut.unlock(io); defer self.mut.unlock(io);
@@ -75,7 +75,7 @@ pub fn Table(comptime T: anytype) type {
errdefer self.values.removeByPtr(val.key_ptr); errdefer self.values.removeByPtr(val.key_ptr);
const offset_offset = self.table_start + (block * 8); const offset_offset = self.table_start + (block * 8);
const offset: u64 = std.mem.readInt(u64, self.cache.map.memory[offset_offset..][0..2], .little); const offset: u64 = std.mem.readInt(u64, self.cache.map.memory[offset_offset..][0..8], .little);
var meta: MetadataReader = .init(io, self.cache, offset); var meta: MetadataReader = .init(io, self.cache, offset);
defer meta.deinit(io); defer meta.deinit(io);
@@ -98,7 +98,7 @@ pub fn Table(comptime T: anytype) type {
// Types // Types
pub const Error = error{} || std.mem.Allocator.Error; pub const Error = error{Canceled} || std.mem.Allocator.Error || Io.Reader.Error;
pub const FragmentEntry = extern struct { pub const FragmentEntry = extern struct {
start: u64, start: u64,
+4 -1
View File
@@ -21,8 +21,11 @@ pub fn init(alloc: std.mem.Allocator, cache: *DecompCache, xattr_start: u64) !Xa
.table = .init(alloc, cache, xattr_start + 16, num), .table = .init(alloc, cache, xattr_start + 16, num),
}; };
} }
pub fn deinit(self: *XattrTable) void {
self.table.deinit();
}
pub fn get(self: XattrTable, alloc: std.mem.Allocator, io: Io, idx: u32) !XattrKVs { pub fn get(self: *XattrTable, alloc: std.mem.Allocator, io: Io, idx: u32) !XattrKVs {
const entry = try self.table.get(io, idx); const entry = try self.table.get(io, idx);
var meta: MetadataReader = .init(io, self.table.cache, self.table_start + entry.ref.block_start); var meta: MetadataReader = .init(io, self.table.cache, self.table_start + entry.ref.block_start);