diff --git a/src/header.zig b/src/header.zig index 6a6169a..be4c180 100644 --- a/src/header.zig +++ b/src/header.zig @@ -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); } }; diff --git a/src/padding.zig b/src/padding.zig index 73308a8..0ea3aa7 100644 --- a/src/padding.zig +++ b/src/padding.zig @@ -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" { diff --git a/src/sections.zig b/src/sections.zig index a8dfb19..474d4e7 100644 --- a/src/sections.zig +++ b/src/sections.zig @@ -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; }