diff --git a/src/PackedUser.zig b/src/PackedUser.zig index a3cb046..6b2fae6 100644 --- a/src/PackedUser.zig +++ b/src/PackedUser.zig @@ -81,7 +81,7 @@ additional_gids_offset: u64, pub const Entry = struct { user: PackedUser, - next: ?[]const u8, + end: usize, }; pub fn fromBytes(bytes: []const u8) Entry { @@ -93,37 +93,40 @@ pub fn fromBytes(bytes: []const u8) Entry { }; const end_blob = end_strings + gids_offset.bytes_read; - const nextStart = pad.roundUp(usize, alignment_bits, end_blob); - var next: ?[]const u8 = null; - if (nextStart < bytes.len) - next = bytes[nextStart..]; - return Entry{ .user = PackedUser{ .inner = inner, .bytes = bytes[start_blob..end_blob], .additional_gids_offset = gids_offset.value, }, - .next = next, + .end = pad.roundUp(usize, alignment_bits, end_blob), }; } pub const Iterator = struct { - section: ?[]const u8, + section: []const u8, + nextStart: usize = 0, shell_reader: ShellReader, + idx: u32 = 0, + total: u32, pub fn next(it: *Iterator) ?PackedUser { - if (it.section) |section| { - const entry = PackedUser.fromBytes(section); - it.section = entry.next; - return entry.user; - } - return null; + if (it.idx == it.total) + return null; + + const entry = PackedUser.fromBytes(it.section[it.nextStart..]); + it.nextStart += entry.end; + it.idx += 1; + return entry.user; } }; -pub fn iterator(section: []const u8, shell_reader: ShellReader) Iterator { - return Iterator{ .section = section, .shell_reader = shell_reader }; +pub fn iterator(section: []const u8, total: u32, shell_reader: ShellReader) Iterator { + return Iterator{ + .section = section, + .total = total, + .shell_reader = shell_reader, + }; } // packTo packs the User record and copies it to the given arraylist. @@ -289,7 +292,7 @@ test "construct PackedUser section" { } var i: u29 = 0; - var it1 = PackedUser.iterator(buf.items, test_shell_reader); + var it1 = PackedUser.iterator(buf.items, users.len, test_shell_reader); while (it1.next()) |user| : (i += 1) { try testing.expectEqual(users[i].uid, user.uid()); try testing.expectEqual(users[i].gid, user.gid()); diff --git a/src/User.zig b/src/User.zig index 5457bfc..8beefb5 100644 --- a/src/User.zig +++ b/src/User.zig @@ -92,7 +92,7 @@ fn strlen(self: *const User) usize { const line_fmt = "{s}:x:{d}:{d}:{s}:{s}:{s}\n"; -const max_line_len = fmt.count(line_fmt, .{ +pub const max_line_len = fmt.count(line_fmt, .{ max_user.name, max_user.uid, max_user.gid, @@ -136,7 +136,7 @@ pub fn fromReader(allocator: Allocator, err: *ErrCtx, reader: anytype) ![]User { users.deinit(); } - var buf: [max_line_len + 1]u8 = undefined; + var buf: [max_line_len]u8 = undefined; while (try reader.readUntilDelimiterOrEof(buf[0..], '\n')) |line| { var user = try fromLine(allocator, err, line); try users.append(user); diff --git a/src/libnss.zig b/src/libnss.zig index 90670df..3c62f58 100644 --- a/src/libnss.zig +++ b/src/libnss.zig @@ -267,7 +267,11 @@ fn setpwent(state: *State) void { defer state.getpwent_iterator_mu.unlock(); const db = state.file.db; - state.getpwent_iterator = PackedUser.iterator(db.users, db.shellReader()); + state.getpwent_iterator = PackedUser.iterator( + db.users, + db.header.num_users, + db.shellReader(), + ); } export fn _nss_turbo_endpwent() void { diff --git a/src/turbo-getent.zig b/src/turbo-getent.zig index 4cc8319..0d32c86 100644 --- a/src/turbo-getent.zig +++ b/src/turbo-getent.zig @@ -9,6 +9,7 @@ const flags = @import("flags.zig"); const DB = @import("DB.zig"); const File = @import("File.zig"); const PackedUser = @import("PackedUser.zig"); +const User = @import("User.zig"); const Mode = enum { group, passwd }; @@ -97,13 +98,10 @@ fn execute( } fn passwd(stdout: anytype, db: *const DB, keys: []const [*:0]const u8) u8 { - var some_notfound = false; - if (keys.len == 0) return passwd_all(stdout, db); - + var some_notfound = false; const shell_reader = db.shellReader(); - for (keys) |key| { const keyZ = mem.span(key); const maybe_packed_user = if (fmt.parseUnsigned(u32, keyZ, 10)) |uid| @@ -124,7 +122,7 @@ fn passwd(stdout: anytype, db: *const DB, keys: []const [*:0]const u8) u8 { } fn passwd_all(stdout: anytype, db: *const DB) u8 { - var it = PackedUser.iterator(db.users, db.shellReader()); + var it = PackedUser.iterator(db.users, db.header.num_users, db.shellReader()); while (it.next()) |packed_user| { const line = packed_user.toUser(db.shellReader()).toLine(); stdout.writeAll(line.constSlice()) catch return 3; @@ -132,9 +130,53 @@ fn passwd_all(stdout: anytype, db: *const DB) u8 { return 0; } +fn group(stdout: anytype, db: *const DB, keys: []const [*:0]const u8) u8 { + if (keys.len == 0) + return group_all(stdout, db); + + var some_notfound = false; + return if (some_notfound) 2 else 0; +} + +fn group_all(stdout: anytype, db: *const DB) u8 { + _ = stdout; + _ = db; + return 0; +} + const testing = std.testing; -test "passwd and passwd_all" { +test "passwd" { + var tf = try File.TestDB.init(testing.allocator); + defer tf.deinit(); + var stdout = ArrayList(u8).init(testing.allocator); + defer stdout.deinit(); + var stderr = ArrayList(u8).init(testing.allocator); + defer stderr.deinit(); + + { + const args = &[_][*:0]const u8{ + "--db", + tf.path, + "passwd", + "root", + "doesnotexist", + "vidmantas", + "0", + "1", + }; + const got = execute(stdout.writer(), stderr.writer(), args); + try testing.expectEqual(got, 2); + const want_root = "root:x:0:0::/root:/bin/bash\n"; + try testing.expectEqualStrings(stdout.items[0..want_root.len], want_root); + const want_vidmantas = "vidmantas:x:128:128:Vidmantas Kaminskas:/home/vidmantas:/bin/bash\n"; + var offset: usize = want_root.len + want_vidmantas.len; + try testing.expectEqualStrings(stdout.items[want_root.len..offset], want_vidmantas); + try testing.expectEqualStrings(stdout.items[offset..], want_root); + } +} + +test "passwd_all" { var tf = try File.TestDB.init(testing.allocator); defer tf.deinit(); var stdout = ArrayList(u8).init(testing.allocator); @@ -146,25 +188,25 @@ test "passwd and passwd_all" { "--db", tf.path, "passwd", - "root", - "doesnotexist", - "vidmantas", - "0", - "1", }; - const got = execute(stdout.writer(), stderr.writer(), args); - try testing.expectEqual(got, 2); - const want_root = "root:x:0:0::/root:/bin/bash\n"; - try testing.expectEqualStrings(stdout.items[0..want_root.len], want_root); - const want_vidmantas = "vidmantas:x:128:128:Vidmantas Kaminskas:/home/vidmantas:/bin/bash\n"; - var offset: usize = want_root.len + want_vidmantas.len; - try testing.expectEqualStrings(stdout.items[want_root.len..offset], want_vidmantas); - try testing.expectEqualStrings(stdout.items[offset..], want_root); -} + var buf: [User.max_line_len]u8 = undefined; -fn group(stdout: anytype, db: *const DB, keys: []const [*:0]const u8) u8 { - _ = db; - _ = stdout; - _ = keys; - return 0; + const got = execute(stdout.writer(), stderr.writer(), args); + try testing.expectEqual(got, 0); + + const want_names = &[_][]const u8{ + "Name" ** 8, + "nobody", + "root", + "svc-bar", + "vidmantas", + }; + + var i: usize = 0; + const reader = io.fixedBufferStream(stdout.items).reader(); + while (try reader.readUntilDelimiterOrEof(buf[0..], '\n')) |line| { + var name = mem.split(u8, line, ":"); + try testing.expectEqualStrings(want_names[i], name.next().?); + i += 1; + } }