//! The initial_ramdisk (initial ramdisk) container format — shared by the build-time //! packer (tools/make-initial-ramdisk.py) and the kernel that unpacks it. Deliberately //! trivial: a header, a table of fixed-size entries, then the concatenated file //! blobs. We own both producer and consumer, so it need be no fancier. //! //! Layout: //! Header (magic, count) //! Entry * count (name, offset, len) — offset/len into the image //! blob bytes... (each entry's file, at its offset) const std = @import("std"); /// "DNRD" — identifies a danos initial_ramdisk image. pub const magic: u32 = 0x444E5244; pub const Header = extern struct { magic: u32, count: u32, }; pub const Entry = extern struct { name: [32]u8, // NUL-padded file name (basename) offset: u64, // byte offset of the blob within the image len: u64, // blob length in bytes }; /// A validated view over an initial_ramdisk image. `init` checks the magic and that the /// entry table fits; `entry` bounds-checks each blob against the image. pub const Reader = struct { image: []const u8, count: u32, pub fn init(image: []const u8) ?Reader { if (image.len < @sizeOf(Header)) return null; const h = std.mem.bytesToValue(Header, image[0..@sizeOf(Header)]); if (h.magic != magic) return null; const table_end = @sizeOf(Header) + @as(usize, h.count) * @sizeOf(Entry); if (table_end > image.len) return null; return .{ .image = image, .count = h.count }; } pub const Item = struct { name: []const u8, blob: []const u8 }; pub fn entry(self: Reader, i: u32) ?Item { if (i >= self.count) return null; const off = @sizeOf(Header) + @as(usize, i) * @sizeOf(Entry); const e = std.mem.bytesToValue(Entry, self.image[off..][0..@sizeOf(Entry)]); if (e.offset > self.image.len or e.len > self.image.len - e.offset) return null; // The name is stored in the entry's fixed field; return a stable slice // into the image (not the value copy) up to the NUL terminator. const name_field = self.image[off .. off + 32]; const nlen = std.mem.indexOfScalar(u8, name_field, 0) orelse name_field.len; return .{ .name = name_field[0..nlen], .blob = self.image[@intCast(e.offset)..][0..@intCast(e.len)], }; } };