diff --git a/src/DB.zig b/src/DB.zig index b81ea93..5a2665f 100644 --- a/src/DB.zig +++ b/src/DB.zig @@ -204,39 +204,73 @@ pub fn iov(self: *const DB) BoundedArray(os.iovec_const, DB_fields.len * 2) { return result; } -pub fn fromBytes(buf: []align(8) const u8) InvalidHeader!DB { - const header = try Header.fromBytes(buf[0..@sizeOf(Header)]); - // At first the tuple below had field names too, but moved it to comments, - // because it segfaulted. https://github.com/ziglang/zig/issues/3915 and - // https://paste.sr.ht/~motiejus/2830736e796801517c1fa8639be6615cd56ada27 - const lengths = .{ - header.nblocks_bdz_gid, // bdz_gid - header.nblocks_bdz_groupname, // bdz_groupname - header.nblocks_bdz_uid, // bdz_uid - header.nblocks_bdz_username, // bdz_username - nblocks_n(u32, header.num_groups * 4), // idx_gid2group - nblocks_n(u32, header.num_groups * 4), // idx_groupname2group - nblocks_n(u32, header.num_users * 4), // idx_uid2user - nblocks_n(u32, header.num_users * 4), // idx_name2user - nblocks_n(u16, header.num_shells * 2), // shell_index - header.nblocks_shell_blob, // shell_blob - header.nblocks_groups, // groups - header.nblocks_users, // users - header.nblocks_groupmembers, // groupmembers - header.nblocks_additional_gids, // additional_gids - }; +const DBNumbers = struct { + header: u64, + bdz_gid: u64, + bdz_groupname: u64, + bdz_uid: u64, + bdz_username: u64, + idx_gid2group: u64, + idx_groupname2group: u64, + idx_uid2user: u64, + idx_name2user: u64, + shell_index: u64, + shell_blob: u64, + groups: u64, + users: u64, + groupmembers: u64, + additional_gids: u64, +}; - var result: DB = undefined; - result.header = header; +// in blocks +fn fieldLengths(header: *const Header) DBNumbers { + return DBNumbers{ + .header = undefined, + .bdz_gid = header.nblocks_bdz_gid, + .bdz_groupname = header.nblocks_bdz_groupname, + .bdz_uid = header.nblocks_bdz_uid, + .bdz_username = header.nblocks_bdz_username, + .idx_gid2group = nblocks_n(u32, header.num_groups * 4), + .idx_groupname2group = nblocks_n(u32, header.num_groups * 4), + .idx_uid2user = nblocks_n(u32, header.num_users * 4), + .idx_name2user = nblocks_n(u32, header.num_users * 4), + .shell_index = nblocks_n(u16, header.num_shells * 2), + .shell_blob = header.nblocks_shell_blob, + .groups = header.nblocks_groups, + .users = header.nblocks_users, + .groupmembers = header.nblocks_groupmembers, + .additional_gids = header.nblocks_additional_gids, + }; +} + +// in blocks +fn fieldOffsets(lengths: DBNumbers) DBNumbers { + var result: DBNumbers = undefined; + result.header = 0; var offset = comptime nblocks_n(u64, @sizeOf(Header)); comptime assert(mem.eql(u8, DB_fields[0].name, "header")); inline for (DB_fields[1..]) |field, i| { - const start = offset << section_length_bits; - const end = (offset + lengths[i]) << section_length_bits; + comptime assert(mem.eql(u8, field.name, meta.fields(DBNumbers)[i + 1].name)); + @field(result, field.name) = offset; + offset += @field(lengths, field.name); + } + return result; +} + +pub fn fromBytes(buf: []align(8) const u8) InvalidHeader!DB { + const header = try Header.fromBytes(buf[0..@sizeOf(Header)]); + const lengths = fieldLengths(header); + const offsets = fieldOffsets(lengths); + + var result: DB = undefined; + result.header = header; + inline for (DB_fields[1..]) |field| { + const start_block = @field(offsets, field.name); + const end = (start_block + @field(lengths, field.name)) << section_length_bits; + const start = start_block << section_length_bits; const slice_type = meta.Child(field.field_type); const value = mem.bytesAsSlice(slice_type, buf[start..end]); @field(result, field.name) = value; - offset += lengths[i]; } return result;