From 68b9c04241ef433f346279fbc153928bcbd360e9 Mon Sep 17 00:00:00 2001 From: Alejandro Sior Date: Tue, 21 Jun 2022 17:31:07 +0200 Subject: gptman: polish create and convert --- cmd/convert/convert.ha | 91 +++++++++++++++++++++++++++++++++++------------- cmd/create/create.ha | 22 +++++++++--- cmd/info/info.ha | 9 ++--- cmd/mkbackup/mkbackup.ha | 8 +++-- cmd/part/part.ha | 31 +++++++++++------ cmd/util.ha | 36 +++++++++++++------ main.ha | 12 +++---- 7 files changed, 145 insertions(+), 64 deletions(-) diff --git a/cmd/convert/convert.ha b/cmd/convert/convert.ha index 807ae7f..b3cfd38 100644 --- a/cmd/convert/convert.ha +++ b/cmd/convert/convert.ha @@ -1,36 +1,76 @@ use fmt; - -use cmd; -use mbr; -use gpt; -use sector; - use os; use io; use fs; use strings; use errors; use rt; +use getopt; + +use cmd; +use mbr; +use gpt; +use sector; + -export fn convert(vol: str, args: []str) void = { - if (len(args) < 2) { - fmt::fatalf("convert: needs disk"); +export fn convert(args: []str) void = { + let nombr = false; + let notranslation = false; + let nohybrid = false; + + const c = getopt::parse(args, + ('m', "do not overwrite the MBR bootstrap"), + ('t', "do not translate partitions to GPT"), + ('H', "do not create a hybrid MBR"), + "disk file" + ); + defer getopt::finish(&c); + + for (let i = 0z; i < len(c.opts); i += 1) { + const opt = c.opts[i]; + switch (opt.0) { + case 'm' => nombr = true; + case 't' => notranslation = true; + case 'H' => nohybrid = true; + }; + }; + + if (len(c.args) < 1) + fmt::fatalf("gpt.convert: need a disk file"); + + let sourcefd = match (os::open(c.args[0], fs::flags::RDONLY)) { + case let f: io::file => + yield f; + case => fmt::fatalf("gpt.convert: could not open file {}", args[1]); }; + defer io::close(sourcefd)!; - let source = os::open(args[1], fs::flags::RDONLY)!; - defer io::close(source)!; + const source = mbr::from(sourcefd)!; + // XXX need mbr::finish() - const source = mbr::from(source)!; + let fd = cmd::openfile(); + defer io::close(fd)!; - const vol = cmd::openvol(vol); - let vol = gpt::from(vol)!; + let vol = cmd::opengpt(fd); defer { + vol.mbr.entries[3] = mbr::entry { + part_type = 0xEE, + lba_begin = 0, + length = -1: u32, + ... + }; + gpt::chksums(vol); gpt::commit(vol)!; gpt::finish(vol); }; - rt::memcpy(vol.mbr, source.bootsector, size(mbr::bootsector)); + if (!nombr) + rt::memcpy(vol.mbr, source.bootsector, size(mbr::bootsector)); + + if (notranslation) + return; + for (let i = 0z; i < 4; i += 1) { const entry = &source.bootsector.entries[i]; if (entry.lba_begin == 0 && entry.length == 0) @@ -39,20 +79,21 @@ export fn convert(vol: str, args: []str) void = { const reader = mbr::partstream_reader(source, entry)!; const partlength = entry.length; - const part = gpt::allocate(vol, partlength) as *gpt::entry; + const part = match (gpt::allocate(vol, partlength)) { + case let e: *gpt::entry => + yield e; + case => + fmt::errorfln("gpt.convert: could not allocate size needed for MBR partition {}", i)!; + continue; + }; const writer = gpt::partstream_writer(vol, part)!; io::copy(&writer, &reader)!; - vol.mbr.entries[i].lba_begin = part.lba_begin: u32; - vol.mbr.entries[i].length = (part.lba_end - part.lba_begin + 1): u32; - }; - - vol.mbr.entries[3] = mbr::entry { - part_type = 0xEE, - lba_begin = 0, - length = -1: u32, - ... + if (!nohybrid) { + vol.mbr.entries[i].lba_begin = part.lba_begin: u32; + vol.mbr.entries[i].length = (part.lba_end - part.lba_begin + 1): u32; + }; }; }; diff --git a/cmd/create/create.ha b/cmd/create/create.ha index 124d86e..7733928 100644 --- a/cmd/create/create.ha +++ b/cmd/create/create.ha @@ -6,15 +6,16 @@ use os; use strconv; use gpt; +use mbr; use cmd; -export fn create(vol: str, args: []str) void = { +export fn create(args: []str) void = { // XXX this is a stub const c = getopt::parse(args, - "create a volume", ('f', "file", "specify another partition file to fit"), - ('l', "length", "specify another length margin") + ('b', "bytes", "specify another length margin (bytes)"), + ('s', "sectors", "specify another length margin (sectors, 512 bytes)") ); defer getopt::finish(&c); @@ -25,17 +26,28 @@ export fn create(vol: str, args: []str) void = { switch (opt.0) { case 'l' => length += (strconv::stoi(opt.1)! / 512 + 1): size; + case 's' => + length += strconv::stoi(opt.1)!: size; case 'f' => const stat = os::stat(opt.1)!; length += stat.sz / 512 + 1; }; }; - const vol = cmd::mkvol(vol); - const vol = gpt::create(vol, length); + const fd = cmd::mkfile(); + defer io::close(fd)!; + + const vol = gpt::create(fd, length); defer { gpt::chksums(vol); gpt::commit(vol)!; gpt::finish(vol); }; + + vol.mbr.entries[3] = mbr::entry { + part_type = 0xEE, + lba_begin = 0, + length = -1: u32, + ... + }; }; diff --git a/cmd/info/info.ha b/cmd/info/info.ha index 75ab499..8c0110a 100644 --- a/cmd/info/info.ha +++ b/cmd/info/info.ha @@ -1,19 +1,20 @@ use fmt; use io; +use os; use gpt; use cmd; fn booltonum(a: bool) str = if (a) { return "1"; } else { return "0"; }; -export fn info(vol: str, args: []str) void = { - const name = vol; - const vol = cmd::opengpt(vol); +export fn info(args: []str) void = { + const fd = cmd::openfile(); + const vol = cmd::opengpt(fd); defer gpt::finish(vol); const header = vol.primary.header; - fmt::printfln("# GPT header info {}", name)!; + fmt::printfln("# GPT header info {}", os::args[1])!; fmt::printfln("revision({})", header.revision)!; fmt::printfln("header_size({})", header.header_size)!; fmt::printfln("header_crc32({})", header.header_crc32)!; diff --git a/cmd/mkbackup/mkbackup.ha b/cmd/mkbackup/mkbackup.ha index 12093b5..b2c9ae6 100644 --- a/cmd/mkbackup/mkbackup.ha +++ b/cmd/mkbackup/mkbackup.ha @@ -4,9 +4,11 @@ use io; use cmd; use gpt; -export fn mkbackup(vol: str, args: []str) void = { - const vol = cmd::openvol(vol); - const vol = match(gpt::from(vol)) { +export fn mkbackup(args: []str) void = { + const fd = cmd::openfile(); + defer io::close(fd)!; + + const vol = match(gpt::from(fd)) { case let g: *gpt::gpt => yield g; case gpt::nogpt => diff --git a/cmd/part/part.ha b/cmd/part/part.ha index a4b114f..138c093 100644 --- a/cmd/part/part.ha +++ b/cmd/part/part.ha @@ -3,18 +3,21 @@ use io; use os; use strconv; -use gpt; use cmd; +use gpt; -export fn part(vol: str, args: []str) void = { +export fn part(args: []str) void = { if (len(args) <= 1) { - partlist(vol, args[1..]); + partlist(args[1..]); return; }; match (strconv::stou(args[1])) { case let i: uint => - const vol = cmd::opengpt(vol); + const fd = cmd::openfile(); + defer io::close(fd)!; + + const vol = cmd::opengpt(fd); defer gpt::finish(vol); partno(vol, i, args[2..]); return; @@ -23,13 +26,16 @@ export fn part(vol: str, args: []str) void = { }; switch (args[1]) { - case "new" => partnew(vol, args[1..]); - case "list" => partlist(vol, args[1..]); + case "new" => partnew(args[1..]); + case "list" => partlist(args[1..]); }; }; -export fn partnew(vol: str, args: []str) void = { - const vol = cmd::opengpt(vol); +export fn partnew(args: []str) void = { + const fd = cmd::openfile(); + defer io::close(fd)!; + + const vol = cmd::opengpt(fd); defer { gpt::chksums(vol); gpt::commit(vol)!; @@ -46,8 +52,11 @@ export fn partnew(vol: str, args: []str) void = { }; }; -export fn partlist(vol: str, args: []str) void = { - const vol = cmd::opengpt(vol); +export fn partlist(args: []str) void = { + const fd = cmd::openfile(); + defer io::close(fd)!; + + const vol = cmd::opengpt(fd); defer gpt::finish(vol); const header = vol.primary.header; const entries = vol.primary.entries; @@ -62,7 +71,7 @@ export fn partlist(vol: str, args: []str) void = { }; fn partinfo(vol: *gpt::gpt, i: size) void = { - const entry = &vol.primary.entries[i]; + const entry = cmd::getgptentry(vol, i); fmt::printfln("# Partition {}", i)!; fmt::printfln("entries[{}].part_type([{},{}])", i, entry.part_type[0], entry.part_type[1])!; diff --git a/cmd/util.ha b/cmd/util.ha index 832a96f..7bbeca8 100644 --- a/cmd/util.ha +++ b/cmd/util.ha @@ -5,33 +5,49 @@ use os; use gpt; -export fn mkvol(vol: str) io::file = { +export fn mkfile() io::file = { + const vol = os::args[1]; + return match (os::create(vol, fs::mode::USER_RWX | fs::mode::GROUP_RX | fs::mode::OTHER_RX, fs::flags::RDWR)) { case let v: io::file => yield v; case => - fmt::fatalf("{}: cannot open file {}", os::args[0], vol); + fmt::fatalf("gpt: cannot open file {}", vol); }; }; -export fn openvol(vol: str) io::file = { +export fn openfile() io::file = { + const vol = os::args[1]; + return match (os::open(vol, fs::flags::RDWR)) { case let v: io::file => yield v; case => - fmt::fatalf("{}: cannot open file {}", os::args[0], vol); + fmt::fatalf("gpt: cannot open file {}", vol); }; }; -export fn opengpt(vol: str) *gpt::gpt = { - const vol = openvol(vol); - - return match (gpt::from(vol)) { +export fn opengpt(fd: io::file) *gpt::gpt = { + return match (gpt::from(fd)) { case let g: *gpt::gpt => yield g; case io::error => - fmt::fatalf("{}: could not properly read disk {}", os::args[0], os::args[1]); + fmt::fatalf("gpt: could not properly read disk"); case => - fmt::fatalf("{}: no valid gpt in disk", os::args[0]); + fmt::fatalf("gpt: no valid gpt in disk"); }; }; + +export fn getgptentry(vol: *gpt::gpt, i: size) *gpt::entry = { + const header = vol.primary.header; + + if (i >= header.entries_len) + fmt::fatalf("gpt: invalid entry index"); + + const entry = &vol.primary.entries[i]; + + if (entry.lba_begin == 0 && entry.lba_end == 0) + fmt::fatalf("gpt: entry {} is not allocated", i); + + return entry; +}; diff --git a/main.ha b/main.ha index 304b56c..09c5bf7 100644 --- a/main.ha +++ b/main.ha @@ -16,17 +16,17 @@ use cmd::part; export fn main() void = { if (len(os::args) < 3) { - fmt::fatalf("{}: expected disk name", os::args[0]); + fmt::fatalf("gpt: expected disk name", os::args[0]); }; const volume = os::args[1]; switch (os::args[2]) { - case "convert" => convert::convert(volume, os::args[2..]); - case "create" => create::create(volume, os::args[2..]); - case "info" => info::info(volume, os::args[2..]); - case "mkbackup" => mkbackup::mkbackup(volume, os::args[2..]); - case "part" => part::part(volume, os::args[2..]); + case "convert" => convert::convert(os::args[2..]); + case "create" => create::create(os::args[2..]); + case "info" => info::info(os::args[2..]); + case "mkbackup" => mkbackup::mkbackup(os::args[2..]); + case "part" => part::part(os::args[2..]); case => fmt::fatalf("{}: no such command {}", os::args[0], os::args[2]); }; }; -- cgit v1.2.3