weekend changes
- move main.zig to it's own package, create lib/ - rename AllSections to DB, remove intermediate tuples - iovec does not allocate - remove error{Overflow} from almost everywhere
This commit is contained in:
parent
886382d900
commit
a8b45911aa
17
build.zig
17
build.zig
@ -50,24 +50,19 @@ pub fn build(b: *zbs.Builder) void {
|
|||||||
cmph.addIncludeDir("deps/cmph/src");
|
cmph.addIncludeDir("deps/cmph/src");
|
||||||
cmph.addIncludeDir("include/deps/cmph");
|
cmph.addIncludeDir("include/deps/cmph");
|
||||||
|
|
||||||
const exe = b.addExecutable("init-exe", "src/main.zig");
|
{
|
||||||
|
const exe = b.addExecutable("turbo-unix2db", "cli/unix2db/main.zig");
|
||||||
exe.setTarget(target);
|
exe.setTarget(target);
|
||||||
exe.setBuildMode(mode);
|
exe.setBuildMode(mode);
|
||||||
addCmphDeps(exe, cmph);
|
addCmphDeps(exe, cmph);
|
||||||
exe.install();
|
exe.install();
|
||||||
|
|
||||||
{
|
|
||||||
const turbonss_test = b.addTest("src/test_main.zig");
|
|
||||||
addCmphDeps(turbonss_test, cmph);
|
|
||||||
const test_step = b.step("test", "Run the tests");
|
|
||||||
test_step.dependOn(&turbonss_test.step);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const run_cmd = exe.run();
|
const turbonss_test = b.addTest("lib/test_all.zig");
|
||||||
run_cmd.step.dependOn(b.getInstallStep());
|
addCmphDeps(turbonss_test, cmph);
|
||||||
const run_step = b.step("run", "Run the app");
|
const test_step = b.step("test", "Run the tests");
|
||||||
run_step.dependOn(&run_cmd.step);
|
test_step.dependOn(&turbonss_test.step);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ const std = @import("std");
|
|||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
const sort = std.sort;
|
const sort = std.sort;
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
const bdz = @import("bdz.zig");
|
const bdz = @import("bdz.zig");
|
||||||
|
|
||||||
@ -33,9 +34,9 @@ extern fn cmph_destroy(mphf: [*]const u8) void;
|
|||||||
// pack packs cmph hashes for the given input and returns a slice ("cmph pack
|
// pack packs cmph hashes for the given input and returns a slice ("cmph pack
|
||||||
// minus first 4 bytes") for further storage. The slice must be freed by the
|
// minus first 4 bytes") for further storage. The slice must be freed by the
|
||||||
// caller.
|
// caller.
|
||||||
pub const Error = error{ OutOfMemory, Overflow };
|
pub fn pack(allocator: Allocator, input: [][*:0]const u8) error{OutOfMemory}![]const u8 {
|
||||||
pub fn pack(allocator: Allocator, input: [][*:0]const u8) Error![]const u8 {
|
assert(input.len <= math.maxInt(c_uint));
|
||||||
const input_len = try math.cast(c_uint, input.len);
|
const input_len = @intCast(c_uint, input.len);
|
||||||
var source = cmph_io_vector_adapter(input.ptr, input_len);
|
var source = cmph_io_vector_adapter(input.ptr, input_len);
|
||||||
defer cmph_io_vector_adapter_destroy(source);
|
defer cmph_io_vector_adapter_destroy(source);
|
||||||
var config = cmph_config_new(source) orelse return error.OutOfMemory;
|
var config = cmph_config_new(source) orelse return error.OutOfMemory;
|
||||||
@ -53,7 +54,7 @@ pub fn pack(allocator: Allocator, input: [][*:0]const u8) Error![]const u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// perfect-hash a list of numbers and return the packed mphf
|
// perfect-hash a list of numbers and return the packed mphf
|
||||||
pub fn packU32(allocator: Allocator, numbers: []const u32) Error![]const u8 {
|
pub fn packU32(allocator: Allocator, numbers: []const u32) error{OutOfMemory}![]const u8 {
|
||||||
var keys: [][6]u8 = try allocator.alloc([6]u8, numbers.len);
|
var keys: [][6]u8 = try allocator.alloc([6]u8, numbers.len);
|
||||||
defer allocator.free(keys);
|
defer allocator.free(keys);
|
||||||
for (numbers) |n, i|
|
for (numbers) |n, i|
|
||||||
@ -67,7 +68,7 @@ pub fn packU32(allocator: Allocator, numbers: []const u32) Error![]const u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// perfect-hash a list of strings and return the packed mphf
|
// perfect-hash a list of strings and return the packed mphf
|
||||||
pub fn packStr(allocator: Allocator, strings: []const []const u8) Error![]const u8 {
|
pub fn packStr(allocator: Allocator, strings: []const []const u8) error{OutOfMemory}![]const u8 {
|
||||||
var arena = std.heap.ArenaAllocator.init(allocator);
|
var arena = std.heap.ArenaAllocator.init(allocator);
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
var keys = try arena.allocator().alloc([*:0]const u8, strings.len);
|
var keys = try arena.allocator().alloc([*:0]const u8, strings.len);
|
@ -115,11 +115,10 @@ pub const PackedGroup = struct {
|
|||||||
return self.groupdata;
|
return self.groupdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
const packErr = validate.InvalidRecord || Allocator.Error || error{Overflow};
|
|
||||||
pub fn packTo(
|
pub fn packTo(
|
||||||
arr: *ArrayList(u8),
|
arr: *ArrayList(u8),
|
||||||
group: GroupStored,
|
group: GroupStored,
|
||||||
) packErr!void {
|
) error{ InvalidRecord, OutOfMemory }!void {
|
||||||
std.debug.assert(arr.items.len & 7 == 0);
|
std.debug.assert(arr.items.len & 7 == 0);
|
||||||
try validate.utf8(group.name);
|
try validate.utf8(group.name);
|
||||||
const len = try validate.downCast(u5, group.name.len - 1);
|
const len = try validate.downCast(u5, group.name.len - 1);
|
@ -3,6 +3,7 @@ const os = std.os;
|
|||||||
const fmt = std.fmt;
|
const fmt = std.fmt;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
|
const meta = std.meta;
|
||||||
const sort = std.sort;
|
const sort = std.sort;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const unicode = std.unicode;
|
const unicode = std.unicode;
|
||||||
@ -14,6 +15,7 @@ const MultiArrayList = std.MultiArrayList;
|
|||||||
const StringHashMap = std.StringHashMap;
|
const StringHashMap = std.StringHashMap;
|
||||||
const AutoHashMap = std.AutoHashMap;
|
const AutoHashMap = std.AutoHashMap;
|
||||||
const BufSet = std.BufSet;
|
const BufSet = std.BufSet;
|
||||||
|
const BoundedArray = std.BoundedArray;
|
||||||
|
|
||||||
const pad = @import("padding.zig");
|
const pad = @import("padding.zig");
|
||||||
const compress = @import("compress.zig");
|
const compress = @import("compress.zig");
|
||||||
@ -51,7 +53,10 @@ const Corpus = struct {
|
|||||||
baseAllocator: Allocator,
|
baseAllocator: Allocator,
|
||||||
usersConst: []const User,
|
usersConst: []const User,
|
||||||
groupsConst: []const Group,
|
groupsConst: []const Group,
|
||||||
) error{ OutOfMemory, InvalidUtf8, Duplicate, NotFound }!Corpus {
|
) error{ OutOfMemory, InvalidUtf8, Duplicate, NotFound, TooMany }!Corpus {
|
||||||
|
if (usersConst.len >= math.maxInt(u32)) return error.TooMany;
|
||||||
|
if (groupsConst.len >= math.maxInt(u32)) return error.TooMany;
|
||||||
|
|
||||||
var arena = ArenaAllocator.init(baseAllocator);
|
var arena = ArenaAllocator.init(baseAllocator);
|
||||||
var allocator = arena.allocator();
|
var allocator = arena.allocator();
|
||||||
errdefer arena.deinit();
|
errdefer arena.deinit();
|
||||||
@ -145,7 +150,7 @@ const Corpus = struct {
|
|||||||
pub fn shellSections(
|
pub fn shellSections(
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
corpus: *const Corpus,
|
corpus: *const Corpus,
|
||||||
) error{ OutOfMemory, Overflow }!ShellSections {
|
) error{OutOfMemory}!ShellSections {
|
||||||
var popcon = ShellWriter.init(allocator);
|
var popcon = ShellWriter.init(allocator);
|
||||||
for (corpus.users.items(.shell)) |shell|
|
for (corpus.users.items(.shell)) |shell|
|
||||||
try popcon.put(shell);
|
try popcon.put(shell);
|
||||||
@ -169,10 +174,10 @@ pub const AdditionalGids = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn userGids(
|
pub fn additionalGids(
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
corpus: *const Corpus,
|
corpus: *const Corpus,
|
||||||
) error{ OutOfMemory, Overflow }!AdditionalGids {
|
) error{OutOfMemory}!AdditionalGids {
|
||||||
var blob = ArrayList(u8).init(allocator);
|
var blob = ArrayList(u8).init(allocator);
|
||||||
errdefer blob.deinit();
|
errdefer blob.deinit();
|
||||||
var idx2offset = try allocator.alloc(u64, corpus.users.len);
|
var idx2offset = try allocator.alloc(u64, corpus.users.len);
|
||||||
@ -227,7 +232,7 @@ pub fn usersSection(
|
|||||||
corpus: *const Corpus,
|
corpus: *const Corpus,
|
||||||
gids: *const AdditionalGids,
|
gids: *const AdditionalGids,
|
||||||
shells: *const ShellSections,
|
shells: *const ShellSections,
|
||||||
) error{ OutOfMemory, Overflow, InvalidRecord }!UsersSection {
|
) error{ OutOfMemory, InvalidRecord, TooMany }!UsersSection {
|
||||||
var idx2offset = try allocator.alloc(u32, corpus.users.len);
|
var idx2offset = try allocator.alloc(u32, corpus.users.len);
|
||||||
errdefer allocator.free(idx2offset);
|
errdefer allocator.free(idx2offset);
|
||||||
// as of writing each user takes 12 bytes + blobs + padding, padded to
|
// as of writing each user takes 12 bytes + blobs + padding, padded to
|
||||||
@ -238,7 +243,9 @@ pub fn usersSection(
|
|||||||
while (i < corpus.users.len) : (i += 1) {
|
while (i < corpus.users.len) : (i += 1) {
|
||||||
// TODO: this is inefficient by calling `.slice()` on every iteration
|
// TODO: this is inefficient by calling `.slice()` on every iteration
|
||||||
const user = corpus.users.get(i);
|
const user = corpus.users.get(i);
|
||||||
const user_offset = try math.cast(u35, blob.items.len);
|
const user_offset = math.cast(u35, blob.items.len) catch |err| switch (err) {
|
||||||
|
error.Overflow => return error.TooMany,
|
||||||
|
};
|
||||||
assert(user_offset & 7 == 0);
|
assert(user_offset & 7 == 0);
|
||||||
idx2offset[i] = @truncate(u32, user_offset >> 3);
|
idx2offset[i] = @truncate(u32, user_offset >> 3);
|
||||||
try PackedUser.packTo(
|
try PackedUser.packTo(
|
||||||
@ -327,7 +334,7 @@ pub fn groupsSection(
|
|||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
corpus: *const Corpus,
|
corpus: *const Corpus,
|
||||||
members_offset: []const u64,
|
members_offset: []const u64,
|
||||||
) error{ OutOfMemory, Overflow, InvalidRecord }!GroupsSection {
|
) error{ OutOfMemory, InvalidRecord }!GroupsSection {
|
||||||
var idx2offset = try allocator.alloc(u32, corpus.groups.len);
|
var idx2offset = try allocator.alloc(u32, corpus.groups.len);
|
||||||
errdefer allocator.free(idx2offset);
|
errdefer allocator.free(idx2offset);
|
||||||
|
|
||||||
@ -338,7 +345,7 @@ pub fn groupsSection(
|
|||||||
while (i < corpus.groups.len) : (i += 1) {
|
while (i < corpus.groups.len) : (i += 1) {
|
||||||
// TODO: this is inefficient; it's calling `.slice()` on every iteration
|
// TODO: this is inefficient; it's calling `.slice()` on every iteration
|
||||||
const group = corpus.groups.get(i);
|
const group = corpus.groups.get(i);
|
||||||
const group_offset = try math.cast(u32, blob.items.len);
|
const group_offset = @intCast(u32, blob.items.len);
|
||||||
assert(group_offset & 7 == 0);
|
assert(group_offset & 7 == 0);
|
||||||
idx2offset[i] = @truncate(u32, group_offset >> 3);
|
idx2offset[i] = @truncate(u32, group_offset >> 3);
|
||||||
const group_stored = GroupStored{
|
const group_stored = GroupStored{
|
||||||
@ -416,29 +423,28 @@ fn nblocks(comptime T: type, arr: []const u8) T {
|
|||||||
return @truncate(T, upper >> 6);
|
return @truncate(T, upper >> 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const AllSections = struct {
|
pub const DB = struct {
|
||||||
allocator: Allocator,
|
// All sections, as they end up in the DB. Order is important.
|
||||||
|
header: []const u8,
|
||||||
bdz_gid: []const u8,
|
bdz_gid: []const u8,
|
||||||
bdz_groupname: []const u8,
|
bdz_groupname: []const u8,
|
||||||
bdz_uid: []const u8,
|
bdz_uid: []const u8,
|
||||||
bdz_username: []const u8,
|
bdz_username: []const u8,
|
||||||
users: UsersSection,
|
|
||||||
shell_sections: ShellSections,
|
|
||||||
shell_reader: ShellReader,
|
|
||||||
additional_gids: AdditionalGids,
|
|
||||||
groupmembers: GroupMembers,
|
|
||||||
groups: GroupsSection,
|
|
||||||
idx_gid2group: []const u32,
|
idx_gid2group: []const u32,
|
||||||
idx_groupname2group: []const u32,
|
idx_groupname2group: []const u32,
|
||||||
idx_uid2user: []const u32,
|
idx_uid2user: []const u32,
|
||||||
idx_name2user: []const u32,
|
idx_name2user: []const u32,
|
||||||
header: []const u8,
|
shell_index: []const u16,
|
||||||
|
shell_blob: []const u8,
|
||||||
|
groups: []const u8,
|
||||||
|
users: []const u8,
|
||||||
|
groupmembers: []const u8,
|
||||||
|
additional_gids: []const u8,
|
||||||
|
|
||||||
pub fn init(
|
pub fn fromCorpus(
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
corpus: *const Corpus,
|
corpus: *const Corpus,
|
||||||
) error{ Overflow, OutOfMemory, InvalidRecord }!AllSections {
|
) error{ OutOfMemory, InvalidRecord, TooMany }!DB {
|
||||||
const gids = corpus.groups.items(.gid);
|
const gids = corpus.groups.items(.gid);
|
||||||
const gnames = corpus.groups.items(.name);
|
const gnames = corpus.groups.items(.name);
|
||||||
const uids = corpus.users.items(.uid);
|
const uids = corpus.users.items(.uid);
|
||||||
@ -457,30 +463,34 @@ pub const AllSections = struct {
|
|||||||
errdefer allocator.free(bdz_username);
|
errdefer allocator.free(bdz_username);
|
||||||
|
|
||||||
var shell = try shellSections(allocator, corpus);
|
var shell = try shellSections(allocator, corpus);
|
||||||
errdefer shell.deinit();
|
defer shell.deinit();
|
||||||
|
|
||||||
var additional_gids = try userGids(allocator, corpus);
|
var additional_gids = try additionalGids(allocator, corpus);
|
||||||
errdefer additional_gids.deinit(allocator);
|
errdefer allocator.free(additional_gids.blob);
|
||||||
|
|
||||||
var users = try usersSection(allocator, corpus, &additional_gids, &shell);
|
var users = try usersSection(allocator, corpus, &additional_gids, &shell);
|
||||||
errdefer users.deinit(allocator);
|
allocator.free(additional_gids.idx2offset);
|
||||||
|
errdefer allocator.free(users.blob);
|
||||||
|
|
||||||
var groupmembers = try groupMembers(allocator, corpus, users.idx2offset);
|
var groupmembers = try groupMembers(allocator, corpus, users.idx2offset);
|
||||||
errdefer groupmembers.deinit(allocator);
|
errdefer allocator.free(groupmembers.blob);
|
||||||
|
|
||||||
var groups = try groupsSection(allocator, corpus, groupmembers.idx2offset);
|
var groups = try groupsSection(allocator, corpus, groupmembers.idx2offset);
|
||||||
errdefer groups.deinit(allocator);
|
allocator.free(groupmembers.idx2offset);
|
||||||
|
errdefer allocator.free(groups.blob);
|
||||||
|
|
||||||
var idx_gid2group = try bdzIdx(u32, allocator, bdz_gid, gids, groups.idx2offset);
|
var idx_gid2group = try bdzIdx(u32, allocator, bdz_gid, gids, groups.idx2offset);
|
||||||
errdefer allocator.free(idx_gid2group);
|
errdefer allocator.free(idx_gid2group);
|
||||||
|
|
||||||
var idx_groupname2group = try bdzIdx([]const u8, allocator, bdz_groupname, gnames, groups.idx2offset);
|
var idx_groupname2group = try bdzIdx([]const u8, allocator, bdz_groupname, gnames, groups.idx2offset);
|
||||||
|
allocator.free(groups.idx2offset);
|
||||||
errdefer allocator.free(idx_groupname2group);
|
errdefer allocator.free(idx_groupname2group);
|
||||||
|
|
||||||
var idx_uid2user = try bdzIdx(u32, allocator, bdz_uid, uids, users.idx2offset);
|
var idx_uid2user = try bdzIdx(u32, allocator, bdz_uid, uids, users.idx2offset);
|
||||||
errdefer allocator.free(idx_uid2user);
|
errdefer allocator.free(idx_uid2user);
|
||||||
|
|
||||||
var idx_name2user = try bdzIdx([]const u8, allocator, bdz_username, unames, users.idx2offset);
|
var idx_name2user = try bdzIdx([]const u8, allocator, bdz_username, unames, users.idx2offset);
|
||||||
|
allocator.free(users.idx2offset);
|
||||||
errdefer allocator.free(idx_name2user);
|
errdefer allocator.free(idx_name2user);
|
||||||
|
|
||||||
const header = Header{
|
const header = Header{
|
||||||
@ -498,59 +508,38 @@ pub const AllSections = struct {
|
|||||||
.nblocks_additional_gids = nblocks(u64, additional_gids.blob),
|
.nblocks_additional_gids = nblocks(u64, additional_gids.blob),
|
||||||
};
|
};
|
||||||
|
|
||||||
return AllSections{
|
return DB{
|
||||||
.allocator = allocator,
|
.header = header.asBytes(),
|
||||||
.bdz_gid = bdz_gid,
|
.bdz_gid = bdz_gid,
|
||||||
.bdz_groupname = bdz_groupname,
|
.bdz_groupname = bdz_groupname,
|
||||||
.bdz_uid = bdz_uid,
|
.bdz_uid = bdz_uid,
|
||||||
.bdz_username = bdz_username,
|
.bdz_username = bdz_username,
|
||||||
.shell_sections = shell,
|
|
||||||
.shell_reader = ShellReader.init(
|
|
||||||
mem.sliceAsBytes(shell.index.constSlice()),
|
|
||||||
mem.sliceAsBytes(shell.blob.constSlice()),
|
|
||||||
),
|
|
||||||
.additional_gids = additional_gids,
|
|
||||||
.users = users,
|
|
||||||
.groupmembers = groupmembers,
|
|
||||||
.groups = groups,
|
|
||||||
.idx_gid2group = idx_gid2group,
|
.idx_gid2group = idx_gid2group,
|
||||||
.idx_groupname2group = idx_groupname2group,
|
.idx_groupname2group = idx_groupname2group,
|
||||||
.idx_uid2user = idx_uid2user,
|
.idx_uid2user = idx_uid2user,
|
||||||
.idx_name2user = idx_name2user,
|
.idx_name2user = idx_name2user,
|
||||||
.header = header.asBytes(),
|
.shell_index = shell.index.constSlice(),
|
||||||
|
.shell_blob = shell.blob.constSlice(),
|
||||||
|
.groups = groups.blob,
|
||||||
|
.users = users.blob,
|
||||||
|
.groupmembers = groupmembers.blob,
|
||||||
|
.additional_gids = additional_gids.blob,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iov(self: *const AllSections) error{OutOfMemory}![]os.iovec_const {
|
pub fn iov(self: *const DB) error{OutOfMemory}![]const os.iovec_const {
|
||||||
const sections = &[_][]const u8{
|
const fields = comptime meta.fieldNames(DB);
|
||||||
self.header,
|
var result = BoundedArray(os.iovec_const, fields.len * 2).init(0) catch |err| switch (err) {
|
||||||
self.bdz_gid,
|
error.Overflow => unreachable,
|
||||||
self.bdz_groupname,
|
|
||||||
self.bdz_uid,
|
|
||||||
self.bdz_username,
|
|
||||||
mem.sliceAsBytes(self.idx_gid2group),
|
|
||||||
mem.sliceAsBytes(self.idx_groupname2group),
|
|
||||||
mem.sliceAsBytes(self.idx_uid2user),
|
|
||||||
mem.sliceAsBytes(self.idx_name2user),
|
|
||||||
mem.sliceAsBytes(self.shell_sections.index.constSlice()),
|
|
||||||
mem.sliceAsBytes(self.shell_sections.blob.constSlice()),
|
|
||||||
self.groups.blob,
|
|
||||||
self.users.blob,
|
|
||||||
self.groupmembers.blob,
|
|
||||||
self.additional_gids.blob,
|
|
||||||
};
|
};
|
||||||
var result = try ArrayList(os.iovec_const).initCapacity(
|
|
||||||
self.allocator,
|
|
||||||
sections.len * 2,
|
|
||||||
);
|
|
||||||
errdefer result.deinit();
|
|
||||||
|
|
||||||
for (sections) |section| {
|
inline for (fields) |fname| {
|
||||||
|
const bytes = mem.sliceAsBytes(@field(self, fname));
|
||||||
result.appendAssumeCapacity(os.iovec_const{
|
result.appendAssumeCapacity(os.iovec_const{
|
||||||
.iov_base = section.ptr,
|
.iov_base = bytes.ptr,
|
||||||
.iov_len = section.len,
|
.iov_len = bytes.len,
|
||||||
});
|
});
|
||||||
const padding = pad.until(usize, section_length_bits, section.len);
|
const padding = pad.until(usize, section_length_bits, bytes.len);
|
||||||
if (padding != 0)
|
if (padding != 0)
|
||||||
result.appendAssumeCapacity(.{
|
result.appendAssumeCapacity(.{
|
||||||
.iov_base = zeroes,
|
.iov_base = zeroes,
|
||||||
@ -558,23 +547,22 @@ pub const AllSections = struct {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.toOwnedSlice();
|
return result.constSlice();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *AllSections) void {
|
pub fn deinit(self: *DB, allocator: Allocator) void {
|
||||||
self.allocator.free(self.bdz_gid);
|
allocator.free(self.bdz_gid);
|
||||||
self.allocator.free(self.bdz_groupname);
|
allocator.free(self.bdz_groupname);
|
||||||
self.allocator.free(self.bdz_uid);
|
allocator.free(self.bdz_uid);
|
||||||
self.allocator.free(self.bdz_username);
|
allocator.free(self.bdz_username);
|
||||||
self.shell_sections.deinit();
|
allocator.free(self.idx_gid2group);
|
||||||
self.additional_gids.deinit(self.allocator);
|
allocator.free(self.idx_groupname2group);
|
||||||
self.users.deinit(self.allocator);
|
allocator.free(self.idx_uid2user);
|
||||||
self.groupmembers.deinit(self.allocator);
|
allocator.free(self.idx_name2user);
|
||||||
self.groups.deinit(self.allocator);
|
allocator.free(self.groups);
|
||||||
self.allocator.free(self.idx_gid2group);
|
allocator.free(self.users);
|
||||||
self.allocator.free(self.idx_groupname2group);
|
allocator.free(self.groupmembers);
|
||||||
self.allocator.free(self.idx_uid2user);
|
allocator.free(self.additional_gids);
|
||||||
self.allocator.free(self.idx_name2user);
|
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -704,46 +692,48 @@ test "test groups, group members and users" {
|
|||||||
var corpus = try testCorpus(allocator);
|
var corpus = try testCorpus(allocator);
|
||||||
defer corpus.deinit();
|
defer corpus.deinit();
|
||||||
|
|
||||||
var sections = try AllSections.init(allocator, &corpus);
|
var db = try DB.fromCorpus(allocator, &corpus);
|
||||||
defer sections.deinit();
|
defer db.deinit(allocator);
|
||||||
|
|
||||||
const blob = sections.groupmembers.blob;
|
// TODO: replace with an integration test when high-level
|
||||||
var i: usize = 0;
|
// reader API is present
|
||||||
while (i < corpus.groups.len) : (i += 1) {
|
//const blob = sections.groupmembers.blob;
|
||||||
const offset = sections.groupmembers.idx2offset[i];
|
//var i: usize = 0;
|
||||||
var vit = try compress.VarintSliceIterator(blob[offset..]);
|
//while (i < corpus.groups.len) : (i += 1) {
|
||||||
var it = compress.DeltaDecompressionIterator(&vit);
|
//const offset = sections.groupmembers.idx2offset[i];
|
||||||
for (corpus.group2users[i]) |user_idx| {
|
//var vit = try compress.VarintSliceIterator(blob[offset..]);
|
||||||
const got_user_offset = (try it.next()).?;
|
//var it = compress.DeltaDecompressionIterator(&vit);
|
||||||
const want_user_offset = sections.users.idx2offset[user_idx];
|
//for (corpus.group2users[i]) |user_idx| {
|
||||||
try testing.expectEqual(got_user_offset, want_user_offset);
|
// const got_user_offset = (try it.next()).?;
|
||||||
}
|
// const want_user_offset = sections.users.idx2offset[user_idx];
|
||||||
try testing.expectEqual(it.next(), null);
|
// try testing.expectEqual(got_user_offset, want_user_offset);
|
||||||
}
|
//}
|
||||||
|
//try testing.expectEqual(it.next(), null);
|
||||||
|
//}
|
||||||
|
|
||||||
var it = PackedUser.iterator(sections.users.blob, sections.shell_reader);
|
//var it = PackedUser.iterator(sections.users.blob, sections.shell_reader);
|
||||||
i = 0;
|
//i = 0;
|
||||||
while (i < corpus.users.len) : (i += 1) {
|
//while (i < corpus.users.len) : (i += 1) {
|
||||||
const got = (try it.next()).?;
|
// const got = (try it.next()).?;
|
||||||
const user = corpus.users.get(i);
|
// const user = corpus.users.get(i);
|
||||||
try testing.expectEqual(user.uid, got.uid());
|
// try testing.expectEqual(user.uid, got.uid());
|
||||||
try testing.expectEqual(user.gid, got.gid());
|
// try testing.expectEqual(user.gid, got.gid());
|
||||||
try testing.expectEqualStrings(user.name, got.name());
|
// try testing.expectEqualStrings(user.name, got.name());
|
||||||
try testing.expectEqualStrings(user.gecos, got.gecos());
|
// try testing.expectEqualStrings(user.gecos, got.gecos());
|
||||||
try testing.expectEqualStrings(user.home, got.home());
|
// try testing.expectEqualStrings(user.home, got.home());
|
||||||
try testing.expectEqualStrings(user.shell, got.shell(sections.shell_reader));
|
// try testing.expectEqualStrings(user.shell, got.shell(sections.shell_reader));
|
||||||
}
|
//}
|
||||||
|
|
||||||
var iovec = try sections.iov();
|
var iovec = try db.iov();
|
||||||
allocator.free(iovec);
|
_ = iovec;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "userGids" {
|
test "additionalGids" {
|
||||||
const allocator = testing.allocator;
|
const allocator = testing.allocator;
|
||||||
var corpus = try testCorpus(allocator);
|
var corpus = try testCorpus(allocator);
|
||||||
defer corpus.deinit();
|
defer corpus.deinit();
|
||||||
|
|
||||||
var additional_gids = try userGids(allocator, &corpus);
|
var additional_gids = try additionalGids(allocator, &corpus);
|
||||||
defer additional_gids.deinit(allocator);
|
defer additional_gids.deinit(allocator);
|
||||||
|
|
||||||
var user_idx: usize = 0;
|
var user_idx: usize = 0;
|
@ -5,6 +5,7 @@ const StringArrayHashMap = std.StringArrayHashMap;
|
|||||||
const StringHashMap = std.StringHashMap;
|
const StringHashMap = std.StringHashMap;
|
||||||
const BoundedArray = std.BoundedArray;
|
const BoundedArray = std.BoundedArray;
|
||||||
const StringContext = std.hash_map.StringContext;
|
const StringContext = std.hash_map.StringContext;
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
pub const max_shells = 255;
|
pub const max_shells = 255;
|
||||||
pub const max_shell_len = 256;
|
pub const max_shell_len = 256;
|
||||||
@ -55,11 +56,12 @@ pub const ShellWriter = struct {
|
|||||||
pub fn init(
|
pub fn init(
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
shells: BoundedArray([]const u8, max_shells),
|
shells: BoundedArray([]const u8, max_shells),
|
||||||
) error{ Overflow, OutOfMemory }!ShellSections {
|
) error{OutOfMemory}!ShellSections {
|
||||||
|
assert(shells.len <= max_shells);
|
||||||
var self = ShellSections{
|
var self = ShellSections{
|
||||||
.len = @intCast(u8, shells.len),
|
.len = @intCast(u8, shells.len),
|
||||||
.index = try BoundedArray(u16, max_shells).init(shells.len),
|
.index = BoundedArray(u16, max_shells).init(shells.len) catch unreachable,
|
||||||
.blob = try BoundedArray(u8, (max_shells + 1) * max_shell_len).init(0),
|
.blob = BoundedArray(u8, (max_shells + 1) * max_shell_len).init(0) catch unreachable,
|
||||||
.shell2idx = StringHashMap(u8).init(allocator),
|
.shell2idx = StringHashMap(u8).init(allocator),
|
||||||
};
|
};
|
||||||
if (shells.len == 0) return self;
|
if (shells.len == 0) return self;
|
||||||
@ -68,11 +70,11 @@ pub const ShellWriter = struct {
|
|||||||
for (shells.constSlice()) |shell, idx| {
|
for (shells.constSlice()) |shell, idx| {
|
||||||
const idx8 = @intCast(u8, idx);
|
const idx8 = @intCast(u8, idx);
|
||||||
const offset = @intCast(u16, self.blob.len);
|
const offset = @intCast(u16, self.blob.len);
|
||||||
try self.blob.appendSlice(shell);
|
self.blob.appendSliceAssumeCapacity(shell);
|
||||||
try self.shell2idx.put(self.blob.constSlice()[offset..], idx8);
|
try self.shell2idx.put(self.blob.constSlice()[offset..], idx8);
|
||||||
self.index.set(idx8, offset);
|
self.index.set(idx8, offset);
|
||||||
}
|
}
|
||||||
try self.index.append(@intCast(u8, self.blob.len));
|
self.index.appendAssumeCapacity(@intCast(u8, self.blob.len));
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,10 +128,9 @@ pub const ShellWriter = struct {
|
|||||||
// toOwnedSections returns the analyzed ShellSections. Resets the shell
|
// toOwnedSections returns the analyzed ShellSections. Resets the shell
|
||||||
// popularity contest. ShellSections memory is allocated by the ShellWriter
|
// popularity contest. ShellSections memory is allocated by the ShellWriter
|
||||||
// allocator, and must be deInit'ed by the caller.
|
// allocator, and must be deInit'ed by the caller.
|
||||||
pub fn toOwnedSections(
|
pub fn toOwnedSections(self: *ShellWriter, limit: u10) error{OutOfMemory}!ShellSections {
|
||||||
self: *ShellWriter,
|
assert(limit <= max_shells);
|
||||||
limit: u10,
|
|
||||||
) error{ Overflow, OutOfMemory }!ShellSections {
|
|
||||||
var deque = PriorityDequeue(KV, void, cmpShells).init(self.allocator, {});
|
var deque = PriorityDequeue(KV, void, cmpShells).init(self.allocator, {});
|
||||||
defer deque.deinit();
|
defer deque.deinit();
|
||||||
|
|
||||||
@ -142,7 +143,9 @@ pub const ShellWriter = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const total = std.math.min(deque.count(), limit);
|
const total = std.math.min(deque.count(), limit);
|
||||||
var topShells = try BoundedArray([]const u8, max_shells).init(total);
|
var topShells = BoundedArray([]const u8, max_shells).init(total) catch |err| switch (err) {
|
||||||
|
error.Overflow => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
var i: u32 = 0;
|
var i: u32 = 0;
|
||||||
while (i < total) : (i += 1)
|
while (i < total) : (i += 1)
|
@ -1,5 +1,4 @@
|
|||||||
test "turbonss test suite" {
|
test "turbonss test suite" {
|
||||||
_ = @import("main.zig");
|
|
||||||
_ = @import("header.zig");
|
_ = @import("header.zig");
|
||||||
_ = @import("so.zig");
|
_ = @import("so.zig");
|
||||||
_ = @import("sections.zig");
|
_ = @import("sections.zig");
|
@ -1,8 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
pub const InvalidRecord = error{InvalidRecord};
|
pub fn downCast(comptime T: type, n: u64) error{InvalidRecord}!T {
|
||||||
|
|
||||||
pub fn downCast(comptime T: type, n: u64) InvalidRecord!T {
|
|
||||||
return std.math.cast(T, n) catch |err| switch (err) {
|
return std.math.cast(T, n) catch |err| switch (err) {
|
||||||
error.Overflow => {
|
error.Overflow => {
|
||||||
return error.InvalidRecord;
|
return error.InvalidRecord;
|
||||||
@ -10,7 +8,7 @@ pub fn downCast(comptime T: type, n: u64) InvalidRecord!T {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn utf8(s: []const u8) InvalidRecord!void {
|
pub fn utf8(s: []const u8) error{InvalidRecord}!void {
|
||||||
if (!std.unicode.utf8ValidateSlice(s)) {
|
if (!std.unicode.utf8ValidateSlice(s)) {
|
||||||
return error.InvalidRecord;
|
return error.InvalidRecord;
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user