Compare commits
2 Commits
2b0625e178
...
700993b0e3
| Author | SHA1 | Date | |
|---|---|---|---|
| 700993b0e3 | |||
| 78d1ee2937 |
+16
-7
@@ -19,7 +19,7 @@ alloc: std.mem.Allocator,
|
|||||||
|
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
buffers: std.ArrayList(Buffer),
|
buffers: std.ArrayList(Buffer),
|
||||||
buffer_queue: std.SinglyLinkedList,
|
buffer_queue: std.SinglyLinkedList = .{},
|
||||||
|
|
||||||
pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
|
pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
|
||||||
return .{
|
return .{
|
||||||
@@ -37,22 +37,31 @@ pub fn deinit(self: Self) void {
|
|||||||
|
|
||||||
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);
|
var buf = try alloc.alloc(u8, in.len * 2);
|
||||||
defer alloc.free(buf);
|
defer alloc.free(buf);
|
||||||
return lzmaDecomp(buf, in, out);
|
return lzmaDecomp(alloc, &buf, in, out) catch |err| return switch (err) {
|
||||||
|
error.OutOfMemory => Error.OutOfMemory,
|
||||||
|
else => Error.ReadFailed,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
var self: Self = @fieldParentPtr("interface", d.?);
|
var self: *Self = @fieldParentPtr("interface", @constCast(d.?));
|
||||||
const buf_node = self.buffer_queue.popFirst();
|
const buf_node = self.buffer_queue.popFirst();
|
||||||
var buf: *Buffer = undefined;
|
var buf: *Buffer = undefined;
|
||||||
if (buf_node == null) {
|
if (buf_node == null) {
|
||||||
const new_buf = try self.buffers.addOne(self.alloc);
|
const new_buf = try self.buffers.addOne(self.alloc);
|
||||||
new_buf.* = .{ .{}, try self.alloc.alloc(u8, self.block_size + lzma.block_size_max) };
|
new_buf.* = .{ .node = .{}, .buf = try self.alloc.alloc(u8, self.block_size) };
|
||||||
buf = new_buf;
|
buf = new_buf;
|
||||||
} else {
|
} else {
|
||||||
buf = @fieldParentPtr("node", buf_node);
|
buf = @fieldParentPtr("node", buf_node.?);
|
||||||
}
|
}
|
||||||
defer self.buffer_queue.prepend(&buf.node);
|
defer self.buffer_queue.prepend(&buf.node);
|
||||||
return lzmaDecomp(self.alloc, &buf.buf, in, out);
|
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 {
|
||||||
|
|||||||
+12
-9
@@ -19,7 +19,7 @@ alloc: std.mem.Allocator,
|
|||||||
|
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
buffers: std.ArrayList(Buffer),
|
buffers: std.ArrayList(Buffer),
|
||||||
buffer_queue: std.SinglyLinkedList,
|
buffer_queue: std.SinglyLinkedList = .{},
|
||||||
|
|
||||||
pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
|
pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
|
||||||
return .{
|
return .{
|
||||||
@@ -37,25 +37,28 @@ pub fn deinit(self: Self) void {
|
|||||||
|
|
||||||
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);
|
var buf = try alloc.alloc(u8, in.len * 2);
|
||||||
defer alloc.free(buf);
|
defer alloc.free(buf);
|
||||||
return lzmaDecomp(buf, in, out);
|
return xzDecomp(alloc, &buf, in, out) catch return Error.ReadFailed;
|
||||||
}
|
}
|
||||||
var self: Self = @fieldParentPtr("interface", d.?);
|
var self: *Self = @fieldParentPtr("interface", @constCast(d.?));
|
||||||
const buf_node = self.buffer_queue.popFirst();
|
const buf_node = self.buffer_queue.popFirst();
|
||||||
var buf: *Buffer = undefined;
|
var buf: *Buffer = undefined;
|
||||||
if (buf_node == null) {
|
if (buf_node == null) {
|
||||||
const new_buf = try self.buffers.addOne(self.alloc);
|
const new_buf = try self.buffers.addOne(self.alloc);
|
||||||
new_buf.* = .{ .{}, try self.alloc.alloc(u8, self.block_size + xz.block_size_max) };
|
new_buf.* = .{ .node = .{}, .buf = try self.alloc.alloc(u8, self.block_size) };
|
||||||
buf = new_buf;
|
buf = new_buf;
|
||||||
} else {
|
} else {
|
||||||
buf = @fieldParentPtr("node", buf_node);
|
buf = @fieldParentPtr("node", buf_node.?);
|
||||||
}
|
}
|
||||||
defer self.buffer_queue.prepend(&buf.node);
|
defer self.buffer_queue.prepend(&buf.node);
|
||||||
return lzmaDecomp(self.alloc, &buf.buf, in, out);
|
return xzDecomp(self.alloc, &buf.buf, in, out) catch {
|
||||||
|
// self.err = err;
|
||||||
|
return Error.ReadFailed;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn lzmaDecomp(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 {
|
||||||
var rdr: Reader = .fixed(in);
|
var rdr: Reader = .fixed(in);
|
||||||
var d = try xz.Decompress.init(&rdr, alloc, buffer.*);
|
var d = try xz.Decompress.init(&rdr, alloc, buffer.*);
|
||||||
defer {
|
defer {
|
||||||
@@ -73,5 +76,5 @@ 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 {
|
||||||
var buf = try alloc.alloc(u8, in.len);
|
var buf = try alloc.alloc(u8, in.len);
|
||||||
defer alloc.free(buf);
|
defer alloc.free(buf);
|
||||||
return lzmaDecomp(alloc, &buf, in, out) catch return Error.ReadFailed;
|
return xzDecomp(alloc, &buf, in, out) catch return Error.ReadFailed;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -19,7 +19,7 @@ alloc: std.mem.Allocator,
|
|||||||
|
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
buffers: std.ArrayList(Buffer),
|
buffers: std.ArrayList(Buffer),
|
||||||
buffer_queue: std.SinglyLinkedList,
|
buffer_queue: std.SinglyLinkedList = .{},
|
||||||
|
|
||||||
pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
|
pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
|
||||||
return .{
|
return .{
|
||||||
@@ -41,15 +41,15 @@ fn decomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8
|
|||||||
defer alloc.free(buf);
|
defer alloc.free(buf);
|
||||||
return zlibDecomp(buf, in, out);
|
return zlibDecomp(buf, in, out);
|
||||||
}
|
}
|
||||||
var self: Self = @fieldParentPtr("interface", d.?);
|
var self: *Self = @fieldParentPtr("interface", @constCast(d.?));
|
||||||
const buf_node = self.buffer_queue.popFirst();
|
const buf_node = self.buffer_queue.popFirst();
|
||||||
var buf: *Buffer = undefined;
|
var buf: *Buffer = undefined;
|
||||||
if (buf_node == null) {
|
if (buf_node == null) {
|
||||||
const new_buf = try self.buffers.addOne(self.alloc);
|
const new_buf = try self.buffers.addOne(self.alloc);
|
||||||
new_buf.* = .{ .{}, try self.alloc.alloc(u8, self.block_size) };
|
new_buf.* = .{ .node = .{}, .buf = try self.alloc.alloc(u8, self.block_size) };
|
||||||
buf = new_buf;
|
buf = new_buf;
|
||||||
} else {
|
} else {
|
||||||
buf = @fieldParentPtr("node", buf_node);
|
buf = @fieldParentPtr("node", buf_node.?);
|
||||||
}
|
}
|
||||||
defer self.buffer_queue.prepend(&buf.node);
|
defer self.buffer_queue.prepend(&buf.node);
|
||||||
return zlibDecomp(buf.buf, in, out);
|
return zlibDecomp(buf.buf, in, out);
|
||||||
|
|||||||
+4
-4
@@ -19,7 +19,7 @@ alloc: std.mem.Allocator,
|
|||||||
|
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
buffers: std.ArrayList(Buffer),
|
buffers: std.ArrayList(Buffer),
|
||||||
buffer_queue: std.SinglyLinkedList,
|
buffer_queue: std.SinglyLinkedList = .{},
|
||||||
|
|
||||||
pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
|
pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
|
||||||
return .{
|
return .{
|
||||||
@@ -41,15 +41,15 @@ fn decomp(d: ?*const Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8
|
|||||||
defer alloc.free(buf);
|
defer alloc.free(buf);
|
||||||
return zstdDecomp(buf, in, out);
|
return zstdDecomp(buf, in, out);
|
||||||
}
|
}
|
||||||
var self: Self = @fieldParentPtr("interface", d.?);
|
var self: *Self = @fieldParentPtr("interface", @constCast(d.?));
|
||||||
const buf_node = self.buffer_queue.popFirst();
|
const buf_node = self.buffer_queue.popFirst();
|
||||||
var buf: *Buffer = undefined;
|
var buf: *Buffer = undefined;
|
||||||
if (buf_node == null) {
|
if (buf_node == null) {
|
||||||
const new_buf = try self.buffers.addOne(self.alloc);
|
const new_buf = try self.buffers.addOne(self.alloc);
|
||||||
new_buf.* = .{ .{}, try self.alloc.alloc(u8, self.block_size + zstd.block_size_max) };
|
new_buf.* = .{ .node = .{}, .buf = try self.alloc.alloc(u8, self.block_size + zstd.block_size_max) };
|
||||||
buf = new_buf;
|
buf = new_buf;
|
||||||
} else {
|
} else {
|
||||||
buf = @fieldParentPtr("node", buf_node);
|
buf = @fieldParentPtr("node", buf_node.?);
|
||||||
}
|
}
|
||||||
defer self.buffer_queue.prepend(&buf.node);
|
defer self.buffer_queue.prepend(&buf.node);
|
||||||
return zstdDecomp(buf.buf, in, out);
|
return zstdDecomp(buf.buf, in, out);
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@ pub fn readDirectory(alloc: std.mem.Allocator, rdr: *Reader, size: u32) ![]DirEn
|
|||||||
|
|
||||||
tot_red += @sizeOf(Header);
|
tot_red += @sizeOf(Header);
|
||||||
|
|
||||||
for (hdr.count + 1) |_| {
|
for (0..hdr.count + 1) |_| {
|
||||||
try rdr.readSliceEndian(RawEntry, @ptrCast(&raw), .little);
|
try rdr.readSliceEndian(RawEntry, @ptrCast(&raw), .little);
|
||||||
|
|
||||||
const new_name = try alloc.alloc(u8, raw.name_size + 1);
|
const new_name = try alloc.alloc(u8, raw.name_size + 1);
|
||||||
|
|||||||
+3
-32
@@ -63,12 +63,12 @@ pub fn open(self: File, alloc: std.mem.Allocator, io: Io, filepath: []const u8)
|
|||||||
alloc.free(entries);
|
alloc.free(entries);
|
||||||
}
|
}
|
||||||
const path = std.mem.trim(u8, filepath, "/");
|
const path = std.mem.trim(u8, filepath, "/");
|
||||||
const first_element: []u8 = std.mem.sliceTo(path, "/");
|
const first_element: []const u8 = std.mem.sliceTo(path, '/');
|
||||||
|
|
||||||
var search_slice = entries;
|
var search_slice = entries;
|
||||||
var idx: usize = undefined;
|
var idx: usize = undefined;
|
||||||
while (search_slice.len > 0) {
|
while (search_slice.len > 0) {
|
||||||
idx = search_slice / 2;
|
idx = search_slice.len / 2;
|
||||||
const middle = search_slice[idx];
|
const middle = search_slice[idx];
|
||||||
switch (std.mem.order(u8, first_element, middle.name)) {
|
switch (std.mem.order(u8, first_element, middle.name)) {
|
||||||
.eq => break,
|
.eq => break,
|
||||||
@@ -85,36 +85,7 @@ pub fn open(self: File, alloc: std.mem.Allocator, io: Io, filepath: []const u8)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract(self: File, alloc: std.mem.Allocator, io: Io, filepath: []const u8, options: ExtractionOptions) !void {
|
pub fn extract(self: File, alloc: std.mem.Allocator, io: Io, filepath: []const u8, options: ExtractionOptions) !void {
|
||||||
var cache: SharedCache = try .init(alloc, 10); // TODO: calculate a good initial cache size.
|
return self.inode.extract(alloc, io, self.archive.file, self.archive.super, filepath, options);
|
||||||
defer cache.deinit();
|
|
||||||
var decomp = switch (self.archive.super.compression) {
|
|
||||||
.gzip => {},
|
|
||||||
.lzma => {},
|
|
||||||
.xz => {},
|
|
||||||
.zstd => {},
|
|
||||||
else => unreachable,
|
|
||||||
};
|
|
||||||
return self.extractReal(alloc, io, &cache, &decomp.interface, filepath, options);
|
|
||||||
}
|
|
||||||
fn extractReal(self: File, alloc: std.mem.Allocator, io: Io, cache: *SharedCache, decomp: *const Decompressor, filepath: []const u8, options: ExtractionOptions) !void {
|
|
||||||
_ = options;
|
|
||||||
switch (self.inode.hdr.inode_type) {
|
|
||||||
.file, .ext_file => {
|
|
||||||
var ext = try self.inode.dataExtractor(
|
|
||||||
self.archive.file,
|
|
||||||
cache,
|
|
||||||
decomp,
|
|
||||||
self.archive.super.block_size,
|
|
||||||
);
|
|
||||||
|
|
||||||
var atomic_file = try Io.Dir.cwd().createFileAtomic(io, filepath, .{});
|
|
||||||
defer atomic_file.deinit(io);
|
|
||||||
|
|
||||||
try ext.extract(alloc, io, atomic_file.file);
|
|
||||||
try atomic_file.link(io);
|
|
||||||
},
|
|
||||||
else => return error.TODO,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
|
|||||||
+319
-6
@@ -7,6 +7,7 @@ const Io = std.Io;
|
|||||||
const Archive = @import("archive.zig");
|
const Archive = @import("archive.zig");
|
||||||
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 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");
|
||||||
@@ -122,6 +123,18 @@ pub fn gid(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decom
|
|||||||
pub fn uid(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const Decompressor, id_table_start: u64) !u16 {
|
pub fn uid(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const Decompressor, id_table_start: u64) !u16 {
|
||||||
return LookupTable.lookupValue(u16, alloc, io, decomp, fil, id_table_start, self.hdr.uid_idx);
|
return LookupTable.lookupValue(u16, alloc, io, decomp, fil, id_table_start, self.hdr.uid_idx);
|
||||||
}
|
}
|
||||||
|
pub fn xattrIndex(self: Inode) !u32 {
|
||||||
|
return switch (self.data) {
|
||||||
|
.ext_dir => |e| e.xattr_idx,
|
||||||
|
.ext_file => |e| e.xattr_idx,
|
||||||
|
.ext_symlink => |e| e.xattr_idx,
|
||||||
|
.ext_block_dev => |e| e.xattr_idx,
|
||||||
|
.ext_char_dev => |e| e.xattr_idx,
|
||||||
|
.ext_fifo => |e| e.xattr_idx,
|
||||||
|
.ext_socket => |e| e.xattr_idx,
|
||||||
|
else => Error.NotExtended,
|
||||||
|
};
|
||||||
|
}
|
||||||
// Get an inode's xattr values. If the inode does not have xattr values (including if the inode is not an extended type), an empty slice is returned.
|
// Get an inode's xattr values. If the inode does not have xattr values (including if the inode is not an extended type), an empty slice is returned.
|
||||||
pub fn xattrValues(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const Decompressor, xattr_table_start: u64) ![]XattrTable.XattrOwned {
|
pub fn xattrValues(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const Decompressor, xattr_table_start: u64) ![]XattrTable.XattrOwned {
|
||||||
const idx = switch (self.data) {
|
const idx = switch (self.data) {
|
||||||
@@ -198,9 +211,309 @@ pub const Header = extern struct {
|
|||||||
|
|
||||||
// Extract
|
// Extract
|
||||||
|
|
||||||
pub fn extract(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, super: Archive.Superblock, path: []const u8, options: ExtractionOptions) !void {}
|
const FileRet = struct {
|
||||||
pub fn extractDir(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, super: Archive.Superblock, path: []const u8, options: ExtractionOptions) !void {}
|
file: Io.File,
|
||||||
pub fn extractRegFile(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, super: Archive.Superblock, path: []const u8, options: ExtractionOptions) !void {}
|
inode: Inode,
|
||||||
pub fn extractSymlink(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, super: Archive.Superblock, path: []const u8, options: ExtractionOptions) !void {}
|
};
|
||||||
pub fn extractDevice(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, super: Archive.Superblock, path: []const u8, options: ExtractionOptions) !void {}
|
const Tables = struct {
|
||||||
pub fn extractIPC(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, super: Archive.Superblock, path: []const u8, options: ExtractionOptions) !void {}
|
id: LookupTable.CachedTable(u16),
|
||||||
|
frag: LookupTable.CachedTable(FragEntry),
|
||||||
|
xattr: XattrTable,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn extract(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, super: Archive.Superblock, path: []const u8, options: ExtractionOptions) !void {
|
||||||
|
var decomp = switch (super.compression) {
|
||||||
|
.gzip => try @import("decomp/zlib.zig").init(alloc, super.block_size),
|
||||||
|
.lzma => try @import("decomp/lzma.zig").init(alloc, super.block_size),
|
||||||
|
.xz => try @import("decomp/xz.zig").init(alloc, super.block_size),
|
||||||
|
.zstd => try @import("decomp/zstd.zig").init(alloc, super.block_size),
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
defer decomp.deinit();
|
||||||
|
|
||||||
|
var frag_table: LookupTable.CachedTable(FragEntry) = .init(alloc, fil, &decomp.interface, super.frag_start, super.frag_count);
|
||||||
|
defer frag_table.deinit(io);
|
||||||
|
|
||||||
|
var group: Io.Group = .init;
|
||||||
|
defer group.cancel(io);
|
||||||
|
var que: Io.Queue(FileRet) = .init(&[1]FileRet{undefined} ** 12);
|
||||||
|
defer que.close(io);
|
||||||
|
|
||||||
|
switch (self.hdr.inode_type) {
|
||||||
|
.dir, .ext_dir => group.async(io, extractDir, .{
|
||||||
|
self,
|
||||||
|
alloc,
|
||||||
|
io,
|
||||||
|
fil,
|
||||||
|
&decomp.interface,
|
||||||
|
&frag_table,
|
||||||
|
super.block_size,
|
||||||
|
super.dir_start,
|
||||||
|
path,
|
||||||
|
options,
|
||||||
|
&que,
|
||||||
|
}),
|
||||||
|
.file, .ext_file => group.async(io, extractRegFile, .{
|
||||||
|
self,
|
||||||
|
alloc,
|
||||||
|
io,
|
||||||
|
file,
|
||||||
|
&decomp.interface,
|
||||||
|
&frag_table,
|
||||||
|
super.block_size,
|
||||||
|
path,
|
||||||
|
options,
|
||||||
|
&que,
|
||||||
|
}),
|
||||||
|
.symlink, .ext_symlink => group.async(Io, extractSymlink, .{ self, io, path, options, &que }),
|
||||||
|
else => group.async(io, extractDevice, .{ self, alloc, io, super, path, options, &que }),
|
||||||
|
}
|
||||||
|
|
||||||
|
var id_table: LookupTable.CachedTable(u16) = .init(alloc, fil, decomp, super.id_start, super.id_count);
|
||||||
|
defer id_table.deinit(io);
|
||||||
|
var xattr_table: XattrTable = try .init(alloc, io, fil, decomp, super.xattr_start);
|
||||||
|
defer xattr_table.deinit(io);
|
||||||
|
|
||||||
|
for (que.getOne(io)) |res| {
|
||||||
|
const ret = res catch break;
|
||||||
|
|
||||||
|
const inode: Inode = ret.inode;
|
||||||
|
defer inode.deinit(alloc);
|
||||||
|
const ret_file: Io.File = ret.file;
|
||||||
|
defer ret_file.close(io);
|
||||||
|
|
||||||
|
if (!options.ignore_xattr) {
|
||||||
|
if (inode.xattrIndex()) |idx| {
|
||||||
|
const xattrs = try xattr_table.get(io, idx);
|
||||||
|
for (xattrs) |x| {
|
||||||
|
// TODO: Check error.
|
||||||
|
const xattr_res = std.os.linux.fsetxattr(ret_file.handle, x.key, x.value.ptr, x.value.len, 0);
|
||||||
|
if (xattr_res != 0 and options.verbose)
|
||||||
|
options.verbose_writer.?.print("setxattr failed with code: {}\n", .{xattr_res}) catch {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!options.ignore_permissions) {
|
||||||
|
try ret_file.setPermissions(io, inode.hdr.permissions);
|
||||||
|
try ret_file.setOwner(io, try id_table.get(io, inode.hdr.uid_idx), try id_table.get(io, inode.hdr.gid_idx));
|
||||||
|
}
|
||||||
|
if (!que.type_erased.closed and group.token.raw == null) que.close(io);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn extractDir(
|
||||||
|
self: Inode,
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
io: Io,
|
||||||
|
fil: OffsetFile,
|
||||||
|
decomp: *const Decompressor,
|
||||||
|
frag: *LookupTable.CachedTable(FragEntry),
|
||||||
|
block_size: u32,
|
||||||
|
dir_start: u64,
|
||||||
|
inode_start: u64,
|
||||||
|
path: []const u8,
|
||||||
|
options: ExtractionOptions,
|
||||||
|
que: *Io.Queue(FileRet),
|
||||||
|
) !void {
|
||||||
|
defer alloc.free(path);
|
||||||
|
|
||||||
|
const dirs = try self.readDirectory(alloc, io, fil, decomp, dir_start);
|
||||||
|
defer {
|
||||||
|
for (dirs) |d|
|
||||||
|
d.deinit(alloc);
|
||||||
|
alloc.free(dirs);
|
||||||
|
}
|
||||||
|
|
||||||
|
var group: Io.Group = .init;
|
||||||
|
defer group.cancel(io);
|
||||||
|
|
||||||
|
for (dirs) |d| {
|
||||||
|
var rdr = try fil.readerAt(io, d.block_start + inode_start, &[0]u8{});
|
||||||
|
var meta: MetadataReader = .init(alloc, &rdr.interface, decomp);
|
||||||
|
try meta.interface.discardAll(d.block_offset);
|
||||||
|
|
||||||
|
const inode = try read(alloc, &meta.interface, block_size);
|
||||||
|
|
||||||
|
const new_path = try std.mem.concat(alloc, u8, &[_][]const u8{ path, "/", d.name });
|
||||||
|
|
||||||
|
switch (inode.hdr.inode_type) {
|
||||||
|
.dir, .ext_dir => group.async(io, extractDir, .{
|
||||||
|
self,
|
||||||
|
alloc,
|
||||||
|
io,
|
||||||
|
fil,
|
||||||
|
&decomp.interface,
|
||||||
|
&frag,
|
||||||
|
block_size,
|
||||||
|
dir_start,
|
||||||
|
new_path,
|
||||||
|
options,
|
||||||
|
&que,
|
||||||
|
}),
|
||||||
|
.file, .ext_file => group.async(io, extractRegFile, .{
|
||||||
|
self,
|
||||||
|
alloc,
|
||||||
|
io,
|
||||||
|
file,
|
||||||
|
&decomp.interface,
|
||||||
|
&frag,
|
||||||
|
block_size,
|
||||||
|
new_path,
|
||||||
|
options,
|
||||||
|
&que,
|
||||||
|
}),
|
||||||
|
.symlink, .ext_symlink => group.async(Io, extractSymlink, .{ self, alloc, io, new_path, options, &que }),
|
||||||
|
else => group.async(io, extractDevice, .{ self, alloc, io, new_path, options, &que }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try group.await(io);
|
||||||
|
|
||||||
|
try que.putOne(io, .{ .file = try Io.Dir.cwd().openFile(io, path, .{}), .inode = self });
|
||||||
|
}
|
||||||
|
pub fn extractRegFile(
|
||||||
|
self: Inode,
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
io: Io,
|
||||||
|
fil: OffsetFile,
|
||||||
|
decomp: *const Decompressor,
|
||||||
|
frag: *LookupTable.CachedTable(FragEntry),
|
||||||
|
block_size: u32,
|
||||||
|
path: []const u8,
|
||||||
|
options: ExtractionOptions,
|
||||||
|
que: *Io.Queue(FileRet),
|
||||||
|
) !void {
|
||||||
|
_ = options;
|
||||||
|
defer alloc.free(path);
|
||||||
|
|
||||||
|
const atom = try Io.Dir.cwd().createFileAtomic(io, path, .{});
|
||||||
|
defer atom.deinit(io);
|
||||||
|
|
||||||
|
var size: u64 = undefined;
|
||||||
|
var start: u64 = undefined;
|
||||||
|
var blocks: []file.BlockSize = undefined;
|
||||||
|
var frag_idx: u32 = undefined;
|
||||||
|
var frag_offset: u32 = undefined;
|
||||||
|
switch (self.data) {
|
||||||
|
.file => |f| {
|
||||||
|
size = f.size;
|
||||||
|
start = f.block_start;
|
||||||
|
blocks = f.block_sizes;
|
||||||
|
frag_idx = f.frag_idx;
|
||||||
|
frag_offset = f.frag_block_offset;
|
||||||
|
},
|
||||||
|
.ext_file => |f| {
|
||||||
|
size = f.size;
|
||||||
|
start = f.block_start;
|
||||||
|
blocks = f.block_sizes;
|
||||||
|
frag_idx = f.frag_idx;
|
||||||
|
frag_offset = f.frag_block_offset;
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
|
||||||
|
const ext: DataExtractor = .init(fil, decomp, block_size, size, start, blocks);
|
||||||
|
ext.addFrag(frag_offset, try frag.get(io, frag_idx));
|
||||||
|
|
||||||
|
var group: Io.Group = .init;
|
||||||
|
defer group.cancel(io);
|
||||||
|
|
||||||
|
ext.extractAsync(alloc, io, &group, atom.file);
|
||||||
|
|
||||||
|
try group.await(io);
|
||||||
|
|
||||||
|
try atom.link(io);
|
||||||
|
|
||||||
|
try que.putOne(io, .{ .file = atom.file, .inode = self });
|
||||||
|
}
|
||||||
|
pub fn extractSymlink(
|
||||||
|
self: Inode,
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
io: Io,
|
||||||
|
path: []const u8,
|
||||||
|
options: ExtractionOptions,
|
||||||
|
que: *Io.Queue(FileRet),
|
||||||
|
) !void {
|
||||||
|
defer alloc.free(path);
|
||||||
|
|
||||||
|
_ = options;
|
||||||
|
_ = que;
|
||||||
|
// TODO: handle symlink options
|
||||||
|
const target = try self.symlinkTarget();
|
||||||
|
|
||||||
|
try Io.Dir.cwd().symLink(io, target, path, .{});
|
||||||
|
|
||||||
|
// TODO: On Linux you can't set permission & xattrs on symlinks (they inherit from their target), but on Mac you can.
|
||||||
|
}
|
||||||
|
pub fn extractDevice(
|
||||||
|
self: Inode,
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
io: Io,
|
||||||
|
path: []const u8,
|
||||||
|
options: ExtractionOptions,
|
||||||
|
que: *Io.Queue(FileRet),
|
||||||
|
) !void {
|
||||||
|
defer alloc.free(path);
|
||||||
|
|
||||||
|
var dev: u32 = 0;
|
||||||
|
var mode: u32 = undefined;
|
||||||
|
|
||||||
|
switch (self.data) {
|
||||||
|
.char_dev => |d| {
|
||||||
|
dev = d.dev;
|
||||||
|
mode = std.posix.DT.CHR;
|
||||||
|
},
|
||||||
|
.block_dev => |d| {
|
||||||
|
dev = d.dev;
|
||||||
|
mode = std.posix.DT.BLK;
|
||||||
|
},
|
||||||
|
.ext_char_dev => |d| {
|
||||||
|
dev = d.dev;
|
||||||
|
mode = std.posix.DT.BLK;
|
||||||
|
},
|
||||||
|
.ext_block_dev => |d| {
|
||||||
|
dev = d.dev;
|
||||||
|
mode = std.posix.DT.BLK;
|
||||||
|
},
|
||||||
|
.fifo, .ext_fifo => mode = std.posix.DT.FIFO,
|
||||||
|
.socket, .ext_socket => mode = std.posix.DT.SOCK,
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
|
||||||
|
const sentinel_path = try std.mem.concatMaybeSentinel(alloc, u8, &[1][]const u8{path}, 0);
|
||||||
|
defer alloc.free(sentinel_path);
|
||||||
|
const res = std.os.linux.mknod(sentinel_path, mode, dev);
|
||||||
|
if (res != 0 and options.verbose)
|
||||||
|
options.verbose_writer.?.print("mknod failed with code: {}\n", .{res}) catch {};
|
||||||
|
|
||||||
|
try que.putOne(io, .{
|
||||||
|
.file = try Io.Dir.cwd().openFile(io, path, .{}),
|
||||||
|
.inode = self,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn applyMetadataLoop(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const Decompressor, super: Archive.Superblock, que: *Io.Queue(FileRet), options: ExtractionOptions) !void {
|
||||||
|
var id_table: LookupTable.CachedTable(u16) = .init(alloc, fil, decomp, super.id_start, super.id_count);
|
||||||
|
defer id_table.deinit(io);
|
||||||
|
var xattr_table: XattrTable = try .init(alloc, io, fil, decomp, super.xattr_start);
|
||||||
|
defer xattr_table.deinit(io);
|
||||||
|
for (try que.getOne(io)) |ret| {
|
||||||
|
const inode: Inode = ret.inode;
|
||||||
|
defer inode.deinit(alloc);
|
||||||
|
const ret_file: Io.File = ret.file;
|
||||||
|
defer ret_file.close(io);
|
||||||
|
|
||||||
|
if (!options.ignore_xattr) {
|
||||||
|
if (inode.xattrIndex()) |idx| {
|
||||||
|
const xattrs = try xattr_table.get(io, idx);
|
||||||
|
for (xattrs) |x| {
|
||||||
|
// TODO: Check error.
|
||||||
|
_ = std.os.linux.fsetxattr(ret_file.handle, x.key, x.value.ptr, x.value.len, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!options.ignore_permissions) {
|
||||||
|
try ret_file.setPermissions(io, inode.hdr.permissions);
|
||||||
|
try ret_file.setOwner(io, try id_table.get(io, inode.hdr.uid_idx), try id_table.get(io, inode.hdr.gid_idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ pub fn CachedTable(comptime T: anytype) type {
|
|||||||
|
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
fil: OffsetFile,
|
fil: OffsetFile,
|
||||||
|
decomp: *const Decompressor,
|
||||||
|
|
||||||
table_start: u64,
|
table_start: u64,
|
||||||
total_num: u32,
|
total_num: u32,
|
||||||
|
|
||||||
@@ -39,10 +41,12 @@ pub fn CachedTable(comptime T: anytype) type {
|
|||||||
|
|
||||||
mut: Io.Mutex = .init,
|
mut: Io.Mutex = .init,
|
||||||
|
|
||||||
pub fn init(alloc: std.mem.Allocator, fil: OffsetFile, offset: u64, total_num: u32) Table {
|
pub fn init(alloc: std.mem.Allocator, fil: OffsetFile, decomp: *const Decompressor, offset: u64, total_num: u32) Table {
|
||||||
return .{
|
return .{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
.fil = fil,
|
.fil = fil,
|
||||||
|
.decomp = decomp,
|
||||||
|
|
||||||
.table_start = offset,
|
.table_start = offset,
|
||||||
.total_num = total_num,
|
.total_num = total_num,
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const SharedCache = @import("shared_cache.zig");
|
|||||||
const DataExtractor = @This();
|
const DataExtractor = @This();
|
||||||
|
|
||||||
fil: OffsetFile,
|
fil: OffsetFile,
|
||||||
cache: *SharedCache,
|
// cache: *SharedCache,
|
||||||
decomp: *const Decompressor,
|
decomp: *const Decompressor,
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
|
|
||||||
@@ -23,10 +23,10 @@ blocks: []BlockSize,
|
|||||||
frag_offset: u32 = 0,
|
frag_offset: u32 = 0,
|
||||||
frag_entry: ?FragEntry = null,
|
frag_entry: ?FragEntry = null,
|
||||||
|
|
||||||
pub fn init(fil: OffsetFile, cache: *SharedCache, decomp: *const Decompressor, block_size: u32, file_size: u64, data_start: u64, blocks: []BlockSize) DataExtractor {
|
pub fn init(fil: OffsetFile, decomp: *const Decompressor, block_size: u32, file_size: u64, data_start: u64, blocks: []BlockSize) DataExtractor {
|
||||||
return .{
|
return .{
|
||||||
.fil = fil,
|
.fil = fil,
|
||||||
.cache = cache,
|
// .cache = cache,
|
||||||
.decomp = decomp,
|
.decomp = decomp,
|
||||||
.block_size = block_size,
|
.block_size = block_size,
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ alloc: std.mem.Allocator,
|
|||||||
|
|
||||||
fil: OffsetFile,
|
fil: OffsetFile,
|
||||||
io: Io,
|
io: Io,
|
||||||
cache: *SharedCache,
|
// cache: *SharedCache,
|
||||||
decomp: *const Decompressor,
|
decomp: *const Decompressor,
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ sparse_block: bool = false,
|
|||||||
|
|
||||||
interface: Io.Reader,
|
interface: Io.Reader,
|
||||||
|
|
||||||
pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, cache: *SharedCache, decomp: *const Decompressor, block_size: u32, file_size: u64, data_start: u64, blocks: []BlockSize) !DataReader {
|
pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const Decompressor, block_size: u32, file_size: u64, data_start: u64, blocks: []BlockSize) !DataReader {
|
||||||
return .{
|
return .{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, cache: *SharedCac
|
|||||||
.blocks = blocks,
|
.blocks = blocks,
|
||||||
|
|
||||||
.interface = .{
|
.interface = .{
|
||||||
.buffer = try cache.getCache(io),
|
.buffer = try alloc.alloc(u8, block_size),
|
||||||
.seek = 0,
|
.seek = 0,
|
||||||
.end = 0,
|
.end = 0,
|
||||||
.vtable = &.{
|
.vtable = &.{
|
||||||
@@ -60,10 +60,7 @@ pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, cache: *SharedCac
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn deinit(self: *DataReader) void {
|
pub fn deinit(self: *DataReader) void {
|
||||||
if (self.interface.buffer.len > 0) {
|
self.alloc.free(self.interface.buffer);
|
||||||
const buf_nod: *SharedCache.BufferNode = @fieldParentPtr("cache", self.interface.buffer);
|
|
||||||
self.cache.returnCache(buf_nod);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn addFrag(self: *DataReader, frag_offset: u32, entry: FragEntry) void {
|
pub fn addFrag(self: *DataReader, frag_offset: u32, entry: FragEntry) void {
|
||||||
self.frag_offset = frag_offset;
|
self.frag_offset = frag_offset;
|
||||||
|
|||||||
+2
-2
@@ -40,8 +40,8 @@ pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const De
|
|||||||
.value_cache = .init(alloc),
|
.value_cache = .init(alloc),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn deinit(self: *XattrCachedTable) void {
|
pub fn deinit(self: *XattrCachedTable, io: Io) void {
|
||||||
self.table.deinit();
|
self.table.deinit(io);
|
||||||
self.value_cache.deinit();
|
self.value_cache.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user