start with Header
This commit is contained in:
parent
00cf0e4a66
commit
8c8570e6d1
@ -156,7 +156,7 @@ OFFSET TYPE NAME DESCRIPTION
|
|||||||
0 [4]u8 magic always 0xf09fa4b7
|
0 [4]u8 magic always 0xf09fa4b7
|
||||||
4 u8 version now `0`
|
4 u8 version now `0`
|
||||||
5 u16 bom 0x1234
|
5 u16 bom 0x1234
|
||||||
7 u6 num_shells max value: 63
|
u8 num_shells max value: 63. Padding is strange on little endian.
|
||||||
8 u32 num_users number of passwd entries
|
8 u32 num_users number of passwd entries
|
||||||
12 u32 num_groups number of group entries
|
12 u32 num_groups number of group entries
|
||||||
16 u32 offset_cmph_uid2user
|
16 u32 offset_cmph_uid2user
|
||||||
@ -186,6 +186,11 @@ header field. For example, `cmph_gid2group` comes immediately after the header,
|
|||||||
and `idx_groupname2group` comes after `idx_gid2group`, whose offset is
|
and `idx_groupname2group` comes after `idx_gid2group`, whose offset is
|
||||||
`offset_idx`, and size can be calculated.
|
`offset_idx`, and size can be calculated.
|
||||||
|
|
||||||
|
`num_shells` would fit to u6; however, we would need 2 bits of padding (all
|
||||||
|
other fields are byte-aligned). If we instead do `u2` followed by `u6`, the
|
||||||
|
byte would look very unusual on a little-endian architecture. Therefore we will
|
||||||
|
just refuse loading the file if the number of shells exceeds 63.
|
||||||
|
|
||||||
Primitive types
|
Primitive types
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
63
src/header.zig
Normal file
63
src/header.zig
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const HeaderSize = @bitSizeOf(Header) / 8;
|
||||||
|
const Magic = [4]u8{ 0xf0, 0x9f, 0xa4, 0xb7 };
|
||||||
|
const Version = 0;
|
||||||
|
const Bom = 0x1234;
|
||||||
|
|
||||||
|
const Header = packed struct {
|
||||||
|
magic: [4]u8,
|
||||||
|
version: u8,
|
||||||
|
bom: u16,
|
||||||
|
num_shells: u8,
|
||||||
|
num_users: u32,
|
||||||
|
num_groups: u32,
|
||||||
|
offset_cmph_uid2user: u32,
|
||||||
|
offset_cmph_groupname2group: u32,
|
||||||
|
offset_cmph_username2user: u32,
|
||||||
|
offset_idx: u32,
|
||||||
|
offset_groups: u32,
|
||||||
|
offset_users: u32,
|
||||||
|
offset_groupmembers: u32,
|
||||||
|
offset_additional_gids: u32,
|
||||||
|
|
||||||
|
// TODO(motiejus) should we be returning *Header instead? That way all
|
||||||
|
// stacks could be smaller by 48 bytes, and we would be referring to
|
||||||
|
// it's fields in the mmap'ed region.
|
||||||
|
pub fn init(blob: [HeaderSize]u8) Header {
|
||||||
|
return @bitCast(Header, blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn asArray(self: *const Header) [HeaderSize]u8 {
|
||||||
|
return @bitCast([HeaderSize]u8, self.*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
test "header size is byte-aligned" {
|
||||||
|
try testing.expectEqual(HeaderSize * 8, @bitSizeOf(Header));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "header pack and unpack" {
|
||||||
|
const header = Header{
|
||||||
|
.magic = Magic,
|
||||||
|
.version = Version,
|
||||||
|
.bom = Bom,
|
||||||
|
.num_shells = 0,
|
||||||
|
.num_users = 0,
|
||||||
|
.num_groups = 0,
|
||||||
|
.offset_cmph_uid2user = 0,
|
||||||
|
.offset_cmph_groupname2group = 0,
|
||||||
|
.offset_cmph_username2user = 0,
|
||||||
|
.offset_idx = 0,
|
||||||
|
.offset_groups = 0,
|
||||||
|
.offset_users = 0,
|
||||||
|
.offset_groupmembers = 0,
|
||||||
|
.offset_additional_gids = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const blob = header.asArray();
|
||||||
|
const header2 = Header.init(blob);
|
||||||
|
try testing.expectEqual(header, header2);
|
||||||
|
}
|
@ -4,7 +4,6 @@ const PriorityDequeue = std.PriorityDequeue;
|
|||||||
const StringArrayHashMap = std.StringArrayHashMap;
|
const StringArrayHashMap = std.StringArrayHashMap;
|
||||||
const StringHashMap = std.StringHashMap;
|
const StringHashMap = std.StringHashMap;
|
||||||
const BoundedArray = std.BoundedArray;
|
const BoundedArray = std.BoundedArray;
|
||||||
const testing = std.testing;
|
|
||||||
const StringContext = std.hash_map.StringContext;
|
const StringContext = std.hash_map.StringContext;
|
||||||
|
|
||||||
// MaxShells is the maximum number of "popular" shells.
|
// MaxShells is the maximum number of "popular" shells.
|
||||||
@ -182,6 +181,8 @@ inline fn roundUp4Padding(n: u12) u12 {
|
|||||||
return ((n + 3) & ~@intCast(u12, 3)) - n;
|
return ((n + 3) & ~@intCast(u12, 3)) - n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
test "basic shellpopcon" {
|
test "basic shellpopcon" {
|
||||||
var popcon = ShellWriter.init(testing.allocator);
|
var popcon = ShellWriter.init(testing.allocator);
|
||||||
defer popcon.deinit();
|
defer popcon.deinit();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
test "turbonss test suite" {
|
test "turbonss test suite" {
|
||||||
_ = @import("main.zig");
|
_ = @import("main.zig");
|
||||||
_ = @import("shell.zig");
|
_ = @import("shell.zig");
|
||||||
|
_ = @import("header.zig");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user