wip writing of users

This commit is contained in:
Motiejus Jakštys 2022-03-06 13:11:06 +02:00 committed by Motiejus Jakštys
parent e3fd1c833c
commit a6349cd114
2 changed files with 43 additions and 32 deletions

View File

@ -232,25 +232,27 @@ pub fn userGids(allocator: Allocator, corpus: *const Corpus) userGidsErr!UserGid
var name2offset = StringHashMap(u32).init(allocator);
errdefer name2offset.deinit();
// zero'th entry is empty, so groupless users can refer to it.
try compress.appendUvarint(&blob, 0);
var scratch = try allocator.alloc(u32, 256);
defer allocator.free(scratch);
for (corpus.users) |user| {
const usergroups_maybe = corpus.username2groups.get(user.name);
if (usergroups_maybe == null)
continue;
const usergroups = usergroups_maybe.?;
try name2offset.putNoClobber(user.name, try math.cast(u32, blob.items.len));
scratch = try allocator.realloc(scratch, usergroups.len);
scratch.len = usergroups.len;
for (usergroups) |group, i|
scratch[i] = group.gid;
compress.deltaCompress(u32, scratch) catch |err| switch (err) {
error.NotSorted => unreachable,
};
try compress.appendUvarint(&blob, usergroups.len);
for (scratch) |gid|
try compress.appendUvarint(&blob, gid);
if (corpus.username2groups.get(user.name)) |usergroups| {
try name2offset.putNoClobber(user.name, try math.cast(u32, blob.items.len));
scratch = try allocator.realloc(scratch, usergroups.len);
scratch.len = usergroups.len;
for (usergroups) |group, i|
scratch[i] = group.gid;
compress.deltaCompress(u32, scratch) catch |err| switch (err) {
error.NotSorted => unreachable,
};
try compress.appendUvarint(&blob, usergroups.len);
for (scratch) |gid|
try compress.appendUvarint(&blob, gid);
} else {
try name2offset.putNoClobber(user.name, 0);
}
}
return UserGids{
@ -259,18 +261,25 @@ pub fn userGids(allocator: Allocator, corpus: *const Corpus) userGidsErr!UserGid
};
}
pub const usersSectionErr = Allocator.Error || error{Overflow};
pub fn usersSection(
allocator: Allocator,
corpus: *const Corpus,
gids: *const UserGids,
shells: *const ShellSections,
) usersSectionErr![]const u8 {
) error{ OutOfMemory, Overflow }![]const u8 {
// as of writing each user takes 15 bytes + strings + padding, padded to
// 8 bytes. 24 is a very optimistic lower bound.
// 8 bytes. 24 is an optimistic lower bound for an average record size.
var buf = try ArrayList(u8).initCapacity(allocator, 24 * corpus.users.len);
_ = gids;
_ = shells;
for (corpus.users) |user| {
const offset = gids.name2offset.get(user.name).?;
std.debug.assert(offset & 7 == 0);
try userImport.PackedUserConst.packTo(
&buf,
user,
@truncate(u29, @shrExact(offset, 3)),
shells.indices.get,
);
}
return buf.toOwnedSlice();
}

View File

@ -6,6 +6,7 @@ const InvalidRecord = validate.InvalidRecord;
const assert = std.debug.assert;
const mem = std.mem;
const math = std.math;
const Allocator = mem.Allocator;
const ArrayList = std.ArrayList;
@ -196,6 +197,7 @@ fn packedUser(immutable: bool) type {
pub fn packTo(
arr: *ArrayList(u8),
user: User,
additional_gids_offset: u29,
idxFn: shell2idxProto,
) packErr!void {
// function arguments are consts. We need to mutate the underlying
@ -213,7 +215,7 @@ fn packedUser(immutable: bool) type {
const inner = Inner{
.uid = user.uid,
.gid = user.gid,
.additional_gids_offset = std.math.maxInt(u29),
.additional_gids_offset = additional_gids_offset,
.shell_here = idxFn(user.shell) == null,
.shell_len_or_idx = idxFn(user.shell) orelse shell_len,
.home_len = home_len,
@ -241,10 +243,10 @@ fn packedUser(immutable: bool) type {
pub fn maxSize() usize {
comptime {
const unpadded = InnerSize +
std.math.maxInt(u6) + 1 + // home
std.math.maxInt(u5) + 1 + // name
std.math.maxInt(u6) + 1 + // shell
std.math.maxInt(u8); // gecos
math.maxInt(u6) + 1 + // home
math.maxInt(u5) + 1 + // name
math.maxInt(u6) + 1 + // shell
math.maxInt(u8); // gecos
return pad.roundUp(u64, alignmentBits, unpadded);
}
}
@ -346,7 +348,7 @@ test "construct PackedUser section" {
.shell = "/usr/bin/nologin",
}, User{
.uid = 0,
.gid = std.math.maxInt(u32),
.gid = math.maxInt(u32),
.name = "Name" ** 8,
.gecos = "Gecos" ** 51,
.home = "Home" ** 16,
@ -360,7 +362,7 @@ test "construct PackedUser section" {
.shell = "/",
} };
for (users) |user|
try PackedUserConst.packTo(&buf, user, testShellIndex);
try PackedUserConst.packTo(&buf, user, math.maxInt(u29), testShellIndex);
var i: u29 = 0;
var it1 = PackedUserConst.iterator(buf.items, testShell);
@ -368,7 +370,7 @@ test "construct PackedUser section" {
try testing.expectEqual(users[i].uid, user.uid());
try testing.expectEqual(users[i].gid, user.gid());
try testing.expectEqual(
@as(u29, std.math.maxInt(u29)),
@as(u29, math.maxInt(u29)),
user.additionalGidsOffset(),
);
try testing.expectEqualStrings(users[i].name, user.name());
@ -405,14 +407,14 @@ test "PackedUser.maxSize()" {
defer buf.deinit();
const largeUser = User{
.uid = std.math.maxInt(u32),
.gid = std.math.maxInt(u32),
.uid = math.maxInt(u32),
.gid = math.maxInt(u32),
.name = "Name" ** 8, // 32
.gecos = "Gecos" ** 51, // 255
.home = "Home" ** 16, // 64
.shell = "She.LllL" ** 8, // 64
};
try PackedUserConst.packTo(&buf, largeUser, testShellIndex);
try PackedUserConst.packTo(&buf, largeUser, math.maxInt(u29), testShellIndex);
try testing.expectEqual(PackedUserConst.maxSize(), buf.items.len);
}