From 2030f5c8ea087334f9fbbdee2e23db97704b821c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20N=C3=B8rfjand=20Stengaard?= Date: Tue, 6 Dec 2022 23:12:56 +0100 Subject: [PATCH] Add support for formatting non-rdb partitions. Update information displayed for rdb fs export command --- src/Hst.Imager.ConsoleApp/CommandHandler.cs | 4 +- .../RdbCommandFactory.cs | 18 ++- .../Commands/RdbFsExportCommand.cs | 13 +- .../Commands/RdbPartFormatCommand.cs | 125 ++++++++++++++++-- 4 files changed, 138 insertions(+), 22 deletions(-) diff --git a/src/Hst.Imager.ConsoleApp/CommandHandler.cs b/src/Hst.Imager.ConsoleApp/CommandHandler.cs index b8e9d31..1ee9f3e 100644 --- a/src/Hst.Imager.ConsoleApp/CommandHandler.cs +++ b/src/Hst.Imager.ConsoleApp/CommandHandler.cs @@ -371,10 +371,10 @@ public static async Task RdbPartImport(string sourcePath, string destinationPath await Execute(command); } - public static async Task RdbPartFormat(string path, int partitionNumber, string name) + public static async Task RdbPartFormat(string path, int partitionNumber, string name, bool nonRdb, string chs, string dosType) { await Execute(new RdbPartFormatCommand(GetLogger(), GetCommandHelper(), - await GetPhysicalDrives(), path, partitionNumber, name)); + await GetPhysicalDrives(), path, partitionNumber, name, nonRdb, chs, dosType)); } public static async Task RdbPartKill(string path, int partitionNumber, string hexBootBytes) diff --git a/src/Hst.Imager.ConsoleApp/RdbCommandFactory.cs b/src/Hst.Imager.ConsoleApp/RdbCommandFactory.cs index cef84a2..a63a56c 100644 --- a/src/Hst.Imager.ConsoleApp/RdbCommandFactory.cs +++ b/src/Hst.Imager.ConsoleApp/RdbCommandFactory.cs @@ -567,12 +567,28 @@ private static Command CreateRdbPartFormat() name: "VolumeName", description: "Name of the volume (e.g. Workbench)."); + var nonRdbOption = new Option( + new[] { "--non-rdb" }, + description: "Set non-RDB.", + getDefaultValue: () => false); + + var chsOption = new Option( + new[] { "-chs" }, + description: "Format from cylinders, heads and sectors. Optional for non-RDB partition."); + + var dosTypeOption = new Option( + new[] { "--dos-type", "-dt" }, + description: "DOS type for the partition to use (e.g. DOS3, PFS3). Required for non-RDB partition."); + var rdbPartFormatCommand = new Command("format", "Format partition."); rdbPartFormatCommand.SetHandler(CommandHandler.RdbPartFormat, pathArgument, partitionNumber, - volumeNameArgument); + volumeNameArgument, nonRdbOption, chsOption, dosTypeOption); rdbPartFormatCommand.AddArgument(pathArgument); rdbPartFormatCommand.AddArgument(partitionNumber); rdbPartFormatCommand.AddArgument(volumeNameArgument); + rdbPartFormatCommand.AddOption(nonRdbOption); + rdbPartFormatCommand.AddOption(chsOption); + rdbPartFormatCommand.AddOption(dosTypeOption); return rdbPartFormatCommand; } diff --git a/src/Hst.Imager.Core/Commands/RdbFsExportCommand.cs b/src/Hst.Imager.Core/Commands/RdbFsExportCommand.cs index 8124f5b..922baec 100644 --- a/src/Hst.Imager.Core/Commands/RdbFsExportCommand.cs +++ b/src/Hst.Imager.Core/Commands/RdbFsExportCommand.cs @@ -56,9 +56,7 @@ public override async Task Execute(CancellationToken token) } var fileSystemHeaderBlocks = rigidDiskBlock.FileSystemHeaderBlocks.ToList(); - - OnDebugMessage($"Exporting file system number '{fileSystemNumber}'"); - + if (fileSystemNumber < 1 || fileSystemNumber > fileSystemHeaderBlocks.Count) { return new Result(new Error($"Invalid file system number '{fileSystemNumber}'")); @@ -68,10 +66,11 @@ public override async Task Execute(CancellationToken token) var fileSystemBytes = fileSystemHeaderBlock.LoadSegBlocks.SelectMany(x => x.Data).ToArray(); long fileSystemSize = fileSystemBytes.Length; - OnDebugMessage($"DOS type '0x{fileSystemHeaderBlock.DosType.FormatHex()}' ({fileSystemHeaderBlock.DosType.FormatDosType()})"); - OnDebugMessage($"Version '{fileSystemHeaderBlock.VersionFormatted}'"); - OnDebugMessage($"Size '{fileSystemSize.FormatBytes()}' ({fileSystemSize} bytes)"); - OnDebugMessage($"File system name '{fileSystemHeaderBlock.FileSystemName}'"); + OnInformationMessage($"- File system number '{fileSystemNumber}'"); + OnInformationMessage($"- DOS type '0x{fileSystemHeaderBlock.DosType.FormatHex()}' ({fileSystemHeaderBlock.DosType.FormatDosType()})"); + OnInformationMessage($"- Version '{fileSystemHeaderBlock.VersionFormatted}'"); + OnInformationMessage($"- Size '{fileSystemSize.FormatBytes()}' ({fileSystemSize} bytes)"); + OnInformationMessage($"- File system name '{fileSystemHeaderBlock.FileSystemName}'"); OnDebugMessage($"Writing file system to '{fileSystemPath}'"); await File.WriteAllBytesAsync(fileSystemPath, fileSystemBytes, token); diff --git a/src/Hst.Imager.Core/Commands/RdbPartFormatCommand.cs b/src/Hst.Imager.Core/Commands/RdbPartFormatCommand.cs index 9dde7fc..a41dfde 100644 --- a/src/Hst.Imager.Core/Commands/RdbPartFormatCommand.cs +++ b/src/Hst.Imager.Core/Commands/RdbPartFormatCommand.cs @@ -1,5 +1,6 @@ namespace Hst.Imager.Core.Commands { + using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -7,6 +8,8 @@ using Amiga.Extensions; using Amiga.FileSystems.FastFileSystem; using Amiga.FileSystems.Pfs3; + using Amiga.RigidDiskBlocks; + using Extensions; using Hst.Core; using Hst.Core.Extensions; using Microsoft.Extensions.Logging; @@ -19,9 +22,13 @@ public class RdbPartFormatCommand : CommandBase private readonly string path; private readonly int partitionNumber; private readonly string name; + private readonly bool nonRdb; + private readonly string chs; + private readonly string dosType; public RdbPartFormatCommand(ILogger logger, ICommandHelper commandHelper, - IEnumerable physicalDrives, string path, int partitionNumber, string name) + IEnumerable physicalDrives, string path, int partitionNumber, string name, bool nonRdb, + string chs, string dosType) { this.logger = logger; this.commandHelper = commandHelper; @@ -29,12 +36,50 @@ public RdbPartFormatCommand(ILogger logger, ICommandHelper comma this.path = path; this.partitionNumber = partitionNumber; this.name = name; + this.nonRdb = nonRdb; + this.chs = chs; + this.dosType = dosType; } public override async Task Execute(CancellationToken token) { + DiskGeometry nonRdbDiskGeometry = new DiskGeometry + { + Heads = 16, + Sectors = 63 + }; + + if (nonRdb && string.IsNullOrWhiteSpace(dosType)) + { + return new Result(new Error($"DOS type is required for formatting a non-RDB partition")); + } + + if (nonRdb && !string.IsNullOrWhiteSpace(chs)) + { + var values = chs.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); + + if (values.Length != 3) + { + return new Result(new Error($"Invalid cylinders, heads and sectors value '{chs}'")); + } + + if (!int.TryParse(values[0], out var cylinders) || !int.TryParse(values[1], out var heads) || + !int.TryParse(values[2], out var sectors)) + { + return new Result(new Error($"Invalid cylinders, heads and sectors value '{chs}'")); + } + + nonRdbDiskGeometry = new DiskGeometry + { + DiskSize = (long)cylinders * heads * sectors * 512, + Cylinders = cylinders, + Heads = heads, + Sectors = sectors + }; + } + OnInformationMessage($"Formatting partition in Rigid Disk Block at '{path}'"); - + OnDebugMessage($"Opening '{path}' as writable"); var mediaResult = commandHelper.GetWritableMedia(physicalDrives, path, allowPhysicalDrive: true); @@ -44,21 +89,60 @@ public override async Task Execute(CancellationToken token) } using var media = mediaResult.Value; + + if (nonRdb && media.IsPhysicalDrive) + { + return new Result(new Error($"Physical drives doesn't support non RDB")); + } + await using var stream = media.Stream; - OnDebugMessage("Reading Rigid Disk Block"); + List partitionBlocks; + if (!nonRdb) + { + OnDebugMessage("Reading Rigid Disk Block"); + + var rigidDiskBlock = await commandHelper.GetRigidDiskBlock(stream); - var rigidDiskBlock = await commandHelper.GetRigidDiskBlock(stream); + if (rigidDiskBlock == null) + { + return new Result(new Error("Rigid Disk Block not found")); + } - if (rigidDiskBlock == null) + partitionBlocks = rigidDiskBlock.PartitionBlocks.ToList(); + } + else { - return new Result(new Error("Rigid Disk Block not found")); + var cylinderSize = (long)nonRdbDiskGeometry.Heads * nonRdbDiskGeometry.Sectors * 512; + var cylinders = nonRdbDiskGeometry.Cylinders == 0 + ? Convert.ToInt64((double)stream.Length / cylinderSize) + : nonRdbDiskGeometry.Cylinders; + var partitionSize = cylinderSize * cylinders; + + if (stream.Length != partitionSize) + { + stream.SetLength(partitionSize); + } + + partitionBlocks = new List + { + new PartitionBlock + { + DriveName = "DH0", + DosType = DosTypeHelper.FormatDosType(dosType), + Surfaces = (uint)nonRdbDiskGeometry.Heads, + BlocksPerTrack = (uint)nonRdbDiskGeometry.Sectors, + Reserved = 2, + PartitionSize = partitionSize, + LowCyl = 0, + HighCyl = (uint)(cylinders - 1), + FileSystemBlockSize = 512 + } + }; } - - var partitionBlocks = rigidDiskBlock.PartitionBlocks.ToList(); OnDebugMessage($"Formatting partition number '{partitionNumber}':"); - + if (partitionNumber < 1 || partitionNumber > partitionBlocks.Count) { return new Result(new Error($"Invalid partition number '{partitionNumber}'")); @@ -66,10 +150,27 @@ public override async Task Execute(CancellationToken token) var partitionBlock = partitionBlocks[partitionNumber - 1]; - OnInformationMessage($"- Name '{partitionBlock.DriveName}'"); - OnInformationMessage($"- DOS type '0x{partitionBlock.DosType.FormatHex()}' ({partitionBlock.DosType.FormatDosType()})"); + OnInformationMessage( + $"- Size '{partitionBlock.PartitionSize.FormatBytes()}' ({partitionBlock.PartitionSize} bytes)"); + if (nonRdb) + { + OnInformationMessage($"- Cylinders '{(partitionBlock.HighCyl - partitionBlock.LowCyl + 1)}'"); + OnInformationMessage($"- Heads '{partitionBlock.Surfaces}'"); + OnInformationMessage($"- Sectors '{partitionBlock.BlocksPerTrack}'"); + } + + OnInformationMessage($"- Low Cyl '{partitionBlock.LowCyl}'"); + OnInformationMessage($"- High Cyl '{partitionBlock.HighCyl}'"); + OnInformationMessage($"- Reserved '{partitionBlock.Reserved}'"); + if (!nonRdb) + { + OnInformationMessage($"- Name '{partitionBlock.DriveName}'"); + } + + OnInformationMessage( + $"- DOS type '0x{partitionBlock.DosType.FormatHex()}' ({partitionBlock.DosType.FormatDosType()})"); OnInformationMessage($"- Volume name '{name}'"); - + switch (partitionBlock.DosTypeFormatted) { case "DOS\\1":