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);
|
var frag_table: Lookup.Table(Lookup.FragmentEntry) = .init(alloc, cache, super.frag_start, super.frag_count);
|
||||||
defer frag_table.deinit();
|
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);
|
try extractReal(alloc, io, cache, super, &sel, &frag_table, path, inode, null, false);
|
||||||
|
|
||||||
ret_loop.await(io) catch |err| {
|
try ret_loop.await(io);
|
||||||
// TODO: Drain sel
|
|
||||||
return err;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extractReal(
|
fn extractReal(
|
||||||
@@ -59,7 +56,14 @@ fn extractReal(
|
|||||||
parent: ?*Atomic(usize),
|
parent: ?*Atomic(usize),
|
||||||
origin: bool,
|
origin: bool,
|
||||||
) Error!void {
|
) 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) {
|
switch (inode.data) {
|
||||||
.dir, .ext_dir => sel.async(
|
.dir, .ext_dir => sel.async(
|
||||||
@@ -72,7 +76,16 @@ fn extractReal(
|
|||||||
extractFile,
|
extractFile,
|
||||||
.{ alloc, io, cache, super.block_size, frag_table, path, inode, parent, origin },
|
.{ 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;
|
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
|
// 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) {
|
while (true) {
|
||||||
const finished = try sel.await();
|
const finished = try sel.await();
|
||||||
|
|
||||||
@@ -220,7 +319,7 @@ fn returnLoop(alloc: std.mem.Allocator, sel: *Io.Select(ReturnUnion), options: E
|
|||||||
.dir_ret => |d| {
|
.dir_ret => |d| {
|
||||||
const ret = try d;
|
const ret = try d;
|
||||||
if (ret.sub_files.load(.unordered) != 0) {
|
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);
|
if (!ret.origin) alloc.free(ret.path);
|
||||||
return err;
|
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);
|
if (!ret.origin) alloc.free(ret.path);
|
||||||
alloc.destroy(ret.sub_files);
|
alloc.destroy(ret.sub_files);
|
||||||
|
|
||||||
if (!options.ignore_permissions and !options.ignore_xattr) {
|
if (!options.ignore_permissions and (!options.ignore_xattr and ret.xattr_idx != null)) {
|
||||||
// TODO: set permissions & xattr.
|
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| {
|
.file_ret => |f| {
|
||||||
@@ -256,7 +365,8 @@ const ReturnUnion = union(enum) {
|
|||||||
void_ret: Error!void,
|
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 {
|
const FileReturn = struct {
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ const std = @import("std");
|
|||||||
const Io = std.Io;
|
const Io = std.Io;
|
||||||
|
|
||||||
const DataBlock = @import("inode.zig").DataBlock;
|
const DataBlock = @import("inode.zig").DataBlock;
|
||||||
const InodeRef = @import("inode.zig").Ref;
|
|
||||||
const DecompCache = @import("decomp_cache.zig");
|
const DecompCache = @import("decomp_cache.zig");
|
||||||
const MetadataReader = @import("meta_rdr.zig");
|
const MetadataReader = @import("meta_rdr.zig");
|
||||||
|
|
||||||
@@ -106,9 +105,3 @@ pub const FragmentEntry = extern struct {
|
|||||||
size: DataBlock,
|
size: DataBlock,
|
||||||
_: u32,
|
_: 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