add tests for upper limits
This commit is contained in:
parent
26fbfc5f08
commit
78dc63669d
34
README.md
34
README.md
|
@ -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
|
||||
|
|
20
src/user.zig
20
src/user.zig
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue