Switched to single-threaded extraction for easier debugging.
Fixed a few issues
This commit is contained in:
@@ -91,8 +91,6 @@ pub fn finished(self: *DecompCache, io: Io, offset: u64) void {
|
||||
return;
|
||||
}
|
||||
|
||||
self.mut.lockUncancelable(io);
|
||||
defer self.mut.unlock(io);
|
||||
const use = cache.?.usage.fetchSub(1, .acquire);
|
||||
if (use == 0)
|
||||
self.cond.broadcast(io);
|
||||
|
||||
+110
-241
@@ -15,45 +15,16 @@ const XattrTable = @import("xattr.zig");
|
||||
pub fn extract(alloc: std.mem.Allocator, io: Io, inode: Inode, cache: *DecompCache, super: Superblock, ext_loc: []const u8, options: ExtractionOptions) !void {
|
||||
const path = std.mem.trim(u8, ext_loc, "/");
|
||||
|
||||
var buf: [1000]ReturnUnion = undefined;
|
||||
var sel: Io.Select(ReturnUnion) = .init(io, &buf);
|
||||
|
||||
defer {
|
||||
std.debug.print("starting cancel loop...\n", .{});
|
||||
while (sel.cancel()) |ret| {
|
||||
std.debug.print("HELLO!\n", .{});
|
||||
switch (ret) {
|
||||
.dir_ret => |d| {
|
||||
const res = d catch continue;
|
||||
if (!res.origin)
|
||||
alloc.free(res.path);
|
||||
alloc.destroy(res.sub_files);
|
||||
},
|
||||
.file_ret => |f| {
|
||||
const res = f catch continue;
|
||||
if (!res.origin)
|
||||
alloc.free(res.path);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
std.debug.print("goodbye\n", .{});
|
||||
}
|
||||
|
||||
var id_table: Lookup.Table(u16) = .init(alloc, cache, super.id_start, super.id_count);
|
||||
defer id_table.deinit();
|
||||
defer id_table.deinit(io);
|
||||
|
||||
var xattr_table: XattrTable = try .init(alloc, cache, super.xattr_start);
|
||||
defer xattr_table.deinit();
|
||||
|
||||
var ret_loop = io.async(returnLoop, .{ alloc, io, &id_table, &xattr_table, &sel, options });
|
||||
defer xattr_table.deinit(io);
|
||||
|
||||
var frag_table: Lookup.Table(Lookup.FragmentEntry) = .init(alloc, cache, super.frag_start, super.frag_count);
|
||||
defer frag_table.deinit();
|
||||
defer frag_table.deinit(io);
|
||||
|
||||
try extractReal(alloc, io, cache, super, &sel, &frag_table, path, inode, null, true);
|
||||
|
||||
try ret_loop.await(io);
|
||||
try extractReal(alloc, io, cache, super, &frag_table, &id_table, &xattr_table, options, path, inode, true);
|
||||
}
|
||||
|
||||
fn extractReal(
|
||||
@@ -61,39 +32,32 @@ fn extractReal(
|
||||
io: Io,
|
||||
cache: *DecompCache,
|
||||
super: Superblock,
|
||||
sel: *Io.Select(ReturnUnion),
|
||||
frag_table: *Lookup.Table(Lookup.FragmentEntry),
|
||||
id_table: *Lookup.Table(u16),
|
||||
xattr_table: *XattrTable,
|
||||
options: ExtractionOptions,
|
||||
path: []const u8,
|
||||
inode: Inode,
|
||||
parent: ?*Atomic(usize),
|
||||
origin: bool,
|
||||
) Error!void {
|
||||
io.checkCancel() catch |err| {
|
||||
if (parent != null) _ = parent.?.fetchSub(1, .acquire);
|
||||
return err;
|
||||
defer if (!origin) {
|
||||
inode.deinit(alloc);
|
||||
alloc.free(path);
|
||||
};
|
||||
|
||||
switch (inode.data) {
|
||||
.dir, .ext_dir => sel.async(
|
||||
.dir_ret,
|
||||
extractDir,
|
||||
.{ alloc, io, cache, super, sel, frag_table, path, inode, parent, origin },
|
||||
),
|
||||
.file, .ext_file => sel.async(
|
||||
.file_ret,
|
||||
extractFile,
|
||||
.{ alloc, io, cache, super.block_size, frag_table, path, inode, parent, origin },
|
||||
),
|
||||
.symlink, .ext_symlink => sel.async(
|
||||
.void_ret,
|
||||
extractSymlink,
|
||||
.{ alloc, io, path, inode, parent, origin },
|
||||
),
|
||||
else => sel.async(
|
||||
.file_ret,
|
||||
extractNod,
|
||||
.{ alloc, path, inode, parent, origin },
|
||||
),
|
||||
.dir, .ext_dir => {
|
||||
const res = try extractDir(alloc, io, cache, super, frag_table, id_table, xattr_table, options, path, inode);
|
||||
try res.finish(alloc, io, id_table, xattr_table, options);
|
||||
},
|
||||
.file, .ext_file => {
|
||||
const res = try extractFile(io, cache, super.block_size, frag_table, path, inode);
|
||||
try res.finish(alloc, io, id_table, xattr_table, options);
|
||||
},
|
||||
.symlink, .ext_symlink => try extractSymlink(io, path, inode),
|
||||
else => {
|
||||
const res = try extractNod(alloc, path, inode);
|
||||
try res.finish(alloc, io, id_table, xattr_table, options);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,21 +66,13 @@ fn extractDir(
|
||||
io: Io,
|
||||
cache: *DecompCache,
|
||||
super: Superblock,
|
||||
sel: *Io.Select(ReturnUnion),
|
||||
frag_table: *Lookup.Table(Lookup.FragmentEntry),
|
||||
id_table: *Lookup.Table(u16),
|
||||
xattr_table: *XattrTable,
|
||||
options: ExtractionOptions,
|
||||
path: []const u8,
|
||||
inode: Inode,
|
||||
parent: ?*Atomic(usize),
|
||||
origin: bool,
|
||||
) Error!DirReturn {
|
||||
std.debug.print("started extract of {s}\n", .{path});
|
||||
defer {
|
||||
if (parent != null)
|
||||
_ = parent.?.fetchSub(1, .acquire);
|
||||
if (!origin) inode.deinit(alloc);
|
||||
}
|
||||
errdefer if (!origin) alloc.free(path);
|
||||
|
||||
) Error!DirReturn(false) {
|
||||
try Io.Dir.cwd().createDirPath(io, path);
|
||||
|
||||
const dir = inode.directory(alloc, io, cache, super.dir_start) catch |err| switch (err) {
|
||||
@@ -125,18 +81,9 @@ fn extractDir(
|
||||
};
|
||||
defer dir.deinit(alloc);
|
||||
|
||||
const sub_files = try alloc.create(Atomic(usize));
|
||||
sub_files.* = .init(dir.entries.len);
|
||||
|
||||
const ret: DirReturn = .{
|
||||
const ret: DirReturn(false) = .{
|
||||
.hdr = inode.hdr,
|
||||
.path = path,
|
||||
.sub_files = sub_files,
|
||||
.origin = origin,
|
||||
|
||||
.uid_idx = inode.hdr.uid_idx,
|
||||
.gid_idx = inode.hdr.gid_idx,
|
||||
.mod_time = inode.hdr.mod_time,
|
||||
.permissions = inode.hdr.permission,
|
||||
|
||||
.xattr_idx = switch (inode.data) {
|
||||
.ext_dir => |d| if (d.xattr_idx != 0xFFFFFFFF) d.xattr_idx else null,
|
||||
@@ -146,56 +93,42 @@ fn extractDir(
|
||||
|
||||
for (dir.entries) |entry| {
|
||||
const new_inode: Inode = try .initDirEntry(alloc, io, cache, super.inode_start, super.block_size, entry);
|
||||
errdefer new_inode.deinit(alloc);
|
||||
|
||||
const new_path = try std.mem.concat(alloc, u8, &.{ path, "/", entry.name });
|
||||
errdefer alloc.free(new_path);
|
||||
const new_path = std.mem.concat(alloc, u8, &.{ path, "/", entry.name }) catch |err| {
|
||||
new_inode.deinit(alloc);
|
||||
return err;
|
||||
};
|
||||
|
||||
try extractReal(
|
||||
alloc,
|
||||
io,
|
||||
cache,
|
||||
super,
|
||||
sel,
|
||||
frag_table,
|
||||
id_table,
|
||||
xattr_table,
|
||||
options,
|
||||
new_path,
|
||||
new_inode,
|
||||
sub_files,
|
||||
false,
|
||||
);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
fn extractFile(
|
||||
alloc: std.mem.Allocator,
|
||||
io: Io,
|
||||
cache: *DecompCache,
|
||||
block_size: u32,
|
||||
frag_table: *Lookup.Table(Lookup.FragmentEntry),
|
||||
path: []const u8,
|
||||
inode: Inode,
|
||||
parent: ?*Atomic(usize),
|
||||
origin: bool,
|
||||
) Error!FileReturn {
|
||||
std.debug.print("started extract of {s}\n", .{path});
|
||||
defer {
|
||||
if (parent != null)
|
||||
_ = parent.?.fetchSub(1, .acquire);
|
||||
if (!origin) inode.deinit(alloc);
|
||||
}
|
||||
errdefer if (!origin) alloc.free(path);
|
||||
|
||||
) Error!FileReturn(false) {
|
||||
var atomic = try Io.Dir.cwd().createFileAtomic(io, path, .{});
|
||||
defer atomic.deinit(io);
|
||||
|
||||
var ret: FileReturn = .{
|
||||
var ret: FileReturn(false) = .{
|
||||
.hdr = inode.hdr,
|
||||
.path = path,
|
||||
.origin = origin,
|
||||
|
||||
.uid_idx = inode.hdr.uid_idx,
|
||||
.gid_idx = inode.hdr.gid_idx,
|
||||
.permissions = inode.hdr.permission,
|
||||
.mod_time = inode.hdr.mod_time,
|
||||
};
|
||||
|
||||
const data: DataExtractor = switch (inode.data) {
|
||||
@@ -235,17 +168,7 @@ fn extractFile(
|
||||
|
||||
return ret;
|
||||
}
|
||||
fn extractSymlink(alloc: std.mem.Allocator, io: Io, path: []const u8, inode: Inode, parent: ?*Atomic(usize), origin: bool) Error!void {
|
||||
std.debug.print("started extract of {s}\n", .{path});
|
||||
defer {
|
||||
if (parent != null)
|
||||
_ = parent.?.fetchSub(1, .acquire);
|
||||
if (!origin) {
|
||||
inode.deinit(alloc);
|
||||
alloc.free(path);
|
||||
}
|
||||
}
|
||||
|
||||
fn extractSymlink(io: Io, path: []const u8, inode: Inode) Error!void {
|
||||
const target = switch (inode.data) {
|
||||
.symlink => |s| s.target,
|
||||
.ext_symlink => |s| s.target,
|
||||
@@ -254,23 +177,10 @@ fn extractSymlink(alloc: std.mem.Allocator, io: Io, path: []const u8, inode: Ino
|
||||
|
||||
try Io.Dir.cwd().symLink(io, target, path, .{});
|
||||
}
|
||||
fn extractNod(alloc: std.mem.Allocator, path: []const u8, inode: Inode, parent: ?*Atomic(usize), origin: bool) Error!FileReturn {
|
||||
std.debug.print("started extract of {s}\n", .{path});
|
||||
defer {
|
||||
if (parent != null)
|
||||
_ = parent.?.fetchSub(1, .acquire);
|
||||
if (!origin) inode.deinit(alloc);
|
||||
}
|
||||
errdefer if (!origin) alloc.free(path);
|
||||
|
||||
var ret: FileReturn = .{
|
||||
fn extractNod(alloc: std.mem.Allocator, path: []const u8, inode: Inode) Error!FileReturn(false) {
|
||||
var ret: FileReturn(false) = .{
|
||||
.hdr = inode.hdr,
|
||||
.path = path,
|
||||
.origin = origin,
|
||||
|
||||
.uid_idx = inode.hdr.uid_idx,
|
||||
.gid_idx = inode.hdr.gid_idx,
|
||||
.permissions = inode.hdr.permission,
|
||||
.mod_time = inode.hdr.mod_time,
|
||||
};
|
||||
|
||||
const DT = std.os.linux.DT;
|
||||
@@ -324,133 +234,92 @@ fn extractNod(alloc: std.mem.Allocator, path: []const u8, inode: Inode, parent:
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Loop
|
||||
fn setMetadata(alloc: std.mem.Allocator, io: Io, id_table: *Lookup.Table(u16), xattr_table: *XattrTable, options: ExtractionOptions, hdr: Inode.Header, xattr_idx: ?u32, path: []const u8) Error!void {
|
||||
if (options.ignore_permissions and (options.ignore_xattr or xattr_idx == null)) return;
|
||||
|
||||
fn returnLoop(alloc: std.mem.Allocator, io: Io, id_table: *Lookup.Table(u16), xattr_table: *XattrTable, sel: *Io.Select(ReturnUnion), options: ExtractionOptions) !void {
|
||||
var origin_finished = false;
|
||||
while (!origin_finished) {
|
||||
const finished = try sel.await();
|
||||
|
||||
switch (finished) {
|
||||
.dir_ret => |d| {
|
||||
const ret = try d;
|
||||
if (ret.sub_files.load(.unordered) != 0) {
|
||||
sel.queue.putOne(io, .{ .dir_ret = ret }) catch |err| {
|
||||
if (!ret.origin) alloc.free(ret.path);
|
||||
alloc.destroy(ret.sub_files);
|
||||
return err;
|
||||
};
|
||||
continue;
|
||||
}
|
||||
defer {
|
||||
if (!ret.origin) {
|
||||
alloc.free(ret.path);
|
||||
} else {
|
||||
origin_finished = true;
|
||||
}
|
||||
}
|
||||
defer std.debug.print("finished extract of {s}\n", .{ret.path});
|
||||
alloc.destroy(ret.sub_files);
|
||||
|
||||
if (!options.ignore_permissions and (!options.ignore_xattr and ret.xattr_idx != null)) {
|
||||
const file = try Io.Dir.cwd().openFile(io, ret.path, .{});
|
||||
const file = try Io.Dir.cwd().openFile(io, path, .{});
|
||||
defer file.close(io);
|
||||
|
||||
if (!options.ignore_permissions) {
|
||||
try file.setTimestamps(io, .{
|
||||
.modify_timestamp = .init(.{ .nanoseconds = @as(i96, @intCast(ret.mod_time)) * std.time.ns_per_s }),
|
||||
});
|
||||
try file.setPermissions(io, @enumFromInt(ret.permissions));
|
||||
try file.setOwner(io, try id_table.get(io, ret.uid_idx), try id_table.get(io, ret.gid_idx));
|
||||
try file.setTimestamps(io, .{ .modify_timestamp = .init(Io.Timestamp.fromNanoseconds(@as(i96, @intCast(hdr.mod_time)) * std.time.ns_per_s)) });
|
||||
try file.setPermissions(io, @enumFromInt(hdr.permission));
|
||||
try file.setOwner(io, try id_table.get(io, hdr.uid_idx), try id_table.get(io, hdr.gid_idx));
|
||||
}
|
||||
if (!options.ignore_xattr and ret.xattr_idx != null) {
|
||||
const xattrs = xattr_table.get(alloc, io, ret.xattr_idx.?) catch |err| {
|
||||
std.debug.print("YO {}\n", .{err});
|
||||
return err;
|
||||
};
|
||||
|
||||
if (!options.ignore_permissions and xattr_idx != null) {
|
||||
var xattrs = try xattr_table.get(alloc, io, xattr_idx.?);
|
||||
defer xattrs.deinit(alloc);
|
||||
|
||||
for (xattrs.xattrs) |x| {
|
||||
const res = std.os.linux.fsetxattr(file.handle, x.key, x.value.ptr, x.value.len, 0);
|
||||
if (res != 0)
|
||||
return error.SetXattrFailed;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
.file_ret => |f| {
|
||||
const ret = try f;
|
||||
defer {
|
||||
if (!ret.origin) {
|
||||
alloc.free(ret.path);
|
||||
} else {
|
||||
origin_finished = true;
|
||||
}
|
||||
}
|
||||
defer std.debug.print("finished extract of {s}\n", .{ret.path});
|
||||
|
||||
if (!options.ignore_permissions and (!options.ignore_xattr and ret.xattr_idx != null)) {
|
||||
const file = try Io.Dir.cwd().openFile(io, ret.path, .{});
|
||||
defer file.close(io);
|
||||
|
||||
if (!options.ignore_permissions) {
|
||||
try file.setTimestamps(io, .{
|
||||
.modify_timestamp = .init(.{ .nanoseconds = @as(i96, @intCast(ret.mod_time)) * std.time.ns_per_s }),
|
||||
});
|
||||
try file.setPermissions(io, @enumFromInt(ret.permissions));
|
||||
try file.setOwner(io, try id_table.get(io, ret.uid_idx), try id_table.get(io, ret.gid_idx));
|
||||
}
|
||||
if (!options.ignore_xattr and ret.xattr_idx != null) {
|
||||
const xattrs = xattr_table.get(alloc, io, ret.xattr_idx.?) catch |err| {
|
||||
std.debug.print("YO!!! {s} {}\n", .{ ret.path, err });
|
||||
return err;
|
||||
};
|
||||
defer xattrs.deinit(alloc);
|
||||
|
||||
for (xattrs.xattrs) |x| {
|
||||
const res = std.os.linux.fsetxattr(file.handle, x.key, x.value.ptr, x.value.len, 0);
|
||||
if (res != 0)
|
||||
return error.SetXattrFailed;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
.void_ret => |v| try v,
|
||||
return Error.SetXattrError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Utility types
|
||||
|
||||
const ReturnUnion = union(enum) {
|
||||
file_ret: Error!FileReturn,
|
||||
dir_ret: Error!DirReturn,
|
||||
void_ret: Error!void,
|
||||
};
|
||||
|
||||
const Error = error{ Canceled, MknodError } || Directory.Error || Io.Dir.CreateFileAtomicError || Io.File.Atomic.LinkError ||
|
||||
const Error = error{ Canceled, MknodError, SetXattrError } || Directory.Error || Io.Dir.CreateFileAtomicError || Io.File.Atomic.LinkError ||
|
||||
DataExtractor.Error || Io.Dir.SymLinkError || Io.Dir.CreateDirPathError;
|
||||
|
||||
const FileReturn = struct {
|
||||
path: []const u8,
|
||||
origin: bool,
|
||||
const ReturnUnion = union(enum) {
|
||||
file: Error!FileReturn,
|
||||
dir: Error!DirReturn(true),
|
||||
void: Error!void,
|
||||
};
|
||||
|
||||
uid_idx: u32,
|
||||
gid_idx: u32,
|
||||
mod_time: u32,
|
||||
permissions: u16,
|
||||
fn FileReturn(comptime async: bool) type {
|
||||
return if (async)
|
||||
struct {
|
||||
hdr: Inode.Header,
|
||||
path: []const u8,
|
||||
parent: ?*Atomic(u32),
|
||||
|
||||
xattr_idx: ?u32 = null,
|
||||
};
|
||||
const DirReturn = struct {
|
||||
path: []const u8,
|
||||
sub_files: *Atomic(usize),
|
||||
origin: bool,
|
||||
|
||||
uid_idx: u32,
|
||||
gid_idx: u32,
|
||||
mod_time: u32,
|
||||
permissions: u16,
|
||||
fn finish(self: FileReturn(async), alloc: std.mem.Allocator, io: Io, id_table: *Lookup.Table(u16), xattr_table: *XattrTable, options: ExtractionOptions) Error!void {
|
||||
defer if (self.parent != null) {
|
||||
_ = self.parent.?.fetchSub(1, .acquire);
|
||||
};
|
||||
return setMetadata(alloc, io, id_table, xattr_table, options, self.hdr, self.xattr_idx, self.path);
|
||||
}
|
||||
}
|
||||
else
|
||||
struct {
|
||||
hdr: Inode.Header,
|
||||
path: []const u8,
|
||||
|
||||
xattr_idx: ?u32 = null,
|
||||
};
|
||||
|
||||
fn finish(self: FileReturn(async), alloc: std.mem.Allocator, io: Io, id_table: *Lookup.Table(u16), xattr_table: *XattrTable, options: ExtractionOptions) Error!void {
|
||||
return setMetadata(alloc, io, id_table, xattr_table, options, self.hdr, self.xattr_idx, self.path);
|
||||
}
|
||||
};
|
||||
}
|
||||
fn DirReturn(comptime async: bool) type {
|
||||
return if (async)
|
||||
struct {
|
||||
hdr: Inode.Header,
|
||||
path: []const u8,
|
||||
parent: ?*Atomic(u32),
|
||||
|
||||
xattr_idx: ?u32 = null,
|
||||
|
||||
fn finish(self: DirReturn(async), alloc: std.mem.Allocator, io: Io, id_table: *Lookup.Table(u16), xattr_table: *XattrTable, options: ExtractionOptions) Error!void {
|
||||
defer if (self.parent != null) {
|
||||
_ = self.parent.?.fetchSub(1, .acquire);
|
||||
};
|
||||
return setMetadata(alloc, io, id_table, xattr_table, options, self.hdr, self.xattr_idx, self.path);
|
||||
}
|
||||
}
|
||||
else
|
||||
struct {
|
||||
hdr: Inode.Header,
|
||||
path: []const u8,
|
||||
|
||||
xattr_idx: ?u32 = null,
|
||||
|
||||
fn finish(self: DirReturn(async), alloc: std.mem.Allocator, io: Io, id_table: *Lookup.Table(u16), xattr_table: *XattrTable, options: ExtractionOptions) Error!void {
|
||||
return setMetadata(alloc, io, id_table, xattr_table, options, self.hdr, self.xattr_idx, self.path);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+3
-2
@@ -4,6 +4,7 @@ const Io = std.Io;
|
||||
const DecompCache = @import("decomp_cache.zig");
|
||||
const InodeRef = @import("inode.zig").Ref;
|
||||
const MetadataReader = @import("meta_rdr.zig");
|
||||
|
||||
const XattrEntryTable = @import("lookup.zig").Table(XattrEntry);
|
||||
|
||||
const XattrTable = @This();
|
||||
@@ -21,8 +22,8 @@ pub fn init(alloc: std.mem.Allocator, cache: *DecompCache, xattr_start: u64) !Xa
|
||||
.table = .init(alloc, cache, xattr_start + 16, num),
|
||||
};
|
||||
}
|
||||
pub fn deinit(self: *XattrTable) void {
|
||||
self.table.deinit();
|
||||
pub fn deinit(self: *XattrTable, io: Io) void {
|
||||
self.table.deinit(io);
|
||||
}
|
||||
|
||||
pub fn get(self: *XattrTable, alloc: std.mem.Allocator, io: Io, idx: u32) !XattrKVs {
|
||||
|
||||
Reference in New Issue
Block a user