Further progress on extraction
This commit is contained in:
@@ -12,7 +12,7 @@ ignore_permissions: bool = false,
|
|||||||
/// Verbose logging
|
/// Verbose logging
|
||||||
verbose: bool = false,
|
verbose: bool = false,
|
||||||
/// Verbose logging writer. If not set, stdout is used.
|
/// Verbose logging writer. If not set, stdout is used.
|
||||||
verbose_logger: ?std.io.AnyWriter = null,
|
verbose_logger: std.io.AnyWriter = std.io.getStdOut().writer().any(),
|
||||||
/// Number of threads used during extraction. Defualts to std.Thread.getCpuCount().
|
/// Number of threads used during extraction. Defualts to std.Thread.getCpuCount().
|
||||||
thread_count: usize,
|
thread_count: usize,
|
||||||
|
|
||||||
|
|||||||
+114
-27
@@ -185,13 +185,11 @@ pub fn File(comptime T: type) type {
|
|||||||
|
|
||||||
const WaitGroup = std.Thread.WaitGroup;
|
const WaitGroup = std.Thread.WaitGroup;
|
||||||
const Pool = std.Thread.Pool;
|
const Pool = std.Thread.Pool;
|
||||||
|
const Mutex = std.Thread.Mutex;
|
||||||
|
|
||||||
pub const ExtractError = error{FileExists};
|
pub const ExtractError = error{FileExists};
|
||||||
|
|
||||||
pub fn extract(self: Self, op: *ExtractionOptions, path: []const u8) !void {
|
pub fn extract(self: Self, op: ExtractionOptions, path: []const u8) !void {
|
||||||
if (op.verbose and op.verbose_logger == null) {
|
|
||||||
op.verbose_logger = std.io.getStdOut().writer().any();
|
|
||||||
}
|
|
||||||
var exists = true;
|
var exists = true;
|
||||||
var stat: ?std.fs.File.Stat = null;
|
var stat: ?std.fs.File.Stat = null;
|
||||||
if (std.fs.cwd().statFile(path)) |s| {
|
if (std.fs.cwd().statFile(path)) |s| {
|
||||||
@@ -222,33 +220,43 @@ pub fn File(comptime T: type) type {
|
|||||||
defer pol.deinit();
|
defer pol.deinit();
|
||||||
var errs: std.ArrayList(anyerror) = .init(self.rdr.alloc);
|
var errs: std.ArrayList(anyerror) = .init(self.rdr.alloc);
|
||||||
defer errs.deinit();
|
defer errs.deinit();
|
||||||
try self.extractReal(op, &errs, &wg, &pol, path);
|
try self.extractReal(op, &errs, &wg, &pol, path, true);
|
||||||
wg.wait();
|
wg.wait();
|
||||||
if (errs.items.len > 0) return errs.items[0];
|
if (errs.items.len > 0) return errs.items[0];
|
||||||
}
|
}
|
||||||
fn extractReal(
|
fn extractReal(
|
||||||
self: Self,
|
self: Self,
|
||||||
op: *ExtractionOptions,
|
op: ExtractionOptions,
|
||||||
errs: *std.ArrayList(anyerror),
|
errs: *std.ArrayList(anyerror),
|
||||||
wg: *WaitGroup,
|
wg: *WaitGroup,
|
||||||
pol: *Pool,
|
pol: *Pool,
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
|
first: bool,
|
||||||
|
comptime on_finish: anytype,
|
||||||
|
finish_args: anytype,
|
||||||
) !void {
|
) !void {
|
||||||
|
if (op.verbose) {
|
||||||
|
std.fmt.format(op.verbose_logger, "extracting inode {} \"{s}\" to {s}...\n", .{ self.inode.hdr.num, self.name, path }) catch {};
|
||||||
|
}
|
||||||
return switch (self.inode.hdr.type) {
|
return switch (self.inode.hdr.type) {
|
||||||
.dir, .ext_dir => self.extractDir(op, errs, wg, pol, path),
|
.dir, .ext_dir => self.extractDir(op, errs, wg, pol, path, first),
|
||||||
.file, .ext_file => self.extractReg(op, errs, wg, pol, path),
|
.file, .ext_file => self.extractReg(op, errs, wg, pol, path, first),
|
||||||
.symlink, .ext_symlink => self.extractSymlink(op, errs, wg, pol, path),
|
.symlink, .ext_symlink => self.extractSymlink(op, errs, wg, pol, path, first),
|
||||||
.block_dev,
|
.block_dev,
|
||||||
.ext_block_dev,
|
.ext_block_dev,
|
||||||
.char_dev,
|
.char_dev,
|
||||||
.ext_char_dev,
|
.ext_char_dev,
|
||||||
.fifo,
|
.fifo,
|
||||||
.ext_fifo,
|
.ext_fifo,
|
||||||
=> self.extractDev(op, path),
|
=> {
|
||||||
|
try self.extractDev(op, path);
|
||||||
|
if (!first) self.deinit();
|
||||||
|
return;
|
||||||
|
},
|
||||||
else => {
|
else => {
|
||||||
if (op.verbose) {
|
if (op.verbose) {
|
||||||
std.fmt.format(
|
std.fmt.format(
|
||||||
op.verbose_logger.?,
|
op.verbose_logger,
|
||||||
"inode {} \"{s}\" is a socket file. Ignoring.\n",
|
"inode {} \"{s}\" is a socket file. Ignoring.\n",
|
||||||
.{ self.inode.hdr.num, self.name },
|
.{ self.inode.hdr.num, self.name },
|
||||||
) catch {};
|
) catch {};
|
||||||
@@ -256,31 +264,104 @@ pub fn File(comptime T: type) type {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
fn extractDir(self: Self, op: *ExtractionOptions, errs: *std.ArrayList(anyerror), wg: *WaitGroup, pol: *Pool, path: []const u8) !void {
|
fn extractDir(
|
||||||
|
self: Self,
|
||||||
|
op: ExtractionOptions,
|
||||||
|
errs: *std.ArrayList(anyerror),
|
||||||
|
wg: *WaitGroup,
|
||||||
|
pol: *Pool,
|
||||||
|
path: []const u8,
|
||||||
|
comptime on_finish: anytype,
|
||||||
|
finish_args: anytype,
|
||||||
|
) !void {
|
||||||
if (errs.items.len > 0) return;
|
if (errs.items.len > 0) return;
|
||||||
_ = self;
|
wg.start();
|
||||||
_ = op;
|
var dir_wg: WaitGroup = .{};
|
||||||
_ = wg;
|
dir_wg.startMany(self.entries.?.len);
|
||||||
_ = pol;
|
for (self.entries.?) |e| {
|
||||||
_ = path;
|
const fil: Self = try .initFromEntry(self.rdr, e);
|
||||||
|
}
|
||||||
return error{TODO}.TODO;
|
return error{TODO}.TODO;
|
||||||
}
|
}
|
||||||
fn extractReg(self: Self, op: *ExtractionOptions, errs: *std.ArrayList(anyerror), wg: *WaitGroup, pol: *Pool, path: []const u8) !void {
|
fn extractReg(
|
||||||
|
self: Self,
|
||||||
|
op: ExtractionOptions,
|
||||||
|
errs: *std.ArrayList(anyerror),
|
||||||
|
wg: *WaitGroup,
|
||||||
|
pol: *Pool,
|
||||||
|
path: []const u8,
|
||||||
|
first: bool,
|
||||||
|
comptime on_finish: anytype,
|
||||||
|
finish_args: anytype,
|
||||||
|
) !void {
|
||||||
if (errs.items.len > 0) return;
|
if (errs.items.len > 0) return;
|
||||||
const fil = try std.fs.cwd().createFile(path, .{});
|
const fil = try std.fs.cwd().createFile(path, .{});
|
||||||
@constCast(&self.data_reader.?).setPool(pol);
|
@constCast(&self.data_reader.?).setPool(pol);
|
||||||
wg.start();
|
wg.start();
|
||||||
try self.data_reader.?.writeToNoBlock(errs, fil, wg, extractRegFinish, .{ self, fil });
|
var fil_errs: std.ArrayList(anyerror) = .init(self.rdr.alloc);
|
||||||
_ = op;
|
try self.data_reader.?.writeToNoBlock(fil_errs, fil, wg, extractRegFinish, .{ self, op, fil, &fil_errs, first });
|
||||||
//TODO: add some way of verbose logging of the errors for this file in particular.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fn extractRegFinish(self: Self, fil: std.fs.File) void {
|
fn extractRegFinish(
|
||||||
|
self: Self,
|
||||||
|
op: ExtractionOptions,
|
||||||
|
fil: std.fs.File,
|
||||||
|
errs: *std.ArrayList(anyerror),
|
||||||
|
fil_errs: *std.ArrayList(anyerror),
|
||||||
|
first: bool,
|
||||||
|
comptime on_finish: anytype,
|
||||||
|
finish_args: anytype,
|
||||||
|
) void {
|
||||||
defer fil.close();
|
defer fil.close();
|
||||||
//TODO: set owners & permissions. Check if we need to call self.deinit();
|
defer fil_errs.deinit();
|
||||||
_ = self;
|
defer if (!first) self.deinit();
|
||||||
|
if (fil_errs.items.len > 0) {
|
||||||
|
if (op.verbose) {
|
||||||
|
for (fil_errs.items) |err| {
|
||||||
|
std.fmt.format(op.verbose_logger, "error extracting inode {} \"{s}\": {}\n", .{ self.inode.num, self.name, err }) catch {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errs.append(fil_errs.items[0]) catch {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!op.ignore_permissions) {
|
||||||
|
const fil_uid = self.uid() catch |err| {
|
||||||
|
if (op.verbose) {
|
||||||
|
std.fmt.format(op.verbose_logger, "error getting uid: {}\n", .{err}) catch {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const fil_gid = self.gid() catch |err| {
|
||||||
|
if (op.verbose) {
|
||||||
|
std.fmt.format(op.verbose_logger, "error getting gid: {}\n", .{err}) catch {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fil.chmod(self.inode.hdr.perm) catch |err| {
|
||||||
|
if (op.verbose) {
|
||||||
|
std.fmt.format(op.verbose_logger, "error setting permissions: {}\n", .{err}) catch {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fil.chown(fil_uid, fil_gid) catch |err| {
|
||||||
|
if (op.verbose) {
|
||||||
|
std.fmt.format(op.verbose_logger, "error setting owners: {}\n", .{err}) catch {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn extractSymlink(self: Self, op: *ExtractionOptions, errs: *std.ArrayList(anyerror), wg: *WaitGroup, pol: *Pool, path: []const u8) !void {
|
fn extractSymlink(
|
||||||
|
self: Self,
|
||||||
|
op: ExtractionOptions,
|
||||||
|
errs: *std.ArrayList(anyerror),
|
||||||
|
wg: *WaitGroup,
|
||||||
|
pol: *Pool,
|
||||||
|
path: []const u8,
|
||||||
|
first: bool,
|
||||||
|
comptime on_finish: anytype,
|
||||||
|
finish_args: anytype,
|
||||||
|
) !void {
|
||||||
if (errs.items.len > 0) return;
|
if (errs.items.len > 0) return;
|
||||||
_ = self;
|
_ = self;
|
||||||
_ = op;
|
_ = op;
|
||||||
@@ -289,11 +370,17 @@ pub fn File(comptime T: type) type {
|
|||||||
_ = path;
|
_ = path;
|
||||||
return error{TODO}.TODO;
|
return error{TODO}.TODO;
|
||||||
}
|
}
|
||||||
fn extractDev(self: Self, op: *ExtractionOptions, path: []const u8) !void {
|
fn extractDev(
|
||||||
|
self: Self,
|
||||||
|
op: ExtractionOptions,
|
||||||
|
path: []const u8,
|
||||||
|
comptime on_finish: anytype,
|
||||||
|
finish_args: anytype,
|
||||||
|
) !void {
|
||||||
if (comptime builtin.os.tag != .linux) {
|
if (comptime builtin.os.tag != .linux) {
|
||||||
if (op.verbose) {
|
if (op.verbose) {
|
||||||
std.fmt.format(
|
std.fmt.format(
|
||||||
op.verbose_logger.?,
|
op.verbose_logger,
|
||||||
"inode {} \"{s}\" is a device/fifo file and the OS is not Linux. Ignoring.\n",
|
"inode {} \"{s}\" is a device/fifo file and the OS is not Linux. Ignoring.\n",
|
||||||
.{ self.inode.hdr.num, self.name },
|
.{ self.inode.hdr.num, self.name },
|
||||||
) catch {};
|
) catch {};
|
||||||
|
|||||||
+1
-1
@@ -34,5 +34,5 @@ test "ExtractFile" {
|
|||||||
defer fil.deinit();
|
defer fil.deinit();
|
||||||
var op: ExtractionOptions = try .init();
|
var op: ExtractionOptions = try .init();
|
||||||
op.verbose = true;
|
op.verbose = true;
|
||||||
try fil.extract(&op, file_extr_loc);
|
try fil.extract(op, file_extr_loc);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user