Xattr table lookup
Finished Symlink & mknod inodes
This commit is contained in:
+122
-12
@@ -37,14 +37,11 @@ pub fn extract(alloc: std.mem.Allocator, io: Io, inode: Inode, cache: *DecompCac
|
||||
var frag_table: Lookup.Table(Lookup.FragmentEntry) = .init(alloc, cache, super.frag_start, super.frag_count);
|
||||
defer frag_table.deinit();
|
||||
|
||||
var ret_loop = io.async(returnLoop, .{ alloc, &sel, options });
|
||||
var ret_loop = io.async(returnLoop, .{ alloc, io, &sel, options });
|
||||
|
||||
try extractReal(alloc, io, cache, super, &sel, &frag_table, path, inode, null, false);
|
||||
|
||||
ret_loop.await(io) catch |err| {
|
||||
// TODO: Drain sel
|
||||
return err;
|
||||
};
|
||||
try ret_loop.await(io);
|
||||
}
|
||||
|
||||
fn extractReal(
|
||||
@@ -59,7 +56,14 @@ fn extractReal(
|
||||
parent: ?*Atomic(usize),
|
||||
origin: bool,
|
||||
) Error!void {
|
||||
try io.checkCancel();
|
||||
io.checkCancel() catch |err| {
|
||||
if (parent != null) _ = parent.?.fetchSub(1, .acquire);
|
||||
if (!origin) {
|
||||
alloc.free(path);
|
||||
inode.deinit(alloc);
|
||||
}
|
||||
return err;
|
||||
};
|
||||
|
||||
switch (inode.data) {
|
||||
.dir, .ext_dir => sel.async(
|
||||
@@ -72,7 +76,16 @@ fn extractReal(
|
||||
extractFile,
|
||||
.{ alloc, io, cache, super.block_size, frag_table, path, inode, parent, origin },
|
||||
),
|
||||
else => return error.Canceled,
|
||||
.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 },
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,10 +222,96 @@ fn extractFile(
|
||||
|
||||
return ret;
|
||||
}
|
||||
fn extractSymlink(alloc: std.mem.Allocator, io: Io, path: []const u8, inode: Inode, parent: ?*Atomic(usize), origin: bool) Error!void {
|
||||
defer {
|
||||
if (parent != null)
|
||||
_ = parent.?.fetchSub(1, .acquire);
|
||||
if (!origin) {
|
||||
inode.deinit(alloc);
|
||||
alloc.free(path);
|
||||
}
|
||||
}
|
||||
|
||||
const target = switch (inode.data) {
|
||||
.symlink => |s| s.target,
|
||||
.ext_symlink => |s| s.target,
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
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 {
|
||||
defer {
|
||||
if (parent != null)
|
||||
_ = parent.?.fetchSub(1, .acquire);
|
||||
if (!origin) inode.deinit(alloc);
|
||||
}
|
||||
errdefer if (!origin) alloc.free(path);
|
||||
|
||||
var ret: FileReturn = .{
|
||||
.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;
|
||||
|
||||
var dev: u32 = 0;
|
||||
var mode: u32 = undefined;
|
||||
|
||||
switch (inode.data) {
|
||||
.char_dev => |d| {
|
||||
dev = d.device;
|
||||
mode = DT.CHR;
|
||||
},
|
||||
.ext_char_dev => |d| {
|
||||
dev = d.device;
|
||||
mode = DT.CHR;
|
||||
if (d.xattr_idx != 0xFFFFFFFF)
|
||||
ret.xattr_idx = d.xattr_idx;
|
||||
},
|
||||
.block_dev => |d| {
|
||||
dev = d.device;
|
||||
mode = DT.BLK;
|
||||
},
|
||||
.ext_block_dev => |d| {
|
||||
dev = d.device;
|
||||
mode = DT.BLK;
|
||||
if (d.xattr_idx != 0xFFFFFFFF)
|
||||
ret.xattr_idx = d.xattr_idx;
|
||||
},
|
||||
.fifo => mode = DT.FIFO,
|
||||
.ext_fifo => |f| {
|
||||
mode = DT.FIFO;
|
||||
if (f.xattr_idx != 0xFFFFFFFF)
|
||||
ret.xattr_idx = f.xattr_idx;
|
||||
},
|
||||
.socket => mode = DT.SOCK,
|
||||
.ext_socket => |s| {
|
||||
mode = DT.SOCK;
|
||||
if (s.xattr_idx != 0xFFFFFFFF)
|
||||
ret.xattr_idx = s.xattr_idx;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
const sentinel_path = try std.mem.concatWithSentinel(alloc, u8, &.{path}, 0);
|
||||
defer alloc.free(sentinel_path);
|
||||
|
||||
const res = std.os.linux.mknod(sentinel_path, mode, dev);
|
||||
if (res != 0)
|
||||
return Error.MknodError;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Loop
|
||||
|
||||
fn returnLoop(alloc: std.mem.Allocator, sel: *Io.Select(ReturnUnion), options: ExtractionOptions) !void {
|
||||
fn returnLoop(alloc: std.mem.Allocator, io: Io, id_table: Lookup.Table(u16), xattr_table: Lookup.Table(Lookup.XattrEntry), sel: *Io.Select(ReturnUnion), options: ExtractionOptions) !void {
|
||||
while (true) {
|
||||
const finished = try sel.await();
|
||||
|
||||
@@ -220,7 +319,7 @@ fn returnLoop(alloc: std.mem.Allocator, sel: *Io.Select(ReturnUnion), options: E
|
||||
.dir_ret => |d| {
|
||||
const ret = try d;
|
||||
if (ret.sub_files.load(.unordered) != 0) {
|
||||
sel.queue.putOne(sel.io, .{ .dir_ret = ret }) catch |err| {
|
||||
sel.queue.putOne(io, .{ .dir_ret = ret }) catch |err| {
|
||||
if (!ret.origin) alloc.free(ret.path);
|
||||
return err;
|
||||
};
|
||||
@@ -229,8 +328,18 @@ fn returnLoop(alloc: std.mem.Allocator, sel: *Io.Select(ReturnUnion), options: E
|
||||
if (!ret.origin) alloc.free(ret.path);
|
||||
alloc.destroy(ret.sub_files);
|
||||
|
||||
if (!options.ignore_permissions and !options.ignore_xattr) {
|
||||
// TODO: set permissions & xattr.
|
||||
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) {}
|
||||
}
|
||||
},
|
||||
.file_ret => |f| {
|
||||
@@ -256,7 +365,8 @@ const ReturnUnion = union(enum) {
|
||||
void_ret: Error!void,
|
||||
};
|
||||
|
||||
const Error = error{Canceled} || Directory.Error || Io.Dir.CreateFileAtomicError || Io.File.Atomic.LinkError || DataExtractor.Error;
|
||||
const Error = error{ Canceled, MknodError } || Directory.Error || Io.Dir.CreateFileAtomicError || Io.File.Atomic.LinkError ||
|
||||
DataExtractor.Error || Io.Dir.SymLinkError;
|
||||
|
||||
const FileReturn = struct {
|
||||
path: []const u8,
|
||||
|
||||
@@ -2,7 +2,6 @@ const std = @import("std");
|
||||
const Io = std.Io;
|
||||
|
||||
const DataBlock = @import("inode.zig").DataBlock;
|
||||
const InodeRef = @import("inode.zig").Ref;
|
||||
const DecompCache = @import("decomp_cache.zig");
|
||||
const MetadataReader = @import("meta_rdr.zig");
|
||||
|
||||
@@ -106,9 +105,3 @@ pub const FragmentEntry = extern struct {
|
||||
size: DataBlock,
|
||||
_: u32,
|
||||
};
|
||||
|
||||
pub const XattrEntry = extern struct {
|
||||
ref: InodeRef,
|
||||
count: u32,
|
||||
size: u32,
|
||||
};
|
||||
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
const std = @import("std");
|
||||
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();
|
||||
|
||||
table_start: u64,
|
||||
|
||||
table: XattrEntryTable,
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator, cache: *DecompCache, xattr_start: u64) !XattrTable {
|
||||
const table_start = std.mem.readInt(u64, cache.map.memory[xattr_start..][0..8], .little);
|
||||
const num = std.mem.readInt(u32, cache.map.memory[xattr_start + 8 ..][0..4], .little);
|
||||
return .{
|
||||
.table_start = table_start,
|
||||
|
||||
.table = .init(alloc, cache, xattr_start + 16, num),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get(self: XattrTable, alloc: std.mem.Allocator, io: Io, idx: u32) !XattrKVs {
|
||||
const entry = try self.table.get(io, idx);
|
||||
|
||||
var meta: MetadataReader = .init(io, self.table.cache, self.table_start + entry.ref.block_start);
|
||||
defer meta.deinit(io);
|
||||
try meta.interface.discardAll(entry.ref.block_offset);
|
||||
|
||||
const xattrs = try alloc.alloc(Xattr, entry.count);
|
||||
errdefer alloc.free(xattrs);
|
||||
|
||||
for (xattrs) |*x| {
|
||||
var key: KeyEntry = undefined;
|
||||
try meta.interface.readSliceEndian(KeyEntry, @ptrCast(&key), .little);
|
||||
|
||||
key.name_size += switch (key.type.prefix) {
|
||||
.user => 5,
|
||||
.trusted => 8,
|
||||
.security => 9,
|
||||
};
|
||||
x.key = try alloc.allocSentinel(u8, key.name_size, 0);
|
||||
errdefer alloc.free(x.key);
|
||||
|
||||
switch (key.type.prefix) {
|
||||
.user => @memcpy(x.key[0..5], "user."),
|
||||
.trusted => @memcpy(x.key[0..8], "trusted."),
|
||||
.security => @memcpy(x.key[0..9], "security."),
|
||||
}
|
||||
|
||||
if (!key.type.out_of_line) {
|
||||
var size: u32 = undefined;
|
||||
try meta.interface.readSliceEndian(u32, @ptrCast(&size), .little);
|
||||
|
||||
x.value = try alloc.alloc(u8, size);
|
||||
errdefer alloc.free(x.value);
|
||||
|
||||
try meta.interface.readSliceEndian(u8, x.value, .little);
|
||||
continue;
|
||||
}
|
||||
try meta.interface.discardAll(4);
|
||||
|
||||
var val_ref: InodeRef = undefined;
|
||||
try meta.interface.readSliceEndian(InodeRef, @ptrCast(&val_ref), .little);
|
||||
|
||||
var val_meta: MetadataReader = .init(io, self.table.cache, self.table_start + val_ref.block_start);
|
||||
defer val_meta.deinit(io);
|
||||
try val_meta.interface.discardAll(val_ref.block_offset);
|
||||
|
||||
var size: u32 = undefined;
|
||||
try val_meta.interface.readSliceEndian(u32, @ptrCast(&size), .little);
|
||||
|
||||
x.value = try alloc.alloc(u8, size);
|
||||
errdefer alloc.free(x.value);
|
||||
|
||||
try val_meta.interface.readSliceEndian(u8, x.value, .little);
|
||||
}
|
||||
|
||||
return .{ .xattrs = xattrs };
|
||||
}
|
||||
|
||||
// Types
|
||||
|
||||
pub const XattrKVs = struct {
|
||||
xattrs: []Xattr,
|
||||
|
||||
pub fn deinit(self: XattrKVs, alloc: std.mem.Allocator) void {
|
||||
for (self.xattrs) |kv|
|
||||
kv.deinit(alloc);
|
||||
alloc.free(self.xattrs);
|
||||
}
|
||||
};
|
||||
pub const Xattr = struct {
|
||||
key: [:0]u8,
|
||||
value: []u8,
|
||||
|
||||
pub fn deinit(self: Xattr, alloc: std.mem.Allocator) void {
|
||||
alloc.free(self.key);
|
||||
alloc.free(self.value);
|
||||
}
|
||||
};
|
||||
const KeyEntry = extern struct {
|
||||
type: packed struct(u16) {
|
||||
prefix: enum(u8) {
|
||||
user,
|
||||
trusted,
|
||||
security,
|
||||
},
|
||||
out_of_line: bool,
|
||||
_: u7,
|
||||
},
|
||||
name_size: u16,
|
||||
};
|
||||
|
||||
const XattrEntry = extern struct {
|
||||
ref: InodeRef,
|
||||
count: u32,
|
||||
size: u32,
|
||||
};
|
||||
Reference in New Issue
Block a user