diff --git a/.zed/settings.json b/.zed/settings.json index 25f8c6e..47f4e2e 100644 --- a/.zed/settings.json +++ b/.zed/settings.json @@ -9,14 +9,9 @@ "usePlaceholders": false, }, "settings": { - // "build_on_save": true, + "build_on_save": true, "use_placeholders": false, - "build_on_save_args": [ - "-fincremental", - "-Dallow_lzo=true", - "-Ddebug=true", - "test", - ], + "build_on_save_args": ["-fincremental", "-Dallow_lzo=true"], }, }, }, diff --git a/mise.toml b/mise.toml index 3b9ae66..ef36926 100644 --- a/mise.toml +++ b/mise.toml @@ -1,2 +1,2 @@ [tools] -zig = "master" +zig = "0.16.0" diff --git a/src/archive.zig b/src/archive.zig index 9e60d8e..5f8ecfe 100644 --- a/src/archive.zig +++ b/src/archive.zig @@ -7,6 +7,7 @@ const config = @import("config"); const ExtractionOptions = @import("options.zig"); const File = @import("file.zig"); +const Inode = @import("inode.zig"); const Superblock = @import("super.zig").Superblock; const DecompCache = @import("util/decomp_cache.zig"); const CompressionType = @import("util/decompress.zig").CompressionType; @@ -16,7 +17,6 @@ const Archive = @This(); const CACHE_MIN = 16 * 1024 * 1024; const CACHE_MAX = 1 * 1024 * 1024 * 1024; -map: MemoryMap, cache: DecompCache, super: Superblock, @@ -37,14 +37,6 @@ pub fn initAdvanced(alloc: std.mem.Allocator, io: Io, file: Io.File, offset: u64 if (!config.use_zig_decomp and config.allow_lzo) _ = c.lzo_init(); - const map = try file.createMemoryMap( - io, - .{ - .offset = offset, - .len = super.size, - .protection = .{ .read = true }, - }, - ); const cache_size = blk: { if (max_cache_size > CACHE_MIN) break :blk CACHE_MIN; const sys_mem = std.process.totalSystemMemory() catch break :blk CACHE_MIN; @@ -54,10 +46,16 @@ pub fn initAdvanced(alloc: std.mem.Allocator, io: Io, file: Io.File, offset: u64 break :blk min; }; return .{ - .map = map, .cache = try .init( alloc, - map, + try file.createMemoryMap( + io, + .{ + .offset = offset, + .len = super.size, + .protection = .{ .read = true }, + }, + ), super.compression, cache_size, ), @@ -67,7 +65,6 @@ pub fn initAdvanced(alloc: std.mem.Allocator, io: Io, file: Io.File, offset: u64 } pub fn deinit(self: *Archive, io: Io) void { self.cache.deinit(io); - self.map.destroy(io); } pub fn root(self: *Archive, alloc: std.mem.Allocator, io: Io) !File { @@ -86,10 +83,18 @@ pub fn open(self: *Archive, alloc: std.mem.Allocator, io: Io, filepath: []const } pub fn extract(self: *Archive, alloc: std.mem.Allocator, io: Io, ext_dir: []const u8, options: ExtractionOptions) !void { - _ = self; - _ = alloc; - _ = io; - _ = ext_dir; - _ = options; - return error.TODO; + const root_inode: Inode = try .fromRef(alloc, io, &self.cache, self.super.inode_start, self.super.block_size, self.super.root_ref); + return root_inode.extract( + alloc, + io, + &self.cache, + self.super.dir_start, + self.super.inode_start, + self.super.frag_start, + self.super.block_size, + self.super.id_start, + self.super.xattr_start, + ext_dir, + options, + ); } diff --git a/src/dir_entry.zig b/src/dir_entry.zig index c54430b..80c7c51 100644 --- a/src/dir_entry.zig +++ b/src/dir_entry.zig @@ -15,6 +15,8 @@ const Entry = extern struct { name_size: u16, }; +pub const Error = error{OutOfMemory} || std.Io.Reader.Error; + const DirEntry = @This(); inode_type: Inode.Type, @@ -28,7 +30,7 @@ pub fn deinit(self: DirEntry, alloc: std.mem.Allocator) void { alloc.free(self.name); } -pub fn readEntries(alloc: std.mem.Allocator, rdr: *Reader, size: u32) ![]DirEntry { +pub fn readEntries(alloc: std.mem.Allocator, rdr: *Reader, size: u32) Error![]DirEntry { var out: std.ArrayList(DirEntry) = try .initCapacity(alloc, 50); errdefer out.deinit(alloc); diff --git a/src/file.zig b/src/file.zig index 46e62c9..6f03281 100644 --- a/src/file.zig +++ b/src/file.zig @@ -7,6 +7,7 @@ const Archive = @import("archive.zig"); const DirEntry = @import("dir_entry.zig"); const ExtractionOptions = @import("options.zig"); const Inode = @import("inode.zig"); +const LookupTable = @import("lookup_table.zig"); const MetadataReader = @import("util/metadata.zig"); pub const Error = error{ @@ -108,11 +109,18 @@ pub fn open(self: File, alloc: std.mem.Allocator, io: Io, filepath: []const u8) return fil.open(alloc, io, filepath[first_element.len..]); } -pub fn extract(self: File, alloc: std.mem.Allocator, io: Io, ext_loc: []const u8, options: ExtractionOptions) !void { - _ = self; - _ = alloc; - _ = io; - _ = ext_loc; - _ = options; - return error.TODO; +pub fn extract(self: File, alloc: std.mem.Allocator, io: Io, path: []const u8, options: ExtractionOptions) !void { + return self.inode.extract( + alloc, + io, + &self.archive.cache, + self.archive.super.dir_start, + self.archive.super.inode_start, + self.archive.super.frag_start, + self.archive.super.block_size, + self.archive.super.id_start, + self.archive.super.xattr_start, + path, + options, + ); } diff --git a/src/frag.zig b/src/frag.zig new file mode 100644 index 0000000..9333f24 --- /dev/null +++ b/src/frag.zig @@ -0,0 +1,7 @@ +const BlockSize = @import("inode_data/file.zig").BlockSize; + +pub const FragEntry = extern struct { + start: u64, + size: BlockSize, + _: u32, +}; diff --git a/src/inode.zig b/src/inode.zig index 4ae910e..843e100 100644 --- a/src/inode.zig +++ b/src/inode.zig @@ -5,9 +5,13 @@ const Io = std.Io; const Reader = Io.Reader; const DirEntry = @import("dir_entry.zig"); +const ExtractionOptions = @import("options.zig"); +const FragEntry = @import("frag.zig").FragEntry; const DirTypes = @import("inode_data/dir.zig"); const FileTypes = @import("inode_data/file.zig"); const MiscTypes = @import("inode_data/misc.zig"); +const LookupTable = @import("lookup_table.zig"); +const DataExtract = @import("util/data_extract.zig"); const DecompCache = @import("util/decomp_cache.zig"); const MetadataReader = @import("util/metadata.zig"); @@ -147,3 +151,255 @@ fn readDirectoryFromData(alloc: std.mem.Allocator, io: Io, cache: *DecompCache, return DirEntry.readEntries(alloc, &meta.interface, d.size); } + +// Extraction + +pub const ExtractionError = error{ SetXattr, Mknod, Canceled } || DirEntry.Error || Io.Dir.CreateFileAtomicError || DataExtract.Error || Io.File.Atomic.LinkError || + Io.Dir.SymLinkError; + +const ExtractReturn = struct { + path: []const u8, + inode: Inode, + + fn deinit(self: ExtractReturn, alloc: std.mem.Allocator) void { + self.inode.deinit(alloc); + alloc.free(self.path); + } + fn setMetadata(self: ExtractReturn, alloc: std.mem.Allocator, io: Io, cache: *DecompCache, id_start: u64, xattr_start: u64, options: ExtractionOptions) !void { + defer self.deinit(alloc); + if (options.ignore_permissions and options.ignore_xattr) return; + + var fil = try Io.Dir.cwd().openFile(io, self.path, .{}); + defer fil.close(io); + + if (!options.ignore_permissions) { + try fil.setTimestamps(io, .{ .modify_timestamp = .{ + .new = .{ .nanoseconds = self.inode.hdr.mod_time * std.time.ns_per_s }, + } }); + try fil.setPermissions(io, @enumFromInt(self.inode.hdr.permissions)); + try fil.setOwner( + io, + try LookupTable.lookup(u16, io, cache, id_start, self.inode.hdr.uid_idx), + try LookupTable.lookup(u16, io, cache, id_start, self.inode.hdr.gid_idx), + ); + } + if (options.ignore_xattr or @hasField(std.os, "linux")) return; + const xattr_idx: u32 = switch (self.inode.data) { + .ext_dir => |d| d.xattr_idx, + .ext_file => |f| f.xattr_idx, + .ext_symlink => |s| s.xattr_idx, + .ext_block_dev, .ext_char_dev => |d| d.xattr_idx, + .ext_fifo, .ext_socket => |i| i.xattr_idx, + else => return, + }; + if (xattr_idx == 0xFFFFFFFF) return; + const xattrs = try LookupTable.xattrLookup(alloc, io, cache, xattr_start, xattr_idx); + defer { + for (xattrs) |kv| + kv.deinit(alloc); + alloc.free(xattrs); + } + + for (xattrs) |kv| { + const res = std.os.linux.fsetxattr(fil.handle, kv.key.ptr, kv.value.ptr, kv.value.len, 0); + if (res != 0) + return ExtractionError.SetXattr; + } + } +}; +const ExtractUnion = union { ret: ExtractionError!ExtractReturn }; + +pub fn extract( + self: Inode, + alloc: std.mem.Allocator, + io: Io, + cache: *DecompCache, + dir_start: u64, + inode_start: u64, + frag_start: u64, + block_size: u32, + id_start: u64, + xattr_start: u64, + ext_loc: []const u8, + options: ExtractionOptions, +) !void { + const path = std.mem.trimEnd(u8, ext_loc, "/"); + + var sel_buf: [5]ExtractUnion = undefined; + var sel: Io.Select(ExtractUnion) = .init(io, &sel_buf); + defer sel.cancelDiscard(); + + var meta_loop = io.async(metadataLoop, .{ alloc, io, cache, id_start, xattr_start, &sel, options }); + + sel.async(.ret, extractReal, .{ self, alloc, io, cache, dir_start, inode_start, frag_start, block_size, &sel, path, true }); + + try meta_loop.await(io); +} +fn extractReal( + self: Inode, + alloc: std.mem.Allocator, + io: Io, + cache: *DecompCache, + dir_start: u64, + inode_start: u64, + frag_start: u64, + block_size: u32, + master_sel: *Io.Select(ExtractUnion), + path: []const u8, + origin: bool, +) ExtractionError!ExtractReturn { + errdefer if (!origin) { + self.deinit(alloc); + alloc.free(path); + }; + switch (self.hdr.inode_type) { + .dir, .ext_dir => { + const entries = self.readDirectory(alloc, io, cache, dir_start) catch |err| switch (err) { + error.NotDirectory => unreachable, + else => |e| return e, + }; + defer { + for (entries) |entry| + entry.deinit(alloc); + alloc.free(entries); + } + + var sel_buf: [5]ExtractUnion = undefined; + var sel: Io.Select(ExtractUnion) = .init(io, &sel_buf); + defer sel.cancelDiscard(); + + var dir_loop = io.async(dirLoop, .{ alloc, io, &sel, master_sel }); + + for (entries) |entry| { + var meta: MetadataReader = .init(io, cache, inode_start + entry.block_start); + defer meta.deinit(); + try meta.interface.discardAll(entry.block_offset); + + var new_inode: Inode = try .fromReader(alloc, &meta.interface, block_size); + errdefer new_inode.deinit(alloc); + + const new_path = try std.mem.concat(alloc, u8, &.{ path, "/", entry.name }); + errdefer alloc.free(new_path); + + sel.async(.ret, extractReal, .{ new_inode, alloc, io, cache, dir_start, inode_start, frag_start, block_size, master_sel, new_path, false }); + } + + try dir_loop.await(io); + }, + .file, .ext_file => { + var atomic = try Io.Dir.cwd().createFileAtomic(io, path, .{}); + defer atomic.deinit(io); + + var data: DataExtract = undefined; + var frag_offset: ?u64 = null; + switch (self.data) { + .file => |f| { + data = .init(cache.decomp, cache.map, block_size, f.block_start, f.size, f.block_sizes); + if (f.frag_idx != 0xFFFFFFFF) { + const entry: FragEntry = try LookupTable.lookup(FragEntry, io, cache, frag_start, f.frag_idx); + if (entry.size.uncompressed) { + data.addFrag(cache.map.memory[entry.start..][0..entry.size.size], f.frag_offset); + } else { + frag_offset = entry.start; + const block = try cache.checkoutBlock(io, entry.start, entry.size.size, block_size); + data.addFrag(block, f.frag_offset); + } + } + }, + .ext_file => |f| { + data = .init(cache.decomp, cache.map, block_size, f.block_start, f.size, f.block_sizes); + if (f.frag_idx != 0xFFFFFFFF) { + const entry: FragEntry = try LookupTable.lookup(FragEntry, io, cache, frag_start, f.frag_idx); + if (entry.size.uncompressed) { + data.addFrag(cache.map.memory[entry.start..][0..entry.size.size], f.frag_offset); + } else { + frag_offset = entry.start; + const block = try cache.checkoutBlock(io, entry.start, entry.size.size, block_size); + data.addFrag(block, f.frag_offset); + } + } + }, + else => unreachable, + } + defer if (frag_offset != null) cache.checkinBlock(io, frag_offset.?); + + try data.asyncExtract(alloc, io, atomic.file); + + try atomic.link(io); + }, + .symlink, .ext_symlink => { + const target = switch (self.data) { + .symlink => |s| s.target, + .ext_symlink => |s| s.target, + else => unreachable, + }; + try Io.Dir.cwd().symLink(io, target, path, .{}); + }, + else => { + var dev: u32 = 0; + var mode: u32 = undefined; + + const DT = std.os.linux.DT; + + switch (self.data) { + .block_dev => |d| { + mode = DT.BLK; + dev = d.dev; + }, + .ext_block_dev => |d| { + mode = DT.BLK; + dev = d.dev; + }, + .char_dev => |d| { + mode = DT.CHR; + dev = d.dev; + }, + .ext_char_dev => |d| { + mode = DT.CHR; + dev = d.dev; + }, + .fifo, .ext_fifo => mode = DT.FIFO, + .socket, .ext_socket => mode = DT.SOCK, + else => unreachable, + } + + const sentinel_path = try std.mem.concatWithSentinel(alloc, u8, &.{path}, 0); + defer alloc.free(sentinel_path); + const res = std.os.linux.mknod(sentinel_path, mode, dev); + if (res != 0) + return ExtractionError.Mknod; + }, + } + + return .{ + .path = path, + .inode = self, + }; +} +fn metadataLoop(alloc: std.mem.Allocator, io: Io, cache: *DecompCache, id_start: u64, xattr_start: u64, sel: *Io.Select(ExtractUnion), options: ExtractionOptions) !void { + defer { + while (sel.cancel()) |ret| { + const res = ret.ret catch continue; + res.deinit(alloc); + } + } + while (sel.group.token.load(.unordered) != null) { + const ret = try sel.await(); + + const res = try ret.ret; + + try res.setMetadata(alloc, io, cache, id_start, xattr_start, options); + } +} +fn dirLoop(alloc: std.mem.Allocator, io: Io, dir_sel: *Io.Select(ExtractUnion), master_sel: *Io.Select(ExtractUnion)) ExtractionError!void { + while (dir_sel.group.token.load(.unordered) != null) { + const ret = try dir_sel.await(); + master_sel.queue.putOne(io, ret) catch |err| switch (err) { + error.Closed => { + const res = try ret.ret; + res.deinit(alloc); + }, + else => |e| return e, + }; + } +} diff --git a/src/inode_data/dir.zig b/src/inode_data/dir.zig index 6b45db0..2538dc7 100644 --- a/src/inode_data/dir.zig +++ b/src/inode_data/dir.zig @@ -21,7 +21,7 @@ pub const ExtDir = extern struct { parent_num: u32, idx_count: u16, block_offset: u16, - xattr_id: u32, + xattr_idx: u32, // index: []DirIndex pub fn read(rdr: *Reader) !ExtDir { diff --git a/src/inode_data/file.zig b/src/inode_data/file.zig index d5c3626..7c46d71 100644 --- a/src/inode_data/file.zig +++ b/src/inode_data/file.zig @@ -1,7 +1,7 @@ const std = @import("std"); const Reader = std.Io.Reader; -pub const BlockSize = packed struct { +pub const BlockSize = packed struct(u32) { size: u24, uncompressed: bool, _: u7, diff --git a/src/lookup_table.zig b/src/lookup_table.zig new file mode 100644 index 0000000..37361ff --- /dev/null +++ b/src/lookup_table.zig @@ -0,0 +1,117 @@ +const std = @import("std"); +const Io = std.Io; + +const Inode = @import("inode.zig"); +const DecompCache = @import("util/decomp_cache.zig"); +const MetadataReader = @import("util/metadata.zig"); + +pub fn lookup(comptime T: anytype, io: Io, cache: *DecompCache, table_start: u64, idx: u32) !T { + const PER_BLOCK = 8192 / @sizeOf(T); + + const block_idx = idx / PER_BLOCK; + const block_offset = idx % PER_BLOCK; + + const offset: u64 = std.mem.readInt(u64, cache.map.memory[table_start + (block_idx * 8) ..][0..8], .little); + + var meta: MetadataReader = .init(io, cache, offset); + defer meta.deinit(); + try meta.interface.discardAll(block_offset * @sizeOf(T)); + + var new: T = undefined; + try meta.interface.readSliceEndian(T, @ptrCast(&new), .little); + return new; +} + +pub const XattrKV = struct { + key: [:0]u8, + value: []u8, + + pub fn deinit(self: XattrKV, alloc: std.mem.Allocator) void { + alloc.free(self.key); + alloc.free(self.value); + } +}; + +const LookupValue = extern struct { + ref: Inode.Ref, + count: u32, + size: u32, +}; +const KeyEntry = extern struct { + prefix: packed struct(u16) { + prefix: enum(u8) { + user, + trusted, + security, + }, + out_of_line: bool, + _: u7, + }, + name_size: u8, +}; + +pub fn xattrLookup(alloc: std.mem.Allocator, io: Io, cache: *DecompCache, xattr_start: u64, idx: u32) ![]XattrKV { + const table_start = std.mem.readInt(u64, cache.map.memory[xattr_start..][0..8], .little); + + const val: LookupValue = try lookup( + LookupValue, + io, + cache, + xattr_start + 16, + idx, + ); + + const out = try alloc.alloc(XattrKV, val.count); + errdefer alloc.free(out); + + var meta: MetadataReader = .init(io, cache, table_start + val.ref.block_start); + defer meta.deinit(); + try meta.interface.discardAll(val.ref.block_offset); + + for (out) |*kv| { + var key_entry: KeyEntry = undefined; + try meta.interface.readSliceEndian(KeyEntry, @ptrCast(&key_entry), .little); + + var key_len = key_entry.name_size; + key_len += switch (key_entry.prefix.prefix) { + .user => 5, + .trusted => 8, + .security => 9, + }; + + kv.key = try alloc.allocSentinel(u8, key_len, 0); + errdefer alloc.free(kv.key); + + try meta.interface.readSliceEndian(u8, kv.key, .little); + + if (key_entry.prefix.out_of_line) { + try meta.interface.discardAll(8); + + var ool_ref: Inode.Ref = undefined; + try meta.interface.readSliceEndian(Inode.Ref, @ptrCast(&ool_ref), .little); + + var ool_meta: MetadataReader = .init(io, cache, table_start + ool_ref.block_start); + defer ool_meta.deinit(); + try ool_meta.interface.discardAll(ool_ref.block_offset); + + kv.value = try readValue(alloc, &ool_meta.interface); + errdefer alloc.free(kv.value); + } else { + kv.value = try readValue(alloc, &meta.interface); + } + } + + return out; +} + +fn readValue(alloc: std.mem.Allocator, rdr: *Io.Reader) ![]u8 { + var val_size: u32 = undefined; + try rdr.readSliceEndian(u32, @ptrCast(&val_size), .little); + + const val = try alloc.alloc(u8, val_size); + errdefer alloc.free(val); + + try rdr.readSliceEndian(u8, val, .little); + + return val; +} diff --git a/src/util/c_decomp.zig b/src/util/c_decomp.zig index 57df311..44d4a2f 100644 --- a/src/util/c_decomp.zig +++ b/src/util/c_decomp.zig @@ -2,7 +2,7 @@ const std = @import("std"); const c = @import("c"); -const Error = @import("decompress.zig").DecompressionError; +const Error = @import("decompress.zig").Error; pub fn zlibDecompress(_: std.mem.Allocator, in: []u8, out: []u8) Error!usize { var strem: c.zng_stream = .{ diff --git a/src/util/data_extract.zig b/src/util/data_extract.zig new file mode 100644 index 0000000..b658c92 --- /dev/null +++ b/src/util/data_extract.zig @@ -0,0 +1,84 @@ +const std = @import("std"); +const Io = std.Io; + +const BlockSize = @import("../inode_data/file.zig").BlockSize; +const Decompress = @import("decompress.zig"); + +const DataExtract = @This(); + +decomp: Decompress.Fn, +map: Io.File.MemoryMap, + +block_size: u32, +block_start: u64, +size: u64, +blocks: []BlockSize, + +frag_data: ?[]u8 = null, +frag_offset: u32 = undefined, + +pub fn init(decomp: Decompress.Fn, map: Io.File.MemoryMap, block_size: u32, block_start: u64, size: u64, blocks: []BlockSize) DataExtract { + return .{ + .decomp = decomp, + .map = map, + + .block_size = block_size, + .block_start = block_start, + .size = size, + .blocks = blocks, + }; +} +pub fn addFrag(self: *DataExtract, frag_block: []u8, frag_offset: u32) void { + self.frag_data = frag_block; + self.frag_offset = frag_offset; +} + +pub const Error = error{} || Io.File.MemoryMap.CreateError || Io.File.WritePositionalError || Decompress.Error; + +pub fn asyncExtract(self: DataExtract, alloc: std.mem.Allocator, io: Io, fil: Io.File) Error!void { + var err: ?Error = null; + + var map = try fil.createMemoryMap(io, .{ .len = self.size, .protection = .{ .write = true }, .undefined_contents = true }); + defer map.destroy(io); + + var group: Io.Group = .init; + defer group.cancel(io); + + var offset: u64 = self.block_start; + for (0..self.blocks.len) |i| { + group.async(io, blockThread, .{ self, alloc, map, offset, i, &err }); + offset += self.blocks[i].size; + } + if (self.frag_data != null) + group.async(io, fragThread, .{ self, map }); + + try group.await(io); + if (err != null) return err.?; + return map.write(io); +} +fn blockThread(self: DataExtract, alloc: std.mem.Allocator, map: Io.File.MemoryMap, read_offset: u64, idx: usize, ret_err: *?Error) error{Canceled}!void { + const block = self.blocks[idx]; + const write_offset = idx * self.block_size; + + const size = if (self.frag_data == null and idx == self.blocks.len - 1) + self.size % self.block_size + else + self.block_size; + + if (block.size == 0) { + @memset(map.memory[write_offset..][0..size], 0); + return; + } else if (block.uncompressed) { + @memcpy(self.map.memory[read_offset..][0..size], map.memory[write_offset..][0..size]); + } + var tmp: [1024 * 1024]u8 = undefined; + _ = self.decomp(alloc, self.map.memory[read_offset..][0..block.size], tmp[0..size]) catch |err| { + ret_err.* = err; + return error.Canceled; + }; + @memcpy(map.memory[write_offset..][0..size], tmp[0..size]); +} +fn fragThread(self: DataExtract, map: Io.File.MemoryMap) error{Canceled}!void { + const size = self.size % self.block_size; + @memcpy(map.memory[self.blocks.len * self.block_size ..][0..size], self.frag_data.?[self.frag_offset..][0..size]); +} diff --git a/src/util/decomp_cache.zig b/src/util/decomp_cache.zig index 481d759..78b4313 100644 --- a/src/util/decomp_cache.zig +++ b/src/util/decomp_cache.zig @@ -4,7 +4,7 @@ const ArrayHashMap = std.array_hash_map.Auto; const Atomic = std.atomic.Value; const Decompress = @import("decompress.zig"); -const DecompressFn = Decompress.DecompressFn; +const Fn = Decompress.Fn; const DecompressType = Decompress.CompressionType; const DecompCache = @This(); @@ -15,7 +15,7 @@ const Cache = struct { }; arena: std.heap.ArenaAllocator, -decomp: DecompressFn, +decomp: Fn, map: Io.File.MemoryMap, @@ -42,6 +42,7 @@ pub fn deinit(self: *DecompCache, io: Io) void { self.mut.lockUncancelable(io); self.cache.deinit(self.arena.child_allocator); self.arena.deinit(); + self.map.destroy(io); } fn makeRoom(self: *DecompCache, io: Io, size: u32) !void { @@ -68,7 +69,7 @@ pub fn checkinBlock(self: *DecompCache, io: Io, offset: u64) void { const res = get.?.usage.fetchSub(1, .acq_rel); if (res == 0) self.cond.broadcast(io); } -pub fn checkoutBlock(self: *DecompCache, io: Io, offset: u64, block_size: u32, max_result_size: u32) ![]u8 { +pub fn checkoutBlock(self: *DecompCache, io: Io, offset: u64, data_size: u32, max_result_size: u32) ![]u8 { { try self.mut.lockShared(io); defer self.mut.unlockShared(io); @@ -90,7 +91,7 @@ pub fn checkoutBlock(self: *DecompCache, io: Io, offset: u64, block_size: u32, m var out = try alloc.alloc(u8, max_result_size); errdefer alloc.free(out); - const out_size = try self.decomp(buf_alloc, self.map.memory[offset..][0..block_size], out); + const out_size = try self.decomp(buf_alloc, self.map.memory[offset..][0..data_size], out); if (out_size != max_result_size) { if (alloc.resize(out, out_size)) { out.len = out_size; diff --git a/src/util/decompress.zig b/src/util/decompress.zig index 5fb9225..d619b5f 100644 --- a/src/util/decompress.zig +++ b/src/util/decompress.zig @@ -6,9 +6,9 @@ const config = @import("config"); const c_decomp = @import("c_decomp.zig"); const zig_decomp = @import("zig_decomp.zig"); -pub const DecompressionError = Io.Reader.Error || std.mem.Allocator.Error; +pub const Error = Io.Reader.Error || std.mem.Allocator.Error; -pub const DecompressFn = *const fn (alloc: std.mem.Allocator, in: []u8, out: []u8) DecompressionError!usize; +pub const Fn = *const fn (alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize; pub const CompressionType = enum(u16) { gzip = 1, @@ -19,7 +19,7 @@ pub const CompressionType = enum(u16) { zstd, }; -pub fn getDecompressFn(t: CompressionType) !DecompressFn { +pub fn getDecompressFn(t: CompressionType) !Fn { return if (config.use_zig_decomp) switch (t) { .lzo => error.LzoUnsupported, .lz4 => error.Lz4Unsupported, diff --git a/src/util/zig_decomp.zig b/src/util/zig_decomp.zig index 5e114d3..9cb0d10 100644 --- a/src/util/zig_decomp.zig +++ b/src/util/zig_decomp.zig @@ -5,7 +5,7 @@ const zstd = std.compress.zstd; const xz = std.compress.xz; const lzma = std.compress.lzma; -const Error = @import("decompress.zig").DecompressionError; +const Error = @import("decompress.zig").Error; pub fn zlibDecompress(_: std.mem.Allocator, in: []u8, out: []u8) Error!usize { var buf: [flate.max_window_len]u8 = undefined;