use errors; use io; use types; use rt; use fmt; use mbr; use sector; export type nogpt = !void; export type gpt = struct { mbr_sec: sector::sector, mbr: *mbr::mbr, primary: block, backup: block }; export type block = struct { header_sec: sector::sector, entries_sec: sector::sector, header: *header, entries: *[128]entry }; fn block_getheader(self: *block) *header = { return self.header_sec.buf: *[*]u8: *header; }; fn block_getentries(self: *block) []entry = { const e = types::slice { data = self.entries_sec.buf: *[*]u8, length = 128, capacity = 128 }; return *(&e: *const []entry); }; fn block_commit(self: *block) void = { sector::commit(&self.header_sec); //sector::commit(&self.entries_sec); }; fn block_fetch(self: *block) void = { sector::fetch(&self.header_sec); sector::fetch(&self.entries_sec); }; fn block_drop(self: *block) void = { sector::finish(&self.header_sec); sector::finish(&self.entries_sec); }; export type header = struct { @offset(0) signature: u64, @offset(8) revision: u32, @offset(12) header_size: u32, @offset(16) header_crc32: u32, @offset(20) reserved0: u32, @offset(24) header_lba: u64, @offset(32) backup_header_lba: u64, @offset(40) first_lba: u64, @offset(48) last_lba: u64, @offset(56) disk_guid: [2]u64, @offset(72) entries_lba: u64, @offset(80) entries_len: u32, @offset(84) entry_size: u32, @offset(88) entries_crc32: u32 }; export type entry = struct { @offset(0) part_type: [2]u64, @offset(16) part: [2]u64, @offset(32) lba_begin: u64, @offset(40) lba_end: u64, @offset(48) attributes: u64, @offset(56) name: [72]u8 }; export fn validate(self: *gpt) bool = { if (getheader(self).signature != 0x5452415020494645) { return false; }; return true; }; export fn from(fd: io::file) (*gpt | nogpt | errors::error) = { const prim_header_sector = sector::map(fd, 1, 1); sector::fetch(&prim_header_sector); const prim_header = prim_header_sector.buf: *[*]u8: *header; // XXX validate header const prim_table_sector = sector::map(fd, prim_header.entries_lba, prim_header.entries_lba + 128*128/512 - 1); sector::fetch(&prim_table_sector); // Create the primary GPT copy const primary = block { header_sec = prim_header_sector, entries_sec = prim_table_sector, header = prim_header, entries = prim_table_sector.buf: *[*]u8: *[128]entry }; const back_header_sector = sector::map(fd, prim_header.backup_header_lba, prim_header.backup_header_lba); sector::fetch(&back_header_sector); const back_header = back_header_sector.buf: *[*]u8: *header; //XXX validate header const back_table_sector = sector::map(fd, back_header.entries_lba, back_header.entries_lba + 128*128/512 - 1); sector::fetch(&back_table_sector); // Create the backup block structure let backup = block { header_sec = back_header_sector, entries_sec = back_table_sector, header = back_header, entries = back_table_sector.buf: *[*]u8: *[128]entry }; const mbr_sec = sector::map(fd, 0, 0); // Allocate the GPT structure let self = alloc(gpt { mbr_sec = mbr_sec, mbr = mbr_sec.buf: *[*]u8: *mbr::mbr, primary = primary, backup = backup }); // Fetch the MBR sector::fetch(&self.mbr_sec); return self; }; // Frees the resources associated with the GPT structure. export fn finish(self: *gpt) void = { sector::finish(&self.mbr_sec); block_drop(&self.primary); block_drop(&self.backup); free(self); }; // Updates the data structures from the disk export fn fetch(self: *gpt) void = { sector::fetch(&self.mbr_sec); block_fetch(&self.primary); block_fetch(&self.backup); }; export fn mkbackup(self: *gpt) void = { rt::memcpy(self.backup.header, self.primary.header, size(header)); rt::memcpy(self.backup.entries, self.primary.entries, size([128]entry)); self.backup.header.header_lba = self.backup.header_sec.lba_begin; self.backup.header.backup_header_lba = self.primary.header_sec.lba_begin; self.backup.header.entries_lba = self.backup.entries_sec.lba_begin; }; // Commits changed done on the data structure to the disk export fn commit(self: *gpt) void = { // XXX: CRC32 checksum sector::commit(&self.mbr_sec); block_commit(&self.primary); block_commit(&self.backup); //const header = getheader(self); // XXX: update copy //sector::commit_at(self.mbr, self.mbr.fd, header.backup_header_lba); }; // Updates the CRC32 checksums of the different blocks export fn chksums(self: *gpt) void = { self.primary.header.header_crc32 = header_crc32(self.primary.header); self.backup.header.header_crc32 = header_crc32(self.backup.header); }; // Gets the MBR structure. Return value is borrowed from argument. export fn getmbr(self: *gpt) *mbr::mbr = { return self.mbr_sec.buf: *[*]u8: *mbr::mbr; }; // Gets the GPT primary header structure. Return value is borrowed from argument. export fn getheader(self: *gpt) *header = { return block_getheader(&self.primary); }; // Gets the GPT primary entries structures. Return value is borrowed from argument. export fn getentries(self: *gpt) []entry = { return block_getentries(&self.primary); };