Added stateless Xattr lookup
This commit is contained in:
@@ -20,6 +20,87 @@ pub fn stateless(comptime T: anytype, fil: OffsetFile, decomp: *const Decompress
|
||||
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 {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
Reference in New Issue
Block a user