Compare commits
2 Commits
84a9cf17b9
...
8186c3fe9a
| Author | SHA1 | Date | |
|---|---|---|---|
| 8186c3fe9a | |||
| 2b49395ab2 |
@@ -24,6 +24,16 @@ pub fn build(b: *std.Build) !void {
|
|||||||
.use_llvm = debug,
|
.use_llvm = debug,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const zstd = b.dependency("zstd", .{ .optimize = optimize, .target = target });
|
||||||
|
lib.root_module.linkLibrary(zstd.artifact("zstd"));
|
||||||
|
|
||||||
|
const c = b.addTranslateC(.{
|
||||||
|
.optimize = optimize,
|
||||||
|
.target = target,
|
||||||
|
.root_source_file = b.path("src/c.h"),
|
||||||
|
});
|
||||||
|
lib.root_module.addImport("c", c.createModule());
|
||||||
|
|
||||||
var version = version_string_option orelse "0.0.0-testing";
|
var version = version_string_option orelse "0.0.0-testing";
|
||||||
if (version[0] == 'v') version = version[1..];
|
if (version[0] == 'v') version = version[1..];
|
||||||
const unsquashfs_options = b.addOptions();
|
const unsquashfs_options = b.addOptions();
|
||||||
@@ -52,11 +62,18 @@ pub fn build(b: *std.Build) !void {
|
|||||||
|
|
||||||
const mod_tests = b.addTest(.{
|
const mod_tests = b.addTest(.{
|
||||||
.root_module = b.createModule(.{
|
.root_module = b.createModule(.{
|
||||||
.optimize = optimize,
|
.optimize = .Debug,
|
||||||
.target = target,
|
.target = target,
|
||||||
.root_source_file = b.path("src/test.zig"),
|
.root_source_file = b.path("src/test.zig"),
|
||||||
|
.imports = &.{
|
||||||
|
.{ .name = "c", .module = c.createModule() },
|
||||||
|
},
|
||||||
|
.valgrind = true,
|
||||||
}),
|
}),
|
||||||
|
.use_llvm = true,
|
||||||
});
|
});
|
||||||
|
mod_tests.root_module.linkLibrary(zstd.artifact("zstd"));
|
||||||
|
|
||||||
const run_mod_tests = b.addRunArtifact(mod_tests);
|
const run_mod_tests = b.addRunArtifact(mod_tests);
|
||||||
const test_step = b.step("test", "Run tests");
|
const test_step = b.step("test", "Run tests");
|
||||||
test_step.dependOn(&run_mod_tests.step);
|
test_step.dependOn(&run_mod_tests.step);
|
||||||
|
|||||||
+6
-19
@@ -1,6 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Io = std.Io;
|
const Io = std.Io;
|
||||||
|
|
||||||
|
const Decomp = @import("decomp.zig");
|
||||||
const ExtractionOptions = @import("options.zig");
|
const ExtractionOptions = @import("options.zig");
|
||||||
const File = @import("file.zig");
|
const File = @import("file.zig");
|
||||||
const Inode = @import("inode.zig");
|
const Inode = @import("inode.zig");
|
||||||
@@ -15,7 +16,7 @@ const Archive = @This();
|
|||||||
file: OffsetFile,
|
file: OffsetFile,
|
||||||
super: Superblock,
|
super: Superblock,
|
||||||
|
|
||||||
stateless_decomp: Decompressor,
|
stateless_decomp: *const Decompressor,
|
||||||
|
|
||||||
pub fn init(io: Io, file: std.Io.File, offset: u64) !Archive {
|
pub fn init(io: Io, file: std.Io.File, offset: u64) !Archive {
|
||||||
var rdr = file.reader(io, &[0]u8{});
|
var rdr = file.reader(io, &[0]u8{});
|
||||||
@@ -26,14 +27,7 @@ pub fn init(io: Io, file: std.Io.File, offset: u64) !Archive {
|
|||||||
.file = .init(file, offset),
|
.file = .init(file, offset),
|
||||||
.super = super,
|
.super = super,
|
||||||
|
|
||||||
.stateless_decomp = switch (super.compression) {
|
.stateless_decomp = try Decomp.StatelessDecomp(super.compression),
|
||||||
.gzip => @import("decomp/zlib.zig").stateless_decompressor,
|
|
||||||
.lzma => @import("decomp/lzma.zig").stateless_decompressor,
|
|
||||||
.lzo => return error.LzoUnsupported,
|
|
||||||
.xz => @import("decomp/xz.zig").stateless_decompressor,
|
|
||||||
.lz4 => return error.Lz4Unsupported,
|
|
||||||
.zstd => @import("decomp/zstd.zig").stateless_decompressor,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +37,7 @@ pub fn root(self: Archive, alloc: std.mem.Allocator, io: Io) !File {
|
|||||||
alloc,
|
alloc,
|
||||||
io,
|
io,
|
||||||
self.file,
|
self.file,
|
||||||
&self.stateless_decomp,
|
self.stateless_decomp,
|
||||||
self.super.inode_start,
|
self.super.inode_start,
|
||||||
self.super.block_size,
|
self.super.block_size,
|
||||||
self.super.root_ref,
|
self.super.root_ref,
|
||||||
@@ -65,7 +59,7 @@ pub fn extract(self: Archive, alloc: std.mem.Allocator, io: Io, extract_dir: []c
|
|||||||
alloc,
|
alloc,
|
||||||
io,
|
io,
|
||||||
self.file,
|
self.file,
|
||||||
&self.stateless_decomp,
|
self.stateless_decomp,
|
||||||
self.super.inode_start,
|
self.super.inode_start,
|
||||||
self.super.block_size,
|
self.super.block_size,
|
||||||
self.super.root_ref,
|
self.super.root_ref,
|
||||||
@@ -128,14 +122,7 @@ pub const Superblock = extern struct {
|
|||||||
mod_time: u32,
|
mod_time: u32,
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
frag_count: u32,
|
frag_count: u32,
|
||||||
compression: enum(u16) {
|
compression: Decomp.Enum,
|
||||||
gzip = 1,
|
|
||||||
lzma,
|
|
||||||
lzo,
|
|
||||||
xz,
|
|
||||||
lz4,
|
|
||||||
zstd,
|
|
||||||
},
|
|
||||||
block_log: u16,
|
block_log: u16,
|
||||||
flags: packed struct(u16) {
|
flags: packed struct(u16) {
|
||||||
inode_uncompressed: bool,
|
inode_uncompressed: bool,
|
||||||
|
|||||||
@@ -48,12 +48,14 @@ pub fn main(init: std.process.Init) !void {
|
|||||||
var out = stdout.writer(io, &[0]u8{});
|
var out = stdout.writer(io, &[0]u8{});
|
||||||
defer out.interface.flush() catch {};
|
defer out.interface.flush() catch {};
|
||||||
|
|
||||||
try handleArgs(init.minimal.args, &out.interface);
|
// try handleArgs(init.minimal.args, &out.interface);
|
||||||
if (archive.len == 0) {
|
// if (archive.len == 0) {
|
||||||
try out.interface.print("You must provide a squashfs archive\n", .{});
|
// try out.interface.print("You must provide a squashfs archive\n", .{});
|
||||||
try out.interface.print(help_mgs, .{});
|
// try out.interface.print(help_mgs, .{});
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
archive = "testing/LinuxPATest.sfs";
|
||||||
|
extLoc = "testing/LinuxPABinTest";
|
||||||
|
|
||||||
var fil = try Io.Dir.cwd().openFile(io, archive, .{}); //TODO: Handle error gracefully.
|
var fil = try Io.Dir.cwd().openFile(io, archive, .{}); //TODO: Handle error gracefully.
|
||||||
defer fil.close(io);
|
defer fil.close(io);
|
||||||
|
|||||||
@@ -2,6 +2,26 @@ const std = @import("std");
|
|||||||
|
|
||||||
const Decompressor = @import("util/decompressor.zig");
|
const Decompressor = @import("util/decompressor.zig");
|
||||||
|
|
||||||
|
pub const Enum = enum(u16) {
|
||||||
|
gzip = 1,
|
||||||
|
lzma,
|
||||||
|
lzo,
|
||||||
|
xz,
|
||||||
|
lz4,
|
||||||
|
zstd,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn StatelessDecomp(val: Enum) !*const Decompressor {
|
||||||
|
return switch (val) {
|
||||||
|
.gzip => &@import("decomp/zlib.zig").stateless_decompressor,
|
||||||
|
.lzma => &@import("decomp/lzma.zig").stateless_decompressor,
|
||||||
|
.lzo => error.LzoUnsupported,
|
||||||
|
.xz => &@import("decomp/xz.zig").stateless_decompressor,
|
||||||
|
.lz4 => error.Lz4Unsupported,
|
||||||
|
.zstd => &@import("decomp/zstd.zig").stateless_decompressor,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub const Decomp = union(enum) {
|
pub const Decomp = union(enum) {
|
||||||
gzip: @import("decomp/zlib.zig"),
|
gzip: @import("decomp/zlib.zig"),
|
||||||
lzma: @import("decomp/lzma.zig"),
|
lzma: @import("decomp/lzma.zig"),
|
||||||
|
|||||||
+12
-4
@@ -4,6 +4,8 @@ const Reader = std.Io.Reader;
|
|||||||
const zstd = std.compress.zstd;
|
const zstd = std.compress.zstd;
|
||||||
const Node = std.SinglyLinkedList.Node;
|
const Node = std.SinglyLinkedList.Node;
|
||||||
|
|
||||||
|
const c = @import("c");
|
||||||
|
|
||||||
const Decompressor = @import("../util/decompressor.zig");
|
const Decompressor = @import("../util/decompressor.zig");
|
||||||
const Error = Decompressor.Error;
|
const Error = Decompressor.Error;
|
||||||
|
|
||||||
@@ -67,8 +69,14 @@ inline fn zstdDecomp(buffer: []u8, in: []u8, out: []u8) !usize {
|
|||||||
|
|
||||||
pub const stateless_decompressor: Decompressor = .{ .decomp_fn = statelessDecomp };
|
pub const stateless_decompressor: Decompressor = .{ .decomp_fn = statelessDecomp };
|
||||||
|
|
||||||
fn statelessDecomp(_: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
fn statelessDecomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
const buf = try alloc.alloc(u8, out.len + zstd.block_size_max);
|
_ = d;
|
||||||
defer alloc.free(buf);
|
_ = alloc;
|
||||||
return zstdDecomp(buf, in, out);
|
const res = c.ZSTD_decompress(out.ptr, out.len, in.ptr, in.len);
|
||||||
|
if (c.ZSTD_isError(res) == 1)
|
||||||
|
return Error.ReadFailed;
|
||||||
|
return res;
|
||||||
|
// const buf = try alloc.alloc(u8, out.len + zstd.block_size_max);
|
||||||
|
// defer alloc.free(buf);
|
||||||
|
// return zstdDecomp(buf, in, out);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -37,7 +37,7 @@ pub fn init(alloc: std.mem.Allocator, archive: Archive, in: Inode, name: []const
|
|||||||
}
|
}
|
||||||
pub fn fromDirEntry(alloc: std.mem.Allocator, io: Io, archive: Archive, ent: DirEntry) !File {
|
pub fn fromDirEntry(alloc: std.mem.Allocator, io: Io, archive: Archive, ent: DirEntry) !File {
|
||||||
var rdr = try archive.file.readerAt(io, archive.super.inode_start + ent.block_start, &[0]u8{});
|
var rdr = try archive.file.readerAt(io, archive.super.inode_start + ent.block_start, &[0]u8{});
|
||||||
var meta: MetadataReader = .init(alloc, &rdr.interface, &archive.stateless_decomp);
|
var meta: MetadataReader = .init(alloc, &rdr.interface, archive.stateless_decomp);
|
||||||
try meta.interface.discardAll(ent.block_offset);
|
try meta.interface.discardAll(ent.block_offset);
|
||||||
|
|
||||||
var in: Inode = try .read(alloc, &meta.interface, archive.super.block_size);
|
var in: Inode = try .read(alloc, &meta.interface, archive.super.block_size);
|
||||||
@@ -54,7 +54,7 @@ pub fn open(self: File, alloc: std.mem.Allocator, io: Io, filepath: []const u8)
|
|||||||
alloc,
|
alloc,
|
||||||
io,
|
io,
|
||||||
self.archive.file,
|
self.archive.file,
|
||||||
&self.archive.stateless_decomp,
|
self.archive.stateless_decomp,
|
||||||
self.archive.super.dir_start,
|
self.archive.super.dir_start,
|
||||||
);
|
);
|
||||||
defer {
|
defer {
|
||||||
|
|||||||
@@ -1,7 +1,84 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Io = std.Io;
|
||||||
|
|
||||||
const BlockSize = @import("inode_data/file.zig").BlockSize;
|
const BlockSize = @import("inode_data/file.zig").BlockSize;
|
||||||
|
const LookupTable = @import("lookup_table.zig");
|
||||||
|
const Decompressor = @import("util/decompressor.zig");
|
||||||
|
const MetadataReader = @import("util/metadata.zig");
|
||||||
|
const OffsetFile = @import("util/offset_file.zig");
|
||||||
|
|
||||||
|
const FragManager = @This();
|
||||||
|
|
||||||
pub const FragEntry = extern struct {
|
pub const FragEntry = extern struct {
|
||||||
start: u64,
|
start: u64,
|
||||||
size: BlockSize,
|
size: BlockSize,
|
||||||
_: u32,
|
_: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
fil: OffsetFile,
|
||||||
|
decomp: *const Decompressor,
|
||||||
|
block_size: u32,
|
||||||
|
|
||||||
|
entries: []FragEntry,
|
||||||
|
|
||||||
|
frag_cache: std.array_hash_map.Auto(u32, []u8),
|
||||||
|
cache_mut: std.Io.Mutex = .init,
|
||||||
|
|
||||||
|
pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const Decompressor, frag_start: u64, frag_num: u32, block_size: u32) !FragManager {
|
||||||
|
var buf: [8 * 1024]u8 = undefined;
|
||||||
|
var rdr = try fil.readerAt(io, frag_start, &buf);
|
||||||
|
var first_offset: u64 = undefined;
|
||||||
|
try rdr.interface.readSliceEndian(u64, @ptrCast(&first_offset), .little);
|
||||||
|
|
||||||
|
rdr = try fil.readerAt(io, first_offset, &buf);
|
||||||
|
var meta: MetadataReader = .init(alloc, &rdr.interface, decomp);
|
||||||
|
|
||||||
|
const entries = try alloc.alloc(FragEntry, frag_num);
|
||||||
|
errdefer alloc.free(entries);
|
||||||
|
|
||||||
|
try meta.interface.readSliceEndian(FragEntry, entries, .little);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.alloc = alloc,
|
||||||
|
.fil = fil,
|
||||||
|
.decomp = decomp,
|
||||||
|
.block_size = block_size,
|
||||||
|
|
||||||
|
.entries = entries,
|
||||||
|
|
||||||
|
.frag_cache = .empty,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub fn deinit(self: *FragManager, io: Io) void {
|
||||||
|
self.cache_mut.lockUncancelable(io);
|
||||||
|
self.alloc.free(self.entries);
|
||||||
|
for (self.frag_cache.values()) |v|
|
||||||
|
self.alloc.free(v);
|
||||||
|
self.frag_cache.deinit(self.alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: *FragManager, io: Io, idx: u32) ![]u8 {
|
||||||
|
if (self.frag_cache.contains(idx))
|
||||||
|
return self.frag_cache.get(idx).?;
|
||||||
|
|
||||||
|
try self.cache_mut.lock(io);
|
||||||
|
defer self.cache_mut.unlock(io);
|
||||||
|
|
||||||
|
const entry = self.entries[idx];
|
||||||
|
|
||||||
|
const out = try self.alloc.alloc(u8, if (entry.size.uncompressed) entry.size.size else self.block_size);
|
||||||
|
|
||||||
|
var buf: [1024 * 1024]u8 = undefined;
|
||||||
|
var rdr = try self.fil.readerAt(io, entry.start, &buf);
|
||||||
|
if (entry.size.uncompressed) {
|
||||||
|
try rdr.interface.readSliceAll(out);
|
||||||
|
} else {
|
||||||
|
@branchHint(.likely);
|
||||||
|
try rdr.interface.fill(entry.size.size);
|
||||||
|
_ = try self.decomp.Decompress(self.alloc, buf[0..entry.size.size], out);
|
||||||
|
}
|
||||||
|
|
||||||
|
try self.frag_cache.put(self.alloc, idx, out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|||||||
+38
-47
@@ -9,6 +9,7 @@ const Decomp = @import("decomp.zig").Decomp;
|
|||||||
const DirEntry = @import("directory.zig");
|
const DirEntry = @import("directory.zig");
|
||||||
const ExtractionOptions = @import("options.zig");
|
const ExtractionOptions = @import("options.zig");
|
||||||
const FragEntry = @import("frag.zig").FragEntry;
|
const FragEntry = @import("frag.zig").FragEntry;
|
||||||
|
const FragManager = @import("frag.zig");
|
||||||
const dir = @import("inode_data/dir.zig");
|
const dir = @import("inode_data/dir.zig");
|
||||||
const file = @import("inode_data/file.zig");
|
const file = @import("inode_data/file.zig");
|
||||||
const misc = @import("inode_data/misc.zig");
|
const misc = @import("inode_data/misc.zig");
|
||||||
@@ -215,6 +216,9 @@ const PathRet = struct {
|
|||||||
inode: Inode,
|
inode: Inode,
|
||||||
xattr_idx: ?u32 = null,
|
xattr_idx: ?u32 = null,
|
||||||
};
|
};
|
||||||
|
fn DirCompare(_: void, a: PathRet, b: PathRet) std.math.Order{
|
||||||
|
|
||||||
|
}
|
||||||
const ExtractReturnUnion = union(enum) {
|
const ExtractReturnUnion = union(enum) {
|
||||||
path_ret: ExtractError!PathRet,
|
path_ret: ExtractError!PathRet,
|
||||||
};
|
};
|
||||||
@@ -247,32 +251,16 @@ pub fn extract(
|
|||||||
defer decomp_base.deinit();
|
defer decomp_base.deinit();
|
||||||
const decomp = decomp_base.decompressor();
|
const decomp = decomp_base.decompressor();
|
||||||
|
|
||||||
var frag_table: CachedTable(FragEntry) = .init(alloc, fil, decomp, super.frag_start, super.frag_count);
|
var frags: FragManager = try .init(alloc, io, fil, decomp, super.frag_start, super.frag_count, super.block_size);
|
||||||
defer if (!options.ignore_permissions) frag_table.deinit(io);
|
defer frags.deinit(io);
|
||||||
try frag_table.fill(io);
|
|
||||||
|
|
||||||
var arena: std.heap.ArenaAllocator = .init(alloc);
|
|
||||||
defer arena.deinit();
|
|
||||||
|
|
||||||
var sel_buf = [1]ExtractReturnUnion{undefined} ** 10;
|
var sel_buf = [1]ExtractReturnUnion{undefined} ** 10;
|
||||||
var sel: Io.Select(ExtractReturnUnion) = .init(io, &sel_buf);
|
var sel: Io.Select(ExtractReturnUnion) = .init(io, &sel_buf);
|
||||||
defer sel.cancelDiscard();
|
defer sel.cancelDiscard();
|
||||||
|
|
||||||
switch (self.hdr.inode_type) {
|
var fold_queu: std.PriorityDequeue(PathRet, void, comptime compareFn: fn (Context, T, T) Order)
|
||||||
.dir, .ext_dir => try sel.concurrent(
|
|
||||||
.path_ret,
|
try sel.concurrent(.path_ret, extractReal, .{ self, alloc, io, fil, decomp, super, &frags, &sel, path });
|
||||||
extractDir,
|
|
||||||
.{ self, alloc, io, fil, decomp, &sel, &arena, super.dir_start, super.inode_start, &frag_table, super.block_size, path },
|
|
||||||
),
|
|
||||||
.file, .ext_file => try sel.concurrent(
|
|
||||||
.path_ret,
|
|
||||||
extractFile,
|
|
||||||
.{ self, alloc, io, fil, decomp, &frag_table, super.block_size, path },
|
|
||||||
),
|
|
||||||
.symlink, .ext_symlink => try sel.concurrent(.path_ret, extractSymlink, .{ self, io, path }),
|
|
||||||
else => if (@hasField(std.os, "linux"))
|
|
||||||
try sel.concurrent(.path_ret, extractDevOrIPC, .{ self, alloc, path }),
|
|
||||||
}
|
|
||||||
|
|
||||||
var xattr_table: ?XattrTable = if (!options.ignore_xattr)
|
var xattr_table: ?XattrTable = if (!options.ignore_xattr)
|
||||||
try .init(alloc, io, fil, decomp, super.xattr_start)
|
try .init(alloc, io, fil, decomp, super.xattr_start)
|
||||||
@@ -295,6 +283,7 @@ pub fn extract(
|
|||||||
|
|
||||||
// std.debug.print("Waiting for return...", .{});
|
// std.debug.print("Waiting for return...", .{});
|
||||||
const ret = try sel.await();
|
const ret = try sel.await();
|
||||||
|
defer sel.queue.putOneUncancelable(io, ret) catch {};
|
||||||
// std.debug.print("Got One...\n", .{});
|
// std.debug.print("Got One...\n", .{});
|
||||||
const path_ret = try ret.path_ret;
|
const path_ret = try ret.path_ret;
|
||||||
|
|
||||||
@@ -328,18 +317,33 @@ pub fn extract(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn extractReal(
|
||||||
|
self: Inode,
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
io: Io,
|
||||||
|
fil: OffsetFile,
|
||||||
|
decomp: *const Decompressor,
|
||||||
|
super: Archive.Superblock,
|
||||||
|
frags: *FragManager,
|
||||||
|
sel: *Io.Select(ExtractReturnUnion),
|
||||||
|
path: []const u8,
|
||||||
|
) ExtractError!PathRet {
|
||||||
|
return switch (self.hdr.inode_type) {
|
||||||
|
.dir, .ext_dir => extractDir(self, alloc, io, fil, decomp, super, sel, frags, path),
|
||||||
|
.file, .ext_file => extractFile(self, alloc, io, fil, decomp, frags, super.block_size, path),
|
||||||
|
.symlink, .ext_symlink => extractSymlink(self, io, path),
|
||||||
|
else => extractDevOrIPC(self, alloc, path),
|
||||||
|
};
|
||||||
|
}
|
||||||
fn extractDir(
|
fn extractDir(
|
||||||
self: Inode,
|
self: Inode,
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
io: Io,
|
io: Io,
|
||||||
fil: OffsetFile,
|
fil: OffsetFile,
|
||||||
decomp: *const Decompressor,
|
decomp: *const Decompressor,
|
||||||
|
super: Archive.Superblock,
|
||||||
parent_select: *Io.Select(ExtractReturnUnion),
|
parent_select: *Io.Select(ExtractReturnUnion),
|
||||||
arena: *std.heap.ArenaAllocator,
|
frags: *FragManager,
|
||||||
dir_start: u64,
|
|
||||||
inode_start: u64,
|
|
||||||
frag: *CachedTable(FragEntry),
|
|
||||||
block_size: u32,
|
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
) ExtractError!PathRet {
|
) ExtractError!PathRet {
|
||||||
try Io.Dir.cwd().createDirPath(io, path);
|
try Io.Dir.cwd().createDirPath(io, path);
|
||||||
@@ -350,7 +354,7 @@ fn extractDir(
|
|||||||
|
|
||||||
var num: usize = 0;
|
var num: usize = 0;
|
||||||
{
|
{
|
||||||
const dir_entries = self.readDirectory(alloc, io, fil, decomp, dir_start) catch |err| switch (err) {
|
const dir_entries = self.readDirectory(alloc, io, fil, decomp, super.dir_start) catch |err| switch (err) {
|
||||||
Error.NotDirectory => unreachable,
|
Error.NotDirectory => unreachable,
|
||||||
else => return @errorCast(err),
|
else => return @errorCast(err),
|
||||||
};
|
};
|
||||||
@@ -362,29 +366,16 @@ fn extractDir(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (dir_entries) |d| {
|
for (dir_entries) |d| {
|
||||||
var rdr = try fil.readerAt(io, d.block_start + inode_start, &[0]u8{});
|
var rdr = try fil.readerAt(io, d.block_start + super.inode_start, &[0]u8{});
|
||||||
var meta_rdr: MetadataReader = .init(alloc, &rdr.interface, decomp);
|
var meta_rdr: MetadataReader = .init(alloc, &rdr.interface, decomp);
|
||||||
try meta_rdr.interface.discardAll(d.block_offset);
|
try meta_rdr.interface.discardAll(d.block_offset);
|
||||||
const inode = try read(arena.allocator(), &meta_rdr.interface, block_size);
|
const inode = try read(alloc, &meta_rdr.interface, super.block_size);
|
||||||
errdefer inode.deinit(arena.allocator());
|
errdefer inode.deinit(alloc);
|
||||||
|
|
||||||
const new_path = try std.mem.concat(arena.allocator(), u8, &[_][]const u8{ path, "/", d.name });
|
const new_path = try std.mem.concat(alloc, u8, &[_][]const u8{ path, "/", d.name });
|
||||||
errdefer arena.allocator().free(new_path);
|
errdefer alloc.free(new_path);
|
||||||
|
|
||||||
switch (d.type) {
|
try sel.concurrent(.path_ret, extractReal, .{ self, alloc, io, fil, decomp, super, frags, &sel, new_path });
|
||||||
.dir => try sel.concurrent(
|
|
||||||
.path_ret,
|
|
||||||
extractDir,
|
|
||||||
.{ inode, alloc, io, fil, decomp, parent_select, arena, dir_start, inode_start, frag, block_size, new_path },
|
|
||||||
),
|
|
||||||
.file => try sel.concurrent(
|
|
||||||
.path_ret,
|
|
||||||
extractFile,
|
|
||||||
.{ inode, alloc, io, fil, decomp, frag, block_size, new_path },
|
|
||||||
),
|
|
||||||
.symlink => try sel.concurrent(.path_ret, extractSymlink, .{ inode, io, new_path }),
|
|
||||||
else => try sel.concurrent(.path_ret, extractDevOrIPC, .{ inode, alloc, new_path }),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,7 +399,7 @@ fn extractFile(
|
|||||||
io: Io,
|
io: Io,
|
||||||
fil: OffsetFile,
|
fil: OffsetFile,
|
||||||
decomp: *const Decompressor,
|
decomp: *const Decompressor,
|
||||||
frag: *CachedTable(FragEntry),
|
frag: *FragManager,
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
) ExtractError!PathRet {
|
) ExtractError!PathRet {
|
||||||
|
|||||||
+12
-41
@@ -10,7 +10,7 @@ const OffsetFile = @import("offset_file.zig");
|
|||||||
|
|
||||||
// const SharedCache = @import("shared_cache.zig");
|
// const SharedCache = @import("shared_cache.zig");
|
||||||
|
|
||||||
pub const Error = error{OutOfMemory} || Io.File.Reader.SeekError || Io.Writer.Error;
|
pub const Error = error{OutOfMemory} || Io.File.Reader.SeekError || Io.Writer.Error || Io.File.Writer.Error;
|
||||||
|
|
||||||
const DataExtractor = @This();
|
const DataExtractor = @This();
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ start: u64,
|
|||||||
blocks: []BlockSize,
|
blocks: []BlockSize,
|
||||||
|
|
||||||
frag_offset: u32 = 0,
|
frag_offset: u32 = 0,
|
||||||
frag_entry: ?FragEntry = null,
|
frag_block: ?[]u8 = null,
|
||||||
|
|
||||||
err: ?Error = null,
|
err: ?Error = null,
|
||||||
|
|
||||||
@@ -38,14 +38,14 @@ pub fn init(fil: OffsetFile, decomp: *const Decompressor, block_size: u32, file_
|
|||||||
.blocks = blocks,
|
.blocks = blocks,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn addFrag(self: *DataExtractor, frag_offset: u32, entry: FragEntry) void {
|
pub fn addFrag(self: *DataExtractor, frag_offset: u32, block: []u8) void {
|
||||||
self.frag_offset = frag_offset;
|
self.frag_offset = frag_offset;
|
||||||
self.frag_entry = entry;
|
self.frag_block = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn numBlocks(self: DataExtractor) usize {
|
fn numBlocks(self: DataExtractor) usize {
|
||||||
var num = self.blocks.len;
|
var num = self.blocks.len;
|
||||||
if (self.frag_entry != null) num += 1;
|
if (self.frag_block != null) num += 1;
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,8 +60,8 @@ pub fn extractAsync(self: DataExtractor, alloc: std.mem.Allocator, io: Io, fil:
|
|||||||
group.async(io, blockThread, .{ self, alloc, io, fil, read_offset, idx, &err });
|
group.async(io, blockThread, .{ self, alloc, io, fil, read_offset, idx, &err });
|
||||||
read_offset += self.blocks[idx].size;
|
read_offset += self.blocks[idx].size;
|
||||||
}
|
}
|
||||||
if (self.frag_entry != null)
|
if (self.frag_block != null)
|
||||||
group.async(io, fragThread, .{ self, alloc, io, fil, &err });
|
group.async(io, fragThread, .{ self, io, fil, &err });
|
||||||
|
|
||||||
group.await(io) catch |cancel| return err orelse cancel;
|
group.await(io) catch |cancel| return err orelse cancel;
|
||||||
}
|
}
|
||||||
@@ -126,55 +126,26 @@ fn blockThread(self: DataExtractor, alloc: std.mem.Allocator, io: Io, fil: Io.Fi
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn fragThread(self: DataExtractor, alloc: std.mem.Allocator, io: Io, fil: Io.File, ret_err: *?Error) Io.Cancelable!void {
|
fn fragThread(self: DataExtractor, io: Io, fil: Io.File, ret_err: *?Error) Io.Cancelable!void {
|
||||||
const frag = self.frag_entry.?;
|
|
||||||
const cur_block_size = self.file_size % self.block_size;
|
const cur_block_size = self.file_size % self.block_size;
|
||||||
|
|
||||||
var wrt = fil.writer(io, &[0]u8{});
|
var write_buf: [10 * 1024]u8 = undefined;
|
||||||
|
var wrt = fil.writer(io, &write_buf);
|
||||||
wrt.seekTo(self.blocks.len * self.block_size) catch |err| {
|
wrt.seekTo(self.blocks.len * self.block_size) catch |err| {
|
||||||
ret_err.* = err;
|
ret_err.* = err;
|
||||||
if (err == error.Canceled) io.recancel();
|
if (err == error.Canceled) io.recancel();
|
||||||
return Io.Cancelable.Canceled;
|
return Io.Cancelable.Canceled;
|
||||||
};
|
};
|
||||||
defer wrt.flush() catch {};
|
|
||||||
|
|
||||||
var rdr = self.fil.readerAt(io, frag.start, &[0]u8{}) catch |err| {
|
wrt.interface.writeAll(self.frag_block.?[self.frag_offset .. self.frag_offset + cur_block_size]) catch |err| {
|
||||||
ret_err.* = err;
|
ret_err.* = err;
|
||||||
if (err == error.Canceled) io.recancel();
|
if (err == error.Canceled) io.recancel();
|
||||||
return Io.Cancelable.Canceled;
|
return Io.Cancelable.Canceled;
|
||||||
};
|
};
|
||||||
if (frag.size.uncompressed) {
|
|
||||||
rdr.interface.discardAll(self.frag_offset) catch |err| {
|
|
||||||
ret_err.* = err;
|
|
||||||
if (err == error.Canceled) io.recancel();
|
|
||||||
return Io.Cancelable.Canceled;
|
|
||||||
};
|
|
||||||
rdr.interface.streamExact(&wrt.interface, cur_block_size) catch |err| {
|
|
||||||
ret_err.* = err;
|
|
||||||
if (err == error.Canceled) io.recancel();
|
|
||||||
return Io.Cancelable.Canceled;
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
@branchHint(.likely);
|
|
||||||
|
|
||||||
var cache: [1024 * 1024]u8 = undefined;
|
wrt.flush() catch |err| {
|
||||||
var tmp: [1024 * 1024]u8 = undefined;
|
|
||||||
|
|
||||||
rdr.interface.readSliceAll(cache[0..frag.size.size]) catch |err| {
|
|
||||||
ret_err.* = err;
|
ret_err.* = err;
|
||||||
if (err == error.Canceled) io.recancel();
|
if (err == error.Canceled) io.recancel();
|
||||||
return Io.Cancelable.Canceled;
|
return Io.Cancelable.Canceled;
|
||||||
};
|
};
|
||||||
_ = self.decomp.Decompress(alloc, cache[0..frag.size.size], tmp[0..self.block_size]) catch |err| {
|
|
||||||
ret_err.* = err;
|
|
||||||
if (err == error.Canceled) io.recancel();
|
|
||||||
return Io.Cancelable.Canceled;
|
|
||||||
};
|
|
||||||
wrt.interface.writeAll(tmp[self.frag_offset .. self.frag_offset + cur_block_size]) catch |err| {
|
|
||||||
ret_err.* = err;
|
|
||||||
if (err == error.Canceled) io.recancel();
|
|
||||||
return Io.Cancelable.Canceled;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-24
@@ -6,7 +6,6 @@ const Reader = Io.Reader;
|
|||||||
const Writer = Io.Writer;
|
const Writer = Io.Writer;
|
||||||
const Limit = Io.Limit;
|
const Limit = Io.Limit;
|
||||||
|
|
||||||
const FragEntry = @import("../frag.zig").FragEntry;
|
|
||||||
const BlockSize = @import("../inode_data/file.zig").BlockSize;
|
const BlockSize = @import("../inode_data/file.zig").BlockSize;
|
||||||
const Decompressor = @import("decompressor.zig");
|
const Decompressor = @import("decompressor.zig");
|
||||||
const OffsetFile = @import("offset_file.zig");
|
const OffsetFile = @import("offset_file.zig");
|
||||||
@@ -28,7 +27,7 @@ cur_offset: u64,
|
|||||||
blocks: []BlockSize,
|
blocks: []BlockSize,
|
||||||
|
|
||||||
frag_offset: u32 = 0,
|
frag_offset: u32 = 0,
|
||||||
frag_entry: ?FragEntry = null,
|
frag_block: ?[]u8 = null,
|
||||||
|
|
||||||
block_idx: usize = 0,
|
block_idx: usize = 0,
|
||||||
sparse_block: bool = false,
|
sparse_block: bool = false,
|
||||||
@@ -64,14 +63,14 @@ pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const De
|
|||||||
pub fn deinit(self: *DataReader) void {
|
pub fn deinit(self: *DataReader) void {
|
||||||
self.alloc.free(self.interface.buffer);
|
self.alloc.free(self.interface.buffer);
|
||||||
}
|
}
|
||||||
pub fn addFrag(self: *DataReader, frag_offset: u32, entry: FragEntry) void {
|
pub fn addFrag(self: *DataReader, frag_offset: u32, block: []u8) void {
|
||||||
self.frag_offset = frag_offset;
|
self.frag_offset = frag_offset;
|
||||||
self.frag_entry = entry;
|
self.frag_block = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn numBlocks(self: DataReader) usize {
|
fn numBlocks(self: DataReader) usize {
|
||||||
var num = self.blocks.len;
|
var num = self.blocks.len;
|
||||||
if (self.frag_entry != null) num += 1;
|
if (self.frag_block != null) num += 1;
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
fn advanceBuffer(self: *DataReader) !void {
|
fn advanceBuffer(self: *DataReader) !void {
|
||||||
@@ -81,26 +80,13 @@ fn advanceBuffer(self: *DataReader) !void {
|
|||||||
defer self.block_idx += 1;
|
defer self.block_idx += 1;
|
||||||
|
|
||||||
self.interface.end = if (self.block_idx == self.numBlocks() - 1)
|
self.interface.end = if (self.block_idx == self.numBlocks() - 1)
|
||||||
self.size % self.block_size
|
self.file_size % self.block_size
|
||||||
else
|
else
|
||||||
self.block_size;
|
self.block_size;
|
||||||
|
|
||||||
// Fragment
|
// Fragment
|
||||||
if (self.block_idx == self.blocks.len) {
|
if (self.block_idx == self.blocks.len) {
|
||||||
const entry = self.frag_entry.?;
|
@memcpy(self.interface.buffer[0..self.interface.end], self.frag_block.?[self.frag_offset .. self.frag_offset + self.interface.end]);
|
||||||
if (entry.size.uncompressed) {
|
|
||||||
var rdr = try self.fil.readerAt(self.io, entry.start + self.frag_offset, &[0]u8{});
|
|
||||||
try rdr.interface.readSliceAll(self.interface.buffer[0..self.interface.end]);
|
|
||||||
} else {
|
|
||||||
@branchHint(.likely);
|
|
||||||
const tmp = try self.cache.getOne(self.io);
|
|
||||||
defer self.cache.putOne(tmp) catch {};
|
|
||||||
|
|
||||||
var rdr = try self.fil.readerAt(self.io, entry.start, &[0]u8{});
|
|
||||||
try rdr.interface.readSliceAll(tmp.cache[0..entry.size.size]);
|
|
||||||
_ = try self.decomp.Decompress(self.alloc, tmp.cache[0..entry.size.size], self.interface.buffer[0..self.block_size]);
|
|
||||||
@memmove(self.interface.buffer[0..self.interface.end], self.interface.buffer[self.frag_offset .. self.frag_offset + self.interface.end]);
|
|
||||||
}
|
|
||||||
self.interface.seek = 0;
|
self.interface.seek = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -120,12 +106,13 @@ fn advanceBuffer(self: *DataReader) !void {
|
|||||||
} else {
|
} else {
|
||||||
@branchHint(.likely);
|
@branchHint(.likely);
|
||||||
const tmp = try self.cache.getOne(self.io);
|
const tmp = try self.cache.getOne(self.io);
|
||||||
defer self.cache.putOne(tmp) catch {};
|
defer self.cache.putOne(self.io, tmp) catch {};
|
||||||
|
|
||||||
var rdr = try self.fil.readerAt(self.io, self.cur_offset, &[0]u8{});
|
var rdr_buf: [50 * 1024]u8 = undefined;
|
||||||
try rdr.interface.readSliceAll(tmp.cache[0..block.size]);
|
var rdr = try self.fil.readerAt(self.io, self.cur_offset, &rdr_buf);
|
||||||
|
try rdr.interface.readSliceAll(tmp[0..block.size]);
|
||||||
self.cur_offset += block.size;
|
self.cur_offset += block.size;
|
||||||
_ = try self.decomp.Decompress(self.alloc, tmp.cache[0..block.size], self.interface.buffer[0..self.interface.end]);
|
_ = try self.decomp.Decompress(self.alloc, tmp[0..block.size], self.interface.buffer[0..self.interface.end]);
|
||||||
}
|
}
|
||||||
self.interface.seek = 0;
|
self.interface.seek = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user