cloning users and groups
This commit is contained in:
parent
7df1296ce1
commit
3c4455efeb
|
@ -7,11 +7,28 @@ const InvalidRecord = validate.InvalidRecord;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
const ArrayList = std.ArrayList;
|
const ArrayList = std.ArrayList;
|
||||||
|
const BufSet = std.BufSet;
|
||||||
|
|
||||||
pub const Group = struct {
|
pub const Group = struct {
|
||||||
gid: u32,
|
gid: u32,
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
members: std.BufSet,
|
members: BufSet,
|
||||||
|
|
||||||
|
pub fn clone(self: *const Group, allocator: Allocator) Allocator.Error!Group {
|
||||||
|
var name = try allocator.alloc(u8, self.name.len);
|
||||||
|
mem.copy(u8, name, self.name);
|
||||||
|
return Group{
|
||||||
|
.gid = self.gid,
|
||||||
|
.name = name,
|
||||||
|
.members = try self.members.cloneWithAllocator(allocator),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Group, allocator: Allocator) void {
|
||||||
|
allocator.free(self.name);
|
||||||
|
self.members.deinit();
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const GroupStored = struct {
|
const GroupStored = struct {
|
||||||
|
@ -119,6 +136,18 @@ const PackedGroup = struct {
|
||||||
|
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
for (members) |member| {
|
||||||
|
try bufset.insert(member);
|
||||||
|
}
|
||||||
|
return bufset;
|
||||||
|
}
|
||||||
|
|
||||||
test "PackedGroup alignment" {
|
test "PackedGroup alignment" {
|
||||||
try testing.expectEqual(@sizeOf(PackedGroup) * 8, @bitSizeOf(PackedGroup));
|
try testing.expectEqual(@sizeOf(PackedGroup) * 8, @bitSizeOf(PackedGroup));
|
||||||
}
|
}
|
||||||
|
@ -155,3 +184,24 @@ test "construct PackedGroups" {
|
||||||
try testing.expectEqual(groups.len, i);
|
try testing.expectEqual(groups.len, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "Group.clone" {
|
||||||
|
var allocator = testing.allocator;
|
||||||
|
var arena = std.heap.ArenaAllocator.init(allocator);
|
||||||
|
defer arena.deinit();
|
||||||
|
|
||||||
|
var members = BufSet.init(allocator);
|
||||||
|
try members.insert("member1");
|
||||||
|
try members.insert("member2");
|
||||||
|
defer members.deinit();
|
||||||
|
|
||||||
|
var cloned = try members.cloneWithAllocator(arena.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"));
|
||||||
|
}
|
||||||
|
|
|
@ -44,8 +44,12 @@ const Corpus = struct {
|
||||||
|
|
||||||
var users = try allocator.alloc(User, usersConst.len);
|
var users = try allocator.alloc(User, usersConst.len);
|
||||||
var groups = try allocator.alloc(Group, groupsConst.len);
|
var groups = try allocator.alloc(Group, groupsConst.len);
|
||||||
std.mem.copy(User, users, usersConst);
|
for (usersConst) |user, i| {
|
||||||
std.mem.copy(Group, groups, groupsConst);
|
users[i] = try user.clone(allocator);
|
||||||
|
}
|
||||||
|
for (groupsConst) |group, i| {
|
||||||
|
groups[i] = try group.clone(allocator);
|
||||||
|
}
|
||||||
|
|
||||||
sort.sort(User, users, {}, cmpUser);
|
sort.sort(User, users, {}, cmpUser);
|
||||||
sort.sort(Group, groups, {}, cmpGroup);
|
sort.sort(Group, groups, {}, cmpGroup);
|
||||||
|
@ -84,8 +88,10 @@ const Corpus = struct {
|
||||||
var groupname2users = StringHashMap(ArrayList(*const User)).init(allocator);
|
var groupname2users = StringHashMap(ArrayList(*const User)).init(allocator);
|
||||||
var username2groups = StringHashMap(ArrayList(*const Group)).init(allocator);
|
var username2groups = StringHashMap(ArrayList(*const Group)).init(allocator);
|
||||||
for (groups) |group| {
|
for (groups) |group| {
|
||||||
const cnt = group.members.count();
|
var members = try ArrayList(*const User).initCapacity(
|
||||||
var members = try ArrayList(*const User).initCapacity(allocator, cnt);
|
allocator,
|
||||||
|
group.members.count(),
|
||||||
|
);
|
||||||
|
|
||||||
var it = group.members.iterator();
|
var it = group.members.iterator();
|
||||||
while (it.next()) |memberName| {
|
while (it.next()) |memberName| {
|
||||||
|
@ -95,15 +101,11 @@ const Corpus = struct {
|
||||||
return error.NotFound;
|
return error.NotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
var groupUsers: *ArrayList(*const Group) = undefined;
|
var groupsOfMember = try username2groups.getOrPut(memberName.*);
|
||||||
var result = try username2groups.getOrPut(memberName.*);
|
if (!groupsOfMember.found_existing) {
|
||||||
if (!result.found_existing) {
|
groupsOfMember.value_ptr.* = ArrayList(*const Group).init(allocator);
|
||||||
groupUsers = &ArrayList(*const Group).init(allocator);
|
|
||||||
result.value_ptr = groupUsers;
|
|
||||||
} else {
|
|
||||||
groupUsers = result.value_ptr;
|
|
||||||
}
|
}
|
||||||
try groupUsers.*.append(&group);
|
try groupsOfMember.value_ptr.*.append(&group);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = try groupname2users.getOrPut(group.name);
|
var result = try groupname2users.getOrPut(group.name);
|
||||||
|
@ -156,14 +158,6 @@ fn cmpGroup(_: void, a: Group, b: Group) bool {
|
||||||
|
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
|
||||||
fn someMembers(allocator: Allocator, members: []const []const u8) !BufSet {
|
|
||||||
var bufset = BufSet.init(allocator);
|
|
||||||
for (members) |member| {
|
|
||||||
try bufset.insert(member);
|
|
||||||
}
|
|
||||||
return bufset;
|
|
||||||
}
|
|
||||||
|
|
||||||
test "test corpus" {
|
test "test corpus" {
|
||||||
const allocator = testing.allocator;
|
const allocator = testing.allocator;
|
||||||
|
|
||||||
|
@ -190,13 +184,22 @@ test "test corpus" {
|
||||||
.shell = "/",
|
.shell = "/",
|
||||||
} };
|
} };
|
||||||
|
|
||||||
var members1 = try someMembers(allocator, &[_][]const u8{"vidmantas"});
|
var members1 = try groupImport.someMembers(
|
||||||
|
allocator,
|
||||||
|
&[_][]const u8{"vidmantas"},
|
||||||
|
);
|
||||||
defer members1.deinit();
|
defer members1.deinit();
|
||||||
|
|
||||||
var members2 = try someMembers(allocator, &[_][]const u8{ "svc-bar", "Name" ** 8 });
|
var members2 = try groupImport.someMembers(
|
||||||
|
allocator,
|
||||||
|
&[_][]const u8{ "svc-bar", "Name" ** 8 },
|
||||||
|
);
|
||||||
defer members2.deinit();
|
defer members2.deinit();
|
||||||
|
|
||||||
var members3 = try someMembers(allocator, &[_][]const u8{});
|
var members3 = try groupImport.someMembers(
|
||||||
|
allocator,
|
||||||
|
&[_][]const u8{ "svc-bar", "Name" ** 8, "vidmantas" },
|
||||||
|
);
|
||||||
defer members3.deinit();
|
defer members3.deinit();
|
||||||
|
|
||||||
var groups = [_]Group{ Group{
|
var groups = [_]Group{ Group{
|
||||||
|
@ -209,7 +212,7 @@ test "test corpus" {
|
||||||
.members = members2,
|
.members = members2,
|
||||||
}, Group{
|
}, Group{
|
||||||
.gid = 9999,
|
.gid = 9999,
|
||||||
.name = "empty",
|
.name = "all",
|
||||||
.members = members3,
|
.members = members3,
|
||||||
} };
|
} };
|
||||||
|
|
||||||
|
@ -218,6 +221,17 @@ test "test corpus" {
|
||||||
try testing.expectEqualStrings(corpus.users[0].name, "Name" ** 8);
|
try testing.expectEqualStrings(corpus.users[0].name, "Name" ** 8);
|
||||||
try testing.expectEqualStrings(corpus.users[1].name, "svc-bar");
|
try testing.expectEqualStrings(corpus.users[1].name, "svc-bar");
|
||||||
try testing.expectEqualStrings(corpus.users[2].name, "vidmantas");
|
try testing.expectEqualStrings(corpus.users[2].name, "vidmantas");
|
||||||
|
|
||||||
|
//if (corpus.uid2user.get(1000)) |user| {
|
||||||
|
// std.debug.print("user: {s}\n", .{user});
|
||||||
|
// std.debug.print("user.*.name: {d}\n", .{user.*.name});
|
||||||
|
// try testing.expectEqualStrings(user.*.name, "vidmantas");
|
||||||
|
//} else {
|
||||||
|
// try testing.expect(false);
|
||||||
|
//}
|
||||||
|
//try testing.expectEqualStrings(corpus.uid2user.get(1000).?.name, "vidmantas");
|
||||||
|
//try testing.expectEqualStrings(corpus.uid2user.get(0).?.name, "Name" ** 8);
|
||||||
|
//try testing.expectEqualStrings(corpus.uid2user.get(1002).?.name, "svc-bar");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testUser(name: []const u8) User {
|
fn testUser(name: []const u8) User {
|
||||||
|
|
56
src/user.zig
56
src/user.zig
|
@ -21,6 +21,44 @@ pub const User = struct {
|
||||||
gecos: []const u8,
|
gecos: []const u8,
|
||||||
home: []const u8,
|
home: []const u8,
|
||||||
shell: []const u8,
|
shell: []const u8,
|
||||||
|
|
||||||
|
// deep-clones a User record with a given Allocator.
|
||||||
|
pub fn clone(self: *const User, allocator: Allocator) Allocator.Error!User {
|
||||||
|
const stringdata = try allocator.alloc(u8, self.stringdata_len());
|
||||||
|
//std.debug.print("\nptr to stringdata: {d}\n", .{@ptrToInt(stringdata.ptr)});
|
||||||
|
const gecos_start = self.name.len;
|
||||||
|
const home_start = gecos_start + self.gecos.len;
|
||||||
|
const shell_start = home_start + self.shell.len;
|
||||||
|
mem.copy(u8, stringdata[0..self.name.len], self.name);
|
||||||
|
mem.copy(u8, stringdata[gecos_start..], self.gecos);
|
||||||
|
mem.copy(u8, stringdata[home_start..], self.home);
|
||||||
|
mem.copy(u8, stringdata[shell_start..], self.shell);
|
||||||
|
|
||||||
|
const u = User{
|
||||||
|
.uid = self.uid,
|
||||||
|
.gid = self.gid,
|
||||||
|
.name = stringdata[0..self.name.len],
|
||||||
|
.gecos = stringdata[gecos_start .. gecos_start + self.gecos.len],
|
||||||
|
.home = stringdata[home_start .. home_start + self.home.len],
|
||||||
|
.shell = stringdata[shell_start .. shell_start + self.shell.len],
|
||||||
|
};
|
||||||
|
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stringdata_len(self: *const User) usize {
|
||||||
|
return self.name.len +
|
||||||
|
self.gecos.len +
|
||||||
|
self.home.len +
|
||||||
|
self.shell.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *const User, allocator: Allocator) void {
|
||||||
|
//allocator.free(self.stringdata);
|
||||||
|
//self.* = undefined;
|
||||||
|
const slice = self.home.ptr[0..self.stringdata_len()];
|
||||||
|
allocator.free(slice);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const PackedUserMut = packedUser(false);
|
pub const PackedUserMut = packedUser(false);
|
||||||
|
@ -389,3 +427,21 @@ test "PackedUser.maxSize()" {
|
||||||
try PackedUserConst.packTo(&buf, largeUser, testShellIndex);
|
try PackedUserConst.packTo(&buf, largeUser, testShellIndex);
|
||||||
try testing.expectEqual(PackedUserConst.maxSize(), buf.items.len);
|
try testing.expectEqual(PackedUserConst.maxSize(), buf.items.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "User.clone" {
|
||||||
|
var allocator = testing.allocator;
|
||||||
|
const user = User{
|
||||||
|
.uid = 1000,
|
||||||
|
.gid = 1000,
|
||||||
|
.name = "vidmantas",
|
||||||
|
.gecos = "Vidmantas Kaminskas",
|
||||||
|
.home = "/home/vidmantas",
|
||||||
|
.shell = "/bin/bash",
|
||||||
|
};
|
||||||
|
var user2 = try user.clone(allocator);
|
||||||
|
user2.shell = "/bin/zsh";
|
||||||
|
|
||||||
|
defer user2.deinit(allocator);
|
||||||
|
|
||||||
|
try testing.expectEqualStrings(user.shell, "/bin/bash");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue