Finished (theoretically) file extraction.

This commit is contained in:
Caleb Gardner
2026-05-30 17:29:50 -05:00
parent 578911ba67
commit c52fb15609
2 changed files with 70 additions and 19 deletions
+53 -12
View File
@@ -10,17 +10,36 @@ const Superblock = @import("archive.zig").Superblock;
const Directory = @import("directory.zig"); 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");
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, "/");
var buf: [50]ReturnUnion = undefined; var buf: [50]ReturnUnion = undefined;
var sel: Io.Select(ReturnUnion) = .init(io, &buf); var sel: Io.Select(ReturnUnion) = .init(io, &buf);
defer sel.cancelDiscard();
defer {
while (sel.cancel()) |ret| {
switch (ret) {
.dir_ret => |d| {
const res = d catch continue;
alloc.free(res.path);
},
.file_ret => |f| {
const res = f catch continue;
alloc.free(res.path);
},
else => {},
}
}
}
var frag_table: Lookup.Table(Lookup.FragmentEntry) = .init(alloc, cache, super.frag_start, super.frag_count);
defer frag_table.deinit();
var ret_loop = io.async(returnLoop, .{ alloc, &sel, options }); var ret_loop = io.async(returnLoop, .{ alloc, &sel, options });
try extractReal(alloc, io, cache, super, &sel, path, inode, null, false); try extractReal(alloc, io, cache, super, &sel, &frag_table, path, inode, null, false);
ret_loop.await(io) catch |err| { ret_loop.await(io) catch |err| {
// TODO: Drain sel // TODO: Drain sel
@@ -34,6 +53,7 @@ fn extractReal(
cache: *DecompCache, cache: *DecompCache,
super: Superblock, super: Superblock,
sel: *Io.Select(ReturnUnion), sel: *Io.Select(ReturnUnion),
frag_table: *Lookup.Table(Lookup.FragmentEntry),
path: []const u8, path: []const u8,
inode: Inode, inode: Inode,
parent: ?*Atomic(usize), parent: ?*Atomic(usize),
@@ -45,7 +65,12 @@ fn extractReal(
.dir, .ext_dir => sel.async( .dir, .ext_dir => sel.async(
.dir_ret, .dir_ret,
extractDir, extractDir,
.{ alloc, io, cache, super, sel, path, inode, parent, origin }, .{ alloc, io, cache, super, sel, frag_table, path, inode, parent, origin },
),
.file, .ext_file => sel.async(
.file_ret,
extractFile,
.{ alloc, io, cache, super.block_size, frag_table, path, inode, parent, origin },
), ),
else => return error.Canceled, else => return error.Canceled,
} }
@@ -57,6 +82,7 @@ fn extractDir(
cache: *DecompCache, cache: *DecompCache,
super: Superblock, super: Superblock,
sel: *Io.Select(ReturnUnion), sel: *Io.Select(ReturnUnion),
frag_table: *Lookup.Table(Lookup.FragmentEntry),
path: []const u8, path: []const u8,
inode: Inode, inode: Inode,
parent: ?*Atomic(usize), parent: ?*Atomic(usize),
@@ -106,6 +132,7 @@ fn extractDir(
cache, cache,
super, super,
sel, sel,
frag_table,
new_path, new_path,
new_inode, new_inode,
sub_files, sub_files,
@@ -119,6 +146,7 @@ fn extractFile(
io: Io, io: Io,
cache: *DecompCache, cache: *DecompCache,
block_size: u32, block_size: u32,
frag_table: *Lookup.Table(Lookup.FragmentEntry),
path: []const u8, path: []const u8,
inode: Inode, inode: Inode,
parent: ?*Atomic(usize), parent: ?*Atomic(usize),
@@ -131,7 +159,7 @@ fn extractFile(
} }
errdefer if (!origin) alloc.free(path); errdefer if (!origin) alloc.free(path);
const atomic = try Io.Dir.cwd().createFileAtomic(io, path, .{}); var atomic = try Io.Dir.cwd().createFileAtomic(io, path, .{});
defer atomic.deinit(io); defer atomic.deinit(io);
var ret: FileReturn = .{ var ret: FileReturn = .{
@@ -144,29 +172,42 @@ fn extractFile(
.mod_time = inode.hdr.mod_time, .mod_time = inode.hdr.mod_time,
}; };
var data: DataExtractor = switch (inode.data) { const data: DataExtractor = switch (inode.data) {
.file => |f| blk: { .file => |f| blk: {
var data: DataExtractor = .init(cache, block_size, f.size, f.data_start, f.blocks); var data: DataExtractor = .init(cache, block_size, f.size, f.data_start, f.blocks);
if (f.frag_idx != 0xFFFFFFFF) { if (f.frag_idx != 0xFFFFFFFF) {
// TODO const entry: Lookup.FragmentEntry = try frag_table.get(io, f.frag_idx);
if (entry.size.uncompressed) {
data.addFragment(cache.map.memory[entry.start..][0..entry.size.size], f.frag_offset);
} else {
const block = try cache.get(io, entry.start, entry.size.size, block_size);
data.addFragment(block, f.frag_offset);
}
} }
break :blk data; break :blk data;
}, },
.ext_file => |f| blk: { .ext_file => |f| blk: {
var data: DataExtractor = .init(cache, block_size, f.size, f.data_start, f.blocks); var data: DataExtractor = .init(cache, block_size, f.size, f.data_start, f.blocks);
if (f.frag_idx != 0xFFFFFFFF) { if (f.frag_idx != 0xFFFFFFFF) {
//TODO const entry: Lookup.FragmentEntry = try frag_table.get(io, f.frag_idx);
if (entry.size.uncompressed) {
data.addFragment(cache.map.memory[entry.start..][0..entry.size.size], f.frag_offset);
} else {
const block = try cache.get(io, entry.start, entry.size.size, block_size);
data.addFragment(block, f.frag_offset);
}
} }
if (f.xattr_idx != 0xFFFFFFFF)
ret.xattr_idx = f.xattr_idx;
break :blk data; break :blk data;
}, },
else => unreachable, else => unreachable,
}; };
try data.asyncExtract(io, atomic.file);
try atomic.link(io); try atomic.link(io);
// return .{
// .path = path, return ret;
// };
return error.Canceled;
} }
// Loop // Loop
@@ -215,7 +256,7 @@ const ReturnUnion = union(enum) {
void_ret: Error!void, void_ret: Error!void,
}; };
const Error = error{Canceled} || Directory.Error; const Error = error{Canceled} || Directory.Error || Io.Dir.CreateFileAtomicError || Io.File.Atomic.LinkError || DataExtractor.Error;
const FileReturn = struct { const FileReturn = struct {
path: []const u8, path: []const u8,
+17 -7
View File
@@ -1,6 +1,8 @@
const std = @import("std"); const std = @import("std");
const Io = std.Io; const Io = std.Io;
const DataBlock = @import("inode.zig").DataBlock;
const InodeRef = @import("inode.zig").Ref;
const DecompCache = @import("decomp_cache.zig"); const DecompCache = @import("decomp_cache.zig");
const MetadataReader = @import("meta_rdr.zig"); const MetadataReader = @import("meta_rdr.zig");
@@ -26,7 +28,7 @@ pub fn Table(comptime T: anytype) type {
return struct { return struct {
const PER_BLOCK = 8192 / @sizeOf(T); const PER_BLOCK = 8192 / @sizeOf(T);
const Table = @This(); const LookupTable = @This();
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
@@ -35,9 +37,9 @@ pub fn Table(comptime T: anytype) type {
num: u32, num: u32,
values: std.AutoHashMap(u32, []T), values: std.AutoHashMap(u32, []T),
mut: Io.RwLock, mut: Io.RwLock = .init,
pub fn init(alloc: std.mem.Allocator, cache: *DecompCache, table_start: u64, num_values: u32) Table { pub fn init(alloc: std.mem.Allocator, cache: *DecompCache, table_start: u64, num_values: u32) LookupTable {
return .{ return .{
.alloc = alloc, .alloc = alloc,
@@ -48,14 +50,14 @@ pub fn Table(comptime T: anytype) type {
.values = .init(alloc), .values = .init(alloc),
}; };
} }
pub fn deinit(self: *Table) 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();
} }
pub fn get(self: *Table, io: Io, idx: u32) Error!T { pub fn get(self: *LookupTable, io: Io, idx: u32) Error!T {
const block = idx / PER_BLOCK; const block = idx / PER_BLOCK;
const block_idx = idx % PER_BLOCK; const block_idx = idx % PER_BLOCK;
{ {
@@ -99,6 +101,14 @@ pub fn Table(comptime T: anytype) type {
pub const Error = error{} || std.mem.Allocator.Error; pub const Error = error{} || std.mem.Allocator.Error;
pub const FragmentEntry = extern struct {}; pub const FragmentEntry = extern struct {
start: u64,
size: DataBlock,
_: u32,
};
pub const XattrEntry = extern struct {}; pub const XattrEntry = extern struct {
ref: InodeRef,
count: u32,
size: u32,
};