Re-added all C decompressors
Some cleanup Remove inode arena Added deinit to Archive to destroy the File.MemoryMap
This commit is contained in:
@@ -20,6 +20,10 @@
|
|||||||
.url = "git+https://github.com/CalebQ42/zig-minilzo.git#7cbae997b91a44d74b7cd6c073584dc9562a6c90",
|
.url = "git+https://github.com/CalebQ42/zig-minilzo.git#7cbae997b91a44d74b7cd6c073584dc9562a6c90",
|
||||||
.hash = "minilzo-2.10.0-Ij7BO8wLAADeWI4Pe4jp8XTDsDaquZR14oZ7_9yKKDWP",
|
.hash = "minilzo-2.10.0-Ij7BO8wLAADeWI4Pe4jp8XTDsDaquZR14oZ7_9yKKDWP",
|
||||||
},
|
},
|
||||||
|
.xz = .{
|
||||||
|
.url = "git+https://github.com/akunaakwei/zig-xz.git#e2d389262c8291907e3e4c6fb119819141c16c0f",
|
||||||
|
.hash = "xz-5.8.2-6v47_JYeAABSL-jonprpL5-E_YaaGc4B5xrbe93WsJ3G",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
.paths = .{
|
.paths = .{
|
||||||
"build.zig",
|
"build.zig",
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ pub fn init(io: Io, file: std.Io.File, offset: u64) !Archive {
|
|||||||
.stateless_decomp = try Decomp.StatelessDecomp(super.compression),
|
.stateless_decomp = try Decomp.StatelessDecomp(super.compression),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
pub fn deinit(self: Archive, io: Io) void {
|
||||||
|
self.file.deinit(io);
|
||||||
|
}
|
||||||
|
|
||||||
/// The root folder of the Archive. Used to open other Files.
|
/// The root folder of the Archive. Used to open other Files.
|
||||||
pub fn root(self: Archive, alloc: std.mem.Allocator, io: Io) !File {
|
pub fn root(self: Archive, alloc: std.mem.Allocator, io: Io) !File {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const Writer = Io.Writer;
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
const config = @import("config");
|
const config = @import("config");
|
||||||
const squashfs = @import("zig_squashfs");
|
const squashfs = @import("squashfs");
|
||||||
|
|
||||||
//TODO: Add more options
|
//TODO: Add more options
|
||||||
const help_mgs =
|
const help_mgs =
|
||||||
|
|||||||
@@ -1 +1,7 @@
|
|||||||
#include <zstd.h>
|
#include <zstd.h>
|
||||||
|
#include <zlib-ng.h>
|
||||||
|
#include <lzma.h>
|
||||||
|
#ifdef ALLOW_LZO
|
||||||
|
#include <lzo/minilzo.h>
|
||||||
|
#endif
|
||||||
|
#include <lz4.h>
|
||||||
|
|||||||
+43
-19
@@ -1,7 +1,16 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
|
const options = @import("options");
|
||||||
|
|
||||||
const Decompressor = @import("util/decompressor.zig");
|
const Decompressor = @import("util/decompressor.zig");
|
||||||
|
|
||||||
|
const zlib = if (options.use_zig_decomp) @import("decomp/zig_zlib.zig") else @import("decomp/c_zlib.zig");
|
||||||
|
const lzma = if (options.use_zig_decomp) @import("decomp/zig_lzma.zig") else @import("decomp/c_lzma.zig");
|
||||||
|
const lzo = if (options.use_zig_decomp or !options.allow_lzo) void else @import("decomp/c_lzo.zig");
|
||||||
|
const xz = if (options.use_zig_decomp) @import("decomp/zig_xz.zig") else @import("decomp/c_xz.zig");
|
||||||
|
const lz4 = if (options.use_zig_decomp) void else @import("decomp/c_lz4.zig");
|
||||||
|
const zstd = if (options.use_zig_decomp) @import("decomp/zig_zstd.zig") else @import("decomp/c_zstd.zig");
|
||||||
|
|
||||||
pub const Enum = enum(u16) {
|
pub const Enum = enum(u16) {
|
||||||
gzip = 1,
|
gzip = 1,
|
||||||
lzma,
|
lzma,
|
||||||
@@ -13,40 +22,55 @@ pub const Enum = enum(u16) {
|
|||||||
|
|
||||||
pub fn StatelessDecomp(val: Enum) !*const Decompressor {
|
pub fn StatelessDecomp(val: Enum) !*const Decompressor {
|
||||||
return switch (val) {
|
return switch (val) {
|
||||||
.gzip => &@import("decomp/zlib.zig").stateless_decompressor,
|
.gzip => &zlib.stateless_decompressor,
|
||||||
.lzma => &@import("decomp/lzma.zig").stateless_decompressor,
|
.lzma => &lzma.stateless_decompressor,
|
||||||
.lzo => error.LzoUnsupported,
|
.lzo => if (options.use_zig_decomp or !options.allow_lzo)
|
||||||
.xz => &@import("decomp/xz.zig").stateless_decompressor,
|
error.LzoUnsupported
|
||||||
.lz4 => error.Lz4Unsupported,
|
else
|
||||||
.zstd => &@import("decomp/zstd.zig").stateless_decompressor,
|
&lzo.stateless_decompressor,
|
||||||
|
.xz => &xz.stateless_decompressor,
|
||||||
|
.lz4 => if (options.use_zig_decomp)
|
||||||
|
error.Lz4Unsupported
|
||||||
|
else
|
||||||
|
&lz4.stateless_decompressor,
|
||||||
|
.zstd => &zstd.stateless_decompressor,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const Decomp = union(enum) {
|
pub const Decomp = union(enum) {
|
||||||
gzip: @import("decomp/zlib.zig"),
|
gzip: zlib,
|
||||||
lzma: @import("decomp/lzma.zig"),
|
lzma: lzma,
|
||||||
lzo: void,
|
lzo: lzo,
|
||||||
xz: @import("decomp/xz.zig"),
|
xz: xz,
|
||||||
lz4: void,
|
lz4: lz4,
|
||||||
zstd: @import("decomp/zstd.zig"),
|
zstd: zstd,
|
||||||
|
|
||||||
|
pub fn init(val: Enum, alloc: std.mem.Allocator) !Decomp {
|
||||||
|
return switch (val) {
|
||||||
|
.gzip => .{ .gzip = zlib.init(alloc) },
|
||||||
|
.lzma => .{ .lzma = .{} },
|
||||||
|
.lzo => .{ .lzo = .{} },
|
||||||
|
.xz => .{ .xz = .{} },
|
||||||
|
.lz4 => .{ .lz4 = .{} },
|
||||||
|
.zstd => .{ .zstd = zstd.init(alloc) },
|
||||||
|
};
|
||||||
|
}
|
||||||
pub fn deinit(self: *Decomp) void {
|
pub fn deinit(self: *Decomp) void {
|
||||||
switch (self.*) {
|
switch (self.*) {
|
||||||
.gzip => self.gzip.deinit(),
|
.gzip => self.gzip.deinit(),
|
||||||
.lzma => self.lzma.deinit(),
|
|
||||||
.xz => self.xz.deinit(),
|
|
||||||
.zstd => self.zstd.deinit(),
|
.zstd => self.zstd.deinit(),
|
||||||
else => unreachable,
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decompressor(self: *Decomp) *Decompressor {
|
pub fn decompressor(self: *Decomp) *const Decompressor {
|
||||||
return switch (self.*) {
|
return switch (self.*) {
|
||||||
.gzip => &self.gzip.interface,
|
.gzip => &self.gzip.interface,
|
||||||
.lzma => &self.lzma.interface,
|
.lzma => &lzma.stateless_decompressor,
|
||||||
.xz => &self.xz.interface,
|
.lzo => &lzo.stateless_decompressor,
|
||||||
|
.xz => &xz.stateless_decompressor,
|
||||||
|
.lz4 => &lz4.stateless_decompressor,
|
||||||
.zstd => &self.zstd.interface,
|
.zstd => &self.zstd.interface,
|
||||||
else => unreachable,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const c = @import("c");
|
||||||
|
|
||||||
|
const Decompressor = @import("../util/decompressor.zig");
|
||||||
|
const Error = Decompressor.Error;
|
||||||
|
|
||||||
|
pub const stateless_decompressor: Decompressor = .{ .decomp_fn = statelessDecomp };
|
||||||
|
|
||||||
|
fn statelessDecomp(_: ?*const Decompressor, _: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
const res = c.LZ4_decompress_fast(in.ptr, out.ptr, out.len);
|
||||||
|
if (res < 0) return Error.ReadFailed;
|
||||||
|
return @abs(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lzma_allocator
|
||||||
|
|
||||||
|
fn lzmaAlloc(ptr: ?*anyopaque, size: usize, _: usize) callconv(.c) ?*anyopaque {
|
||||||
|
var alloc: *std.mem.Allocator = @ptrCast(@alignCast(@constCast(ptr)));
|
||||||
|
return alloc.rawAlloc(size, .@"1", 0);
|
||||||
|
}
|
||||||
|
fn lzmaFree(ptr: ?*anyopaque, mem_ptr: ?*anyopaque) callconv(.c) void {
|
||||||
|
var alloc: *std.mem.Allocator = @ptrCast(@alignCast(@constCast(ptr)));
|
||||||
|
alloc.rawFree(@ptrCast(mem_ptr), .@"1", 0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Io = std.Io;
|
||||||
|
const Reader = std.Io.Reader;
|
||||||
|
const zstd = std.compress.zstd;
|
||||||
|
const Node = std.SinglyLinkedList.Node;
|
||||||
|
|
||||||
|
const c = @import("c");
|
||||||
|
|
||||||
|
const Decompressor = @import("../util/decompressor.zig");
|
||||||
|
const Error = Decompressor.Error;
|
||||||
|
|
||||||
|
const Queue = std.Io.Queue(c.lzma_stream);
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub const stateless_decompressor: Decompressor = .{ .decomp_fn = statelessDecomp };
|
||||||
|
|
||||||
|
fn statelessDecomp(_: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
var stream: c.lzma_stream = .{
|
||||||
|
.allocator = &.{
|
||||||
|
.alloc = lzmaAlloc,
|
||||||
|
.free = lzmaFree,
|
||||||
|
.@"opaque" = @constCast(&alloc),
|
||||||
|
},
|
||||||
|
.next_in = in.ptr,
|
||||||
|
.avail_in = in.len,
|
||||||
|
.next_out = out.ptr,
|
||||||
|
.avail_out = out.len,
|
||||||
|
};
|
||||||
|
|
||||||
|
var res = c.lzma_alone_decoder(&stream, stream.avail_out * 2);
|
||||||
|
if (res != c.LZMA_OK) return Error.ReadFailed;
|
||||||
|
while (res == c.LZMA_OK)
|
||||||
|
res = c.lzma_code(&stream, c.LZMA_RUN);
|
||||||
|
if (res != c.LZMA_FINISH) return Error.ReadFailed;
|
||||||
|
return stream.total_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lzma_allocator
|
||||||
|
|
||||||
|
fn lzmaAlloc(ptr: ?*anyopaque, size: usize, _: usize) callconv(.c) ?*anyopaque {
|
||||||
|
var alloc: *std.mem.Allocator = @ptrCast(@alignCast(@constCast(ptr)));
|
||||||
|
return alloc.rawAlloc(size, .@"1", 0);
|
||||||
|
}
|
||||||
|
fn lzmaFree(ptr: ?*anyopaque, mem_ptr: ?*anyopaque) callconv(.c) void {
|
||||||
|
var alloc: *std.mem.Allocator = @ptrCast(@alignCast(@constCast(ptr)));
|
||||||
|
alloc.rawFree(@ptrCast(mem_ptr), .@"1", 0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Io = std.Io;
|
||||||
|
const Reader = std.Io.Reader;
|
||||||
|
const zstd = std.compress.zstd;
|
||||||
|
const Node = std.SinglyLinkedList.Node;
|
||||||
|
|
||||||
|
const c = @import("c");
|
||||||
|
|
||||||
|
const Decompressor = @import("../util/decompressor.zig");
|
||||||
|
const Error = Decompressor.Error;
|
||||||
|
|
||||||
|
const Queue = std.Io.Queue(c.lzma_stream);
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub const stateless_decompressor: Decompressor = .{ .decomp_fn = statelessDecomp };
|
||||||
|
|
||||||
|
fn statelessDecomp(_: ?*const Decompressor, _: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
_ = c.lzo_init();
|
||||||
|
var out_len = out.len;
|
||||||
|
const res = c.lzo1x_decompress_safe(in.ptr, in.len, out.ptr, &out_len, null);
|
||||||
|
if (res != c.LZO_E_OK) return Error.ReadFailed;
|
||||||
|
return out_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lzma_allocator
|
||||||
|
|
||||||
|
fn lzmaAlloc(ptr: ?*anyopaque, size: usize, _: usize) callconv(.c) ?*anyopaque {
|
||||||
|
var alloc: *std.mem.Allocator = @ptrCast(@alignCast(@constCast(ptr)));
|
||||||
|
return alloc.rawAlloc(size, .@"1", 0);
|
||||||
|
}
|
||||||
|
fn lzmaFree(ptr: ?*anyopaque, mem_ptr: ?*anyopaque) callconv(.c) void {
|
||||||
|
var alloc: *std.mem.Allocator = @ptrCast(@alignCast(@constCast(ptr)));
|
||||||
|
alloc.rawFree(@ptrCast(mem_ptr), .@"1", 0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Io = std.Io;
|
||||||
|
const Reader = std.Io.Reader;
|
||||||
|
const zstd = std.compress.zstd;
|
||||||
|
const Node = std.SinglyLinkedList.Node;
|
||||||
|
|
||||||
|
const c = @import("c");
|
||||||
|
|
||||||
|
const Decompressor = @import("../util/decompressor.zig");
|
||||||
|
const Error = Decompressor.Error;
|
||||||
|
|
||||||
|
const Queue = std.Io.Queue(c.lzma_stream);
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub const stateless_decompressor: Decompressor = .{ .decomp_fn = statelessDecomp };
|
||||||
|
|
||||||
|
fn statelessDecomp(_: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
var stream: c.lzma_stream = .{
|
||||||
|
.allocator = &.{
|
||||||
|
.alloc = lzmaAlloc,
|
||||||
|
.free = lzmaFree,
|
||||||
|
.@"opaque" = @constCast(&alloc),
|
||||||
|
},
|
||||||
|
.next_in = in.ptr,
|
||||||
|
.avail_in = in.len,
|
||||||
|
.next_out = out.ptr,
|
||||||
|
.avail_out = out.len,
|
||||||
|
};
|
||||||
|
|
||||||
|
var res = c.lzma_alone_decoder(&stream, stream.avail_out * 2);
|
||||||
|
if (res != c.LZMA_OK) return Error.ReadFailed;
|
||||||
|
while (res == c.LZMA_OK)
|
||||||
|
res = c.lzma_code(&stream, c.LZMA_RUN);
|
||||||
|
if (res != c.LZMA_FINISH) return Error.ReadFailed;
|
||||||
|
return stream.total_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lzma_allocator
|
||||||
|
|
||||||
|
fn lzmaAlloc(ptr: ?*anyopaque, size: usize, _: usize) callconv(.c) ?*anyopaque {
|
||||||
|
var alloc: *std.mem.Allocator = @ptrCast(@alignCast(@constCast(ptr)));
|
||||||
|
return alloc.rawAlloc(size, .@"1", 0);
|
||||||
|
}
|
||||||
|
fn lzmaFree(ptr: ?*anyopaque, mem_ptr: ?*anyopaque) callconv(.c) void {
|
||||||
|
var alloc: *std.mem.Allocator = @ptrCast(@alignCast(@constCast(ptr)));
|
||||||
|
alloc.rawFree(@ptrCast(mem_ptr), .@"1", 0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Io = std.Io;
|
||||||
|
const Reader = std.Io.Reader;
|
||||||
|
const zstd = std.compress.zstd;
|
||||||
|
const Node = std.SinglyLinkedList.Node;
|
||||||
|
|
||||||
|
const c = @import("c");
|
||||||
|
|
||||||
|
const Decompressor = @import("../util/decompressor.zig");
|
||||||
|
const Error = Decompressor.Error;
|
||||||
|
|
||||||
|
const Queue = std.Io.Queue(c.zng_stream);
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
interface: Decompressor = .{ .decomp_fn = decomp },
|
||||||
|
|
||||||
|
io: Io,
|
||||||
|
|
||||||
|
ctx: []c.zng_stream,
|
||||||
|
ctx_queue: Queue,
|
||||||
|
|
||||||
|
pub fn init(alloc: std.mem.Allocator, io: Io, block_size: u32) !Self {
|
||||||
|
const buf = try alloc.alloc(c.zng_stream, 20); // TODO: Choose a better number instead of a random one.
|
||||||
|
var queue: Queue = .init(buf);
|
||||||
|
for (0..20) |_|
|
||||||
|
try queue.putOne(io, .{
|
||||||
|
.zalloc = zalloc,
|
||||||
|
.zfree = zfree,
|
||||||
|
});
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.alloc = alloc,
|
||||||
|
.io = io,
|
||||||
|
|
||||||
|
.block_size = block_size,
|
||||||
|
.ctx = buf,
|
||||||
|
.ctx_queue = queue,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub fn deinit(self: *Self, alloc: std.mem.Allocator) void {
|
||||||
|
self.ctx_queue.close(self.io);
|
||||||
|
alloc.free(self.ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
if (d == null) {
|
||||||
|
return statelessDecomp(d, alloc, in, out);
|
||||||
|
}
|
||||||
|
var self: *Self = @fieldParentPtr("interface", @constCast(d.?));
|
||||||
|
|
||||||
|
const stream = self.ctx_queue.getOne(self.io) catch return Error.ReadFailed;
|
||||||
|
defer self.ctx_queue.putOne(self.io, stream) catch {};
|
||||||
|
|
||||||
|
stream.@"opaque" = @constCast(&alloc);
|
||||||
|
stream.next_in = in.ptr;
|
||||||
|
stream.avail_in = @truncate(in.len);
|
||||||
|
stream.next_out = out.ptr;
|
||||||
|
stream.avail_out = @truncate(out.len);
|
||||||
|
|
||||||
|
try zlibDecomp(&stream, in, out);
|
||||||
|
|
||||||
|
return stream.total_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn zlibDecomp(stream: *c.zng_stream) !void {
|
||||||
|
_ = c.zng_inflateReset(stream);
|
||||||
|
|
||||||
|
const res = c.zng_inflate(stream, c.Z_FULL_FLUSH);
|
||||||
|
if (res != c.Z_OK) return Error.ReadFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stateless
|
||||||
|
|
||||||
|
pub const stateless_decompressor: Decompressor = .{ .decomp_fn = statelessDecomp };
|
||||||
|
|
||||||
|
fn statelessDecomp(_: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
var stream: c.zng_stream = .{
|
||||||
|
.@"opaque" = @constCast(&alloc),
|
||||||
|
.next_in = in.ptr,
|
||||||
|
.avail_in = @truncate(in.len),
|
||||||
|
.next_out = out.ptr,
|
||||||
|
.avail_out = @truncate(out.len),
|
||||||
|
};
|
||||||
|
try zlibDecomp(&stream);
|
||||||
|
return stream.total_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// zalloc
|
||||||
|
|
||||||
|
fn zalloc(ptr: ?*anyopaque, size: c_uint, len: c_uint) callconv(.c) ?*anyopaque {
|
||||||
|
var alloc: *std.mem.Allocator = @ptrCast(ptr);
|
||||||
|
return alloc.rawAlloc(size * len, .@"1", 0);
|
||||||
|
}
|
||||||
|
fn zfree(ptr: ?*anyopaque, mem_ptr: ?*anyopaque) callconv(.c) void {
|
||||||
|
var alloc: *std.mem.Allocator = @ptrCast(ptr);
|
||||||
|
alloc.rawFree(@ptrCast(mem_ptr), .@"1", 0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Io = std.Io;
|
||||||
|
const Reader = std.Io.Reader;
|
||||||
|
const zstd = std.compress.zstd;
|
||||||
|
const Node = std.SinglyLinkedList.Node;
|
||||||
|
|
||||||
|
const c = @import("c");
|
||||||
|
|
||||||
|
const Decompressor = @import("../util/decompressor.zig");
|
||||||
|
const Error = Decompressor.Error;
|
||||||
|
|
||||||
|
const Queue = std.Io.Queue([]u8);
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
interface: Decompressor = .{ .decomp_fn = decomp },
|
||||||
|
|
||||||
|
io: Io,
|
||||||
|
|
||||||
|
ctx: []?*c.ZSTD_DCtx,
|
||||||
|
ctx_queue: Queue,
|
||||||
|
|
||||||
|
pub fn init(alloc: std.mem.Allocator, io: Io, block_size: u32) !Self {
|
||||||
|
const buf = try alloc.alloc(?*c.ZSTD_DCtx, 20); // TODO: Choose a better number instead of a random one.
|
||||||
|
var queue: Queue = .init(buf);
|
||||||
|
for (0..20) |_|
|
||||||
|
try queue.putOne(io, c.ZSTD_createDCtx());
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.alloc = alloc,
|
||||||
|
.io = io,
|
||||||
|
|
||||||
|
.block_size = block_size,
|
||||||
|
.ctx = buf,
|
||||||
|
.ctx_queue = queue,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub fn deinit(self: *Self, alloc: std.mem.Allocator) void {
|
||||||
|
self.ctx_queue.close(self.io);
|
||||||
|
for (self.ctx) |ctx|
|
||||||
|
c.ZSTD_freeDCtx(ctx);
|
||||||
|
alloc.free(self.ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
if (d == null) {
|
||||||
|
return statelessDecomp(d, alloc, in, out);
|
||||||
|
}
|
||||||
|
var self: *Self = @fieldParentPtr("interface", @constCast(d.?));
|
||||||
|
|
||||||
|
const ctx = self.ctx_queue.getOne(self.io) catch return Error.ReadFailed;
|
||||||
|
defer self.ctx_queue.putOne(self.io, ctx) catch {};
|
||||||
|
|
||||||
|
_ = c.ZSTD_DCtx_reset(ctx, c.ZSTD_reset_session_only);
|
||||||
|
|
||||||
|
const res = c.ZSTD_decompressDCtx(ctx, out.ptr, out.len, in.ptr, in.len);
|
||||||
|
if (c.ZSTD_isError(res) != 0)
|
||||||
|
return Error.ReadFailed;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stateless
|
||||||
|
|
||||||
|
pub const stateless_decompressor: Decompressor = .{ .decomp_fn = statelessDecomp };
|
||||||
|
|
||||||
|
fn statelessDecomp(_: ?*const Decompressor, _: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
const res = c.ZSTD_decompress(out.ptr, out.len, in.ptr, in.len);
|
||||||
|
if (c.ZSTD_isError(res) != 0)
|
||||||
|
return Error.ReadFailed;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const Io = std.Io;
|
||||||
const Reader = std.Io.Reader;
|
const Reader = std.Io.Reader;
|
||||||
const lzma = std.compress.lzma;
|
const lzma = std.compress.lzma;
|
||||||
const Node = std.SinglyLinkedList.Node;
|
const Node = std.SinglyLinkedList.Node;
|
||||||
@@ -6,6 +7,8 @@ const Node = std.SinglyLinkedList.Node;
|
|||||||
const Decompressor = @import("../util/decompressor.zig");
|
const Decompressor = @import("../util/decompressor.zig");
|
||||||
const Error = Decompressor.Error;
|
const Error = Decompressor.Error;
|
||||||
|
|
||||||
|
const Queue = Io.Queue([]u8);
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
const Buffer = struct {
|
const Buffer = struct {
|
||||||
@@ -16,57 +19,49 @@ const Buffer = struct {
|
|||||||
interface: Decompressor = .{ .decomp_fn = decomp },
|
interface: Decompressor = .{ .decomp_fn = decomp },
|
||||||
|
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
|
io: Io,
|
||||||
|
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
buffers: std.ArrayList(Buffer),
|
buf: [][]u8,
|
||||||
buffer_queue: std.SinglyLinkedList = .{},
|
buf_queue: Queue,
|
||||||
|
|
||||||
|
pub fn init(alloc: std.mem.Allocator, io: Io, block_size: u32) !Self {
|
||||||
|
const buf = try alloc.alloc([]u8, 20); // TODO: Choose a better number instead of a random one.
|
||||||
|
var queue: Queue = .init(buf);
|
||||||
|
for (0..20) |_|
|
||||||
|
try queue.putOne(io, try alloc.alloc(u8, block_size));
|
||||||
|
|
||||||
pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
|
|
||||||
return .{
|
return .{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
|
.io = io,
|
||||||
|
|
||||||
.block_size = block_size,
|
.block_size = block_size,
|
||||||
.buffers = try .initCapacity(alloc, 5),
|
.buf = buf,
|
||||||
|
.buf_queue = queue,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
for (self.buffers.items) |buf|
|
self.buf_queue.close(self.io);
|
||||||
self.alloc.free(buf.buf);
|
for (self.buf) |buf|
|
||||||
self.buffers.deinit(self.alloc);
|
self.alloc.free(buf);
|
||||||
|
self.alloc.free(self.buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
fn decomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
if (d == null) {
|
if (d == null) {
|
||||||
var buf = try alloc.alloc(u8, in.len * 2);
|
return statelessDecomp(d, alloc, in, out);
|
||||||
defer alloc.free(buf);
|
|
||||||
return lzmaDecomp(alloc, &buf, in, out) catch |err| return switch (err) {
|
|
||||||
error.OutOfMemory => Error.OutOfMemory,
|
|
||||||
else => Error.ReadFailed,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
var self: *Self = @fieldParentPtr("interface", @constCast(d.?));
|
var self: *Self = @fieldParentPtr("interface", @constCast(d.?));
|
||||||
const buf_node = self.buffer_queue.popFirst();
|
|
||||||
var buf: *Buffer = undefined;
|
const buf = self.buf_queue.getOne(self.io) catch return Error.ReadFailed;
|
||||||
if (buf_node == null) {
|
defer self.buf_queue.putOne(self.io, buf) catch {};
|
||||||
const new_buf = try self.buffers.addOne(self.alloc);
|
|
||||||
new_buf.* = .{ .node = .{}, .buf = try self.alloc.alloc(u8, self.block_size) };
|
return lzmaDecomp(self.alloc, &buf.buf, in, out) catch return Error.ReadFailed;
|
||||||
buf = new_buf;
|
|
||||||
} else {
|
|
||||||
buf = @fieldParentPtr("node", buf_node.?);
|
|
||||||
}
|
|
||||||
defer self.buffer_queue.prepend(&buf.node);
|
|
||||||
return lzmaDecomp(self.alloc, &buf.buf, in, out) catch |err| {
|
|
||||||
// self.err = err;
|
|
||||||
return switch (err) {
|
|
||||||
error.OutOfMemory => Error.OutOfMemory,
|
|
||||||
else => Error.ReadFailed,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn lzmaDecomp(alloc: std.mem.Allocator, buffer: *[]u8, in: []u8, out: []u8) !usize {
|
inline fn lzmaDecomp(alloc: std.mem.Allocator, buffer: *[]u8, in: []u8, out: []u8) !usize {
|
||||||
var rdr: Reader = .fixed(in);
|
var rdr: Reader = .fixed(in);
|
||||||
var d = try lzma.Decompress.initOptions(&rdr, alloc, buffer.*, .{ .allow_incomplete = true }, 3 * 1024 * 1024);
|
var d = try lzma.Decompress.initOptions(&rdr, alloc, buffer.*, .{});
|
||||||
defer {
|
defer {
|
||||||
buffer.* = d.takeBuffer();
|
buffer.* = d.takeBuffer();
|
||||||
d.deinit();
|
d.deinit();
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const Io = std.Io;
|
||||||
const Reader = std.Io.Reader;
|
const Reader = std.Io.Reader;
|
||||||
const xz = std.compress.xz;
|
const xz = std.compress.xz;
|
||||||
const Node = std.SinglyLinkedList.Node;
|
const Node = std.SinglyLinkedList.Node;
|
||||||
@@ -6,6 +7,8 @@ const Node = std.SinglyLinkedList.Node;
|
|||||||
const Decompressor = @import("../util/decompressor.zig");
|
const Decompressor = @import("../util/decompressor.zig");
|
||||||
const Error = Decompressor.Error;
|
const Error = Decompressor.Error;
|
||||||
|
|
||||||
|
const Queue = Io.Queue([]u8);
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
const Buffer = struct {
|
const Buffer = struct {
|
||||||
@@ -16,46 +19,44 @@ const Buffer = struct {
|
|||||||
interface: Decompressor = .{ .decomp_fn = decomp },
|
interface: Decompressor = .{ .decomp_fn = decomp },
|
||||||
|
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
|
io: Io,
|
||||||
|
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
buffers: std.ArrayList(Buffer),
|
buf: [][]u8,
|
||||||
buffer_queue: std.SinglyLinkedList = .{},
|
buf_queue: Queue,
|
||||||
|
|
||||||
|
pub fn init(alloc: std.mem.Allocator, io: Io, block_size: u32) !Self {
|
||||||
|
const buf = try alloc.alloc([]u8, 20); // TODO: Choose a better number instead of a random one.
|
||||||
|
var queue: Queue = .init(buf);
|
||||||
|
for (0..20) |_|
|
||||||
|
try queue.putOne(io, try alloc.alloc(u8, block_size));
|
||||||
|
|
||||||
pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
|
|
||||||
return .{
|
return .{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
|
.io = io,
|
||||||
|
|
||||||
.block_size = block_size,
|
.block_size = block_size,
|
||||||
.buffers = try .initCapacity(alloc, 5),
|
.buf = buf,
|
||||||
|
.buf_queue = queue,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
for (self.buffers.items) |buf|
|
self.buf_queue.close(self.io);
|
||||||
self.alloc.free(buf.buf);
|
for (self.buf) |buf|
|
||||||
self.buffers.deinit(self.alloc);
|
self.alloc.free(buf);
|
||||||
|
self.alloc.free(self.buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
fn decomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
if (d == null) {
|
if (d == null) {
|
||||||
var buf = try alloc.alloc(u8, in.len * 2);
|
return statelessDecomp(d, alloc, in, out);
|
||||||
defer alloc.free(buf);
|
|
||||||
return xzDecomp(alloc, &buf, in, out) catch return Error.ReadFailed;
|
|
||||||
}
|
}
|
||||||
var self: *Self = @fieldParentPtr("interface", @constCast(d.?));
|
var self: *Self = @fieldParentPtr("interface", @constCast(d.?));
|
||||||
const buf_node = self.buffer_queue.popFirst();
|
|
||||||
var buf: *Buffer = undefined;
|
const buf = self.buf_queue.getOne(self.io) catch return Error.ReadFailed;
|
||||||
if (buf_node == null) {
|
defer self.buf_queue.putOne(self.io, buf) catch {};
|
||||||
const new_buf = try self.buffers.addOne(self.alloc);
|
|
||||||
new_buf.* = .{ .node = .{}, .buf = try self.alloc.alloc(u8, self.block_size) };
|
return xzDecomp(self.alloc, &buf.buf, in, out) catch return Error.ReadFailed;
|
||||||
buf = new_buf;
|
|
||||||
} else {
|
|
||||||
buf = @fieldParentPtr("node", buf_node.?);
|
|
||||||
}
|
|
||||||
defer self.buffer_queue.prepend(&buf.node);
|
|
||||||
return xzDecomp(self.alloc, &buf.buf, in, out) catch {
|
|
||||||
// self.err = err;
|
|
||||||
return Error.ReadFailed;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn xzDecomp(alloc: std.mem.Allocator, buffer: *[]u8, in: []u8, out: []u8) !usize {
|
inline fn xzDecomp(alloc: std.mem.Allocator, buffer: *[]u8, in: []u8, out: []u8) !usize {
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Reader = std.Io.Reader;
|
const Io = std.Io;
|
||||||
const flate = std.compress.flate;
|
const flate = std.compress.flate;
|
||||||
const Node = std.SinglyLinkedList.Node;
|
const Node = std.SinglyLinkedList.Node;
|
||||||
|
const Reader = Io.Reader;
|
||||||
|
|
||||||
const Decompressor = @import("../util/decompressor.zig");
|
const Decompressor = @import("../util/decompressor.zig");
|
||||||
const Error = Decompressor.Error;
|
const Error = Decompressor.Error;
|
||||||
|
|
||||||
|
const Queue = Io.Queue([]u8);
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
const Buffer = struct {
|
const Buffer = struct {
|
||||||
@@ -16,42 +19,43 @@ const Buffer = struct {
|
|||||||
interface: Decompressor = .{ .decomp_fn = decomp },
|
interface: Decompressor = .{ .decomp_fn = decomp },
|
||||||
|
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
|
io: Io,
|
||||||
|
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
buffers: std.ArrayList(Buffer),
|
buf: [][]u8,
|
||||||
buffer_queue: std.SinglyLinkedList = .{},
|
buf_queue: Queue,
|
||||||
|
|
||||||
|
pub fn init(alloc: std.mem.Allocator, io: Io, block_size: u32) !Self {
|
||||||
|
const buf = try alloc.alloc([]u8, 20); // TODO: Choose a better number instead of a random one.
|
||||||
|
var queue: Queue = .init(buf);
|
||||||
|
for (0..20) |_|
|
||||||
|
try queue.putOne(io, try alloc.alloc(u8, block_size));
|
||||||
|
|
||||||
pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
|
|
||||||
return .{
|
return .{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
|
.io = io,
|
||||||
|
|
||||||
.block_size = block_size,
|
.block_size = block_size,
|
||||||
.buffers = try .initCapacity(alloc, 5),
|
.buf = buf,
|
||||||
|
.buf_queue = queue,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
for (self.buffers.items) |buf|
|
self.buf_queue.close(self.io);
|
||||||
self.alloc.free(buf.buf);
|
for (self.buf) |buf|
|
||||||
self.buffers.deinit(self.alloc);
|
self.alloc.free(buf);
|
||||||
|
self.alloc.free(self.buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
fn decomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
if (d == null) {
|
if (d == null) {
|
||||||
const buf = try alloc.alloc(u8, in.len * 2);
|
return statelessDecomp(d, alloc, in, out);
|
||||||
defer alloc.free(buf);
|
|
||||||
return zlibDecomp(buf, in, out);
|
|
||||||
}
|
}
|
||||||
var self: *Self = @fieldParentPtr("interface", @constCast(d.?));
|
var self: *Self = @fieldParentPtr("interface", @constCast(d.?));
|
||||||
const buf_node = self.buffer_queue.popFirst();
|
|
||||||
var buf: *Buffer = undefined;
|
const buf = self.buf_queue.getOne(self.io) catch return Error.ReadFailed;
|
||||||
if (buf_node == null) {
|
defer self.buf_queue.putOne(self.io, buf) catch {};
|
||||||
const new_buf = try self.buffers.addOne(self.alloc);
|
|
||||||
new_buf.* = .{ .node = .{}, .buf = try self.alloc.alloc(u8, self.block_size) };
|
|
||||||
buf = new_buf;
|
|
||||||
} else {
|
|
||||||
buf = @fieldParentPtr("node", buf_node.?);
|
|
||||||
}
|
|
||||||
defer self.buffer_queue.prepend(&buf.node);
|
|
||||||
return zlibDecomp(buf.buf, in, out);
|
return zlibDecomp(buf.buf, in, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +71,7 @@ inline fn zlibDecomp(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(_: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
const buf = try alloc.alloc(u8, in.len * 2);
|
const buf = try alloc.alloc(u8, out.len);
|
||||||
defer alloc.free(buf);
|
defer alloc.free(buf);
|
||||||
return zlibDecomp(buf, in, out);
|
return zlibDecomp(buf, in, out);
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,6 @@ const std = @import("std");
|
|||||||
const Io = std.Io;
|
const Io = std.Io;
|
||||||
const Reader = std.Io.Reader;
|
const Reader = std.Io.Reader;
|
||||||
const zstd = std.compress.zstd;
|
const zstd = std.compress.zstd;
|
||||||
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;
|
||||||
@@ -70,12 +67,7 @@ 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(_: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
_ = alloc;
|
const buf = try alloc.alloc(u8, out.len + zstd.block_size_max);
|
||||||
const res = c.ZSTD_decompress(out.ptr, out.len, in.ptr, in.len);
|
defer alloc.free(buf);
|
||||||
if (c.ZSTD_isError(res) == 1)
|
return zstdDecomp(buf, in, out);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
+55
-23
@@ -213,21 +213,25 @@ const ExtractError = error{ MknodFailed, CannotSetXattr } || DataExtractor.Error
|
|||||||
const PathRet = struct {
|
const PathRet = struct {
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
inode: Inode,
|
inode: Inode,
|
||||||
xattr_idx: ?u32 = null,
|
origin: bool,
|
||||||
|
|
||||||
fn setMetadata(path_ret: PathRet, alloc: std.mem.Allocator, io: Io, id_table: *CachedTable(u16), xattr_table: ?*XattrTable, options: ExtractionOptions) !void {
|
fn deinit(self: PathRet, alloc: std.mem.Allocator) void {
|
||||||
var fil = Io.Dir.cwd().openFile(io, path_ret.path, .{}) catch |err| {
|
if (self.origin) return;
|
||||||
std.debug.print("{s}: {}\n", .{ path_ret.path, err });
|
alloc.free(self.path);
|
||||||
return err;
|
self.inode.deinit(alloc);
|
||||||
};
|
}
|
||||||
|
fn setMetadata(self: PathRet, alloc: std.mem.Allocator, io: Io, id_table: *CachedTable(u16), xattr_table: ?*XattrTable, options: ExtractionOptions) !void {
|
||||||
|
var fil = try Io.Dir.cwd().openFile(io, self.path, .{});
|
||||||
defer fil.close(io);
|
defer fil.close(io);
|
||||||
|
|
||||||
|
const inode = self.inode;
|
||||||
|
|
||||||
if (!options.ignore_permissions) {
|
if (!options.ignore_permissions) {
|
||||||
try fil.setPermissions(io, @enumFromInt(path_ret.inode.hdr.permissions));
|
try fil.setPermissions(io, @enumFromInt(inode.hdr.permissions));
|
||||||
try fil.setOwner(io, try id_table.get(io, path_ret.inode.hdr.uid_idx), try id_table.get(io, path_ret.inode.hdr.gid_idx));
|
try fil.setOwner(io, try id_table.get(io, inode.hdr.uid_idx), try id_table.get(io, inode.hdr.gid_idx));
|
||||||
}
|
}
|
||||||
if (xattr_table != null) {
|
if (xattr_table != null) {
|
||||||
const idx = path_ret.inode.xattrIndex() catch return;
|
const idx = inode.xattrIndex() catch return;
|
||||||
|
|
||||||
const xattrs = try xattr_table.?.get(alloc, io, idx);
|
const xattrs = try xattr_table.?.get(alloc, io, idx);
|
||||||
defer {
|
defer {
|
||||||
@@ -236,7 +240,7 @@ const PathRet = struct {
|
|||||||
alloc.free(xattrs);
|
alloc.free(xattrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sentinel_path = try std.mem.concatWithSentinel(alloc, u8, &[_][]const u8{path_ret.path}, 0);
|
const sentinel_path = try std.mem.concatWithSentinel(alloc, u8, &[_][]const u8{self.path}, 0);
|
||||||
defer alloc.free(sentinel_path);
|
defer alloc.free(sentinel_path);
|
||||||
for (xattrs) |x| {
|
for (xattrs) |x| {
|
||||||
const xattr_ret = std.os.linux.fsetxattr(fil.handle, x.key, x.value.ptr, x.value.len, 0);
|
const xattr_ret = std.os.linux.fsetxattr(fil.handle, x.key, x.value.ptr, x.value.len, 0);
|
||||||
@@ -271,19 +275,17 @@ pub fn extract(
|
|||||||
) !void {
|
) !void {
|
||||||
const path = std.mem.trimEnd(u8, filepath, "/");
|
const path = std.mem.trimEnd(u8, filepath, "/");
|
||||||
|
|
||||||
const decomp = try @import("decomp.zig").StatelessDecomp(super.compression);
|
var decomp_base: Decomp = .init(super.compression, alloc);
|
||||||
|
const decomp = decomp_base.decompressor();
|
||||||
|
|
||||||
var frag_mgr: FragManager = try .init(alloc, fil, decomp, super.frag_start, super.frag_count, super.block_size);
|
var frag_mgr: FragManager = try .init(alloc, fil, decomp, super.frag_start, super.frag_count, super.block_size);
|
||||||
defer frag_mgr.deinit(io);
|
defer frag_mgr.deinit(io);
|
||||||
|
|
||||||
var arena: std.heap.ArenaAllocator = .init(alloc);
|
|
||||||
defer arena.deinit();
|
|
||||||
|
|
||||||
var sel_buf: [10]ExtractReturnUnion = undefined;
|
var sel_buf: [10]ExtractReturnUnion = undefined;
|
||||||
var sel: Io.Select(ExtractReturnUnion) = .init(io, &sel_buf);
|
var sel: Io.Select(ExtractReturnUnion) = .init(io, &sel_buf);
|
||||||
defer sel.cancelDiscard();
|
defer sel.cancelDiscard();
|
||||||
|
|
||||||
sel.async(.path_ret, extractReal, .{ self, alloc, io, fil, super, decomp, &arena, &sel, &frag_mgr, path });
|
sel.async(.path_ret, extractReal, .{ self, alloc, io, fil, super, decomp, &sel, &frag_mgr, path, true });
|
||||||
|
|
||||||
var id_table: CachedTable(u16) = .init(alloc, fil, decomp, super.id_start, super.id_count);
|
var id_table: CachedTable(u16) = .init(alloc, fil, decomp, super.id_start, super.id_count);
|
||||||
defer id_table.deinit(io);
|
defer id_table.deinit(io);
|
||||||
@@ -303,19 +305,42 @@ pub fn extract(
|
|||||||
const ret = try sel.await();
|
const ret = try sel.await();
|
||||||
const path_ret = try ret.path_ret;
|
const path_ret = try ret.path_ret;
|
||||||
|
|
||||||
if (options.ignore_permissions and xattr_table == null) continue;
|
if (options.ignore_permissions and xattr_table == null) {
|
||||||
|
path_ret.deinit(alloc);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (path_ret.inode.hdr.inode_type == .dir or path_ret.inode.hdr.inode_type == .ext_dir) {
|
if (path_ret.inode.hdr.inode_type == .dir or path_ret.inode.hdr.inode_type == .ext_dir) {
|
||||||
try dir_queue.push(alloc, path_ret);
|
try dir_queue.push(alloc, path_ret);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer path_ret.deinit(alloc);
|
||||||
|
try path_ret.setMetadata(alloc, io, &id_table, if (xattr_table == null) null else &xattr_table.?, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (sel.cancel()) |ret| {
|
||||||
|
const path_ret = try ret.path_ret;
|
||||||
|
|
||||||
|
if (options.ignore_permissions and xattr_table == null) {
|
||||||
|
path_ret.deinit(alloc);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path_ret.inode.hdr.inode_type == .dir or path_ret.inode.hdr.inode_type == .ext_dir) {
|
||||||
|
try dir_queue.push(alloc, path_ret);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
defer path_ret.deinit(alloc);
|
||||||
try path_ret.setMetadata(alloc, io, &id_table, if (xattr_table == null) null else &xattr_table.?, options);
|
try path_ret.setMetadata(alloc, io, &id_table, if (xattr_table == null) null else &xattr_table.?, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
var iter = dir_queue.iterator();
|
var iter = dir_queue.iterator();
|
||||||
while (iter.next()) |path_ret|
|
while (iter.next()) |path_ret| {
|
||||||
|
defer path_ret.deinit(alloc);
|
||||||
try path_ret.setMetadata(alloc, io, &id_table, if (xattr_table == null) null else &xattr_table.?, options);
|
try path_ret.setMetadata(alloc, io, &id_table, if (xattr_table == null) null else &xattr_table.?, options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn extractReal(
|
pub fn extractReal(
|
||||||
self: Inode,
|
self: Inode,
|
||||||
@@ -324,11 +349,17 @@ pub fn extractReal(
|
|||||||
fil: OffsetFile,
|
fil: OffsetFile,
|
||||||
super: Archive.Superblock,
|
super: Archive.Superblock,
|
||||||
decomp: *const Decompressor,
|
decomp: *const Decompressor,
|
||||||
inode_arena: *std.heap.ArenaAllocator,
|
|
||||||
sel: *Io.Select(ExtractReturnUnion),
|
sel: *Io.Select(ExtractReturnUnion),
|
||||||
frag_mgr: *FragManager,
|
frag_mgr: *FragManager,
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
|
origin: bool,
|
||||||
) ExtractError!PathRet {
|
) ExtractError!PathRet {
|
||||||
|
errdefer {
|
||||||
|
if (!origin) {
|
||||||
|
self.deinit(alloc);
|
||||||
|
alloc.free(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
switch (self.hdr.inode_type) {
|
switch (self.hdr.inode_type) {
|
||||||
.dir, .ext_dir => {
|
.dir, .ext_dir => {
|
||||||
try Io.Dir.cwd().createDir(io, path, @enumFromInt(0o777));
|
try Io.Dir.cwd().createDir(io, path, @enumFromInt(0o777));
|
||||||
@@ -343,18 +374,18 @@ pub fn extractReal(
|
|||||||
alloc.free(entries);
|
alloc.free(entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
const inode_alloc = inode_arena.allocator();
|
|
||||||
|
|
||||||
for (entries) |e| {
|
for (entries) |e| {
|
||||||
const new_path = try std.mem.concat(inode_alloc, u8, &[_][]const u8{ path, "/", e.name });
|
const new_path = try std.mem.concat(alloc, u8, &[_][]const u8{ path, "/", e.name });
|
||||||
|
errdefer alloc.free(new_path);
|
||||||
|
|
||||||
var rdr = fil.readerAt(super.inode_start + e.block_start);
|
var rdr = fil.readerAt(super.inode_start + e.block_start);
|
||||||
var meta: MetadataReader = .init(alloc, &rdr, decomp);
|
var meta: MetadataReader = .init(alloc, &rdr, decomp);
|
||||||
try meta.interface.discardAll(e.block_offset);
|
try meta.interface.discardAll(e.block_offset);
|
||||||
|
|
||||||
const new_inode = try read(inode_alloc, &meta.interface, super.block_size);
|
const new_inode = try read(alloc, &meta.interface, super.block_size);
|
||||||
|
errdefer new_inode.deinit(alloc);
|
||||||
|
|
||||||
sel.async(.path_ret, extractReal, .{ new_inode, alloc, io, fil, super, decomp, inode_arena, sel, frag_mgr, new_path });
|
sel.async(.path_ret, extractReal, .{ new_inode, alloc, io, fil, super, decomp, sel, frag_mgr, new_path, false });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.file, .ext_file => {
|
.file, .ext_file => {
|
||||||
@@ -420,5 +451,6 @@ pub fn extractReal(
|
|||||||
return .{
|
return .{
|
||||||
.path = path,
|
.path = path,
|
||||||
.inode = self,
|
.inode = self,
|
||||||
|
.origin = origin,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ test "Basics" {
|
|||||||
var fil = try Io.Dir.cwd().openFile(io, TestArchive, .{});
|
var fil = try Io.Dir.cwd().openFile(io, TestArchive, .{});
|
||||||
defer fil.close(io);
|
defer fil.close(io);
|
||||||
var sfs: Archive = try .init(io, fil, 0);
|
var sfs: Archive = try .init(io, fil, 0);
|
||||||
|
defer sfs.deinit(io);
|
||||||
try std.testing.expectEqualDeep(sfs.super, LinuxPATestCorrectSuperblock);
|
try std.testing.expectEqualDeep(sfs.super, LinuxPATestCorrectSuperblock);
|
||||||
const root_file = try sfs.root(alloc, io);
|
const root_file = try sfs.root(alloc, io);
|
||||||
defer root_file.deinit();
|
defer root_file.deinit();
|
||||||
@@ -30,6 +31,7 @@ test "ExtractSingleFile" {
|
|||||||
var fil = try Io.Dir.cwd().openFile(io, TestArchive, .{});
|
var fil = try Io.Dir.cwd().openFile(io, TestArchive, .{});
|
||||||
defer fil.close(io);
|
defer fil.close(io);
|
||||||
var sfs: Archive = try .init(io, fil, 0);
|
var sfs: Archive = try .init(io, fil, 0);
|
||||||
|
defer sfs.deinit(io);
|
||||||
var test_fil = try sfs.open(alloc, io, TestFile);
|
var test_fil = try sfs.open(alloc, io, TestFile);
|
||||||
defer test_fil.deinit();
|
defer test_fil.deinit();
|
||||||
try test_fil.extract(alloc, io, TestFileExtractLocation, try .Default());
|
try test_fil.extract(alloc, io, TestFileExtractLocation, try .Default());
|
||||||
@@ -45,6 +47,7 @@ test "ExtractCompleteArchive" {
|
|||||||
var fil = try Io.Dir.cwd().openFile(io, TestArchive, .{});
|
var fil = try Io.Dir.cwd().openFile(io, TestArchive, .{});
|
||||||
defer fil.close(io);
|
defer fil.close(io);
|
||||||
var sfs: Archive = try .init(io, fil, 0);
|
var sfs: Archive = try .init(io, fil, 0);
|
||||||
|
defer sfs.deinit(io);
|
||||||
try sfs.extract(alloc, io, TestFullExtractLocation, try .Default());
|
try sfs.extract(alloc, io, TestFullExtractLocation, try .Default());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user