1
Fork 0
turbonss/src/user.zig

77 lines
2.1 KiB
Zig

const std = @import("std");
const Allocator = std.mem.Allocator;
pub const PackedUserSize = @sizeOf(PackedUser);
pub const PackedUser = packed struct {
uid: u32,
gid: u32,
additional_gids_offset: u29,
shell_here: u1,
shell_len_or_place: u6,
homedir_len: u6,
username_is_a_suffix: u1,
username_offset_or_len: u5,
gecos_len: u8,
};
pub const User = struct {
uid: u32,
gid: u32,
name: []const u8,
gecos: []const u8,
home: []const u8,
shell: []const u8,
};
// UserWriter accepts a naive User struct and returns a PackedUser
pub const UserWriter = struct {
// shellIndexFnType is a signature for a function that accepts a shell
// string and returns it's index in the global shell section. Passing a
// function makes tests easier, and removes the Shell dependency of this
// module.
const shellIndexFnType = fn ([]const u8) ?u10;
allocator: Allocator,
shellIndexFn: shellIndexFnType,
pub fn init(allocator: Allocator, shellIndexFn: shellIndexFnType) UserWriter {
return UserWriter{
.allocator = allocator,
.shellIndexFn = shellIndexFn,
};
}
pub fn fromUser(self: *UserWriter, user: User) !PackedUser {
var shell_here: u1 = undefined;
var shell_len_or_place: u6 = undefined;
if (self.shellIndexFn(user.shell)) |idx| {
shell_here = false;
shell_len_or_place = idx;
} else {
shell_here = true;
shell_len_or_place = user.shell.len;
}
var puser = PackedUser{
.uid = user.uid,
.gid = user.gid,
.additional_gids_offset = 0, // second pass
.shell_here = shell_here,
.shell_len_or_place = shell_len_or_place,
.homedir_len = undefined,
.username_is_a_suffix = undefined,
.username_offset_or_len = undefined,
.gecos_len = undefined,
};
return puser;
}
};
const testing = std.testing;
test "PackedUser is byte-aligned" {
try testing.expectEqual(0, @rem(@bitSizeOf(PackedUser), 8));
}