diff --git a/src/extract.zig b/src/extract.zig index 6d571f7..2ce7975 100644 --- a/src/extract.zig +++ b/src/extract.zig @@ -10,17 +10,36 @@ const Superblock = @import("archive.zig").Superblock; const Directory = @import("directory.zig"); const DataExtractor = @import("data/extractor.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 { const path = std.mem.trim(u8, ext_loc, "/"); var buf: [50]ReturnUnion = undefined; 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 }); - 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| { // TODO: Drain sel @@ -34,6 +53,7 @@ fn extractReal( cache: *DecompCache, super: Superblock, sel: *Io.Select(ReturnUnion), + frag_table: *Lookup.Table(Lookup.FragmentEntry), path: []const u8, inode: Inode, parent: ?*Atomic(usize), @@ -45,7 +65,12 @@ fn extractReal( .dir, .ext_dir => sel.async( .dir_ret, 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, } @@ -57,6 +82,7 @@ fn extractDir( cache: *DecompCache, super: Superblock, sel: *Io.Select(ReturnUnion), + frag_table: *Lookup.Table(Lookup.FragmentEntry), path: []const u8, inode: Inode, parent: ?*Atomic(usize), @@ -106,6 +132,7 @@ fn extractDir( cache, super, sel, + frag_table, new_path, new_inode, sub_files, @@ -119,6 +146,7 @@ fn extractFile( io: Io, cache: *DecompCache, block_size: u32, + frag_table: *Lookup.Table(Lookup.FragmentEntry), path: []const u8, inode: Inode, parent: ?*Atomic(usize), @@ -131,7 +159,7 @@ fn extractFile( } 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); var ret: FileReturn = .{ @@ -144,29 +172,42 @@ fn extractFile( .mod_time = inode.hdr.mod_time, }; - var data: DataExtractor = switch (inode.data) { + const data: DataExtractor = switch (inode.data) { .file => |f| blk: { var data: DataExtractor = .init(cache, block_size, f.size, f.data_start, f.blocks); 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; }, .ext_file => |f| blk: { var data: DataExtractor = .init(cache, block_size, f.size, f.data_start, f.blocks); 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; }, else => unreachable, }; + try data.asyncExtract(io, atomic.file); try atomic.link(io); - // return .{ - // .path = path, - // }; - return error.Canceled; + + return ret; } // Loop @@ -215,7 +256,7 @@ const ReturnUnion = union(enum) { 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 { path: []const u8, diff --git a/src/lookup.zig b/src/lookup.zig index 44cd2cf..1117fa2 100644 --- a/src/lookup.zig +++ b/src/lookup.zig @@ -1,6 +1,8 @@ const std = @import("std"); const Io = std.Io; +const DataBlock = @import("inode.zig").DataBlock; +const InodeRef = @import("inode.zig").Ref; const DecompCache = @import("decomp_cache.zig"); const MetadataReader = @import("meta_rdr.zig"); @@ -26,7 +28,7 @@ pub fn Table(comptime T: anytype) type { return struct { const PER_BLOCK = 8192 / @sizeOf(T); - const Table = @This(); + const LookupTable = @This(); alloc: std.mem.Allocator, @@ -35,9 +37,9 @@ pub fn Table(comptime T: anytype) type { num: u32, 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 .{ .alloc = alloc, @@ -48,14 +50,14 @@ pub fn Table(comptime T: anytype) type { .values = .init(alloc), }; } - pub fn deinit(self: *Table) void { + pub fn deinit(self: *LookupTable) void { var iter = self.values.valueIterator(); while (iter.next()) |v| self.alloc.free(v); 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 = idx % PER_BLOCK; { @@ -99,6 +101,14 @@ pub fn Table(comptime T: anytype) type { 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, +};