diff --git a/src/user.zig b/src/user.zig index e54aa47..44b24fc 100644 --- a/src/user.zig +++ b/src/user.zig @@ -1,6 +1,7 @@ const std = @import("std"); const Allocator = std.mem.Allocator; +const ArrayList = std.ArrayList; const cast = std.math.cast; pub const PackedUserSize = @divExact(@bitSizeOf(PackedUser), 8); @@ -27,81 +28,50 @@ pub const User = struct { // 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) ?u6; - allocator: Allocator, + appendTo: ArrayList(u8), shellIndexFn: shellIndexFnType, - pub fn init(allocator: Allocator, shellIndexFn: shellIndexFnType) UserWriter { + pub fn init(appendTo: ArrayList(u8), shellIndexFn: shellIndexFnType) UserWriter { return UserWriter{ - .allocator = allocator, + .appendTo = appendTo, .shellIndexFn = shellIndexFn, }; } - const fromUserErr = std.mem.Allocator.Error || error{InvalidRecord}; + const fromUserErr = error{InvalidRecord}; - pub fn fromUser(self: *UserWriter, user: User) fromUserErr![]const u8 { - const home_len = std.math.cast(u6, user.home.len - 1) catch return error.InvalidRecord; + pub fn appendUser(self: *UserWriter, user: User) !void { + const home_len = cast(u6, user.home.len - 1) catch return error.InvalidRecord; const name_len = cast(u5, user.name.len - 1) catch return error.InvalidRecord; const shell_len = cast(u6, user.shell.len - 1) catch return error.InvalidRecord; const gecos_len = cast(u8, user.gecos.len) catch return error.InvalidRecord; - var bindata_len: u32 = home_len; var puser = PackedUser{ - .uid = @as(u32, user.uid), - .gid = @as(u32, user.gid), + .uid = user.uid, + .gid = user.gid, .additional_gids_offset = std.math.maxInt(u29), // needs second pass - .shell_here = undefined, - .shell_len_or_idx = undefined, + .shell_here = self.shellIndexFn(user.shell) == null, + .shell_len_or_idx = self.shellIndexFn(user.shell) orelse shell_len, .home_len = home_len, - .name_is_a_suffix = undefined, + .name_is_a_suffix = std.mem.endsWith(u8, user.home, user.name), .name_len = name_len, .gecos_len = gecos_len, }; - if (std.mem.endsWith(u8, user.home, user.name)) { - puser.name_is_a_suffix = true; - } else { - puser.name_is_a_suffix = false; - bindata_len += name_len; - } - - bindata_len += gecos_len; - - if (self.shellIndexFn(user.shell)) |idx| { - puser.shell_here = false; - puser.shell_len_or_idx = idx; - } else { - puser.shell_here = true; - puser.shell_len_or_idx = shell_len; - bindata_len += shell_len; - } - - var result = try self.allocator.alloc(u8, PackedUserSize + bindata_len); - - const userPointer = @ptrCast([*]const u8, &puser); - { - var i: u32 = 0; - while (i < PackedUserSize) { - result[i] = userPointer[i]; - i += 1; - } - } - std.mem.copy(u8, result, user.home); + try self.appendTo.appendSlice(std.mem.asBytes(&puser)); + try self.appendTo.appendSlice(user.home); if (!puser.name_is_a_suffix) { - std.mem.copy(u8, result, user.name); + try self.appendTo.appendSlice(user.name); } - std.mem.copy(u8, result, user.gecos); + try self.appendTo.appendSlice(user.gecos); if (puser.shell_here) { - std.mem.copy(u8, result, user.shell); + try self.appendTo.appendSlice(user.shell); } - - return result; } }; @@ -121,7 +91,10 @@ fn testShellIndex(shell: []const u8) ?u6 { } test "construct PackedUser blob" { - var writer = UserWriter.init(testing.allocator, testShellIndex); + var buf = ArrayList(u8).init(testing.allocator); + defer buf.deinit(); + + var writer = UserWriter.init(buf, testShellIndex); const user1 = User{ .uid = 1000, .gid = 1000, @@ -138,8 +111,6 @@ test "construct PackedUser blob" { .home = "/home/service1", .shell = "/usr/bin/nologin", }; - const puser1 = try writer.fromUser(user1); - const puser2 = try writer.fromUser(user2); - defer testing.allocator.free(puser1); - defer testing.allocator.free(puser2); + try writer.appendUser(user1); + try writer.appendUser(user2); }