Finished (?) Xattr Cached table
This commit is contained in:
@@ -2,8 +2,8 @@ const std = @import("std");
|
|||||||
const Io = std.Io;
|
const Io = std.Io;
|
||||||
|
|
||||||
const Decompressor = @import("util/decompressor.zig");
|
const Decompressor = @import("util/decompressor.zig");
|
||||||
const OffsetFile = @import("util/offset_file.zig");
|
|
||||||
const MetadataReader = @import("util/metadata.zig");
|
const MetadataReader = @import("util/metadata.zig");
|
||||||
|
const OffsetFile = @import("util/offset_file.zig");
|
||||||
|
|
||||||
pub fn lookupValue(comptime T: anytype, alloc: std.mem.Allocator, io: Io, decomp: *Decompressor, file: OffsetFile, table_start: u64, idx: u16) !T {
|
pub fn lookupValue(comptime T: anytype, alloc: std.mem.Allocator, io: Io, decomp: *Decompressor, file: OffsetFile, table_start: u64, idx: u16) !T {
|
||||||
const T_PER_BLOCK: u16 = 8192 / @sizeOf(T);
|
const T_PER_BLOCK: u16 = 8192 / @sizeOf(T);
|
||||||
@@ -49,6 +49,10 @@ pub fn CachedTable(comptime T: anytype) type {
|
|||||||
.table = .init(alloc),
|
.table = .init(alloc),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
pub fn deinit(self: *Table, io: Io) void {
|
||||||
|
self.mut.lockUncancelable(io);
|
||||||
|
self.table.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get(self: *Table, io: Io, idx: u32) !T {
|
pub fn get(self: *Table, io: Io, idx: u32) !T {
|
||||||
const block = idx / T_PER_BLOCK;
|
const block = idx / T_PER_BLOCK;
|
||||||
|
|||||||
+16
-12
@@ -17,26 +17,28 @@ alloc: std.mem.Allocator,
|
|||||||
rdr: *Reader,
|
rdr: *Reader,
|
||||||
decomp: *const Decompressor,
|
decomp: *const Decompressor,
|
||||||
|
|
||||||
|
cur_block_start: u32 = 0,
|
||||||
|
next_start_start: u32 = 0,
|
||||||
buf: [8192]u8 = undefined,
|
buf: [8192]u8 = undefined,
|
||||||
|
|
||||||
interface: Reader,
|
|
||||||
err: ?anyerror = null,
|
err: ?anyerror = null,
|
||||||
|
interface: Reader = .{
|
||||||
|
.buffer = &[0]u8{},
|
||||||
|
.end = 0,
|
||||||
|
.seek = 0,
|
||||||
|
.vtable = &.{
|
||||||
|
.stream = stream,
|
||||||
|
.discard = discard,
|
||||||
|
.readVec = readVec,
|
||||||
|
// TODO: Potentially add rebase so that we can guarentee that self.block_start & interface.seek is correct.
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
pub fn init(alloc: std.mem.Allocator, rdr: *Reader, decomp: *const Decompressor) This {
|
pub fn init(alloc: std.mem.Allocator, rdr: *Reader, decomp: *const Decompressor) This {]
|
||||||
return .{
|
return .{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
.rdr = rdr,
|
.rdr = rdr,
|
||||||
.decomp = decomp,
|
.decomp = decomp,
|
||||||
.interface = .{
|
|
||||||
.buffer = &[0]u8{},
|
|
||||||
.end = 0,
|
|
||||||
.seek = 0,
|
|
||||||
.vtable = &.{
|
|
||||||
.stream = stream,
|
|
||||||
.discard = discard,
|
|
||||||
.readVec = readVec,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,6 +46,8 @@ fn advance(self: *This) !void {
|
|||||||
self.interface.seek = 0;
|
self.interface.seek = 0;
|
||||||
var hdr: BlockHeader = undefined;
|
var hdr: BlockHeader = undefined;
|
||||||
try self.rdr.readSliceEndian(BlockHeader, @ptrCast(&hdr), .little);
|
try self.rdr.readSliceEndian(BlockHeader, @ptrCast(&hdr), .little);
|
||||||
|
self.cur_block_start = self.next_start_start;
|
||||||
|
self.next_start_start += hdr.size;
|
||||||
if (hdr.uncompressed) {
|
if (hdr.uncompressed) {
|
||||||
try self.rdr.readSliceEndian(u8, self.buf[0..hdr.size], .little);
|
try self.rdr.readSliceEndian(u8, self.buf[0..hdr.size], .little);
|
||||||
self.interface.end = hdr.size;
|
self.interface.end = hdr.size;
|
||||||
|
|||||||
+267
-3
@@ -1,18 +1,282 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const Io = std.Io;
|
||||||
|
|
||||||
|
const InodeRef = @import("inode.zig").Ref;
|
||||||
const LookupTable = @import("lookup_table.zig");
|
const LookupTable = @import("lookup_table.zig");
|
||||||
const Decompressor = @import("util/decompressor.zig");
|
const Decompressor = @import("util/decompressor.zig");
|
||||||
|
const MetadataReader = @import("util/metadata.zig");
|
||||||
const OffsetFile = @import("util/offset_file.zig");
|
const OffsetFile = @import("util/offset_file.zig");
|
||||||
|
|
||||||
const XattrTable = @This();
|
const XattrCachedTable = @This();
|
||||||
|
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
|
||||||
|
fil: OffsetFile,
|
||||||
|
decomp: *const Decompressor,
|
||||||
|
|
||||||
|
kv_start: u64,
|
||||||
|
|
||||||
|
table: LookupTable.CachedTable(TableValue),
|
||||||
|
value_cache: std.AutoHashMap(InodeRef, []const u8),
|
||||||
|
value_mut: Io.Mutex,
|
||||||
|
|
||||||
|
pub fn init(alloc: std.mem.Allocator, io: Io, fil: OffsetFile, decomp: *const Decompressor, xattr_start: u64) !XattrCachedTable {
|
||||||
|
var rdr = try fil.readerAt(io, xattr_start, &[0]u8{});
|
||||||
|
|
||||||
|
var start: u64 = undefined;
|
||||||
|
try rdr.interface.readSliceEndian(u64, @ptrCast(&start), .little);
|
||||||
|
var num: u32 = undefined;
|
||||||
|
try rdr.interface.readSliceEndian(u32, @ptrCast(&num), .little);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.alloc = alloc,
|
||||||
|
|
||||||
|
.fil = fil,
|
||||||
|
.decomp = decomp,
|
||||||
|
|
||||||
|
.kv_start = start,
|
||||||
|
|
||||||
|
.table = .init(alloc, fil, xattr_start + 16, num),
|
||||||
|
.value_cache = .init(alloc),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub fn deinit(self: *XattrCachedTable) void {
|
||||||
|
self.table.deinit();
|
||||||
|
self.value_cache.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: *XattrCachedTable, alloc: std.mem.Allocator, io: Io, idx: u32) ![]XattrSemiOwned {
|
||||||
|
const lookup = try self.table.get(io, idx);
|
||||||
|
|
||||||
|
var rdr = try self.fil.readerAt(io, self.kv_start + lookup.ref.block_start, &[0]u8{});
|
||||||
|
var meta: MetadataReader = .init(alloc, &rdr.interface, self.decomp);
|
||||||
|
try meta.interface.discardAll(lookup.ref.block_offset);
|
||||||
|
|
||||||
|
const out = try alloc.alloc(XattrSemiOwned, lookup.count);
|
||||||
|
errdefer alloc.free(out);
|
||||||
|
|
||||||
|
for (0..lookup.count) |i| {
|
||||||
|
const key_entry: KeyEntry = undefined;
|
||||||
|
try meta.interface.readSliceEndian(KeyEntry, @ptrCast(&key_entry), .little);
|
||||||
|
|
||||||
|
const key = switch (key_entry.type.namespace) {
|
||||||
|
.user => blk: {
|
||||||
|
const tmp = try alloc.alloc(u8, key_entry.name_size + 1 + 5);
|
||||||
|
errdefer alloc.free(tmp);
|
||||||
|
try meta.interface.readSliceEndian(u8, tmp[5 .. tmp.len - 1], .little);
|
||||||
|
@memset(tmp[0..5], "user.");
|
||||||
|
break :blk tmp;
|
||||||
|
},
|
||||||
|
.trusted => blk: {
|
||||||
|
const tmp = try alloc.alloc(u8, key_entry.name_size + 1 + 8);
|
||||||
|
errdefer alloc.free(tmp);
|
||||||
|
try meta.interface.readSliceEndian(u8, tmp[8 .. tmp.len - 1], .little);
|
||||||
|
@memset(tmp[0..8], "trusted.");
|
||||||
|
break :blk tmp;
|
||||||
|
},
|
||||||
|
.security => blk: {
|
||||||
|
const tmp = try alloc.alloc(u8, key_entry.name_size + 1 + 9);
|
||||||
|
errdefer alloc.free(tmp);
|
||||||
|
try meta.interface.readSliceEndian(u8, tmp[9 .. tmp.len - 1], .little);
|
||||||
|
@memset(tmp[0..9], "security.");
|
||||||
|
break :blk tmp;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
key[key.len - 1] = 0;
|
||||||
|
errdefer alloc.free(key);
|
||||||
|
|
||||||
|
if (key_entry.type.out_of_line) {
|
||||||
|
const value: ValueOutOfLineEntry = undefined;
|
||||||
|
try meta.interface.readSliceEndian(ValueOutOfLineEntry, @ptrCast(&value), .little);
|
||||||
|
|
||||||
|
out[i] = .{
|
||||||
|
.key = key,
|
||||||
|
.value = try self.valueAt(io, value.ref),
|
||||||
|
};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const val_ref: InodeRef = .{ .block_start = meta.cur_block_start, .block_offset = meta.interface.seek };
|
||||||
|
|
||||||
|
try self.value_mut.lock(io);
|
||||||
|
defer self.value_mut.unlock(io);
|
||||||
|
if (self.value_cache.contains(val_ref)) {
|
||||||
|
out[i] = .{
|
||||||
|
.key = key,
|
||||||
|
.value = try self.valueAt(io, val_ref),
|
||||||
|
};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var val_size: u32 = undefined;
|
||||||
|
try meta.interface.readSliceEndian(val_size, @ptrCast(&val_size), .little);
|
||||||
|
|
||||||
|
const val = try self.alloc.alloc(u8, val_size);
|
||||||
|
try meta.interface.readSliceEndian(u8, val, .little);
|
||||||
|
|
||||||
|
try self.value_cache.put(val_ref, val);
|
||||||
|
out[i] = .{
|
||||||
|
.key = key,
|
||||||
|
.value = val,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn valueAt(self: *XattrCachedTable, io: Io, ref: InodeRef) ![]const u8 {
|
||||||
|
try self.value_mut.lock(io);
|
||||||
|
defer self.value_mut.unlock(io);
|
||||||
|
|
||||||
|
if (self.value_cache.contains(ref)) return self.value_cache.get(ref).?;
|
||||||
|
|
||||||
|
var rdr = try self.fil.readerAt(io, self.kv_start + ref.block_start, &[0]u8{});
|
||||||
|
var meta: MetadataReader = .init(self.alloc, &rdr.interface, self.decomp);
|
||||||
|
try meta.interface.discardAll(ref.block_offset);
|
||||||
|
|
||||||
|
var val_size: u32 = undefined;
|
||||||
|
try meta.interface.readSliceEndian(val_size, @ptrCast(&val_size), .little);
|
||||||
|
|
||||||
|
const val = try self.alloc.alloc(u8, val_size);
|
||||||
|
errdefer self.alloc.free(val);
|
||||||
|
try meta.interface.readSliceEndian(u8, val, .little);
|
||||||
|
|
||||||
|
try self.value_cache.put(ref, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
|
|
||||||
pub const Xattr = struct {
|
/// An Xattr return value where the reciever only owns the key value.
|
||||||
|
pub const XattrSemiOwned = struct {
|
||||||
key: [:0]const u8,
|
key: [:0]const u8,
|
||||||
value: []const u8,
|
value: []const u8,
|
||||||
|
|
||||||
|
pub fn deinit(self: XattrSemiOwned, alloc: std.mem.Allocator) void {
|
||||||
|
alloc.free(self.key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/// An Xattr return value where the reciever owns both the key & value.
|
||||||
|
pub const XattrOwned = struct {
|
||||||
|
key: [:0]const u8,
|
||||||
|
value: []const u8,
|
||||||
|
|
||||||
|
pub fn deinit(self: XattrSemiOwned, alloc: std.mem.Allocator) void {
|
||||||
|
alloc.free(self.key);
|
||||||
|
alloc.free(self.value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const TableValue = extern struct {
|
||||||
|
ref: InodeRef,
|
||||||
|
count: u32,
|
||||||
|
size: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
const KeyEntry = extern struct {
|
||||||
|
type: XattrPrefix,
|
||||||
|
name_size: u16,
|
||||||
|
};
|
||||||
|
const ValueOutOfLineEntry = extern struct {
|
||||||
|
_: u32,
|
||||||
|
ref: InodeRef,
|
||||||
|
};
|
||||||
|
|
||||||
|
const XattrPrefix = packed struct(u16) {
|
||||||
|
namespace: enum(u8) {
|
||||||
|
user,
|
||||||
|
trusted,
|
||||||
|
security,
|
||||||
|
|
||||||
|
fn prefixSize(self: @This()) u16 {
|
||||||
|
return switch (self) {
|
||||||
|
.user => 5,
|
||||||
|
.trusted => 8,
|
||||||
|
.security => 9,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
out_of_line: bool,
|
||||||
|
_: u7,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Stateless
|
// Stateless
|
||||||
|
|
||||||
pub fn statelessLookup() ![]Xattr {}
|
pub fn statelessLookup(alloc: std.mem.Allocator, io: Io, decomp: *const Decompressor, fil: OffsetFile, table_start: u64, idx: u16) ![]XattrOwned {
|
||||||
|
var rdr = try fil.readerAt(io, table_start, &[0]u8{});
|
||||||
|
|
||||||
|
var kv_start: u64 = undefined;
|
||||||
|
try rdr.interface.readSliceEndian(u64, @ptrCast(&kv_start), .little);
|
||||||
|
|
||||||
|
const lookup = try LookupTable.lookupValue(TableValue, alloc, io, decomp, fil, table_start + 16, idx);
|
||||||
|
|
||||||
|
rdr = try fil.readerAt(io, kv_start + lookup.ref.block_start, &[0]u8{});
|
||||||
|
var meta: MetadataReader = .init(alloc, &rdr.interface, decomp);
|
||||||
|
try meta.interface.discardAll(lookup.ref.block_offset);
|
||||||
|
|
||||||
|
const out = try alloc.alloc(XattrOwned, lookup.count);
|
||||||
|
errdefer alloc.free(out);
|
||||||
|
|
||||||
|
for (0..lookup.count) |i| {
|
||||||
|
const key_entry: KeyEntry = undefined;
|
||||||
|
try meta.interface.readSliceEndian(KeyEntry, @ptrCast(&key_entry), .little);
|
||||||
|
|
||||||
|
const key = switch (key_entry.type.namespace) {
|
||||||
|
.user => blk: {
|
||||||
|
const tmp = try alloc.alloc(u8, key_entry.name_size + 1 + 5);
|
||||||
|
errdefer alloc.free(tmp);
|
||||||
|
try meta.interface.readSliceEndian(u8, tmp[5 .. tmp.len - 1], .little);
|
||||||
|
@memset(tmp[0..5], "user.");
|
||||||
|
break :blk tmp;
|
||||||
|
},
|
||||||
|
.trusted => blk: {
|
||||||
|
const tmp = try alloc.alloc(u8, key_entry.name_size + 1 + 8);
|
||||||
|
errdefer alloc.free(tmp);
|
||||||
|
try meta.interface.readSliceEndian(u8, tmp[8 .. tmp.len - 1], .little);
|
||||||
|
@memset(tmp[0..8], "trusted.");
|
||||||
|
break :blk tmp;
|
||||||
|
},
|
||||||
|
.security => blk: {
|
||||||
|
const tmp = try alloc.alloc(u8, key_entry.name_size + 1 + 9);
|
||||||
|
errdefer alloc.free(tmp);
|
||||||
|
try meta.interface.readSliceEndian(u8, tmp[9 .. tmp.len - 1], .little);
|
||||||
|
@memset(tmp[0..9], "security.");
|
||||||
|
break :blk tmp;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
key[key.len - 1] = 0;
|
||||||
|
errdefer alloc.free(key);
|
||||||
|
|
||||||
|
if (key_entry.type.out_of_line) {
|
||||||
|
const value: ValueOutOfLineEntry = undefined;
|
||||||
|
try meta.interface.readSliceEndian(ValueOutOfLineEntry, @ptrCast(&value), .little);
|
||||||
|
|
||||||
|
var ool_rdr = try fil.readerAt(io, kv_start + value.ref.block_start, &[0]u8{});
|
||||||
|
var ool_meta: MetadataReader = .init(alloc, &ool_rdr.interface, decomp);
|
||||||
|
try ool_meta.interface.discardAll(value.ref.block_offset);
|
||||||
|
|
||||||
|
var val_size: u32 = undefined;
|
||||||
|
try ool_meta.interface.readSliceEndian(val_size, @ptrCast(&val_size), .little);
|
||||||
|
|
||||||
|
const val = try alloc.alloc(u8, val_size);
|
||||||
|
errdefer alloc.free(val);
|
||||||
|
try ool_meta.interface.readSliceEndian(u8, val, .little);
|
||||||
|
|
||||||
|
out[i] = .{
|
||||||
|
.key = key,
|
||||||
|
.value = val,
|
||||||
|
};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var val_size: u32 = undefined;
|
||||||
|
try meta.interface.readSliceEndian(val_size, @ptrCast(&val_size), .little);
|
||||||
|
|
||||||
|
const val = try alloc.alloc(u8, val_size);
|
||||||
|
try meta.interface.readSliceEndian(u8, val, .little);
|
||||||
|
|
||||||
|
out[i] = .{
|
||||||
|
.key = key,
|
||||||
|
.value = val,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user