diff --git a/lib/Corpus.zig b/lib/Corpus.zig index a622ee7..6c87f82 100644 --- a/lib/Corpus.zig +++ b/lib/Corpus.zig @@ -82,12 +82,11 @@ pub fn init( mem.set(ArrayListUnmanaged(u32), user2groups, ArrayListUnmanaged(u32){}); for (groups.items(.members)) |groupmembers, i| { - var members = try allocator.alloc(u32, groupmembers.count()); + var members = try allocator.alloc(u32, groupmembers.len); members.len = 0; - var it = groupmembers.iterator(); - while (it.next()) |member_name| { - if (name2user.get(member_name.*)) |user_idx| { + for (groupmembers) |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)); @@ -204,29 +203,10 @@ pub fn testCorpus(allocator: Allocator) !Corpus { .shell = "/usr/sbin/nologin", } }; - var members0 = try someMembers( - allocator, - &[_][]const u8{"root"}, - ); - defer members0.deinit(); - - var members1 = try someMembers( - allocator, - &[_][]const u8{"vidmantas"}, - ); - defer members1.deinit(); - - var members2 = try someMembers( - allocator, - &[_][]const u8{ "svc-bar", "vidmantas" }, - ); - defer members2.deinit(); - - var members3 = try someMembers( - allocator, - &[_][]const u8{ "svc-bar", "Name" ** 8, "vidmantas", "root" }, - ); - defer members3.deinit(); + var members0 = &[_][]const u8{"root"}; + var members1 = &[_][]const u8{"vidmantas"}; + var members2 = &[_][]const u8{ "svc-bar", "vidmantas" }; + var members3 = &[_][]const u8{ "svc-bar", "Name" ** 8, "vidmantas", "root" }; const groups = [_]Group{ Group{ .gid = 0, .name = "root", .members = members0 }, diff --git a/lib/DB.zig b/lib/DB.zig index 543f347..a4a0f1e 100644 --- a/lib/DB.zig +++ b/lib/DB.zig @@ -218,6 +218,21 @@ pub fn fromBytes(buf: []align(8) const u8) InvalidHeader!DB { return result; } +// getgrtnam returns a Group entry by name +fn getgrnam(self: *const DB, name: []const u8) ?Group { + const idx = bdz.search(self.bdz_groupname); + const offset = self.idx_groupname2group[idx]; + const entry = PackedGroup.fromBytes(self.groups[offset..]); + if (!mem.eql(name, entry.group.name())) + return null; + + return Group{ + .name = name, + .gid = entry.group.gid(), + .members = null, + }; +} + fn shellSections( allocator: Allocator, corpus: *const Corpus, diff --git a/lib/Group.zig b/lib/Group.zig index d2c115f..ab8aaab 100644 --- a/lib/Group.zig +++ b/lib/Group.zig @@ -2,79 +2,70 @@ const std = @import("std"); const mem = std.mem; const Allocator = mem.Allocator; -const BufSet = std.BufSet; const Group = @This(); gid: u32, name: []const u8, -members: BufSet, +members: []const []const u8, +_members_buf: []const u8 = undefined, pub fn clone(self: *const Group, allocator: Allocator) Allocator.Error!Group { - var name = try allocator.dupe(u8, self.name); + const total_members_len = blk: { + var sum: usize = 0; + for (self.members) |member| sum += member.len; + break :blk sum; + }; + var members = try allocator.alloc([]const u8, self.members.len); + errdefer allocator.free(members); + members.len = self.members.len; + + var buf = try allocator.alloc(u8, total_members_len); + errdefer allocator.free(buf); + buf.len = 0; + + for (self.members) |member, i| { + const old_len = buf.len; + buf.len += member.len; + mem.copy(u8, buf[old_len..], member); + members[i] = buf[old_len..buf.len]; + } + return Group{ .gid = self.gid, - .name = name, - .members = try self.members.cloneWithAllocator(allocator), + .name = try allocator.dupe(u8, self.name), + .members = members, + ._members_buf = buf, }; } pub fn deinit(self: *Group, allocator: Allocator) void { allocator.free(self.name); - self.members.deinit(); + allocator.free(self.members); + allocator.free(self._members_buf); self.* = undefined; } -// someMembers constructs a bufset from an allocator and a list of strings. -pub fn someMembers( - allocator: Allocator, - members: []const []const u8, -) Allocator.Error!BufSet { - var bufset = BufSet.init(allocator); - errdefer bufset.deinit(); - for (members) |member| - try bufset.insert(member); - return bufset; -} - -// cloneArray clones an array of strings. This may be needed -// to change members to []const []const u8 -fn cloneArray(allocator: Allocator, arr: []const []const u8) error{OutOfMemory}![]const []const u8 { - const total_len = blk: { - var sum: usize = 0; - for (arr) |elem| sum += elem.len; - break :blk sum; - }; - var buf = try allocator.alloc(u8, total_len); - var ret = try allocator.alloc([]const u8, arr.len); - ret.len = arr.len; - for (arr) |elem, i| { - const old_len = buf.len; - mem.copy(u8, buf[old_len..], elem); - ret[i] = buf[old_len .. old_len + elem.len]; - } - return ret; -} - const testing = std.testing; test "Group.clone" { - var allocator = testing.allocator; - var arena = std.heap.ArenaAllocator.init(allocator); - defer arena.deinit(); + // TODO: how to do this on stack? + var member1 = try testing.allocator.dupe(u8, "member1"); + defer testing.allocator.free(member1); - var members = BufSet.init(allocator); - try members.insert("member1"); - try members.insert("member2"); - defer members.deinit(); + var group = Group{ + .gid = 1, + .name = "foo", + .members = &[_][]const u8{ member1, "member2" }, + }; - var cloned = try members.cloneWithAllocator(arena.allocator()); + var cloned = try group.clone(testing.allocator); + defer cloned.deinit(testing.allocator); - cloned.remove("member1"); - try cloned.insert("member4"); - try testing.expect(members.contains("member1")); - try testing.expect(!members.contains("member4")); - - try testing.expect(!cloned.contains("member1")); - try testing.expect(cloned.contains("member4")); + group.gid = 2; + group.name = "bar"; + member1[0] = 'x'; + try testing.expectEqual(cloned.gid, 1); + try testing.expectEqualSlices(u8, cloned.name, "foo"); + try testing.expectEqualSlices(u8, cloned.members[0], "member1"); }