Further progress on extraction
This commit is contained in:
+71
-10
@@ -206,8 +206,6 @@ pub fn File(comptime T: type) type {
|
|||||||
.dir, .ext_dir => {
|
.dir, .ext_dir => {
|
||||||
if (exists and stat.?.kind != .directory) {
|
if (exists and stat.?.kind != .directory) {
|
||||||
return ExtractError.FileExists;
|
return ExtractError.FileExists;
|
||||||
} else if (!exists) {
|
|
||||||
try std.fs.cwd().makeDir(path);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
else => if (exists) return ExtractError.FileExists,
|
else => if (exists) return ExtractError.FileExists,
|
||||||
@@ -236,31 +234,85 @@ pub fn File(comptime T: type) type {
|
|||||||
) !void {
|
) !void {
|
||||||
if (errs.items.len > 0) return;
|
if (errs.items.len > 0) return;
|
||||||
if (op.verbose) {
|
if (op.verbose) {
|
||||||
std.fmt.format(op.verbose_logger, "extracting inode {} \"{s}\" to {s}...\n", .{ self.inode.hdr.num, self.name, path }) catch {};
|
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 => {
|
.dir, .ext_dir => {
|
||||||
wg.start();
|
wg.start();
|
||||||
|
defer std.debug.print("{}\n", .{wg.state.raw});
|
||||||
errdefer wg.finish();
|
errdefer wg.finish();
|
||||||
|
std.fs.cwd().makeDir(path) catch |err| {
|
||||||
|
if (err != std.fs.Dir.MakeError.PathAlreadyExists) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var dir_wg = try self.rdr.alloc.create(WaitGroup);
|
||||||
|
dir_wg.* = .{};
|
||||||
for (self.entries.?) |ent| {
|
for (self.entries.?) |ent| {
|
||||||
var fil = initFromEntry(self.rdr, ent) catch |err| {
|
var fil = initFromEntry(self.rdr, ent) catch |err| {
|
||||||
|
std.fmt.format(
|
||||||
|
op.verbose_logger,
|
||||||
|
"error extracting inode {} \"{s}\": {}\n",
|
||||||
|
.{ ent.num, path, err },
|
||||||
|
) catch {};
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
const ext_path = blk: {
|
||||||
|
if (path[path.len - 1] == '/') {
|
||||||
|
var new = self.rdr.alloc.alloc(u8, path.len + ent.name.len) catch |err| {
|
||||||
|
break :blk err;
|
||||||
|
};
|
||||||
|
@memcpy(new[0..path.len], path);
|
||||||
|
@memcpy(new[path.len..], ent.name);
|
||||||
|
break :blk new;
|
||||||
|
}
|
||||||
|
var new = self.rdr.alloc.alloc(u8, path.len + ent.name.len + 1) catch |err| {
|
||||||
|
break :blk err;
|
||||||
|
};
|
||||||
|
@memcpy(new[0..path.len], path);
|
||||||
|
new[path.len] = '/';
|
||||||
|
@memcpy(new[path.len + 1 ..], ent.name);
|
||||||
|
break :blk new;
|
||||||
|
} catch |err| {
|
||||||
|
std.fmt.format(
|
||||||
|
op.verbose_logger,
|
||||||
|
"error extracting inode {} \"{s}\": {}\n",
|
||||||
|
.{ ent.num, path, err },
|
||||||
|
) catch {};
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
fil.extractReal(op, ext_path, errs, dir_wg, pol, false) catch |err| {
|
||||||
|
std.fmt.format(
|
||||||
|
op.verbose_logger,
|
||||||
|
"error extracting inode {} \"{s}\": {}\n",
|
||||||
|
.{ ent.num, path, err },
|
||||||
|
) catch {};
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
dir_wg.wait();
|
||||||
|
wg.finish();
|
||||||
|
std.debug.print("finished: {s}\n", .{path});
|
||||||
},
|
},
|
||||||
.file, .ext_file => {
|
.file, .ext_file => {
|
||||||
wg.start();
|
wg.start();
|
||||||
errdefer wg.finish();
|
errdefer wg.finish();
|
||||||
var ext_fil = try std.fs.cwd().createFile(path, .{});
|
var ext_fil = try std.fs.cwd().createFile(path, .{});
|
||||||
errdefer ext_fil.close();
|
errdefer ext_fil.close();
|
||||||
var fil_errs: std.ArrayList(anyerror) = .init(self.rdr.alloc);
|
var fil_errs = try self.rdr.alloc.create(std.ArrayList(anyerror));
|
||||||
|
errdefer self.rdr.alloc.destroy(fil_errs);
|
||||||
|
fil_errs.* = .init(self.rdr.alloc);
|
||||||
errdefer fil_errs.deinit();
|
errdefer fil_errs.deinit();
|
||||||
@constCast(&self.data_reader.?).setPool(pol);
|
@constCast(&self.data_reader.?).setPool(pol);
|
||||||
try self.data_reader.?.writeToNoBlock(errs, ext_fil, filExtractFinish, .{
|
try self.data_reader.?.writeToNoBlock(errs, ext_fil, extractRegFinish, .{
|
||||||
self,
|
self,
|
||||||
op,
|
op,
|
||||||
path,
|
path,
|
||||||
&fil_errs,
|
fil_errs,
|
||||||
errs,
|
errs,
|
||||||
wg,
|
wg,
|
||||||
ext_fil,
|
ext_fil,
|
||||||
@@ -282,7 +334,15 @@ pub fn File(comptime T: type) type {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
fn filExtractFinish(
|
// fn extractFileFinish(
|
||||||
|
// self: Self,
|
||||||
|
// op: ExtractionOptions,
|
||||||
|
// path: []const u8,
|
||||||
|
// dir_wg: *WaitGroup,
|
||||||
|
// dir_wg_mut: *Mutex,
|
||||||
|
// wg: *WaitGroup,
|
||||||
|
// ) void {}
|
||||||
|
fn extractRegFinish(
|
||||||
self: Self,
|
self: Self,
|
||||||
op: ExtractionOptions,
|
op: ExtractionOptions,
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
@@ -292,19 +352,20 @@ pub fn File(comptime T: type) type {
|
|||||||
fil: std.fs.File,
|
fil: std.fs.File,
|
||||||
first: bool,
|
first: bool,
|
||||||
) void {
|
) void {
|
||||||
|
defer std.debug.print("{}\n", .{wg.state.raw});
|
||||||
defer wg.finish();
|
defer wg.finish();
|
||||||
defer fil.close();
|
defer fil.close();
|
||||||
|
defer self.rdr.alloc.destroy(fil_errs);
|
||||||
defer if (!first) self.deinit();
|
defer if (!first) self.deinit();
|
||||||
|
defer if (!first) self.rdr.alloc.free(path);
|
||||||
if (fil_errs.items.len > 0) {
|
if (fil_errs.items.len > 0) {
|
||||||
if (op.verbose) {
|
if (op.verbose) {
|
||||||
for (fil_errs.items) |err| {
|
|
||||||
std.fmt.format(
|
std.fmt.format(
|
||||||
op.verbose_logger,
|
op.verbose_logger,
|
||||||
"error extracting inode {} to \"{s}\": {}\n",
|
"error extracting inode {} to \"{s}\": {}\n",
|
||||||
.{ self.inode.hdr.num, path, err },
|
.{ self.inode.hdr.num, path, fil_errs.items[0] },
|
||||||
) catch {};
|
) catch {};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
errs.append(fil_errs.items[0]) catch {};
|
errs.append(fil_errs.items[0]) catch {};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -61,7 +61,7 @@ pub fn SfsReader(comptime T: type) type {
|
|||||||
}
|
}
|
||||||
/// Extract the entire archive to the given path & with the given options.
|
/// Extract the entire archive to the given path & with the given options.
|
||||||
/// Equivelent to calling extract on the root File.
|
/// Equivelent to calling extract on the root File.
|
||||||
pub fn extract(self: *Self, op: *ExtractionOptions, path: []const u8) !void {
|
pub fn extract(self: *Self, op: ExtractionOptions, path: []const u8) !void {
|
||||||
var rt = try self.root();
|
var rt = try self.root();
|
||||||
defer rt.deinit();
|
defer rt.deinit();
|
||||||
return rt.extract(op, path);
|
return rt.extract(op, path);
|
||||||
|
|||||||
+13
-6
@@ -190,8 +190,10 @@ pub fn DataReader(comptime T: type) type {
|
|||||||
if (self.pool == null) return DataReaderError.ThreadPoolNotSet;
|
if (self.pool == null) return DataReaderError.ThreadPoolNotSet;
|
||||||
var mut: std.Thread.Mutex = .{};
|
var mut: std.Thread.Mutex = .{};
|
||||||
var cur_idx: usize = 0;
|
var cur_idx: usize = 0;
|
||||||
var block_wg: std.Thread.WaitGroup = .{};
|
var block_wg = try self.alloc.create(std.Thread.WaitGroup);
|
||||||
var finish_mut: std.Thread.Mutex = .{};
|
block_wg.* = .{};
|
||||||
|
const finish_mut = try self.alloc.create(std.Thread.Mutex);
|
||||||
|
finish_mut.* = .{};
|
||||||
var completed: ?std.AutoHashMap(usize, []u8) = null;
|
var completed: ?std.AutoHashMap(usize, []u8) = null;
|
||||||
if (!comptime std.meta.hasFn(@TypeOf(writer), "pwrite")) {
|
if (!comptime std.meta.hasFn(@TypeOf(writer), "pwrite")) {
|
||||||
completed = std.AutoHashMap(usize, []u8).init(self.alloc);
|
completed = std.AutoHashMap(usize, []u8).init(self.alloc);
|
||||||
@@ -207,9 +209,9 @@ pub fn DataReader(comptime T: type) type {
|
|||||||
},
|
},
|
||||||
blk: {
|
blk: {
|
||||||
if (comptime std.meta.hasFn(@TypeOf(writer), "pwrite")) {
|
if (comptime std.meta.hasFn(@TypeOf(writer), "pwrite")) {
|
||||||
break :blk .{ self, &block_wg, errs, i, writer, &finish_mut, on_finish, on_finish_args };
|
break :blk .{ self, block_wg, errs, i, writer, finish_mut, on_finish, on_finish_args };
|
||||||
} else {
|
} else {
|
||||||
break :blk .{ self, &block_wg, &mut, &cur_idx, errs, &completed.?, i, writer, &finish_mut, on_finish, on_finish_args };
|
break :blk .{ self, block_wg, &mut, &cur_idx, errs, &completed.?, i, writer, finish_mut, on_finish, on_finish_args };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -267,7 +269,7 @@ pub fn DataReader(comptime T: type) type {
|
|||||||
writer: anytype,
|
writer: anytype,
|
||||||
) void {
|
) void {
|
||||||
if (errs.items.len > 0) return;
|
if (errs.items.len > 0) return;
|
||||||
if (self.sizes[idx].size == 0) {
|
if (idx < self.sizes.len and self.sizes[idx].size == 0) {
|
||||||
var pos = idx * self.block_size;
|
var pos = idx * self.block_size;
|
||||||
if (self.frag.len == 0 and idx == self.sizes.len - 1) {
|
if (self.frag.len == 0 and idx == self.sizes.len - 1) {
|
||||||
pos += self.file_size % self.block_size;
|
pos += self.file_size % self.block_size;
|
||||||
@@ -351,8 +353,13 @@ pub fn DataReader(comptime T: type) type {
|
|||||||
self.writeBlockToPWrite(errs, idx, writer);
|
self.writeBlockToPWrite(errs, idx, writer);
|
||||||
finish_mut.lock();
|
finish_mut.lock();
|
||||||
block_wg.finish();
|
block_wg.finish();
|
||||||
defer finish_mut.unlock();
|
defer {
|
||||||
|
const done = block_wg.isDone();
|
||||||
|
finish_mut.unlock();
|
||||||
|
if (done) self.alloc.destroy(finish_mut);
|
||||||
|
}
|
||||||
if (block_wg.isDone()) {
|
if (block_wg.isDone()) {
|
||||||
|
self.alloc.destroy(block_wg);
|
||||||
@call(.auto, on_finish, on_finish_args);
|
@call(.auto, on_finish, on_finish_args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-6
@@ -6,8 +6,6 @@ pub const ExtractionOptions = @import("extract_options.zig");
|
|||||||
pub const SfsFile = SfsReader(std.fs.File);
|
pub const SfsFile = SfsReader(std.fs.File);
|
||||||
|
|
||||||
const test_archive = "testing/LinuxPATest.sfs";
|
const test_archive = "testing/LinuxPATest.sfs";
|
||||||
const test_file = "Start.exe";
|
|
||||||
const file_extr_loc = "testing/Start.exe";
|
|
||||||
|
|
||||||
test "OpenFile" {
|
test "OpenFile" {
|
||||||
const sfs_fil = try std.fs.cwd().openFile(test_archive, .{});
|
const sfs_fil = try std.fs.cwd().openFile(test_archive, .{});
|
||||||
@@ -27,15 +25,31 @@ test "OpenFile" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "ExtractFile" {
|
test "ExtractSingleFile" {
|
||||||
std.fs.cwd().deleteFile(file_extr_loc) catch {};
|
const single_file = "Start.exe";
|
||||||
|
const single_file_extr_loc = "testing/Start.exe";
|
||||||
|
|
||||||
|
std.fs.cwd().deleteFile(single_file_extr_loc) catch {};
|
||||||
const sfs_fil = try std.fs.cwd().openFile(test_archive, .{});
|
const sfs_fil = try std.fs.cwd().openFile(test_archive, .{});
|
||||||
defer sfs_fil.close();
|
defer sfs_fil.close();
|
||||||
var rdr: SfsFile = try .init(std.testing.allocator, sfs_fil, 0);
|
var rdr: SfsFile = try .init(std.testing.allocator, sfs_fil, 0);
|
||||||
defer rdr.deinit();
|
defer rdr.deinit();
|
||||||
const fil = try rdr.open(test_file);
|
const fil = try rdr.open(single_file);
|
||||||
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, single_file_extr_loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "ExtractAll" {
|
||||||
|
const extr_dir = "testing/testExtract";
|
||||||
|
|
||||||
|
std.fs.cwd().deleteTree(extr_dir) catch {};
|
||||||
|
const sfs_fil = try std.fs.cwd().openFile(test_archive, .{});
|
||||||
|
defer sfs_fil.close();
|
||||||
|
var rdr: SfsFile = try .init(std.testing.allocator, sfs_fil, 0);
|
||||||
|
defer rdr.deinit();
|
||||||
|
var op: ExtractionOptions = try .init();
|
||||||
|
op.verbose = true;
|
||||||
|
try rdr.extract(op, extr_dir);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user