2022-02-17 11:16:30 +02:00
|
|
|
const std = @import("std");
|
2022-02-18 20:29:45 +02:00
|
|
|
const shell = @import("shell.zig");
|
2022-02-17 11:16:30 +02:00
|
|
|
|
2022-02-19 16:04:13 +02:00
|
|
|
const HeaderSize = @divExact(@bitSizeOf(Header), 8);
|
2022-02-17 11:16:30 +02:00
|
|
|
const Magic = [4]u8{ 0xf0, 0x9f, 0xa4, 0xb7 };
|
|
|
|
const Version = 0;
|
|
|
|
const Bom = 0x1234;
|
|
|
|
|
2022-02-18 15:25:10 +02:00
|
|
|
pub const SectionLength = 64;
|
|
|
|
|
2022-02-18 17:24:22 +02:00
|
|
|
const InvalidHeader = error{
|
2022-02-18 07:16:11 +02:00
|
|
|
InvalidMagic,
|
|
|
|
InvalidVersion,
|
|
|
|
InvalidBom,
|
|
|
|
TooManyShells,
|
2022-02-18 07:42:43 +02:00
|
|
|
InvalidOffset,
|
2022-02-18 07:16:11 +02:00
|
|
|
};
|
|
|
|
|
2022-02-17 11:16:30 +02:00
|
|
|
const Header = packed struct {
|
|
|
|
magic: [4]u8,
|
|
|
|
version: u8,
|
|
|
|
bom: u16,
|
|
|
|
num_shells: u8,
|
|
|
|
num_users: u32,
|
|
|
|
num_groups: u32,
|
2022-02-18 17:24:22 +02:00
|
|
|
offset_bdz_uid2user: u32,
|
|
|
|
offset_bdz_groupname2group: u32,
|
|
|
|
offset_bdz_username2user: u32,
|
2022-02-17 11:16:30 +02:00
|
|
|
offset_idx: u32,
|
|
|
|
offset_groups: u32,
|
|
|
|
offset_users: u32,
|
|
|
|
offset_groupmembers: u32,
|
|
|
|
offset_additional_gids: u32,
|
|
|
|
|
2022-02-18 17:24:22 +02:00
|
|
|
pub fn init(blob: [HeaderSize]u8) InvalidHeader!Header {
|
2022-02-18 07:42:43 +02:00
|
|
|
const self = @bitCast(Header, blob);
|
|
|
|
for (Magic) |item, index| {
|
|
|
|
if (self.magic[index] != item) return error.InvalidMagic;
|
|
|
|
}
|
|
|
|
if (self.version != 0) {
|
|
|
|
return error.InvalidVersion;
|
|
|
|
}
|
|
|
|
if (self.bom != Bom) {
|
|
|
|
return error.InvalidBom;
|
|
|
|
}
|
2022-02-18 20:29:45 +02:00
|
|
|
if (self.num_shells > shell.MaxShells) {
|
2022-02-18 07:42:43 +02:00
|
|
|
return error.TooManyShells;
|
|
|
|
}
|
|
|
|
|
|
|
|
const offsets = [_]u32{
|
2022-02-18 17:24:22 +02:00
|
|
|
self.offset_bdz_uid2user,
|
|
|
|
self.offset_bdz_groupname2group,
|
|
|
|
self.offset_bdz_username2user,
|
2022-02-18 07:42:43 +02:00
|
|
|
self.offset_idx,
|
|
|
|
self.offset_groups,
|
|
|
|
self.offset_users,
|
|
|
|
self.offset_groupmembers,
|
|
|
|
self.offset_additional_gids,
|
|
|
|
};
|
|
|
|
for (offsets) |offset| {
|
2022-02-18 15:25:10 +02:00
|
|
|
if (offset & (SectionLength - 1) != 0) {
|
2022-02-18 07:42:43 +02:00
|
|
|
return error.InvalidOffset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
2022-02-17 11:16:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn asArray(self: *const Header) [HeaderSize]u8 {
|
|
|
|
return @bitCast([HeaderSize]u8, self.*);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const testing = std.testing;
|
|
|
|
|
2022-02-18 17:24:22 +02:00
|
|
|
test "Section length is a power of two" {
|
2022-02-18 15:25:10 +02:00
|
|
|
try testing.expect(std.math.isPowerOfTwo(SectionLength));
|
2022-02-17 11:16:30 +02:00
|
|
|
}
|
|
|
|
|
2022-02-18 17:24:22 +02:00
|
|
|
test "header pack, unpack and validation" {
|
2022-02-18 07:42:43 +02:00
|
|
|
const goodHeader = Header{
|
2022-02-17 11:16:30 +02:00
|
|
|
.magic = Magic,
|
|
|
|
.version = Version,
|
|
|
|
.bom = Bom,
|
|
|
|
.num_shells = 0,
|
|
|
|
.num_users = 0,
|
|
|
|
.num_groups = 0,
|
2022-02-18 17:24:22 +02:00
|
|
|
.offset_bdz_uid2user = 0,
|
|
|
|
.offset_bdz_groupname2group = 0,
|
|
|
|
.offset_bdz_username2user = 0,
|
2022-02-17 11:16:30 +02:00
|
|
|
.offset_idx = 0,
|
|
|
|
.offset_groups = 0,
|
|
|
|
.offset_users = 0,
|
|
|
|
.offset_groupmembers = 0,
|
|
|
|
.offset_additional_gids = 0,
|
|
|
|
};
|
|
|
|
|
2022-02-18 17:24:22 +02:00
|
|
|
const gotHeader = try Header.init(goodHeader.asArray());
|
2022-02-18 07:42:43 +02:00
|
|
|
try testing.expectEqual(goodHeader, gotHeader);
|
|
|
|
|
|
|
|
{
|
|
|
|
var header = goodHeader;
|
|
|
|
header.magic[0] = 0;
|
|
|
|
try testing.expectError(error.InvalidMagic, Header.init(header.asArray()));
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
var header = goodHeader;
|
|
|
|
header.bom = 0x3412;
|
|
|
|
try testing.expectError(error.InvalidBom, Header.init(header.asArray()));
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
var header = goodHeader;
|
2022-02-18 20:29:45 +02:00
|
|
|
header.num_shells = shell.MaxShells + 1;
|
2022-02-18 07:42:43 +02:00
|
|
|
try testing.expectError(error.TooManyShells, Header.init(header.asArray()));
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
var header = goodHeader;
|
2022-02-18 17:24:22 +02:00
|
|
|
header.offset_bdz_uid2user = 65;
|
2022-02-18 07:42:43 +02:00
|
|
|
try testing.expectError(error.InvalidOffset, Header.init(header.asArray()));
|
|
|
|
}
|
2022-02-17 11:16:30 +02:00
|
|
|
}
|