1
Fork 0

add tests for upper limits

This commit is contained in:
Motiejus Jakštys 2022-02-22 15:04:59 +02:00 committed by Motiejus Jakštys
parent 26fbfc5f08
commit 78dc63669d
2 changed files with 34 additions and 20 deletions

View File

@ -130,9 +130,10 @@ Now that we've sketched the implementation of `id(3)`, it's clearer to
understand which operations need to be fast; in order of importance:
1. lookup gid -> group info (this is on hot path in id) without members.
2. lookup uid -> user.
3. lookup groupname -> group.
4. lookup username -> user.
2. lookup username -> user's group memberships.
3. lookup uid -> user.
4. lookup groupname -> group.
5. lookup username -> user.
These indices can use perfect hashing like [bdz from cmph][cmph]: a perfect
hash hashes a list of bytes to a sequential list of integers. Perfect hashing
@ -292,8 +293,25 @@ Varint is an efficiently encoded integer (packed for small values). Same as
[protocol buffer varints][varint], except the largest possible value is `u64`.
They compress integers well.
`groupmembers`, `additional_gids`
---------------------------------
Group memberships
-----------------
There are two group memberships at play:
1. given a username, resolve user's group gids (for `initgroups(3)`).
2. given a group (gid/name), resolve the members' names (e.g. `getgrgid`).
When user's groups are resolved in (1), the additional userdata is not
requested (there is no way to return it). Therefore, it is reasonable to store
the user's memberships completely out-of-bound, keyed by the hash of the
username.
When group's memberships are resolved in (2), the same call also requires other
group information: gid and group name. Therefore it makes sense to store a
pointer to the group members in the group information itself. However, the
memberships are not *always* necessary (see remarks about `id(1)` in this
document), therefore the memberships will be stored separately, outside of the
groups section.
`groupmembers` and `additional_gids` store group and user memberships
respectively: for each group, a list of pointers (offsets) to User records, and
@ -307,16 +325,12 @@ pseudo-code:
```
const PackedList = struct {
length: varint,
members: []varint
members: [length]varint
}
const Groupmembers = PackedList;
const AdditionalGids = PackedList;
```
An entry in `members` field points to the offset into a respective `User` or
`Group` entry (number of bytes relative to the first entry of the type).
`members` in `PackedList` are sorted the same way as in the input.
A packed list is a list of varints.
Complete file structure

View File

@ -32,15 +32,15 @@ pub const PackedUser = packed struct {
}
pub fn realHomeLen(self: *const PackedUser) usize {
return self.home_len + 1;
return @as(u32, self.home_len) + 1;
}
pub fn realNameLen(self: *const PackedUser) usize {
return self.name_len + 1;
return @as(u32, self.name_len) + 1;
}
pub fn realShellLen(self: *const PackedUser) usize {
return self.shell_len_or_idx + 1;
return @as(u32, self.shell_len_or_idx) + 1;
}
pub fn realGecosLen(self: *const PackedUser) usize {
@ -180,7 +180,7 @@ pub const UserReader = struct {
if (u.name_is_a_suffix) {
const name_start = u.realHomeLen() - u.realNameLen();
name = entry.blob[name_start..u.realHomeLen()];
pos = u.home_len + 1;
pos = u.realHomeLen();
} else {
const name_start = u.realHomeLen();
name = entry.blob[name_start .. name_start + u.realNameLen()];
@ -269,12 +269,12 @@ test "construct PackedUser blob" {
.home = "/home/service1",
.shell = "/usr/bin/nologin",
}, User{
.uid = 1002,
.gid = 1002,
.name = "user-account",
.gecos = "",
.home = "/a",
.shell = "/bin/zsh",
.uid = 0,
.gid = 4294967295,
.name = "n" ** 32,
.gecos = "g" ** 255,
.home = "h" ** 64,
.shell = "s" ** 64,
} };
for (users) |user| {
try writer.appendUser(user);