From 2e4364b8638aaf9455562546ace8748f76b7d0fa Mon Sep 17 00:00:00 2001 From: "Caleb J. Gardner" Date: Sat, 5 Sep 2026 22:37:04 -0500 Subject: [PATCH] Started work on xattr table reading --- src/table.zig | 105 +++++++++++++++++++++++++++++++++------ src/utils/decompress.zig | 22 ++++++-- 2 files changed, 110 insertions(+), 17 deletions(-) diff --git a/src/table.zig b/src/table.zig index f38b144..0822971 100644 --- a/src/table.zig +++ b/src/table.zig @@ -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, + }; +}; diff --git a/src/utils/decompress.zig b/src/utils/decompress.zig index c4e4b73..0cc2e5b 100644 --- a/src/utils/decompress.zig +++ b/src/utils/decompress.zig @@ -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 {}