Try 4, lol.
This commit is contained in:
+14
-128
@@ -1,139 +1,25 @@
|
||||
const std = @import("std");
|
||||
|
||||
const inode = @import("inode/inode.zig");
|
||||
|
||||
const Table = @import("table.zig").Table;
|
||||
const FileHolder = @import("readers/file_holder.zig").FileHolder;
|
||||
const Superblock = @import("superblock.zig").Superblock;
|
||||
const File = @import("file.zig").File;
|
||||
const MetadataReader = @import("readers/metadata.zig").MetadataReader;
|
||||
const DirEntry = @import("directory.zig").DirEntry;
|
||||
const FragEntry = @import("fragment.zig").FragEntry;
|
||||
|
||||
/// A squashfs archive reader. Make sure to call deinit().
|
||||
/// For most actions, you'll want to use Reader.root.
|
||||
pub const Reader = struct {
|
||||
alloc: std.mem.Allocator,
|
||||
holder: FileHolder,
|
||||
super: Superblock,
|
||||
root: File,
|
||||
pub fn Reader(comptime T: type) type {
|
||||
std.debug.assert(std.meta.hasFn(T, "pread"));
|
||||
|
||||
frag_table: Table(FragEntry),
|
||||
export_table: Table(inode.InodeRef),
|
||||
id_table: Table(u32),
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator, filepath: []const u8, offset: u64) !Reader {
|
||||
var holder: FileHolder = try .init(filepath, offset);
|
||||
const super: Superblock = try holder.reader().readStruct(Superblock);
|
||||
try super.validate();
|
||||
var out: Reader = .{
|
||||
.alloc = alloc,
|
||||
.holder = holder,
|
||||
.super = super,
|
||||
.root = undefined,
|
||||
.frag_table = undefined,
|
||||
.export_table = undefined,
|
||||
.id_table = undefined,
|
||||
};
|
||||
out.frag_table = .init(
|
||||
&out,
|
||||
super.frag_table_start,
|
||||
super.frag_count,
|
||||
);
|
||||
out.export_table = .init(
|
||||
&out,
|
||||
super.export_table_start,
|
||||
super.inode_count,
|
||||
);
|
||||
out.id_table = .init(
|
||||
&out,
|
||||
super.id_table_start,
|
||||
super.id_count,
|
||||
);
|
||||
out.root = try out.rootFile();
|
||||
return out;
|
||||
}
|
||||
pub fn deinit(self: *Reader) void {
|
||||
self.frag_table.deinit(self.alloc);
|
||||
self.export_table.deinit(self.alloc);
|
||||
self.id_table.deinit(self.alloc);
|
||||
self.root.deinit(self.alloc);
|
||||
self.holder.deinit();
|
||||
}
|
||||
alloc: std.mem.Allocator,
|
||||
rdr: T,
|
||||
|
||||
pub fn open(self: *Reader, path: []const u8) !File {
|
||||
return self.root.open(self, path);
|
||||
}
|
||||
super: Superblock = undefined,
|
||||
|
||||
fn rootFile(self: *Reader) !File {
|
||||
var offset_rdr = self.holder.readerAt(self.super.root_ref.block_start + self.super.inode_table_start);
|
||||
var meta_rdr: MetadataReader = .init(
|
||||
self.alloc,
|
||||
self.super.decomp,
|
||||
offset_rdr.any(),
|
||||
);
|
||||
defer meta_rdr.deinit();
|
||||
try meta_rdr.skip(self.super.root_ref.offset);
|
||||
return .{
|
||||
.name = "",
|
||||
.inode = try .init(
|
||||
self.alloc,
|
||||
meta_rdr.any(),
|
||||
self.super.block_size,
|
||||
),
|
||||
.parent_path = "",
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const test_sfs_path = "testing/LinuxPATest.sfs";
|
||||
|
||||
test "root iter" {
|
||||
var rdr: Reader = try .init(std.testing.allocator, test_sfs_path, 0);
|
||||
defer rdr.deinit();
|
||||
var rootIter = try rdr.root.iterator(&rdr);
|
||||
defer rootIter.deinit();
|
||||
while (rootIter.next()) |f| {
|
||||
std.debug.print("{s}\n", .{f.name});
|
||||
}
|
||||
}
|
||||
|
||||
test "extract single file" {
|
||||
const sfs_file_path = "PortableApps/Cool_Retro_Term-dac2b4f-x86_64.AppImage";
|
||||
const extract_path = "testing/Cool_Retro_Term-dac2b4f-x86_64.AppImage";
|
||||
std.fs.cwd().deleteFile(extract_path) catch |err| {
|
||||
if (err != std.fs.Dir.DeleteFileError.FileNotFound) {
|
||||
return err;
|
||||
pub fn init(alloc: std.mem.Allocator, rdr: T) Self {
|
||||
const out = Self{
|
||||
.alloc = alloc,
|
||||
.rdr = rdr,
|
||||
};
|
||||
_ = try rdr.pread(std.mem.asBytes(&out.super), 0);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
var rdr: Reader = try .init(std.testing.allocator, test_sfs_path, 0);
|
||||
defer rdr.deinit();
|
||||
var fil = try rdr.open(sfs_file_path);
|
||||
defer fil.deinit(std.testing.allocator);
|
||||
try fil.extract(&rdr, try .init(), extract_path);
|
||||
}
|
||||
|
||||
test "extract single directory" {
|
||||
const sfs_file_path = "Documents";
|
||||
const extract_path = "testing/Documents";
|
||||
try std.fs.cwd().deleteTree(extract_path);
|
||||
var rdr: Reader = try .init(std.testing.allocator, test_sfs_path, 0);
|
||||
defer rdr.deinit();
|
||||
var fil = try rdr.open(sfs_file_path);
|
||||
defer fil.deinit(std.testing.allocator);
|
||||
var config: File.ExtractConfig = try .init();
|
||||
config.verbose = true;
|
||||
try fil.extract(&rdr, config, extract_path);
|
||||
}
|
||||
|
||||
test "full extract" {
|
||||
const extract_path = "testing/testExtract";
|
||||
std.fs.cwd().deleteTree(extract_path) catch |err| {
|
||||
if (err != std.fs.Dir.DeleteFileError.FileNotFound) {
|
||||
return err;
|
||||
}
|
||||
};
|
||||
var rdr: Reader = try .init(std.testing.allocator, test_sfs_path, 0);
|
||||
defer rdr.deinit();
|
||||
try rdr.root.extract(&rdr, try .init(), extract_path);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user