working on iterator

This commit is contained in:
Motiejus Jakštys 2022-02-20 13:17:05 +02:00 committed by Motiejus Jakštys
parent 54ec710f10
commit f2434e3d3c
3 changed files with 89 additions and 39 deletions

View File

@ -1,19 +1,19 @@
const std = @import("std"); const std = @import("std");
const assert = std.debug.assert; const assert = std.debug.assert;
// rounds up a u12 to the nearest factor of 4 and returns the difference // rounds up an int to the nearest factor of nbits.
// (padding)
pub fn roundUpPadding(comptime T: type, comptime nbits: u8, n: T) T {
return roundUp(T, nbits, n) - n;
}
// rounds up a u12 to the nearest factor of 4.
pub fn roundUp(comptime T: type, comptime nbits: u8, n: T) T { pub fn roundUp(comptime T: type, comptime nbits: u8, n: T) T {
comptime assert(nbits < @bitSizeOf(T)); comptime assert(nbits < @bitSizeOf(T));
const factor = comptime (1 << nbits) - 1; const factor = comptime (1 << nbits) - 1;
return ((n + factor) & ~@as(T, factor)); return ((n + factor) & ~@as(T, factor));
} }
// rounds up an integer to the nearest factor of nbits and returns the
// difference (padding)
pub fn roundUpPadding(comptime T: type, comptime nbits: u8, n: T) T {
return roundUp(T, nbits, n) - n;
}
const testing = std.testing; const testing = std.testing;
test "padding" { test "padding" {

View File

@ -25,7 +25,7 @@ pub const ShellReader = struct {
} }
// get returns a shell at the given index. // get returns a shell at the given index.
pub fn get(self: *const ShellReader, idx: u10) []const u8 { pub fn get(self: *const ShellReader, idx: u6) []const u8 {
const shellIndex = self.sectionIndex[idx]; const shellIndex = self.sectionIndex[idx];
const start = shellIndex.offset << 2; const start = shellIndex.offset << 2;
const end = start + shellIndex.len + 1; const end = start + shellIndex.len + 1;

View File

@ -17,6 +17,21 @@ pub const PackedUser = packed struct {
name_is_a_suffix: bool, name_is_a_suffix: bool,
name_len: u5, name_len: u5,
gecos_len: u8, gecos_len: u8,
wip_padding: u8, // https://github.com/ziglang/zig/pull/10941
// blobSize returns the length of the blob storing string values.
pub fn blobLength(self: *const PackedUser) usize {
var result: usize = self.home_len;
if (!self.name_is_a_suffix) {
result += self.name_len;
}
result += self.gecos_len;
if (self.shell_here) {
result += self.shell_len_or_idx;
}
return result;
}
}; };
const PackedUserAlignmentBits = 3; const PackedUserAlignmentBits = 3;
@ -71,6 +86,7 @@ pub const UserWriter = struct {
.name_is_a_suffix = std.mem.endsWith(u8, user.home, user.name), .name_is_a_suffix = std.mem.endsWith(u8, user.home, user.name),
.name_len = name_len, .name_len = name_len,
.gecos_len = gecos_len, .gecos_len = gecos_len,
.wip_padding = 0,
}; };
try self.appendTo.appendSlice(std.mem.asBytes(&puser)); try self.appendTo.appendSlice(std.mem.asBytes(&puser));
@ -92,37 +108,52 @@ pub const UserWriter = struct {
}; };
pub const UserReader = struct { pub const UserReader = struct {
const shellIndexProto = fn (u10) []const u8; const shellIndexProto = fn (u6) []const u8;
blob: []u8,
shellIndex: shellIndexProto, shellIndex: shellIndexProto,
blob: []const u8,
pub const PackedUserEntry = struct { const PackedEntry = struct {
packed_user: *PackedUser, packed_user: *PackedUser,
blob: []const u8, blob: []const u8,
}; };
pub fn init(shellIndex: shellIndexProto, blob: []const u8) UserReader { pub fn init(blob: []u8, shellIndex: shellIndexProto) UserReader {
return UserReader{ return UserReader{
.shellIndex = shellIndex,
.blob = blob, .blob = blob,
.shellIndex = shellIndex,
}; };
} }
pub const PackedUserIterator = struct { pub const PackedIterator = struct {
ur: *const UserReader, ur: *UserReader,
index: u32 = 0, index: usize = 0,
pub fn next(it: *PackedUserIterator) ?PackedUserEntry { pub fn next(it: *PackedIterator) ?PackedEntry {
if (it.index == it.ur.blob.len) return null; if (it.index == it.ur.blob.len) return null;
assert(it.index < it.blob.len); assert(it.index < it.ur.blob.len);
const start = it.index; const endUser = it.index + PackedUserSize;
const end = it.index + it.index + @sizeOf(PackedUser); var packedUser = std.mem.bytesAsValue(
var pu = std.mem.bytesAsValue(it.ur.blob[start..end]); PackedUser,
_ = pu; it.ur.blob[it.index..endUser][0..PackedUserSize],
);
const startBlob = endUser + 1;
const endBlob = startBlob + packedUser.blobLength();
it.index = pad.roundUp(usize, PackedUserAlignmentBits, endBlob + 1);
return PackedEntry{
.packed_user = packedUser,
.blob = it.ur.blob[startBlob..endBlob],
};
} }
}; };
pub fn packedIterator(self: *UserReader) PackedIterator {
return .{ .ur = self };
}
}; };
const testing = std.testing; const testing = std.testing;
@ -140,27 +171,46 @@ fn testShellIndex(shell: []const u8) ?u6 {
return null; return null;
} }
fn testShell(index: u6) []const u8 {
return switch (index) {
0 => "/bin/bash",
1 => "/bin/zsh",
else => unreachable,
};
}
test "construct PackedUser blob" { test "construct PackedUser blob" {
var buf = ArrayList(u8).init(testing.allocator); var buf = ArrayList(u8).init(testing.allocator);
defer buf.deinit(); defer buf.deinit();
var writer = UserWriter.init(&buf, testShellIndex); var writer = UserWriter.init(&buf, testShellIndex);
const user1 = User{ const users = [_]User{
.uid = 1000, User{
.gid = 1000, .uid = 1000,
.name = "vidmantas", .gid = 1000,
.gecos = "Vidmantas Kaminskas", .name = "vidmantas",
.home = "/home/vidmantas", .gecos = "Vidmantas Kaminskas",
.shell = "/bin/bash", .home = "/home/vidmantas",
.shell = "/bin/bash",
},
User{
.uid = 1001,
.gid = 1001,
.name = "svc-foo",
.gecos = "Service Account",
.home = "/home/service1",
.shell = "/usr/bin/nologin",
},
}; };
const user2 = User{ for (users) |user| {
.uid = 1001, try writer.appendUser(user);
.gid = 1001, }
.name = "svc-foo",
.gecos = "Service Account", var rd = UserReader.init(buf.items, testShell);
.home = "/home/service1", var it = rd.packedIterator();
.shell = "/usr/bin/nologin", var i: u32 = 0;
}; while (it.next()) |entry| : (i += 1) {
try writer.appendUser(user1); try testing.expectEqual(users[i].uid, entry.packed_user.uid);
try writer.appendUser(user2); try testing.expectEqual(users[i].gid, entry.packed_user.gid);
}
} }