Moved a lot of things to have explicit alloc arguments

Changed Table to be stateless
This commit is contained in:
Caleb J. Gardner
2026-02-15 10:31:42 -06:00
parent b7b99325da
commit 9a710b98cf
11 changed files with 172 additions and 264 deletions
+36 -91
View File
@@ -31,121 +31,66 @@ pub const FragEntry = packed struct {
const Archive = @This();
// 4 Gigs
const DEFAULT_MEM_SIZE = 4 * 1024 * 1024 * 1024;
parent_alloc: std.mem.Allocator,
alloc: std.heap.ThreadSafeAllocator,
// alloc: std.heap.FixedBufferAllocator,
// fixed_buf: []u8,
thread_count: usize,
fil: OffsetFile,
super: Superblock,
setup: bool = false,
decomp: Decomp.DecompFn,
frag_table: Table(FragEntry) = undefined,
id_table: Table(u16) = undefined,
export_table: Table(InodeRef) = undefined,
frag_table: Table(FragEntry),
id_table: Table(u16),
export_table: Table(InodeRef),
/// Default settings using std.Thread.getCpuCount() threads and the minimum of 4gb or half of system memory for memory usage.
pub fn init(alloc: std.mem.Allocator, fil: File) !Archive {
return initAdvanced(
alloc,
fil,
0,
try std.Thread.getCpuCount(),
);
}
/// Create the Archive dictating the amount of threads used for extraction.
/// If you're planning on only interacting with a small number of files, it should be fine to use few (or one) threads.
pub fn initAdvanced(alloc: std.mem.Allocator, fil: File, offset: u64, threads: usize) !Archive {
/// Begin reading a squashfs archive from the given File at the given offset.
pub fn init(fil: File, offset: u64) !Archive {
var super: Superblock = undefined;
const red = try fil.pread(@ptrCast(&super), offset);
std.debug.assert(red == @sizeOf(Superblock));
_ = try fil.pread(@ptrCast(&super), offset);
try super.validate();
// const fixed_buf = try alloc.alloc(u8, mem);
const decomp: Decomp.DecompFn = switch (super.compression) {
.gzip => Decomp.gzipDecompress,
.lzma => Decomp.lzmaDecompress,
.xz => Decomp.xzDecompress,
.zstd => Decomp.zstdDecompress,
.lz4 => if (config.use_c_libs) Decomp.cLz4 else return error.Lz4Unsupported,
.lzo => if (config.use_c_libs and config.allow_lzo) Decomp.lzoDecompress else return error.LzoUnsupported,
};
const offset_fil: OffsetFile = .init(fil, offset);
return .{
.parent_alloc = alloc,
.alloc = .{ .child_allocator = alloc },
// .fixed_buf = fixed_buf,
.thread_count = if (threads > 0) threads else try std.Thread.getCpuCount(),
.fil = .init(fil, offset),
.decomp = switch (super.compression) {
.gzip => Decomp.gzipDecompress,
.lzma => Decomp.lzmaDecompress,
.xz => Decomp.xzDecompress,
.zstd => Decomp.zstdDecompress,
.lz4 => if (config.use_c_libs) Decomp.cLz4 else return error.Lz4Unsupported,
.lzo => if (config.use_c_libs and config.allow_lzo) Decomp.lzoDecompress else return error.LzoUnsupported,
},
.fil = offset_fil,
.super = super,
.decomp = decomp,
.frag_table = .init(offset_fil, decomp, super.frag_start, super.frag_count),
.id_table = .init(offset_fil, decomp, super.id_start, super.id_count),
.export_table = .init(offset_fil, decomp, super.export_start, super.inode_count),
};
}
pub fn deinit(self: *Archive) void {
// self.parent_alloc.free(self.fixed_buf);
if (self.setup) {
self.frag_table.deinit();
self.export_table.deinit();
self.id_table.deinit();
}
}
pub fn allocator(self: *Archive) std.mem.Allocator {
return self.alloc.allocator();
}
fn setupValues(self: *Archive) !void {
const alloc = self.allocator();
self.frag_table = try .init(alloc, self.fil, self.decomp, self.super.frag_start, self.super.frag_count);
self.id_table = try .init(alloc, self.fil, self.decomp, self.super.id_start, self.super.id_count);
self.export_table = try .init(alloc, self.fil, self.decomp, self.super.export_start, self.super.inode_count);
self.setup = true;
}
pub fn id(self: *Archive, idx: u32) !u16 {
if (!self.setup) try self.setupValues();
return self.id_table.get(idx);
}
pub fn frag(self: *Archive, idx: u32) !FragEntry {
if (!self.setup) try self.setupValues();
return self.frag_table.get(idx);
}
pub fn inode(self: *Archive, num: u32) !Inode {
pub fn inode(self: Archive, num: u32) !Inode {
if (!self.setup) try self.setupValues();
const ref = try self.export_table.get(num - 1);
var rdr = try self.fil.readerAt(ref.block_start + self.super.inode_start, &[0]u8{});
var meta: MetadataReader = .init(self.allocator(), &rdr.interface, &self.decomp);
var meta: MetadataReader = .init(self.alloc, &rdr.interface, &self.decomp);
try meta.interface.discardAll(ref.block_offset);
return try .read(self.allocator(), &meta.interface, self.super.block_size);
return try .read(self.alloc, &meta.interface, self.super.block_size);
}
pub fn root(self: *Archive) !SfsFile {
if (!self.setup) try self.setupValues();
pub fn root(self: Archive, alloc: std.mem.Allocator) !SfsFile {
var rdr = try self.fil.readerAt(self.super.root_ref.block_start + self.super.inode_start, &[0]u8{});
var meta: MetadataReader = .init(self.allocator(), &rdr.interface, self.decomp);
var meta: MetadataReader = .init(alloc, &rdr.interface, self.decomp);
try meta.interface.discardAll(self.super.root_ref.block_offset);
const in: Inode = try .read(self.allocator(), &meta.interface, self.super.block_size);
return .init(self, in, "");
const in: Inode = try .read(alloc, &meta.interface, self.super.block_size);
return .init(alloc, self, in, "");
}
pub fn open(self: *Archive, path: []const u8) !SfsFile {
if (!self.setup) try self.setupValues();
var root_fil = try self.root();
pub fn open(self: Archive, alloc: std.mem.Allocator, path: []const u8) !SfsFile {
var root_fil = try self.root(alloc);
defer if (!SfsFile.pathIsSelf(path)) root_fil.deinit();
return root_fil.open(path);
return root_fil.open(alloc, path);
}
pub fn extract(self: *Archive, path: []const u8, options: ExtractionOptions) !void {
if (!self.setup) try self.setupValues();
var alloc = self.allocator();
pub fn extract(self: Archive, alloc: std.mem.Allocator, path: []const u8, options: ExtractionOptions) !void {
var ext_path: []u8 = undefined;
if (std.fs.cwd().statFile(path)) |stat| {
if (stat.kind == .directory) {
@@ -161,8 +106,8 @@ pub fn extract(self: *Archive, path: []const u8, options: ExtractionOptions) !vo
}
defer if (ext_path.len > path.len) alloc.free(ext_path);
var rdr = try self.fil.readerAt(self.super.root_ref.block_start + self.super.inode_start, &[0]u8{});
var meta: MetadataReader = .init(self.allocator(), &rdr.interface, self.decomp);
var meta: MetadataReader = .init(alloc, &rdr.interface, self.decomp);
try meta.interface.discardAll(self.super.root_ref.block_offset);
const in: Inode = try .read(self.allocator(), &meta.interface, self.super.block_size);
try in.extractToThreaded(self, ext_path, options, self.thread_count);
const in: Inode = try .read(alloc, &meta.interface, self.super.block_size);
try in.extractTo(alloc, self, ext_path, options);
}