summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlejandro Sior <aho@sior.be>2022-06-18 10:40:06 +0200
committerAlejandro Sior <aho@sior.be>2022-06-18 10:40:06 +0200
commitd6181b5e4f6f2dc72907e9f2e73db9ce0075cddd (patch)
treebda9e927101a267102dae6eb214e507b0bd5d9ab
parent12577f3445df86023ba0cbe2462d55ea5dcafe20 (diff)
gptman: implement convert
-rw-r--r--convert/convert.ha81
-rw-r--r--gpt/gpt.ha51
-rw-r--r--mbr/mbr.ha40
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);
+};