working on iterator
This commit is contained in:
parent
54ec710f10
commit
f2434e3d3c
|
@ -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" {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
88
src/user.zig
88
src/user.zig
|
@ -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{
|
||||||
|
User{
|
||||||
.uid = 1000,
|
.uid = 1000,
|
||||||
.gid = 1000,
|
.gid = 1000,
|
||||||
.name = "vidmantas",
|
.name = "vidmantas",
|
||||||
.gecos = "Vidmantas Kaminskas",
|
.gecos = "Vidmantas Kaminskas",
|
||||||
.home = "/home/vidmantas",
|
.home = "/home/vidmantas",
|
||||||
.shell = "/bin/bash",
|
.shell = "/bin/bash",
|
||||||
};
|
},
|
||||||
const user2 = User{
|
User{
|
||||||
.uid = 1001,
|
.uid = 1001,
|
||||||
.gid = 1001,
|
.gid = 1001,
|
||||||
.name = "svc-foo",
|
.name = "svc-foo",
|
||||||
.gecos = "Service Account",
|
.gecos = "Service Account",
|
||||||
.home = "/home/service1",
|
.home = "/home/service1",
|
||||||
.shell = "/usr/bin/nologin",
|
.shell = "/usr/bin/nologin",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
try writer.appendUser(user1);
|
for (users) |user| {
|
||||||
try writer.appendUser(user2);
|
try writer.appendUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
var rd = UserReader.init(buf.items, testShell);
|
||||||
|
var it = rd.packedIterator();
|
||||||
|
var i: u32 = 0;
|
||||||
|
while (it.next()) |entry| : (i += 1) {
|
||||||
|
try testing.expectEqual(users[i].uid, entry.packed_user.uid);
|
||||||
|
try testing.expectEqual(users[i].gid, entry.packed_user.gid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue