Started concrete implementation of extraction
This commit is contained in:
+1
-30
@@ -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 {
|
||||
var cache: SharedCache = try .init(alloc, 10); // TODO: calculate a good initial cache size.
|
||||
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,
|
||||
}
|
||||
return self.inode.extract(alloc, io, self.archive.file, self.archive.super, filepath, options);
|
||||
}
|
||||
|
||||
// Types
|
||||
|
||||
+199
-6
@@ -7,6 +7,7 @@ const Io = std.Io;
|
||||
const Archive = @import("archive.zig");
|
||||
const DirEntry = @import("directory.zig");
|
||||
const ExtractionOptions = @import("options.zig");
|
||||
const FragEntry = @import("frag.zig").FragEntry;
|
||||
const dir = @import("inode_data/dir.zig");
|
||||
const file = @import("inode_data/file.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 {
|
||||
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.
|
||||
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) {
|
||||
@@ -198,9 +211,189 @@ pub const Header = extern struct {
|
||||
|
||||
// Extract
|
||||
|
||||
pub fn extract(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, super: Archive.Superblock, path: []const u8, options: ExtractionOptions) !void {}
|
||||
pub fn extractDir(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, super: Archive.Superblock, path: []const u8, options: ExtractionOptions) !void {}
|
||||
pub fn extractRegFile(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, super: Archive.Superblock, path: []const u8, options: ExtractionOptions) !void {}
|
||||
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 {}
|
||||
pub fn extractIPC(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, super: Archive.Superblock, path: []const u8, options: ExtractionOptions) !void {}
|
||||
const FileRet = struct {
|
||||
file: Io.File,
|
||||
inode: Inode,
|
||||
};
|
||||
const Tables = struct {
|
||||
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_sizee),
|
||||
.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, super, path, options, &que }),
|
||||
.file, .ext_file => group.async(io, extractRegFile, .{ self, alloc, io, file, super, path, options, &que }),
|
||||
.symlink, .ext_symlink => group.async(Io, extractSymlink, .{ self, alloc, io, super, path, options, &que }),
|
||||
.char_dev,
|
||||
.block_dev,
|
||||
.ext_char_dev,
|
||||
.ext_block_dev,
|
||||
=> group.async(io, extractDevice, .{ self, alloc, io, super, path, options, &que }),
|
||||
else => group.async(io, extractIPC, .{ 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});
|
||||
}
|
||||
}
|
||||
}
|
||||
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 (group.token.raw == null and !que.type_erased.closed) que.close(io);
|
||||
}
|
||||
}
|
||||
pub fn extractDir(
|
||||
self: Inode,
|
||||
alloc: std.mem.Allocator,
|
||||
io: Io,
|
||||
fil: OffsetFile,
|
||||
decomp: *const Decompressor,
|
||||
block_size: u32,
|
||||
dir_start: u64,
|
||||
path: []const u8,
|
||||
options: ExtractionOptions,
|
||||
que: *Io.Queue(FileRet),
|
||||
) !void {}
|
||||
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 {
|
||||
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, cache, 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 {}
|
||||
pub fn extractDevice(
|
||||
self: Inode,
|
||||
alloc: std.mem.Allocator,
|
||||
io: Io,
|
||||
path: []const u8,
|
||||
options: ExtractionOptions,
|
||||
que: *Io.Queue(FileRet),
|
||||
) !void {}
|
||||
pub fn extractIPC(
|
||||
self: Inode,
|
||||
alloc: std.mem.Allocator,
|
||||
io: Io,
|
||||
path: []const u8,
|
||||
options: ExtractionOptions,
|
||||
que: *Io.Queue(FileRet),
|
||||
) !void {}
|
||||
|
||||
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,
|
||||
fil: OffsetFile,
|
||||
decomp: *const Decompressor,
|
||||
|
||||
table_start: u64,
|
||||
total_num: u32,
|
||||
|
||||
@@ -39,10 +41,12 @@ pub fn CachedTable(comptime T: anytype) type {
|
||||
|
||||
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 .{
|
||||
.alloc = alloc,
|
||||
.fil = fil,
|
||||
.decomp = decomp,
|
||||
|
||||
.table_start = offset,
|
||||
.total_num = total_num,
|
||||
|
||||
|
||||
+2
-2
@@ -40,8 +40,8 @@ pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const De
|
||||
.value_cache = .init(alloc),
|
||||
};
|
||||
}
|
||||
pub fn deinit(self: *XattrCachedTable) void {
|
||||
self.table.deinit();
|
||||
pub fn deinit(self: *XattrCachedTable, io: Io) void {
|
||||
self.table.deinit(io);
|
||||
self.value_cache.deinit();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user