From d6181b5e4f6f2dc72907e9f2e73db9ce0075cddd Mon Sep 17 00:00:00 2001 From: Alejandro Sior Date: Sat, 18 Jun 2022 10:40:06 +0200 Subject: gptman: implement convert --- convert/convert.ha | 81 ++++++++++++++++++++++++++---------------------------- gpt/gpt.ha | 51 ++++++++++++++++++++++++++++++---- mbr/mbr.ha | 40 ++++++++++++++++++++++++--- 3 files changed, 121 insertions(+), 51 deletions(-) diff --git a/convert/convert.ha b/convert/convert.ha index 98ad124..7ba6bf0 100644 --- a/convert/convert.ha +++ b/convert/convert.ha @@ -9,66 +9,63 @@ use io; use fs; use strings; use errors; +use rt; export fn convert(args: []str) void = { - if (len(args) < 2) { + if (len(args) < 3) { fmt::fatalf("gptman.convert: needs disk"); }; - let file = os::open(args[1], fs::flags::RDWR)!; + let source = os::open(args[1], fs::flags::RDONLY)!; + defer io::close(source)!; + + const source = mbr::from(source)!; + + let freeno: size = 0z; + for (let i = 0z; i < 4; i += 1) { + const entry = &source.bootsector.entries[i]; + + if (entry.lba_begin == 0 && entry.length == 0) + continue; + + freeno += entry.length: size; + }; + + let file = os::create(args[2], fs::mode::USER_RWX | fs::mode::GROUP_RX | fs::mode::OTHER_RX, fs::flags::RDWR)!; defer io::close(file)!; - // let vol = gpt::create(file, 69); - // gpt::mkbackup(vol); - // defer { - // gpt::chksums(vol); - // gpt::commit(vol)!; - // gpt::finish(vol); - // }; - - // vol.mbr.entries[0] = mbr::mbr_entry { - // attributes = 0, - // part_type = 0xEE, - // lba_begin = 1, - // lba_end = -1: u32, - // }; - // vol.mbr.magic = 0xaa55; - - let vol = gpt::from(file)!; + let vol = gpt::create(file, freeno); gpt::mkbackup(vol); defer { gpt::chksums(vol); gpt::commit(vol)!; gpt::finish(vol); }; + + rt::memcpy(vol.mbr, source.bootsector, size(mbr::bootsector)); + for (let i = 0z; i < 4; i += 1) { + const entry = &source.bootsector.entries[i]; + if (entry.lba_begin == 0 && entry.length == 0) + continue; - // fmt::printfln("rev {}", vol.primary.header.revision)!; - - // for (let i = 0z; i < 4; i += 1) { - // fmt::printfln("type {} from {} to {}", vol.mbr.entries[i].part_type, vol.mbr.entries[i].lba_begin, vol.mbr.entries[i].lba_end)!; - // }; - - // vol.primary.header.disk_guid[0] = 0xcafababe; - // vol.primary.header.disk_guid[1] = 0xabababababababab; - - // // 516E7CB6-6ECF-11D6-8FF8-00022D09712B + const reader = mbr::partstream_reader(source, entry)!; + const partlength = entry.length; - // vol.primary.entries[4].part_type[0] = 0x516E7CB66ECF; - // vol.primary.entries[4].lba_begin = 35; - // vol.primary.entries[4].lba_end = 37; - // vol.primary.entries[5].part_type[0] = 0x516E7CB66ECF; - // vol.primary.entries[5].lba_begin = 40; - // vol.primary.entries[5].lba_end = 41; + const part = gpt::allocate(vol, partlength) as *gpt::entry; + const writer = gpt::partstream_writer(vol, part)!; - const much = 4z; - const addr = gpt::findfree(vol, much); - const where = gpt::findfreeentry(vol) as *gpt::entry; + io::copy(&writer, &reader)!; - where.part_type = [0xCAFEBABE, 0xBABABA]; - where.lba_begin = addr; - where.lba_end = addr + much: u64 - 1; + vol.mbr.entries[i].lba_begin = part.lba_begin: u32; + vol.mbr.entries[i].length = (part.lba_end - part.lba_begin + 1): u32; + }; - fmt::printfln("fitting {}: {} and could be put at {}", much, addr, where)!; + vol.mbr.entries[3] = mbr::entry { + part_type = 0xEE, + lba_begin = 0, + length = -1: u32, + ... + }; }; diff --git a/gpt/gpt.ha b/gpt/gpt.ha index 53ca37f..f104584 100644 --- a/gpt/gpt.ha +++ b/gpt/gpt.ha @@ -11,7 +11,7 @@ export type nogpt = !void; export type gpt = struct { mbr_sec: sector::sector, - mbr: *mbr::mbr, + mbr: *mbr::bootsector, primary: block, backup: block }; @@ -104,7 +104,7 @@ export fn from(fd: io::file) (*gpt | nogpt | io::error) = { // Allocate the GPT structure let self = alloc(gpt { mbr_sec = mbr_sec, - mbr = mbr_sec.buf: *[*]u8: *mbr::mbr, + mbr = mbr_sec.buf: *[*]u8: *mbr::bootsector, primary = block { header_sec = prim_header_sec, entries_sec = prim_entries_sec, @@ -129,7 +129,7 @@ export fn create(fd: io::file, freeno: size) *gpt = { const bheader_begin = bentries_begin + 128*128/512; const mbr_sec = sector::map(fd, 0, 1); - const mbr = mbr_sec.buf: *[*]u8: *mbr::mbr; + const mbr = mbr_sec.buf: *[*]u8: *mbr::bootsector; const prim_header_sec = sector::map(fd, 1, 1); const prim_header = prim_header_sec.buf: *[*]u8: *header; @@ -182,7 +182,7 @@ export fn create(fd: io::file, freeno: size) *gpt = { }; // Finds an lba for a new partition that fits the desired length -export fn findfree(self: *gpt, length: u64) u64 = { +fn findfree(self: *gpt, length: u64) u64 = { const header = self.primary.header; const entries = self.primary.entries; @@ -209,7 +209,7 @@ export fn findfree(self: *gpt, length: u64) u64 = { // Finds a GPT entry that is currently not used // The entry pointer returned is borrowed from the arguments -export fn findfreeentry(self: *gpt) nullable *entry = { +fn findfreeentry(self: *gpt) nullable *entry = { const header = self.primary.header; const entries = self.primary.entries; @@ -221,6 +221,47 @@ export fn findfreeentry(self: *gpt) nullable *entry = { return null; }; +// Allocates a partition with a given length (in lba) +export fn allocate(self: *gpt, length: u64) nullable *entry = { + const addr = findfree(self, length); + if (addr == 0) + return null; + + const entry = match (findfreeentry(self)) { + case let e: *entry => + yield e; + case => return null; + }; + + entry.lba_begin = addr; + entry.lba_end = addr + length - 1; + + return entry; +}; + +// Returns a stream to the partition associated with the entry +// in order to write in it +export fn partstream_writer(self: *gpt, entry: *entry) (io::limitstream | io::error) = { + const fd = self.primary.header_sec.fd; + const part = entry.lba_begin * sector::sector_length; + const length = (entry.lba_end - entry.lba_begin + 1) * sector::sector_length; + + + io::seek(fd, part: io::off, io::whence::SET)?; + return io::limitwriter(fd, length); +}; + +// Returns a stream to the partition associated with the entry +// in order to read from it +export fn partstream_reader(self: *gpt, entry: *entry) (io::limitstream | io::error) = { + const fd = self.primary.header_sec.fd; + const part = entry.lba_begin * sector::sector_length; + const length = (entry.lba_end - entry.lba_begin + 1) * sector::sector_length; + + io::seek(fd, part: io::off, io::whence::SET)?; + return io::limitreader(fd, length); +}; + // Frees the resources associated with the GPT structure. export fn finish(self: *gpt) void = { sector::finish(&self.mbr_sec); diff --git a/mbr/mbr.ha b/mbr/mbr.ha index d0622d2..31a9534 100644 --- a/mbr/mbr.ha +++ b/mbr/mbr.ha @@ -8,24 +8,56 @@ def mbr_lba: size = 0; export type nombr = !void; export type mbr = struct { + bootsector_sec: sector::sector, + bootsector: *bootsector +}; + +export type bootsector = struct { @offset(0) bootstrap: [440]u8, @offset(440) udid: u32, @offset(444) reserved: u16, - @offset(446) entries: [4]mbr_entry, + @offset(446) entries: [4]entry, @offset(510) magic: u16, }; -export type mbr_entry = struct { +export type entry = struct { @offset(0) attributes: u8, @offset(4) part_type: u8, @offset(8) lba_begin: u32, - @offset(12) lba_end: u32, + @offset(12) length: u32, }; -export fn validate(self: *mbr) bool = { +export fn bootsector_validate(self: *bootsector) bool = { if (self.magic != 0xaa55) { return false; }; return true; }; + +export fn from(fd: io::file) (*mbr | nombr | io::error) = { + const bootsector_sec = sector::map(fd, 0, 1); + sector::fetch(&bootsector_sec)?; + + const bootsector = bootsector_sec.buf: *[*]u8: *bootsector; + if (!bootsector_validate(bootsector)) { + sector::finish(&bootsector_sec); + return nombr; + }; + + let self = alloc(mbr { + bootsector_sec = bootsector_sec, + bootsector = bootsector + }); + + return self; +}; + +export fn partstream_reader(self: *mbr, entry: *entry) (io::limitstream | io::error) = { + const fd = self.bootsector_sec.fd; + const part = entry.lba_begin * sector::sector_length; + const length = entry.length * sector::sector_length; + + io::seek(fd, part: io::off, io::whence::SET)?; + return io::limitreader(fd, length); +}; -- cgit v1.2.3