Further progress on extraction
This commit is contained in:
+75
-14
@@ -206,8 +206,6 @@ pub fn File(comptime T: type) type {
|
||||
.dir, .ext_dir => {
|
||||
if (exists and stat.?.kind != .directory) {
|
||||
return ExtractError.FileExists;
|
||||
} else if (!exists) {
|
||||
try std.fs.cwd().makeDir(path);
|
||||
}
|
||||
},
|
||||
else => if (exists) return ExtractError.FileExists,
|
||||
@@ -236,31 +234,85 @@ pub fn File(comptime T: type) type {
|
||||
) !void {
|
||||
if (errs.items.len > 0) return;
|
||||
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) {
|
||||
.dir, .ext_dir => {
|
||||
wg.start();
|
||||
defer std.debug.print("{}\n", .{wg.state.raw});
|
||||
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| {
|
||||
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;
|
||||
};
|
||||
}
|
||||
dir_wg.wait();
|
||||
wg.finish();
|
||||
std.debug.print("finished: {s}\n", .{path});
|
||||
},
|
||||
.file, .ext_file => {
|
||||
wg.start();
|
||||
errdefer wg.finish();
|
||||
var ext_fil = try std.fs.cwd().createFile(path, .{});
|
||||
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();
|
||||
@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,
|
||||
op,
|
||||
path,
|
||||
&fil_errs,
|
||||
fil_errs,
|
||||
errs,
|
||||
wg,
|
||||
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,
|
||||
op: ExtractionOptions,
|
||||
path: []const u8,
|
||||
@@ -292,18 +352,19 @@ pub fn File(comptime T: type) type {
|
||||
fil: std.fs.File,
|
||||
first: bool,
|
||||
) void {
|
||||
defer std.debug.print("{}\n", .{wg.state.raw});
|
||||
defer wg.finish();
|
||||
defer fil.close();
|
||||
defer self.rdr.alloc.destroy(fil_errs);
|
||||
defer if (!first) self.deinit();
|
||||
defer if (!first) self.rdr.alloc.free(path);
|
||||
if (fil_errs.items.len > 0) {
|
||||
if (op.verbose) {
|
||||
for (fil_errs.items) |err| {
|
||||
std.fmt.format(
|
||||
op.verbose_logger,
|
||||
"error extracting inode {} to \"{s}\": {}\n",
|
||||
.{ self.inode.hdr.num, path, err },
|
||||
) catch {};
|
||||
}
|
||||
std.fmt.format(
|
||||
op.verbose_logger,
|
||||
"error extracting inode {} to \"{s}\": {}\n",
|
||||
.{ self.inode.hdr.num, path, fil_errs.items[0] },
|
||||
) catch {};
|
||||
}
|
||||
errs.append(fil_errs.items[0]) catch {};
|
||||
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.
|
||||
/// 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();
|
||||
defer rt.deinit();
|
||||
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;
|
||||
var mut: std.Thread.Mutex = .{};
|
||||
var cur_idx: usize = 0;
|
||||
var block_wg: std.Thread.WaitGroup = .{};
|
||||
var finish_mut: std.Thread.Mutex = .{};
|
||||
var block_wg = try self.alloc.create(std.Thread.WaitGroup);
|
||||
block_wg.* = .{};
|
||||
const finish_mut = try self.alloc.create(std.Thread.Mutex);
|
||||
finish_mut.* = .{};
|
||||
var completed: ?std.AutoHashMap(usize, []u8) = null;
|
||||
if (!comptime std.meta.hasFn(@TypeOf(writer), "pwrite")) {
|
||||
completed = std.AutoHashMap(usize, []u8).init(self.alloc);
|
||||
@@ -207,9 +209,9 @@ pub fn DataReader(comptime T: type) type {
|
||||
},
|
||||
blk: {
|
||||
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 {
|
||||
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,
|
||||
) void {
|
||||
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;
|
||||
if (self.frag.len == 0 and idx == self.sizes.len - 1) {
|
||||
pos += self.file_size % self.block_size;
|
||||
@@ -351,8 +353,13 @@ pub fn DataReader(comptime T: type) type {
|
||||
self.writeBlockToPWrite(errs, idx, writer);
|
||||
finish_mut.lock();
|
||||
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()) {
|
||||
self.alloc.destroy(block_wg);
|
||||
@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);
|
||||
|
||||
const test_archive = "testing/LinuxPATest.sfs";
|
||||
const test_file = "Start.exe";
|
||||
const file_extr_loc = "testing/Start.exe";
|
||||
|
||||
test "OpenFile" {
|
||||
const sfs_fil = try std.fs.cwd().openFile(test_archive, .{});
|
||||
@@ -27,15 +25,31 @@ test "OpenFile" {
|
||||
}
|
||||
}
|
||||
|
||||
test "ExtractFile" {
|
||||
std.fs.cwd().deleteFile(file_extr_loc) catch {};
|
||||
test "ExtractSingleFile" {
|
||||
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, .{});
|
||||
defer sfs_fil.close();
|
||||
var rdr: SfsFile = try .init(std.testing.allocator, sfs_fil, 0);
|
||||
defer rdr.deinit();
|
||||
const fil = try rdr.open(test_file);
|
||||
const fil = try rdr.open(single_file);
|
||||
defer fil.deinit();
|
||||
var op: ExtractionOptions = try .init();
|
||||
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