Added stateless Xattr lookup

This commit is contained in:
Caleb Gardner
2026-04-24 04:16:22 -05:00
parent b111859c4d
commit 0d5b727919
+81
View File
@@ -20,6 +20,87 @@ pub fn stateless(comptime T: anytype, fil: OffsetFile, decomp: *const Decompress
return out; return out;
} }
const InodeRef = @import("inode.zig").Ref;
const XattrLookup = packed struct {
// This isn't actuall an inode ref, but is stored that exact same way.
ref: InodeRef,
kv_count: u32,
size: u32,
};
const XattrKey = packed struct {
type: enum(u2) {
user,
trusted,
security,
},
out_of_line: bool,
_: u13,
name_size: u16,
};
pub const XattrValues = std.AutoHashMap([:0]u8, []u8);
pub fn statelessXattr(alloc: std.mem.Allocator, fil: OffsetFile, decomp: *const Decompressor, table_start: u64, idx: u32) !XattrValues {
const xattr_start = try fil.valueAt(u64, table_start);
const block = idx / 512;
const block_idx = idx % 512;
const block_start = try fil.valueAt(u64, table_start + 8 + (block * 8));
var rdr = try fil.readerAt(block_start, &[0]u8{});
var meta_rdr: MetadataReader = .init(&rdr.interface, decomp);
try meta_rdr.interface.discardAll(16 * block_idx);
var lookup: XattrLookup = undefined;
try meta_rdr.interface.readSliceEndian(XattrLookup, @ptrCast(&lookup), .little);
rdr = try fil.readerAt(xattr_start + lookup.ref.block_start, &[0]u8{});
meta_rdr = .init(&rdr.interface, decomp);
try meta_rdr.interface.discardAll(lookup.ref.block_offset);
var out: XattrValues = try .init(alloc);
for (0..lookup.kv_count) |_| {
var key: XattrKey = undefined;
try meta_rdr.interface.readSliceEndian(XattrKey, @ptrCast(&key), .little);
const prefix_size = switch (key.type) {
.user => 4,
.trusted => 7,
.security => 8,
};
const name: [:0]u8 = try alloc.alloc(u8, prefix_size + key.name_size + 1);
name[prefix_size + key.name_size] = 0;
try meta_rdr.interface.readSliceEndian(u8, name[prefix_size .. prefix_size + key.name_size], .little);
switch (key.type) {
.user => @memcpy(name[0..4], "user"),
.trusted => @memcpy(name[0..7], "trusted"),
.security => @memcpy(name[0..8], "security"),
}
if (key.out_of_line) {
try meta_rdr.interface.discardAll(4);
var value_offset: InodeRef = undefined;
try meta_rdr.interface.readSliceEndian(InodeRef, @ptrCast(&value_offset), .little);
var value_rdr = try fil.readerAt(xattr_start + value_offset.block_start, &[0]u8{});
var value_meta: MetadataReader = .init(&value_rdr.interface, decomp);
try value_meta.interface.discardAll(value_offset.block_offset);
var val_size: u32 = undefined;
try value_meta.interface.readSliceEndian(u32, @ptrCast(&val_size), .little);
const value = try alloc.alloc(u8, val_size);
try value_meta.interface.readSliceEndian(u8, value, .little);
try out.put(name, value);
} else {
var val_size: u32 = undefined;
try meta_rdr.interface.readSliceEndian(u32, @ptrCast(&val_size), .little);
const value = try alloc.alloc(u8, val_size);
try meta_rdr.interface.readSliceEndian(u8, value, .little);
try out.put(name, value);
}
}
return out;
}
pub fn CachedTable(comptime T: anytype) type { pub fn CachedTable(comptime T: anytype) type {
return struct { return struct {
const Self = @This(); const Self = @This();