Started work on xattr table reading

This commit is contained in:
Caleb J. Gardner
2026-09-05 22:37:04 -05:00
parent 2e33e19cdd
commit 2e4364b863
2 changed files with 110 additions and 17 deletions
+91 -14
View File
@@ -5,15 +5,14 @@ const util = @import("utils/util.zig");
const MetadataReader = @import("utils/meta.zig");
const Decomp = @import("decomp.zig");
const Reference = @import("inode.zig").Reference;
pub fn Table(comptime T: type) type {
pub fn Lookup(comptime T: type) type {
return struct {
const Self = @This();
const ITEMS_PER_BLOCK = 8192 / @sizeOf(T);
alloc: std.mem.Allocator,
data: []u8,
decomp: Decomp.Fn,
@@ -33,18 +32,18 @@ pub fn Table(comptime T: type) type {
.start = start,
.count = count,
.block_count = std.math.divCeil(u32, count, ITEMS_PER_BLOCK),
.block_count = try std.math.divCeil(u32, count, ITEMS_PER_BLOCK),
};
}
pub fn deinit(self: *Self) void {
pub fn deinit(self: *Self, alloc: std.mem.Allocator) void {
var iter = self.table.valueIterator();
while (iter.next()) |block|
self.alloc.free(block);
alloc.free(block);
self.table.deinit(self.alloc);
self.table.deinit(alloc);
}
fn getBlock(self: *Self, io: Io, idx: u32) ![]T {
fn getBlock(self: *Self, alloc: std.mem.Allocator, io: Io, idx: u32) ![]T {
const init_get = self.table.get(idx);
if (init_get != null) return init_get.?;
@@ -55,26 +54,104 @@ pub fn Table(comptime T: type) type {
const len = if (idx == self.block_count - 1) self.count % ITEMS_PER_BLOCK else ITEMS_PER_BLOCK;
const new_block = try self.alloc.alloc(T, len);
errdefer self.alloc.free(new_block);
const new_block = try alloc.alloc(T, len);
errdefer alloc.free(new_block);
var meta: MetadataReader = .init(self.alloc, self.data[start..], self.decomp);
var meta: MetadataReader = .init(alloc, self.data[start..], self.decomp);
try meta.interface.readSliceEndian(T, new_block, .little);
try self.table.put(self.alloc, idx, new_block);
try self.table.put(alloc, idx, new_block);
return new_block;
}
pub fn get(self: *Self, io: Io, idx: u32) !T {
pub fn get(self: *Self, alloc: std.mem.Allocator, io: Io, idx: u32) !T {
if (idx >= self.count) return error.InvalidIndex;
const block_idx = idx / ITEMS_PER_BLOCK;
const block = self.getBlock(io, block_idx);
const block = self.getBlock(io, alloc, block_idx);
return block[idx % ITEMS_PER_BLOCK];
}
};
}
pub const Xattr = struct {
kv_start: u64,
lookup: Lookup(XattrLookup),
pub fn init(alloc: std.mem.Allocator, data: []u8, decomp: Decomp.Fn, start: u64) !Xattr {
const kv_start = util.readValue(u64, data[start..][0..8]);
const count = util.readValue(u32, data[start..][8..12]);
return .{
.kv_start = kv_start,
.lookup = try .init(alloc, data, decomp, start + 16, count),
};
}
pub fn deinit(self: *Xattr, alloc: std.mem.Allocator) void {
self.lookup.deinit(alloc);
}
pub fn get(self: *Xattr, alloc: std.mem.Allocator, io: Io, idx: u32) !KV {
const lookup = try self.lookup.get(alloc, io, idx);
var meta: MetadataReader = .init(alloc, self.lookup.data[self.kv_start + lookup.ref.start ..], self.lookup.decomp);
try meta.interface.discardAll(lookup.ref.offset);
const kvs = try alloc.alloc(KV, lookup.count);
errdefer alloc.free(kvs);
for (kvs) |*kv| {
const entry = try util.readValueRdr(KeyEntry, &meta.interface);
const prefix = switch (entry.type.type) {
.user => "user.",
.trusted => "trusted.",
.security => "security.",
};
kv.name = try alloc.allocSentinel(u8, entry.name_size + prefix.len, 0);
errdefer alloc.free(kv.name);
try meta.interface.readSliceEndian(u8, kv.name[prefix.len..], .little);
@memcpy(kv.name[0..prefix.len], prefix);
if (entry.type.out_of_line) {}
}
}
//types
pub const KV = struct {
name: [:0]u8,
value: []u8,
pub fn deinit(self: KV, alloc: std.mem.Allocator) void {
alloc.free(self.name);
alloc.free(self.value);
}
};
const XattrLookup = extern struct {
ref: Reference,
count: u32,
size: u32,
};
const KeyEntry = extern struct {
type: packed struct(u16) {
type: enum(u8) {
user,
trusted,
security,
},
out_of_line: bool,
_: u7,
},
name_size: u16,
};
};
+19 -3
View File
@@ -7,12 +7,17 @@ const Decomp = @import("../decomp.zig");
const Directory = @import("../dir.zig");
const MetadataReader = @import("meta.zig");
const DataReader = @import("data_reader.zig");
const Table = @import("../table.zig");
const Super = @import("../archive.zig").Super;
pub fn single(alloc: std.mem.Allocator, io: Io, data: []const u8, decomp: Decomp.Fn, super: Super, inode: Inode, filepath: []const u8, options: Options) !void {
const path = std.mem.trim(u8, filepath, "/");
var pool: std.ArrayList(InodeAndPath) = .initBuffer(&.{.{ .inode = inode, .path = path }});
var pool: std.ArrayList(InodeAndPath) = .initBuffer(&.{.{
.inode = inode,
.path = path,
.root = true,
}});
defer {
while (pool.pop()) |in|
in.deinit(in);
@@ -55,7 +60,11 @@ pub fn single(alloc: std.mem.Allocator, io: Io, data: []const u8, decomp: Decomp
return err;
};
try pool.append(alloc, .{ .inode = new_inode, .path = new_path });
try pool.append(alloc, .{
.inode = new_inode,
.path = new_path,
.root = false,
});
}
try dirs.append(alloc, in);
@@ -136,13 +145,20 @@ pub fn single(alloc: std.mem.Allocator, io: Io, data: []const u8, decomp: Decomp
// TODO: apply permissions & xattrs
}
}
pub fn multi() !void {}
// Utils
const InodeAndPath = struct {
inode: Inode,
path: []const u8,
root: bool,
fn deinit(self: InodeAndPath, alloc: std.mem.Allocator) void {
if (self.root) return;
self.inode.deinit(alloc);
alloc.free(self.path);
}
};
pub fn multi() !void {}
inline fn applyPermissions(alloc: std.mem.Allocator, io: Io, id_table: Table.Lookup(u16), xattr_table: Table.Xattr, inode: Inode, path: []const u8, options: Options) !void {}