Re-writing extraction (again)
This commit is contained in:
+44
-314
@@ -100,7 +100,7 @@ pub fn File(comptime T: type) type {
|
|||||||
const inode: Inode = try .init(&meta, rdr.alloc, rdr.super.block_size);
|
const inode: Inode = try .init(&meta, rdr.alloc, rdr.super.block_size);
|
||||||
return .init(rdr, inode, ent.name);
|
return .init(rdr, inode, ent.name);
|
||||||
}
|
}
|
||||||
pub fn deinit(self: Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
self.rdr.alloc.free(self.name);
|
self.rdr.alloc.free(self.name);
|
||||||
self.inode.deinit(self.rdr.alloc);
|
self.inode.deinit(self.rdr.alloc);
|
||||||
if (self.entries != null) {
|
if (self.entries != null) {
|
||||||
@@ -179,25 +179,6 @@ pub fn File(comptime T: type) type {
|
|||||||
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 {
|
||||||
var exists = true;
|
|
||||||
var stat: ?std.fs.File.Stat = null;
|
|
||||||
if (std.fs.cwd().statFile(path)) |s| {
|
|
||||||
stat = s;
|
|
||||||
} else |err| {
|
|
||||||
if (err == std.fs.File.OpenError.FileNotFound) {
|
|
||||||
exists = false;
|
|
||||||
} else {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (self.inode.hdr.type) {
|
|
||||||
.dir, .ext_dir => {
|
|
||||||
if (exists and stat.?.kind != .directory) {
|
|
||||||
return ExtractError.FileExists;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => if (exists) return ExtractError.FileExists,
|
|
||||||
}
|
|
||||||
var wg: WaitGroup = .{};
|
var wg: WaitGroup = .{};
|
||||||
var pol: Pool = undefined;
|
var pol: Pool = undefined;
|
||||||
try pol.init(.{
|
try pol.init(.{
|
||||||
@@ -207,316 +188,65 @@ 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();
|
||||||
self.extractReal(op, path, &errs, &wg, &pol, true);
|
try self.extractInode(op, &wg, &errs, &pol, self.inode, path);
|
||||||
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 extractInode(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
op: ExtractionOptions,
|
op: ExtractionOptions,
|
||||||
path: []const u8,
|
|
||||||
errs: *std.ArrayList(anyerror),
|
|
||||||
wg: *WaitGroup,
|
wg: *WaitGroup,
|
||||||
|
errs: *std.ArrayList(anyerror),
|
||||||
pol: *Pool,
|
pol: *Pool,
|
||||||
first: bool,
|
inode: Inode,
|
||||||
) void {
|
path: []const u8,
|
||||||
if (errs.items.len > 0) return;
|
) !void {
|
||||||
if (op.verbose) {
|
_ = errs;
|
||||||
std.fmt.format(
|
_ = pol;
|
||||||
op.verbose_logger,
|
|
||||||
"extracting inode {} \"{s}\" to {s}...\n",
|
wg.start();
|
||||||
.{ self.inode.hdr.num, self.name, path },
|
defer wg.finish(); //TODO: When everthing is threaded, this will need to be handled by the threads, not here.
|
||||||
) catch {};
|
switch (inode.hdr.type) {
|
||||||
}
|
.file => {
|
||||||
return switch (self.inode.hdr.type) {
|
var fil = try std.fs.cwd().createFile(path, .{});
|
||||||
.dir, .ext_dir => {
|
defer fil.close();
|
||||||
var complete = false;
|
var data: DataReader(T) = try .init(self.rdr, inode);
|
||||||
wg.start();
|
defer data.deinit();
|
||||||
defer if (!complete) wg.finish();
|
try data.writeTo(fil); // TODO: Thread
|
||||||
std.fs.cwd().makeDir(path) catch |err| {
|
const fil_uid = self.rdr.id_table.get(inode.hdr.uid_idx) catch |err| {
|
||||||
if (err != std.fs.Dir.MakeError.PathAlreadyExists) {
|
|
||||||
errs.append(err) catch {};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const dir_wg = self.rdr.alloc.create(WaitGroup) catch |err| {
|
|
||||||
errs.append(err) catch {};
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
dir_wg.* = .{};
|
|
||||||
for (self.entries.?) |ent| {
|
|
||||||
const 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;
|
|
||||||
};
|
|
||||||
var thr = std.Thread.spawn(.{ .allocator = self.rdr.alloc }, extractReal, .{
|
|
||||||
&fil,
|
|
||||||
op,
|
|
||||||
ext_path,
|
|
||||||
errs,
|
|
||||||
dir_wg,
|
|
||||||
pol,
|
|
||||||
false,
|
|
||||||
}) catch |err| {
|
|
||||||
self.rdr.alloc.free(ext_path);
|
|
||||||
if (op.verbose) {
|
|
||||||
std.fmt.format(
|
|
||||||
op.verbose_logger,
|
|
||||||
"error extracting inode {} \"{s}\": {}\n",
|
|
||||||
.{ ent.num, path, err },
|
|
||||||
) catch {};
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
thr.detach();
|
|
||||||
}
|
|
||||||
var thr = std.Thread.spawn(
|
|
||||||
.{ .allocator = self.rdr.alloc },
|
|
||||||
extractDirWait,
|
|
||||||
.{
|
|
||||||
self,
|
|
||||||
op,
|
|
||||||
path,
|
|
||||||
dir_wg,
|
|
||||||
wg,
|
|
||||||
first,
|
|
||||||
},
|
|
||||||
) catch |err| {
|
|
||||||
if (op.verbose) {
|
if (op.verbose) {
|
||||||
std.fmt.format(
|
std.fmt.format(op.verbose_logger, "error getting uid {} from table: {}\n", .{ inode.hdr.uid_idx, err }) catch {};
|
||||||
op.verbose_logger,
|
|
||||||
"error spawning wait thread for \"{s}\": {}\n",
|
|
||||||
.{ path, err },
|
|
||||||
) catch {};
|
|
||||||
}
|
}
|
||||||
self.extractDirWait(op, path, dir_wg, wg, first);
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
thr.detach();
|
const fil_gid = self.rdr.id_table.get(inode.hdr.gid_idx) catch |err| {
|
||||||
complete = true;
|
if (op.verbose) {
|
||||||
|
std.fmt.format(op.verbose_logger, "error getting gid {} from table: {}\n", .{ inode.hdr.gid_idx, err }) catch {};
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
fil.chmod(inode.hdr.perm) catch |err| {
|
||||||
|
if (op.verbose) {
|
||||||
|
std.fmt.format(op.verbose_logger, "error chmod {s}: {}\n", .{ path, err }) catch {};
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
fil.chown(fil_uid, fil_gid) catch |err| {
|
||||||
|
if (op.verbose) {
|
||||||
|
std.fmt.format(op.verbose_logger, "error chmod {s}: {}\n", .{ path, err }) catch {};
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
//TODO: update mtime.
|
||||||
},
|
},
|
||||||
.file, .ext_file => {
|
.dir => {
|
||||||
var complete = false;
|
std.fs.cwd().makeDir(path); //TODO: Check existence
|
||||||
wg.start();
|
|
||||||
defer if (!complete) wg.finish();
|
|
||||||
var ext_fil = std.fs.cwd().createFile(path, .{}) catch |err| {
|
|
||||||
if (op.verbose) {
|
|
||||||
std.fmt.format(
|
|
||||||
op.verbose_logger,
|
|
||||||
"error creating file \"{s}\": {}\n",
|
|
||||||
.{ path, err },
|
|
||||||
) catch {};
|
|
||||||
}
|
|
||||||
errs.append(err) catch {};
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
defer if (!complete) ext_fil.close();
|
|
||||||
var fil_errs = self.rdr.alloc.create(std.ArrayList(anyerror)) catch |err| {
|
|
||||||
if (op.verbose) {
|
|
||||||
std.fmt.format(
|
|
||||||
op.verbose_logger,
|
|
||||||
"error allocating memory: {}\n",
|
|
||||||
.{err},
|
|
||||||
) catch {};
|
|
||||||
}
|
|
||||||
errs.append(err) catch {};
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
defer if (!complete) self.rdr.alloc.destroy(fil_errs);
|
|
||||||
fil_errs.* = .init(self.rdr.alloc);
|
|
||||||
defer if (!complete) fil_errs.deinit();
|
|
||||||
self.data_reader.?.writeToNoBlock(
|
|
||||||
ext_fil,
|
|
||||||
extractRegFinish,
|
|
||||||
.{
|
|
||||||
self,
|
|
||||||
op,
|
|
||||||
path,
|
|
||||||
fil_errs,
|
|
||||||
errs,
|
|
||||||
wg,
|
|
||||||
ext_fil,
|
|
||||||
first,
|
|
||||||
},
|
|
||||||
) catch |err| {
|
|
||||||
if (op.verbose) {
|
|
||||||
std.fmt.format(
|
|
||||||
op.verbose_logger,
|
|
||||||
"error extracting file \"{s}\": {}\n",
|
|
||||||
.{ path, err },
|
|
||||||
) catch {};
|
|
||||||
}
|
|
||||||
errs.append(err) catch {};
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
complete = true;
|
|
||||||
},
|
|
||||||
.symlink, .ext_symlink => {},
|
|
||||||
.block_dev, .ext_block_dev, .char_dev, .ext_char_dev, .fifo, .ext_fifo => {
|
|
||||||
//TODO: check for all oses that accept unix permissions.
|
|
||||||
},
|
},
|
||||||
|
.symlink => {},
|
||||||
else => {
|
else => {
|
||||||
if (op.verbose) {
|
std.debug.print("TODO: {}\n", .{inode.hdr.type});
|
||||||
std.fmt.format(
|
|
||||||
op.verbose_logger,
|
|
||||||
"inode {} \"{s}\" is a socket file. Ignoring.\n",
|
|
||||||
.{ self.inode.hdr.num, path },
|
|
||||||
) catch {};
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
|
||||||
}
|
|
||||||
fn extractDirWait(
|
|
||||||
self: *Self,
|
|
||||||
op: ExtractionOptions,
|
|
||||||
path: []const u8,
|
|
||||||
dir_wg: *WaitGroup,
|
|
||||||
wg: *WaitGroup,
|
|
||||||
first: bool,
|
|
||||||
) void {
|
|
||||||
dir_wg.wait();
|
|
||||||
self.rdr.alloc.destroy(dir_wg);
|
|
||||||
defer {
|
|
||||||
wg.finish();
|
|
||||||
if (!first) {
|
|
||||||
self.rdr.alloc.free(path);
|
|
||||||
self.deinit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (op.ignore_permissions) return;
|
|
||||||
const dir_uid = self.uid() catch |err| {
|
|
||||||
std.fmt.format(
|
|
||||||
op.verbose_logger,
|
|
||||||
"error getting uid for inode {} \"{s}\": {}\n",
|
|
||||||
.{ self.inode.hdr.num, path, err },
|
|
||||||
) catch {};
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
const dir_gid = self.gid() catch |err| {
|
|
||||||
std.fmt.format(
|
|
||||||
op.verbose_logger,
|
|
||||||
"error getting gid for inode {} \"{s}\": {}\n",
|
|
||||||
.{ self.inode.hdr.num, path, err },
|
|
||||||
) catch {};
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
var ext_dir = std.fs.cwd().openFile(path, .{}) catch |err| {
|
|
||||||
std.fmt.format(
|
|
||||||
op.verbose_logger,
|
|
||||||
"error setting owner & permissions for \"{s}\": {}\n",
|
|
||||||
.{ path, err },
|
|
||||||
) catch {};
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
defer ext_dir.close();
|
|
||||||
ext_dir.chmod(self.inode.hdr.perm) catch |err| {
|
|
||||||
std.fmt.format(
|
|
||||||
op.verbose_logger,
|
|
||||||
"error setting permissions for inode {} \"{s}\": {}\n",
|
|
||||||
.{ self.inode.hdr.num, path, err },
|
|
||||||
) catch {};
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
ext_dir.chown(dir_uid, dir_gid) catch |err| {
|
|
||||||
std.fmt.format(
|
|
||||||
op.verbose_logger,
|
|
||||||
"error setting owner for inode {} \"{s}\": {}\n",
|
|
||||||
.{ self.inode.hdr.num, path, err },
|
|
||||||
) catch {};
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
fn extractRegFinish(
|
|
||||||
self: *Self,
|
|
||||||
op: ExtractionOptions,
|
|
||||||
path: []const u8,
|
|
||||||
fil_errs: *std.ArrayList(anyerror),
|
|
||||||
errs: *std.ArrayList(anyerror),
|
|
||||||
wg: *WaitGroup,
|
|
||||||
fil: std.fs.File,
|
|
||||||
first: bool,
|
|
||||||
) void {
|
|
||||||
defer {
|
|
||||||
wg.finish();
|
|
||||||
fil.close();
|
|
||||||
self.rdr.alloc.destroy(fil_errs);
|
|
||||||
if (!first) {
|
|
||||||
self.deinit();
|
|
||||||
self.rdr.alloc.free(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fil_errs.items.len > 0) {
|
|
||||||
if (op.verbose) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
if (op.ignore_permissions) return;
|
|
||||||
const fil_uid = self.uid() catch |err| {
|
|
||||||
std.fmt.format(
|
|
||||||
op.verbose_logger,
|
|
||||||
"error getting uid for inode {} \"{s}\": {}\n",
|
|
||||||
.{ self.inode.hdr.num, path, err },
|
|
||||||
) catch {};
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
const fil_gid = self.gid() catch |err| {
|
|
||||||
std.fmt.format(
|
|
||||||
op.verbose_logger,
|
|
||||||
"error getting gid for inode {} \"{s}\": {}\n",
|
|
||||||
.{ self.inode.hdr.num, path, err },
|
|
||||||
) catch {};
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
fil.chmod(self.inode.hdr.perm) catch |err| {
|
|
||||||
std.fmt.format(
|
|
||||||
op.verbose_logger,
|
|
||||||
"error setting permissions for inode {} \"{s}\": {}\n",
|
|
||||||
.{ self.inode.hdr.num, path, err },
|
|
||||||
) catch {};
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
fil.chown(fil_uid, fil_gid) catch |err| {
|
|
||||||
std.fmt.format(
|
|
||||||
op.verbose_logger,
|
|
||||||
"error setting owner for inode {} \"{s}\": {}\n",
|
|
||||||
.{ self.inode.hdr.num, path, err },
|
|
||||||
) catch {};
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-4
@@ -101,8 +101,10 @@ pub fn DataReader(comptime T: type) type {
|
|||||||
},
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
for (1..offsets.len) |i| {
|
if (offsets.len > 1) {
|
||||||
offsets[i] = offsets[i - 1] + sizes[i - 1].size;
|
for (1..offsets.len) |i| {
|
||||||
|
offsets[i] = offsets[i - 1] + sizes[i - 1].size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return .{
|
return .{
|
||||||
.alloc = rdr.alloc,
|
.alloc = rdr.alloc,
|
||||||
@@ -115,7 +117,7 @@ pub fn DataReader(comptime T: type) type {
|
|||||||
.completion = .init(rdr.alloc),
|
.completion = .init(rdr.alloc),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn deinit(self: Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
self.alloc.free(self.offsets);
|
self.alloc.free(self.offsets);
|
||||||
self.completion.deinit();
|
self.completion.deinit();
|
||||||
}
|
}
|
||||||
@@ -139,6 +141,7 @@ pub fn DataReader(comptime T: type) type {
|
|||||||
.{ self, i },
|
.{ self, i },
|
||||||
) catch |err| {
|
) catch |err| {
|
||||||
self.completion.addErr(err);
|
self.completion.addErr(err);
|
||||||
|
continue;
|
||||||
};
|
};
|
||||||
thr.detach();
|
thr.detach();
|
||||||
}
|
}
|
||||||
@@ -194,7 +197,7 @@ pub fn DataReader(comptime T: type) type {
|
|||||||
_ = try self.comp.decompress(
|
_ = try self.comp.decompress(
|
||||||
1024 * 1024,
|
1024 * 1024,
|
||||||
self.alloc,
|
self.alloc,
|
||||||
self.rdr.readerAt(self.offsets[idx]),
|
self.rdr.readerAt(self.offsets[idx]).reader(),
|
||||||
block,
|
block,
|
||||||
);
|
);
|
||||||
return block;
|
return block;
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ pub fn ToRead(comptime T: type) type {
|
|||||||
}
|
}
|
||||||
return cur_red;
|
return cur_red;
|
||||||
}
|
}
|
||||||
pub fn reader(self: anytype) std.io.Reader(*Self, anyerror, read) {
|
const Reader = std.io.GenericReader(*Self, anyerror, read);
|
||||||
|
pub fn reader(self: anytype) Reader {
|
||||||
return .{
|
return .{
|
||||||
.context = @constCast(self),
|
.context = @constCast(self),
|
||||||
};
|
};
|
||||||
|
|||||||
+10
-3
@@ -19,10 +19,13 @@ test "OpenFile" {
|
|||||||
var root = try rdr.root();
|
var root = try rdr.root();
|
||||||
defer root.deinit();
|
defer root.deinit();
|
||||||
var iter = root.iterate();
|
var iter = root.iterate();
|
||||||
while (try iter.next()) |*f| {
|
while (true) {
|
||||||
defer f.deinit();
|
var f = try iter.next();
|
||||||
std.debug.print("{s}\n", .{f.name});
|
if (f == null) break;
|
||||||
|
defer f.?.deinit();
|
||||||
|
std.debug.print("{s}\n", .{f.?.name});
|
||||||
}
|
}
|
||||||
|
std.debug.print("Finished OpenFile test", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
test "ExtractSingleFile" {
|
test "ExtractSingleFile" {
|
||||||
@@ -39,6 +42,8 @@ test "ExtractSingleFile" {
|
|||||||
var op: ExtractionOptions = try .init();
|
var op: ExtractionOptions = try .init();
|
||||||
op.verbose = true;
|
op.verbose = true;
|
||||||
try fil.extract(op, single_file_extr_loc);
|
try fil.extract(op, single_file_extr_loc);
|
||||||
|
|
||||||
|
std.debug.print("Finished ExtractSingleFile test\n", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
test "ExtractAll" {
|
test "ExtractAll" {
|
||||||
@@ -52,4 +57,6 @@ test "ExtractAll" {
|
|||||||
const op: ExtractionOptions = try .init();
|
const op: ExtractionOptions = try .init();
|
||||||
// op.verbose = true;
|
// op.verbose = true;
|
||||||
try rdr.extract(op, extr_dir);
|
try rdr.extract(op, extr_dir);
|
||||||
|
|
||||||
|
std.debug.print("Finished ExtractAll test\n", .{});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user