This commit is contained in:
Motiejus Jakštys 2022-03-20 08:42:51 +01:00 committed by Motiejus Jakštys
parent 787fbcf375
commit b220dd92e3
3 changed files with 78 additions and 31 deletions

View File

@ -46,7 +46,7 @@ pub const Header = packed struct {
nblocks_groupmembers: u64,
nblocks_additional_gids: u64,
pub fn fromBytes(blob: [header_size]u8) InvalidHeader!Header {
pub fn fromBytes(blob: []const u8) InvalidHeader!Header {
const self = mem.bytesAsValue(Header, blob);
if (!mem.eql(magic, blob[0..4]))
@ -64,7 +64,7 @@ pub const Header = packed struct {
return self;
}
pub fn asBytes(self: *const Header) [header_size]u8 {
pub fn asBytes(self: *const Header) []const u8 {
return mem.asBytes(self);
}
};

View File

@ -12,31 +12,31 @@ pub fn roundUp(comptime T: type, comptime nbits: u8, n: T) T {
// rounds up an integer to the nearest factor of nbits and returns the
// difference (padding)
pub fn roundUpPadding(comptime T: type, comptime nbits: u8, n: T) T {
pub fn until(comptime T: type, comptime nbits: u8, n: T) T {
return roundUp(T, nbits, n) - n;
}
// arrayList adds padding to an ArrayList(u8) for a given number of nbits
pub fn arrayList(arr: *ArrayList(u8), comptime nbits: u8) Allocator.Error!void {
const padding = roundUpPadding(u64, nbits, arr.items.len);
const padding = until(u64, nbits, arr.items.len);
try arr.*.appendNTimes(0, padding);
}
const testing = std.testing;
test "padding" {
try testing.expectEqual(roundUpPadding(u12, 2, 0), 0);
try testing.expectEqual(roundUpPadding(u12, 2, 1), 3);
try testing.expectEqual(roundUpPadding(u12, 2, 2), 2);
try testing.expectEqual(roundUpPadding(u12, 2, 3), 1);
try testing.expectEqual(roundUpPadding(u12, 2, 4), 0);
try testing.expectEqual(roundUpPadding(u12, 2, 40), 0);
try testing.expectEqual(roundUpPadding(u12, 2, 41), 3);
try testing.expectEqual(roundUpPadding(u12, 2, 42), 2);
try testing.expectEqual(roundUpPadding(u12, 2, 43), 1);
try testing.expectEqual(roundUpPadding(u12, 2, 44), 0);
try testing.expectEqual(roundUpPadding(u12, 2, 4091), 1);
try testing.expectEqual(roundUpPadding(u12, 2, 4092), 0);
try testing.expectEqual(until(u12, 2, 0), 0);
try testing.expectEqual(until(u12, 2, 1), 3);
try testing.expectEqual(until(u12, 2, 2), 2);
try testing.expectEqual(until(u12, 2, 3), 1);
try testing.expectEqual(until(u12, 2, 4), 0);
try testing.expectEqual(until(u12, 2, 40), 0);
try testing.expectEqual(until(u12, 2, 41), 3);
try testing.expectEqual(until(u12, 2, 42), 2);
try testing.expectEqual(until(u12, 2, 43), 1);
try testing.expectEqual(until(u12, 2, 44), 0);
try testing.expectEqual(until(u12, 2, 4091), 1);
try testing.expectEqual(until(u12, 2, 4092), 0);
}
test "arrayList" {

View File

@ -1,4 +1,5 @@
const std = @import("std");
const os = std.os;
const fmt = std.fmt;
const mem = std.mem;
const math = std.math;
@ -6,6 +7,7 @@ const sort = std.sort;
const assert = std.debug.assert;
const unicode = std.unicode;
const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
const ArrayListUnmanaged = std.ArrayListUnmanaged;
const ArrayList = std.ArrayList;
const MultiArrayList = std.MultiArrayList;
@ -30,8 +32,10 @@ const section_length = @import("header.zig").section_length;
const cmph = @import("cmph.zig");
const bdz = @import("bdz.zig");
const zeroes = &[_]u8{0} ** section_length;
const Corpus = struct {
arena: std.heap.ArenaAllocator,
arena: ArenaAllocator,
// sorted by name, by unicode codepoint
users: MultiArrayList(User),
@ -48,7 +52,7 @@ const Corpus = struct {
usersConst: []const User,
groupsConst: []const Group,
) error{ OutOfMemory, InvalidUtf8, Duplicate, NotFound }!Corpus {
var arena = std.heap.ArenaAllocator.init(baseAllocator);
var arena = ArenaAllocator.init(baseAllocator);
var allocator = arena.allocator();
errdefer arena.deinit();
@ -100,8 +104,8 @@ const Corpus = struct {
members.len = 0;
var it = groupmembers.iterator();
while (it.next()) |memberName| {
if (name2user.get(memberName.*)) |user_idx| {
while (it.next()) |member_name| {
if (name2user.get(member_name.*)) |user_idx| {
members.len += 1;
members[members.len - 1] = user_idx;
try user2groups[user_idx].append(allocator, @intCast(u32, i));
@ -429,7 +433,7 @@ pub const AllSections = struct {
idx_groupname2group: []const u32,
idx_uid2user: []const u32,
idx_name2user: []const u32,
header: Header,
header: []const u8,
pub fn init(
allocator: Allocator,
@ -452,13 +456,13 @@ pub const AllSections = struct {
const bdz_username = try cmph.packStr(allocator, unames);
errdefer allocator.free(bdz_username);
var shell_sections = try shellSections(allocator, corpus);
errdefer shell_sections.deinit();
var shell = try shellSections(allocator, corpus);
errdefer shell.deinit();
var additional_gids = try userGids(allocator, corpus);
errdefer additional_gids.deinit(allocator);
var users = try usersSection(allocator, corpus, &additional_gids, &shell_sections);
var users = try usersSection(allocator, corpus, &additional_gids, &shell);
errdefer users.deinit(allocator);
var groupmembers = try groupMembers(allocator, corpus, users.idx2offset);
@ -480,8 +484,8 @@ pub const AllSections = struct {
errdefer allocator.free(idx_name2user);
const header = Header{
.nblocks_shell_blob = nblocks(u8, shell_sections.blob.constSlice()),
.num_shells = shell_sections.len,
.nblocks_shell_blob = nblocks(u8, shell.blob.constSlice()),
.num_shells = shell.len,
.num_groups = groups.len,
.num_users = users.len,
.nblocks_bdz_gid = nblocks(u32, bdz_gid),
@ -500,10 +504,10 @@ pub const AllSections = struct {
.bdz_groupname = bdz_groupname,
.bdz_uid = bdz_uid,
.bdz_username = bdz_username,
.shell_sections = shell_sections,
.shell_sections = shell,
.shell_reader = ShellReader.init(
mem.sliceAsBytes(shell_sections.index.constSlice()),
mem.sliceAsBytes(shell_sections.blob.constSlice()),
mem.sliceAsBytes(shell.index.constSlice()),
mem.sliceAsBytes(shell.blob.constSlice()),
),
.additional_gids = additional_gids,
.users = users,
@ -513,10 +517,50 @@ pub const AllSections = struct {
.idx_groupname2group = idx_groupname2group,
.idx_uid2user = idx_uid2user,
.idx_name2user = idx_name2user,
.header = header,
.header = header.asBytes(),
};
}
pub fn iov(self: *const AllSections) error{OutOfMemory}![]os.iovec_const {
const sections = &[_][]const u8{
self.header,
self.bdz_gid,
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| {
result.appendAssumeCapacity(os.iovec_const{
.iov_base = section.ptr,
.iov_len = section.len,
});
const padding = pad.until(usize, section_length_bits, section.len);
if (padding != 0)
result.appendAssumeCapacity(.{
.iov_base = zeroes,
.iov_len = padding,
});
}
return result.toOwnedSlice();
}
pub fn deinit(self: *AllSections) void {
self.allocator.free(self.bdz_gid);
self.allocator.free(self.bdz_groupname);
@ -689,6 +733,9 @@ test "test groups, group members and users" {
try testing.expectEqualStrings(user.home, got.home());
try testing.expectEqualStrings(user.shell, got.shell(sections.shell_reader));
}
var iovec = try sections.iov();
allocator.free(iovec);
}
test "userGids" {
@ -738,7 +785,7 @@ test "pack gids" {
}
fn testUser(name: []const u8) User {
var result = std.mem.zeroes(User);
var result = mem.zeroes(User);
result.name = name;
return result;
}