Cleanup & fixes
This commit is contained in:
+1
-4
@@ -70,10 +70,7 @@ pub fn extract(self: Archive, alloc: std.mem.Allocator, io: Io, extract_dir: []c
|
|||||||
self.super.block_size,
|
self.super.block_size,
|
||||||
self.super.root_ref,
|
self.super.root_ref,
|
||||||
);
|
);
|
||||||
_ = root_inode;
|
return root_inode.extract(alloc, io, self.file, self.super, extract_dir, options);
|
||||||
_ = extract_dir;
|
|
||||||
_ = options;
|
|
||||||
return error.TODO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the inode with the given inode number.
|
/// Returns the inode with the given inode number.
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const help_mgs =
|
|||||||
\\ -dx Don't set xattr values
|
\\ -dx Don't set xattr values
|
||||||
\\ -dp Don't set permissions (includes setting uid & gid owner)
|
\\ -dp Don't set permissions (includes setting uid & gid owner)
|
||||||
\\
|
\\
|
||||||
\\ -p <threads> Specify how many threads to use. If no present or zero, the system's logical cores count is used.
|
\\ -p <threads> Specify how many threads to use. If not present or zero, the system's logical cores count is used.
|
||||||
\\ -v Verbose
|
\\ -v Verbose
|
||||||
\\
|
\\
|
||||||
\\ --force Force extraction. If the destination already exists, it will be deleted.
|
\\ --force Force extraction. If the destination already exists, it will be deleted.
|
||||||
@@ -42,18 +42,23 @@ var force: bool = false;
|
|||||||
pub fn main(init: std.process.Init) !void {
|
pub fn main(init: std.process.Init) !void {
|
||||||
const alloc = init.gpa;
|
const alloc = init.gpa;
|
||||||
const io = init.io;
|
const io = init.io;
|
||||||
|
|
||||||
var stdout = std.Io.File.stdout();
|
var stdout = std.Io.File.stdout();
|
||||||
|
defer stdout.close(io);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
var arc: squashfs.Archive = try .init(io, fil, offset); //TODO: Update when memory size matters. //TODO: Handle error gracefully.
|
|
||||||
|
var arc: squashfs.Archive = try .init(io, fil, offset); //TODO: Handle error gracefully.
|
||||||
const options: squashfs.ExtractionOptions = .{
|
const options: squashfs.ExtractionOptions = .{
|
||||||
.threads = if (threads == 0) try std.Thread.getCpuCount() else threads,
|
.threads = if (threads == 0) try std.Thread.getCpuCount() else threads,
|
||||||
.verbose = verbose,
|
.verbose = verbose,
|
||||||
@@ -61,6 +66,7 @@ pub fn main(init: std.process.Init) !void {
|
|||||||
.ignore_xattr = ignore_xattrs,
|
.ignore_xattr = ignore_xattrs,
|
||||||
.ignore_permissions = ignore_permissions,
|
.ignore_permissions = ignore_permissions,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (force)
|
if (force)
|
||||||
try Io.Dir.cwd().deleteTree(io, extLoc);
|
try Io.Dir.cwd().deleteTree(io, extLoc);
|
||||||
try arc.extract(alloc, io, extLoc, options); //TODO: Handle error gracefully.
|
try arc.extract(alloc, io, extLoc, options); //TODO: Handle error gracefully.
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Decompressor = @import("util/decompressor.zig");
|
||||||
|
|
||||||
|
pub const Decomp = union(enum) {
|
||||||
|
gzip: @import("decomp/zlib.zig"),
|
||||||
|
lzma: @import("decomp/lzma.zig"),
|
||||||
|
lzo: void,
|
||||||
|
xz: @import("decomp/xz.zig"),
|
||||||
|
lz4: void,
|
||||||
|
zstd: @import("decomp/zstd.zig"),
|
||||||
|
|
||||||
|
pub fn deinit(self: *Decomp) void {
|
||||||
|
switch (self.*) {
|
||||||
|
.gzip => self.gzip.deinit(),
|
||||||
|
.lzma => self.lzma.deinit(),
|
||||||
|
.xz => self.xz.deinit(),
|
||||||
|
.zstd => self.zstd.deinit(),
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decompressor(self: *Decomp) *Decompressor {
|
||||||
|
return switch (self.*) {
|
||||||
|
.gzip => &self.gzip.interface,
|
||||||
|
.lzma => &self.lzma.interface,
|
||||||
|
.xz => &self.xz.interface,
|
||||||
|
.zstd => &self.zstd.interface,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
+3
-3
@@ -29,9 +29,9 @@ pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
|
|||||||
.buffers = try .initCapacity(alloc, 5),
|
.buffers = try .initCapacity(alloc, 5),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn deinit(self: Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
for (self.buffers) |buf|
|
for (self.buffers.items) |buf|
|
||||||
self.alloc.free(buf);
|
self.alloc.free(buf.buf);
|
||||||
self.buffers.deinit(self.alloc);
|
self.buffers.deinit(self.alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -29,9 +29,9 @@ pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
|
|||||||
.buffers = try .initCapacity(alloc, 5),
|
.buffers = try .initCapacity(alloc, 5),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn deinit(self: Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
for (self.buffers) |buf|
|
for (self.buffers.items) |buf|
|
||||||
self.alloc.free(buf);
|
self.alloc.free(buf.buf);
|
||||||
self.buffers.deinit(self.alloc);
|
self.buffers.deinit(self.alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -29,9 +29,9 @@ pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
|
|||||||
.buffers = try .initCapacity(alloc, 5),
|
.buffers = try .initCapacity(alloc, 5),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn deinit(self: Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
for (self.buffers) |buf|
|
for (self.buffers.items) |buf|
|
||||||
self.alloc.free(buf);
|
self.alloc.free(buf.buf);
|
||||||
self.buffers.deinit(self.alloc);
|
self.buffers.deinit(self.alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -29,9 +29,9 @@ pub fn init(alloc: std.mem.Allocator, block_size: u32) !Self {
|
|||||||
.buffers = try .initCapacity(alloc, 5),
|
.buffers = try .initCapacity(alloc, 5),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn deinit(self: Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
for (self.buffers) |buf|
|
for (self.buffers.items) |buf|
|
||||||
self.alloc.free(buf);
|
self.alloc.free(buf.buf);
|
||||||
self.buffers.deinit(self.alloc);
|
self.buffers.deinit(self.alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+61
-43
@@ -5,6 +5,7 @@ const Reader = std.Io.Reader;
|
|||||||
const Io = std.Io;
|
const Io = std.Io;
|
||||||
|
|
||||||
const Archive = @import("archive.zig");
|
const Archive = @import("archive.zig");
|
||||||
|
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;
|
||||||
@@ -163,7 +164,7 @@ pub const Error = error{
|
|||||||
pub const Ref = packed struct(u64) {
|
pub const Ref = packed struct(u64) {
|
||||||
block_offset: u16,
|
block_offset: u16,
|
||||||
block_start: u32,
|
block_start: u32,
|
||||||
_: u16,
|
_: u16 = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Type = enum(u16) {
|
pub const Type = enum(u16) {
|
||||||
@@ -222,60 +223,73 @@ const Tables = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn extract(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, super: Archive.Superblock, path: []const u8, options: ExtractionOptions) !void {
|
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) {
|
var decomp: Decomp = switch (super.compression) {
|
||||||
.gzip => try @import("decomp/zlib.zig").init(alloc, super.block_size),
|
.gzip => .{ .gzip = try @import("decomp/zlib.zig").init(alloc, super.block_size) },
|
||||||
.lzma => try @import("decomp/lzma.zig").init(alloc, super.block_size),
|
.lzma => .{ .lzma = try @import("decomp/lzma.zig").init(alloc, super.block_size) },
|
||||||
.xz => try @import("decomp/xz.zig").init(alloc, super.block_size),
|
.xz => .{ .xz = try @import("decomp/xz.zig").init(alloc, super.block_size) },
|
||||||
.zstd => try @import("decomp/zstd.zig").init(alloc, super.block_size),
|
.zstd => .{ .zstd = try @import("decomp/zstd.zig").init(alloc, super.block_size) },
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
defer decomp.deinit();
|
defer decomp.deinit();
|
||||||
|
|
||||||
var frag_table: LookupTable.CachedTable(FragEntry) = .init(alloc, fil, &decomp.interface, super.frag_start, super.frag_count);
|
var frag_table: LookupTable.CachedTable(FragEntry) = .init(alloc, fil, decomp.decompressor(), super.frag_start, super.frag_count);
|
||||||
defer frag_table.deinit(io);
|
defer frag_table.deinit(io);
|
||||||
|
|
||||||
var group: Io.Group = .init;
|
// var group: Io.Group = .init;
|
||||||
defer group.cancel(io);
|
// defer group.cancel(io);
|
||||||
var que: Io.Queue(FileRet) = .init(&[1]FileRet{undefined} ** 12);
|
|
||||||
|
var que_arr = [1]FileRet{undefined} ** 12;
|
||||||
|
var que: Io.Queue(FileRet) = .init(&que_arr);
|
||||||
defer que.close(io);
|
defer que.close(io);
|
||||||
|
|
||||||
|
const cache_buf = try alloc.alloc([1024 * 1024]u8, 12);
|
||||||
|
defer alloc.free(cache_buf);
|
||||||
|
var cache: Io.Queue([1024 * 1024]u8) = .init(cache_buf);
|
||||||
|
defer cache.close(io);
|
||||||
|
|
||||||
|
const sel_buf: []anyerror!FileRet = try alloc.alloc(anyerror!FileRet, 10);
|
||||||
|
var group: Io.Select(anyerror!FileRet) = .init(io, sel_buf);
|
||||||
|
defer group.cancelDiscard();
|
||||||
|
|
||||||
switch (self.hdr.inode_type) {
|
switch (self.hdr.inode_type) {
|
||||||
.dir, .ext_dir => group.async(io, extractDir, .{
|
.dir, .ext_dir => group.async(FileRet, extractDir, .{
|
||||||
self,
|
self,
|
||||||
alloc,
|
alloc,
|
||||||
io,
|
io,
|
||||||
fil,
|
fil,
|
||||||
&decomp.interface,
|
decomp.decompressor(),
|
||||||
&frag_table,
|
&frag_table,
|
||||||
super.block_size,
|
super.block_size,
|
||||||
super.dir_start,
|
super.dir_start,
|
||||||
|
super.inode_start,
|
||||||
path,
|
path,
|
||||||
options,
|
options,
|
||||||
&que,
|
&que,
|
||||||
|
&cache,
|
||||||
}),
|
}),
|
||||||
.file, .ext_file => group.async(io, extractRegFile, .{
|
.file, .ext_file => group.async(io, extractRegFile, .{
|
||||||
self,
|
self,
|
||||||
alloc,
|
alloc,
|
||||||
io,
|
io,
|
||||||
file,
|
fil,
|
||||||
&decomp.interface,
|
decomp.decompressor(),
|
||||||
&frag_table,
|
&frag_table,
|
||||||
super.block_size,
|
super.block_size,
|
||||||
path,
|
path,
|
||||||
options,
|
|
||||||
&que,
|
&que,
|
||||||
|
&cache,
|
||||||
}),
|
}),
|
||||||
.symlink, .ext_symlink => group.async(Io, extractSymlink, .{ self, io, path, options, &que }),
|
.symlink, .ext_symlink => group.async(io, extractSymlink, .{ self, alloc, io, path, options, &que }),
|
||||||
else => group.async(io, extractDevice, .{ self, alloc, io, super, path, options, &que }),
|
else => group.async(io, extractDevice, .{ self, alloc, io, path, options, &que }),
|
||||||
}
|
}
|
||||||
|
|
||||||
var id_table: LookupTable.CachedTable(u16) = .init(alloc, fil, decomp, super.id_start, super.id_count);
|
var id_table: LookupTable.CachedTable(u16) = .init(alloc, fil, decomp.decompressor(), super.id_start, super.id_count);
|
||||||
defer id_table.deinit(io);
|
defer id_table.deinit(io);
|
||||||
var xattr_table: XattrTable = try .init(alloc, io, fil, decomp, super.xattr_start);
|
var xattr_table: XattrTable = try .init(alloc, io, fil, decomp.decompressor(), super.xattr_start);
|
||||||
defer xattr_table.deinit(io);
|
defer xattr_table.deinit(io);
|
||||||
|
|
||||||
for (que.getOne(io)) |res| {
|
while (true) {
|
||||||
const ret = res catch break;
|
const ret = que.getOne(io) catch break;
|
||||||
|
|
||||||
const inode: Inode = ret.inode;
|
const inode: Inode = ret.inode;
|
||||||
defer inode.deinit(alloc);
|
defer inode.deinit(alloc);
|
||||||
@@ -284,23 +298,25 @@ pub fn extract(self: Inode, alloc: std.mem.Allocator, io: Io, fil: OffsetFile, s
|
|||||||
|
|
||||||
if (!options.ignore_xattr) {
|
if (!options.ignore_xattr) {
|
||||||
if (inode.xattrIndex()) |idx| {
|
if (inode.xattrIndex()) |idx| {
|
||||||
const xattrs = try xattr_table.get(io, idx);
|
const xattrs = try xattr_table.get(alloc, io, idx);
|
||||||
for (xattrs) |x| {
|
for (xattrs) |x| {
|
||||||
// TODO: Check error.
|
// TODO: Check error.
|
||||||
const xattr_res = std.os.linux.fsetxattr(ret_file.handle, x.key, x.value.ptr, x.value.len, 0);
|
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)
|
if (xattr_res != 0 and options.verbose)
|
||||||
options.verbose_writer.?.print("setxattr failed with code: {}\n", .{xattr_res}) catch {};
|
options.verbose_writer.?.print("setxattr failed with code: {}\n", .{xattr_res}) catch {};
|
||||||
|
alloc.free(x.key);
|
||||||
}
|
}
|
||||||
}
|
alloc.free(xattrs);
|
||||||
|
} else |_| {}
|
||||||
}
|
}
|
||||||
if (!options.ignore_permissions) {
|
if (!options.ignore_permissions) {
|
||||||
try ret_file.setPermissions(io, inode.hdr.permissions);
|
try ret_file.setPermissions(io, @enumFromInt(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));
|
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);
|
if (!que.type_erased.closed and group.token.raw == null) que.close(io);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn extractDir(
|
fn extractDir(
|
||||||
self: Inode,
|
self: Inode,
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
io: Io,
|
io: Io,
|
||||||
@@ -313,6 +329,7 @@ pub fn extractDir(
|
|||||||
path: []const u8,
|
path: []const u8,
|
||||||
options: ExtractionOptions,
|
options: ExtractionOptions,
|
||||||
que: *Io.Queue(FileRet),
|
que: *Io.Queue(FileRet),
|
||||||
|
cache: *Io.Queue([1024 * 1024]u8),
|
||||||
) !void {
|
) !void {
|
||||||
defer alloc.free(path);
|
defer alloc.free(path);
|
||||||
|
|
||||||
@@ -341,28 +358,30 @@ pub fn extractDir(
|
|||||||
alloc,
|
alloc,
|
||||||
io,
|
io,
|
||||||
fil,
|
fil,
|
||||||
&decomp.interface,
|
decomp,
|
||||||
&frag,
|
frag,
|
||||||
block_size,
|
block_size,
|
||||||
dir_start,
|
dir_start,
|
||||||
|
inode_start,
|
||||||
new_path,
|
new_path,
|
||||||
options,
|
options,
|
||||||
&que,
|
que,
|
||||||
|
cache,
|
||||||
}),
|
}),
|
||||||
.file, .ext_file => group.async(io, extractRegFile, .{
|
.file, .ext_file => group.async(io, extractRegFile, .{
|
||||||
self,
|
self,
|
||||||
alloc,
|
alloc,
|
||||||
io,
|
io,
|
||||||
file,
|
fil,
|
||||||
&decomp.interface,
|
decomp,
|
||||||
&frag,
|
frag,
|
||||||
block_size,
|
block_size,
|
||||||
new_path,
|
new_path,
|
||||||
options,
|
que,
|
||||||
&que,
|
cache,
|
||||||
}),
|
}),
|
||||||
.symlink, .ext_symlink => group.async(Io, extractSymlink, .{ self, alloc, io, 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 }),
|
else => group.async(io, extractDevice, .{ self, alloc, io, new_path, options, que }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,7 +389,7 @@ pub fn extractDir(
|
|||||||
|
|
||||||
try que.putOne(io, .{ .file = try Io.Dir.cwd().openFile(io, path, .{}), .inode = self });
|
try que.putOne(io, .{ .file = try Io.Dir.cwd().openFile(io, path, .{}), .inode = self });
|
||||||
}
|
}
|
||||||
pub fn extractRegFile(
|
fn extractRegFile(
|
||||||
self: Inode,
|
self: Inode,
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
io: Io,
|
io: Io,
|
||||||
@@ -379,13 +398,12 @@ pub fn extractRegFile(
|
|||||||
frag: *LookupTable.CachedTable(FragEntry),
|
frag: *LookupTable.CachedTable(FragEntry),
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
options: ExtractionOptions,
|
|
||||||
que: *Io.Queue(FileRet),
|
que: *Io.Queue(FileRet),
|
||||||
|
cache: *Io.Queue([1024 * 1024]u8),
|
||||||
) !void {
|
) !void {
|
||||||
_ = options;
|
|
||||||
defer alloc.free(path);
|
defer alloc.free(path);
|
||||||
|
|
||||||
const atom = try Io.Dir.cwd().createFileAtomic(io, path, .{});
|
var atom = try Io.Dir.cwd().createFileAtomic(io, path, .{});
|
||||||
defer atom.deinit(io);
|
defer atom.deinit(io);
|
||||||
|
|
||||||
var size: u64 = undefined;
|
var size: u64 = undefined;
|
||||||
@@ -411,7 +429,7 @@ pub fn extractRegFile(
|
|||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
|
|
||||||
const ext: DataExtractor = .init(fil, decomp, block_size, size, start, blocks);
|
var ext: DataExtractor = .init(fil, decomp, cache, block_size, size, start, blocks);
|
||||||
ext.addFrag(frag_offset, try frag.get(io, frag_idx));
|
ext.addFrag(frag_offset, try frag.get(io, frag_idx));
|
||||||
|
|
||||||
var group: Io.Group = .init;
|
var group: Io.Group = .init;
|
||||||
@@ -425,7 +443,7 @@ pub fn extractRegFile(
|
|||||||
|
|
||||||
try que.putOne(io, .{ .file = atom.file, .inode = self });
|
try que.putOne(io, .{ .file = atom.file, .inode = self });
|
||||||
}
|
}
|
||||||
pub fn extractSymlink(
|
fn extractSymlink(
|
||||||
self: Inode,
|
self: Inode,
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
io: Io,
|
io: Io,
|
||||||
@@ -444,7 +462,7 @@ pub fn extractSymlink(
|
|||||||
|
|
||||||
// TODO: On Linux you can't set permission & xattrs on symlinks (they inherit from their target), but on Mac you can.
|
// TODO: On Linux you can't set permission & xattrs on symlinks (they inherit from their target), but on Mac you can.
|
||||||
}
|
}
|
||||||
pub fn extractDevice(
|
fn extractDevice(
|
||||||
self: Inode,
|
self: Inode,
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
io: Io,
|
io: Io,
|
||||||
@@ -481,7 +499,7 @@ pub fn extractDevice(
|
|||||||
|
|
||||||
const sentinel_path = try std.mem.concatMaybeSentinel(alloc, u8, &[1][]const u8{path}, 0);
|
const sentinel_path = try std.mem.concatMaybeSentinel(alloc, u8, &[1][]const u8{path}, 0);
|
||||||
defer alloc.free(sentinel_path);
|
defer alloc.free(sentinel_path);
|
||||||
const res = std.os.linux.mknod(sentinel_path, mode, dev);
|
const res = std.os.linux.mknod(@ptrCast(sentinel_path), mode, dev);
|
||||||
if (res != 0 and options.verbose)
|
if (res != 0 and options.verbose)
|
||||||
options.verbose_writer.?.print("mknod failed with code: {}\n", .{res}) catch {};
|
options.verbose_writer.?.print("mknod failed with code: {}\n", .{res}) catch {};
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ pub const ExtDir = extern struct {
|
|||||||
parent_num: u32,
|
parent_num: u32,
|
||||||
idx_count: u16,
|
idx_count: u16,
|
||||||
block_offset: u16,
|
block_offset: u16,
|
||||||
xattr_id: u32,
|
xattr_idx: u32,
|
||||||
// index: []DirIndex
|
// index: []DirIndex
|
||||||
|
|
||||||
pub fn read(rdr: *Reader) !ExtDir {
|
pub fn read(rdr: *Reader) !ExtDir {
|
||||||
|
|||||||
@@ -75,14 +75,17 @@ pub fn CachedTable(comptime T: anytype) type {
|
|||||||
try rdr.interface.readSliceEndian(u64, @ptrCast(&offset), .little);
|
try rdr.interface.readSliceEndian(u64, @ptrCast(&offset), .little);
|
||||||
|
|
||||||
const len: u16 = if (self.total_num % T_PER_BLOCK != 0 and block == (self.total_num - 1) / T_PER_BLOCK)
|
const len: u16 = if (self.total_num % T_PER_BLOCK != 0 and block == (self.total_num - 1) / T_PER_BLOCK)
|
||||||
self.total_num % T_PER_BLOCK
|
@truncate(self.total_num % T_PER_BLOCK)
|
||||||
else
|
else
|
||||||
T_PER_BLOCK;
|
T_PER_BLOCK;
|
||||||
|
|
||||||
rdr = try self.fil.readerAt(io, offset, &[0]u8{});
|
rdr = try self.fil.readerAt(io, offset, &[0]u8{});
|
||||||
var meta: MetadataReader = .init(self.alloc, &rdr, self.decomp);
|
var meta: MetadataReader = .init(self.alloc, &rdr.interface, self.decomp);
|
||||||
|
|
||||||
try self.table.put(block, try meta.interface.readSliceEndianAlloc(self.alloc, T, len, .little));
|
const slice = try meta.interface.readSliceEndianAlloc(self.alloc, T, len, .little);
|
||||||
|
try self.table.put(block, slice);
|
||||||
|
|
||||||
|
return slice[block_offset];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ const Writer = std.Io.Writer;
|
|||||||
const ExtractionOptions = @This();
|
const ExtractionOptions = @This();
|
||||||
|
|
||||||
/// The number of threads used for extraction. 0 implies single threaded.
|
/// The number of threads used for extraction. 0 implies single threaded.
|
||||||
threads: usize = 1,
|
threads: usize = 1, // TODO: Update to better integrate with zig 0.16 Io. Maybe limit to only single or multi-threaded.
|
||||||
/// Don't set the file's owner & permissions after extraction
|
/// Don't set the file's owner & permissions after extraction
|
||||||
ignore_permissions: bool = false,
|
ignore_permissions: bool = false,
|
||||||
/// Don't set xattr values. Currently xattrs are never set anyway.
|
/// Don't set xattr values. Currently xattrs are never set anyway.
|
||||||
|
|||||||
+22
-21
@@ -7,13 +7,14 @@ 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");
|
||||||
const SharedCache = @import("shared_cache.zig");
|
|
||||||
|
// const SharedCache = @import("shared_cache.zig");
|
||||||
|
|
||||||
const DataExtractor = @This();
|
const DataExtractor = @This();
|
||||||
|
|
||||||
fil: OffsetFile,
|
fil: OffsetFile,
|
||||||
// cache: *SharedCache,
|
|
||||||
decomp: *const Decompressor,
|
decomp: *const Decompressor,
|
||||||
|
cache: *Io.Queue([1024 * 1024]u8),
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
|
|
||||||
file_size: u64,
|
file_size: u64,
|
||||||
@@ -23,11 +24,11 @@ blocks: []BlockSize,
|
|||||||
frag_offset: u32 = 0,
|
frag_offset: u32 = 0,
|
||||||
frag_entry: ?FragEntry = null,
|
frag_entry: ?FragEntry = null,
|
||||||
|
|
||||||
pub fn init(fil: OffsetFile, decomp: *const Decompressor, block_size: u32, file_size: u64, data_start: u64, blocks: []BlockSize) DataExtractor {
|
pub fn init(fil: OffsetFile, decomp: *const Decompressor, cache: *Io.Queue([1024 * 1024]u8), block_size: u32, file_size: u64, data_start: u64, blocks: []BlockSize) DataExtractor {
|
||||||
return .{
|
return .{
|
||||||
.fil = fil,
|
.fil = fil,
|
||||||
// .cache = cache,
|
|
||||||
.decomp = decomp,
|
.decomp = decomp,
|
||||||
|
.cache = cache,
|
||||||
.block_size = block_size,
|
.block_size = block_size,
|
||||||
|
|
||||||
.file_size = file_size,
|
.file_size = file_size,
|
||||||
@@ -57,7 +58,7 @@ pub fn extractAsync(self: DataExtractor, alloc: std.mem.Allocator, io: Io, group
|
|||||||
group.async(io, fragThread, .{ self, alloc, io, fil });
|
group.async(io, fragThread, .{ self, alloc, io, fil });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blockThread(self: DataExtractor, alloc: std.mem.Allocator, io: Io, fil: Io.File, read_offset: u64, idx: u32) !void {
|
fn blockThread(self: DataExtractor, alloc: std.mem.Allocator, io: Io, fil: Io.File, read_offset: u64, idx: usize) !void {
|
||||||
const block = self.blocks[idx];
|
const block = self.blocks[idx];
|
||||||
|
|
||||||
const cur_block_size = if (idx == self.numBlocks() - 1)
|
const cur_block_size = if (idx == self.numBlocks() - 1)
|
||||||
@@ -76,19 +77,19 @@ fn blockThread(self: DataExtractor, alloc: std.mem.Allocator, io: Io, fil: Io.Fi
|
|||||||
|
|
||||||
var rdr = try self.fil.readerAt(io, read_offset, &[0]u8{});
|
var rdr = try self.fil.readerAt(io, read_offset, &[0]u8{});
|
||||||
if (block.uncompressed) {
|
if (block.uncompressed) {
|
||||||
try rdr.interface.streamExact(&wrt, cur_block_size);
|
try rdr.interface.streamExact(&wrt.interface, cur_block_size);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@branchHint(.likely);
|
@branchHint(.likely);
|
||||||
var cache = try self.cache.getCache(io);
|
var cache = try self.cache.getOne(io);
|
||||||
defer self.cache.returnCache(cache);
|
defer self.cache.putOne(io, cache) catch {};
|
||||||
|
|
||||||
var tmp = try self.cache.getCache(io);
|
var tmp = try self.cache.getOne(io);
|
||||||
defer self.cache.returnCache(tmp);
|
defer self.cache.putOne(io, tmp) catch {};
|
||||||
|
|
||||||
try rdr.interface.readSliceAll(cache.cache[0..block.size]);
|
try rdr.interface.readSliceAll(cache[0..block.size]);
|
||||||
_ = try self.decomp.Decompress(alloc, cache.cache[0..block.size], tmp.cache[0..cur_block_size]);
|
_ = try self.decomp.Decompress(alloc, cache[0..block.size], tmp[0..cur_block_size]);
|
||||||
try wrt.interface.writeAll(tmp.cache[0..cur_block_size]);
|
try wrt.interface.writeAll(tmp[0..cur_block_size]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn fragThread(self: DataExtractor, alloc: std.mem.Allocator, io: Io, fil: Io.File) !void {
|
fn fragThread(self: DataExtractor, alloc: std.mem.Allocator, io: Io, fil: Io.File) !void {
|
||||||
@@ -102,18 +103,18 @@ fn fragThread(self: DataExtractor, alloc: std.mem.Allocator, io: Io, fil: Io.Fil
|
|||||||
var rdr = try self.fil.readerAt(io, frag.start, &[0]u8{});
|
var rdr = try self.fil.readerAt(io, frag.start, &[0]u8{});
|
||||||
if (frag.size.uncompressed) {
|
if (frag.size.uncompressed) {
|
||||||
try rdr.interface.discardAll(self.frag_offset);
|
try rdr.interface.discardAll(self.frag_offset);
|
||||||
try rdr.interface.streamExact(&wrt, cur_block_size);
|
try rdr.interface.streamExact(&wrt.interface, cur_block_size);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@branchHint(.likely);
|
@branchHint(.likely);
|
||||||
var cache = try self.cache.getCache(io);
|
var cache = try self.cache.getOne(io);
|
||||||
defer self.cache.returnCache(cache);
|
defer self.cache.putOne(io, cache) catch {};
|
||||||
|
|
||||||
var tmp = try self.cache.getCache(io);
|
var tmp = try self.cache.getOne(io);
|
||||||
defer self.cache.returnCache(tmp);
|
defer self.cache.putOne(io, tmp) catch {};
|
||||||
|
|
||||||
try rdr.interface.readSliceAll(cache.cache[0..frag.size.size]);
|
try rdr.interface.readSliceAll(cache[0..frag.size.size]);
|
||||||
_ = try self.decomp.Decompress(alloc, cache.cache[0..frag.size.size], tmp.cache[0..self.block_size]);
|
_ = try self.decomp.Decompress(alloc, cache[0..frag.size.size], tmp[0..self.block_size]);
|
||||||
try wrt.interface.writeAll(tmp.cache[0..cur_block_size]);
|
try wrt.interface.writeAll(tmp[0..cur_block_size]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ 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");
|
||||||
const SharedCache = @import("shared_cache.zig");
|
|
||||||
|
// const SharedCache = @import("shared_cache.zig");
|
||||||
|
|
||||||
const DataReader = @This();
|
const DataReader = @This();
|
||||||
|
|
||||||
@@ -18,8 +19,8 @@ alloc: std.mem.Allocator,
|
|||||||
|
|
||||||
fil: OffsetFile,
|
fil: OffsetFile,
|
||||||
io: Io,
|
io: Io,
|
||||||
// cache: *SharedCache,
|
|
||||||
decomp: *const Decompressor,
|
decomp: *const Decompressor,
|
||||||
|
cache: *Io.Queue([]u8),
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
|
|
||||||
file_size: u64,
|
file_size: u64,
|
||||||
@@ -34,13 +35,14 @@ sparse_block: bool = false,
|
|||||||
|
|
||||||
interface: Io.Reader,
|
interface: Io.Reader,
|
||||||
|
|
||||||
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 {
|
pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const Decompressor, cache: *Io.Queue([]u8), block_size: u32, file_size: u64, data_start: u64, blocks: []BlockSize) !DataReader {
|
||||||
return .{
|
return .{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
|
|
||||||
.fil = fil,
|
.fil = fil,
|
||||||
.io = io,
|
.io = io,
|
||||||
.decomp = decomp,
|
.decomp = decomp,
|
||||||
|
.cache = cache,
|
||||||
.block_size = block_size,
|
.block_size = block_size,
|
||||||
|
|
||||||
.file_size = file_size,
|
.file_size = file_size,
|
||||||
@@ -91,8 +93,8 @@ fn advanceBuffer(self: *DataReader) !void {
|
|||||||
try rdr.interface.readSliceAll(self.interface.buffer[0..self.interface.end]);
|
try rdr.interface.readSliceAll(self.interface.buffer[0..self.interface.end]);
|
||||||
} else {
|
} else {
|
||||||
@branchHint(.likely);
|
@branchHint(.likely);
|
||||||
const tmp = try self.cache.getCache(self.io);
|
const tmp = try self.cache.getOne(self.io);
|
||||||
defer self.cache.returnCache(tmp);
|
defer self.cache.putOne(tmp) catch {};
|
||||||
|
|
||||||
var rdr = try self.fil.readerAt(self.io, entry.start, &[0]u8{});
|
var rdr = try self.fil.readerAt(self.io, entry.start, &[0]u8{});
|
||||||
try rdr.interface.readSliceAll(tmp.cache[0..entry.size.size]);
|
try rdr.interface.readSliceAll(tmp.cache[0..entry.size.size]);
|
||||||
@@ -117,8 +119,8 @@ fn advanceBuffer(self: *DataReader) !void {
|
|||||||
self.cur_offset += self.interface.end;
|
self.cur_offset += self.interface.end;
|
||||||
} else {
|
} else {
|
||||||
@branchHint(.likely);
|
@branchHint(.likely);
|
||||||
const tmp = try self.cache.getCache(self.io);
|
const tmp = try self.cache.getOne(self.io);
|
||||||
defer self.cache.returnCache(tmp);
|
defer self.cache.putOne(tmp) catch {};
|
||||||
|
|
||||||
var rdr = try self.fil.readerAt(self.io, self.cur_offset, &[0]u8{});
|
var rdr = try self.fil.readerAt(self.io, self.cur_offset, &[0]u8{});
|
||||||
try rdr.interface.readSliceAll(tmp.cache[0..block.size]);
|
try rdr.interface.readSliceAll(tmp.cache[0..block.size]);
|
||||||
|
|||||||
+17
-15
@@ -18,7 +18,7 @@ kv_start: u64,
|
|||||||
|
|
||||||
table: LookupTable.CachedTable(TableValue),
|
table: LookupTable.CachedTable(TableValue),
|
||||||
value_cache: std.AutoHashMap(InodeRef, []const u8),
|
value_cache: std.AutoHashMap(InodeRef, []const u8),
|
||||||
value_mut: Io.Mutex,
|
value_mut: Io.Mutex = .init,
|
||||||
|
|
||||||
pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const Decompressor, xattr_start: u64) !XattrCachedTable {
|
pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const Decompressor, xattr_start: u64) !XattrCachedTable {
|
||||||
var rdr = try fil.readerAt(io, xattr_start, &[0]u8{});
|
var rdr = try fil.readerAt(io, xattr_start, &[0]u8{});
|
||||||
@@ -36,7 +36,7 @@ pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const De
|
|||||||
|
|
||||||
.kv_start = start,
|
.kv_start = start,
|
||||||
|
|
||||||
.table = .init(alloc, fil, xattr_start + 16, num),
|
.table = .init(alloc, fil, decomp, xattr_start + 16, num),
|
||||||
.value_cache = .init(alloc),
|
.value_cache = .init(alloc),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -56,37 +56,39 @@ pub fn get(self: *XattrCachedTable, alloc: std.mem.Allocator, io: Io, idx: u32)
|
|||||||
errdefer alloc.free(out);
|
errdefer alloc.free(out);
|
||||||
|
|
||||||
for (0..lookup.count) |i| {
|
for (0..lookup.count) |i| {
|
||||||
const key_entry: KeyEntry = undefined;
|
var key_entry: KeyEntry = undefined;
|
||||||
try meta.interface.readSliceEndian(KeyEntry, @ptrCast(&key_entry), .little);
|
try meta.interface.readSliceEndian(KeyEntry, @ptrCast(&key_entry), .little);
|
||||||
|
|
||||||
const key = switch (key_entry.type.namespace) {
|
const key: [:0]u8 = switch (key_entry.type.namespace) {
|
||||||
.user => blk: {
|
.user => blk: {
|
||||||
const tmp = try alloc.alloc(u8, key_entry.name_size + 1 + 5);
|
const tmp = try alloc.alloc(u8, key_entry.name_size + 1 + 5);
|
||||||
errdefer alloc.free(tmp);
|
errdefer alloc.free(tmp);
|
||||||
try meta.interface.readSliceEndian(u8, tmp[5 .. tmp.len - 1], .little);
|
try meta.interface.readSliceEndian(u8, tmp[5 .. tmp.len - 1], .little);
|
||||||
@memset(tmp[0..5], "user.");
|
@memcpy(tmp[0..5], "user.");
|
||||||
break :blk tmp;
|
tmp[tmp.len - 1] = 0;
|
||||||
|
break :blk @ptrCast(tmp);
|
||||||
},
|
},
|
||||||
.trusted => blk: {
|
.trusted => blk: {
|
||||||
const tmp = try alloc.alloc(u8, key_entry.name_size + 1 + 8);
|
const tmp = try alloc.alloc(u8, key_entry.name_size + 1 + 8);
|
||||||
errdefer alloc.free(tmp);
|
errdefer alloc.free(tmp);
|
||||||
try meta.interface.readSliceEndian(u8, tmp[8 .. tmp.len - 1], .little);
|
try meta.interface.readSliceEndian(u8, tmp[8 .. tmp.len - 1], .little);
|
||||||
@memset(tmp[0..8], "trusted.");
|
@memcpy(tmp[0..8], "trusted.");
|
||||||
break :blk tmp;
|
tmp[tmp.len - 1] = 0;
|
||||||
|
break :blk @ptrCast(tmp);
|
||||||
},
|
},
|
||||||
.security => blk: {
|
.security => blk: {
|
||||||
const tmp = try alloc.alloc(u8, key_entry.name_size + 1 + 9);
|
const tmp = try alloc.alloc(u8, key_entry.name_size + 1 + 9);
|
||||||
errdefer alloc.free(tmp);
|
errdefer alloc.free(tmp);
|
||||||
try meta.interface.readSliceEndian(u8, tmp[9 .. tmp.len - 1], .little);
|
try meta.interface.readSliceEndian(u8, tmp[9 .. tmp.len - 1], .little);
|
||||||
@memset(tmp[0..9], "security.");
|
@memcpy(tmp[0..9], "security.");
|
||||||
break :blk tmp;
|
tmp[tmp.len - 1] = 0;
|
||||||
|
break :blk @ptrCast(tmp);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
key[key.len - 1] = 0;
|
|
||||||
errdefer alloc.free(key);
|
errdefer alloc.free(key);
|
||||||
|
|
||||||
if (key_entry.type.out_of_line) {
|
if (key_entry.type.out_of_line) {
|
||||||
const value: ValueOutOfLineEntry = undefined;
|
var value: ValueOutOfLineEntry = undefined;
|
||||||
try meta.interface.readSliceEndian(ValueOutOfLineEntry, @ptrCast(&value), .little);
|
try meta.interface.readSliceEndian(ValueOutOfLineEntry, @ptrCast(&value), .little);
|
||||||
|
|
||||||
out[i] = .{
|
out[i] = .{
|
||||||
@@ -95,7 +97,7 @@ pub fn get(self: *XattrCachedTable, alloc: std.mem.Allocator, io: Io, idx: u32)
|
|||||||
};
|
};
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const val_ref: InodeRef = .{ .block_start = meta.cur_block_start, .block_offset = meta.interface.seek };
|
const val_ref: InodeRef = .{ .block_start = meta.cur_block_start, .block_offset = @truncate(meta.interface.seek) };
|
||||||
|
|
||||||
try self.value_mut.lock(io);
|
try self.value_mut.lock(io);
|
||||||
defer self.value_mut.unlock(io);
|
defer self.value_mut.unlock(io);
|
||||||
@@ -108,7 +110,7 @@ pub fn get(self: *XattrCachedTable, alloc: std.mem.Allocator, io: Io, idx: u32)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var val_size: u32 = undefined;
|
var val_size: u32 = undefined;
|
||||||
try meta.interface.readSliceEndian(val_size, @ptrCast(&val_size), .little);
|
try meta.interface.readSliceEndian(u32, @ptrCast(&val_size), .little);
|
||||||
|
|
||||||
const val = try self.alloc.alloc(u8, val_size);
|
const val = try self.alloc.alloc(u8, val_size);
|
||||||
errdefer alloc.free(val);
|
errdefer alloc.free(val);
|
||||||
@@ -134,7 +136,7 @@ fn valueAt(self: *XattrCachedTable, io: Io, ref: InodeRef) ![]const u8 {
|
|||||||
try meta.interface.discardAll(ref.block_offset);
|
try meta.interface.discardAll(ref.block_offset);
|
||||||
|
|
||||||
var val_size: u32 = undefined;
|
var val_size: u32 = undefined;
|
||||||
try meta.interface.readSliceEndian(val_size, @ptrCast(&val_size), .little);
|
try meta.interface.readSliceEndian(u32, @ptrCast(&val_size), .little);
|
||||||
|
|
||||||
const val = try self.alloc.alloc(u8, val_size);
|
const val = try self.alloc.alloc(u8, val_size);
|
||||||
errdefer self.alloc.free(val);
|
errdefer self.alloc.free(val);
|
||||||
|
|||||||
Reference in New Issue
Block a user