Skip to content

Commit 53b9fe4

Browse files
Improvements to DosDriveManager (#2161)
* Move CurrentDosDirectory property from VirtualDrive to DosDriveBase and make it optional. * Added drive letter/index conversion methods to DosDriveManager. * Replaced internal DosDriveManager.DriveLetters dictionary with new drive letter/index methods. * Complete rewrite of DosDriveManager internal storage to use a single generic array for all drives instead of a dictionary for each drive type. Changed dictionary interface of DosDriveManager to use DosDriveBase instead of VirtualDrive. Added a number of generic methods for mounting, unmounting, and retrieving drives of different types. Added capability to retrieve drives by drive index as well as by drive letter. * Added DosDriveManager.TryGetDriveLetterIndex helper method. Changed internal HasDriveAtIndex to use int instead of ushort. * Fixed problematic use of ElementAtOrDefault when used with DosDriveManager. Applied a few optimizations relating to use of DosDriveManager. * Renamed some drive letter/index helper methods and parameters. * Change drive letter in test to unassigned letter Q: because drive letter Z: is assigned by default as a memory drive (it's just not a virtual drive). * Remove problematic assertions in DosDriveManager (CopyTo methods). * Fixed DOS FCB manager test ParseFilename_InvalidDrive_ContinuesParsing. * Fixed drive count in DosDriveManager. Also removed unnecessary DosDriveManager.NumberOfPotentiallyValidDriveLetters property. The drive manager now knows exactly how many drives are mounted. * Added more documentation to DosDriveManager. * Removed generic exception handler from DosDriveManager.Clear methods. * Fixed DOS IOCTL function for IsDeviceRemovable. AX = media type (0000h removable, 0001h fixed) * [DOS] Fixed DosDriveManager CopyTo() methods. DriveLetterCollection and DriveCollection both had a bug which prevented them from enumerating all drive slots. This had resulted in array elements not set when using CopyTo. * [DOS] Added some DosDriveManager unit tests. * chore: Removed `#region` directives from DosDriveManager. Per project maintainer's request.
1 parent 067d0d0 commit 53b9fe4

14 files changed

Lines changed: 1142 additions & 141 deletions

src/Spice86.Core/Emulator/InterruptHandlers/Dos/DosDiskInt25Handler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public override void Run() {
2525
ushort startingLogicalSector = State.DX;
2626
SegmentedAddress bufferForData = new(State.DS, State.BX);
2727

28-
if (driveNumber >= DosDriveManager.MaxDriveCount || !_dosDriveManager.HasDriveAtIndex(State.AL)) {
28+
if (!_dosDriveManager.HasDriveAtIndex(State.AL)) {
2929
State.AX = 0x8002;
3030
SetCarryFlag(true, true);
3131
} else {

src/Spice86.Core/Emulator/InterruptHandlers/Dos/DosDiskInt26Handler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public override void Run() {
2121
if (LoggerService.IsEnabled(Serilog.Events.LogEventLevel.Warning)) {
2222
LoggerService.Warning("DOS INT26H was called, hope for the best!");
2323
}
24-
if (State.AL >= DosDriveManager.MaxDriveCount || !_dosDriveManager.HasDriveAtIndex(State.AL)) {
24+
if (!_dosDriveManager.HasDriveAtIndex(State.AL)) {
2525
State.AX = 0x8002;
2626
SetCarryFlag(true, true);
2727
} else {

src/Spice86.Core/Emulator/InterruptHandlers/Dos/DosInt21Handler.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -662,12 +662,7 @@ private bool TryGetAllocationInfoDrive(byte driveRequest, out byte driveIndex, o
662662
driveIndex = (byte)(driveRequest - 1);
663663
}
664664

665-
if (driveIndex >= DosDriveManager.MaxDriveCount) {
666-
return false;
667-
}
668-
669-
char driveLetter = (char)('A' + driveIndex);
670-
if (!_dosDriveManager.TryGetValue(driveLetter, out VirtualDrive? resolvedDrive) || resolvedDrive == null) {
665+
if (!_dosDriveManager.TryGetDriveAtIndex(driveIndex, out VirtualDrive? resolvedDrive)) {
671666
return false;
672667
}
673668

@@ -1781,8 +1776,7 @@ public override void Run() {
17811776
public void SelectDefaultDrive() {
17821777
byte driveIndex = State.DL;
17831778
if (driveIndex < DosDriveManager.MaxDriveCount) {
1784-
char driveLetter = (char)('A' + driveIndex);
1785-
if (_dosDriveManager.TryGetValue(driveLetter, out VirtualDrive? mountedDrive)) {
1779+
if (_dosDriveManager.TryGetDriveAtIndex(driveIndex, out VirtualDrive? mountedDrive)) {
17861780
_dosDriveManager.CurrentDrive = mountedDrive;
17871781
}
17881782
} else if (LoggerService.IsEnabled(LogEventLevel.Error)) {

src/Spice86.Core/Emulator/Mcp/EmulatorMcpTools.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,8 @@ public CallToolResult QueryDosState() {
11541154
lock (_services.ToolsLock) {
11551155
Dos dos = GetDos();
11561156
List<DosDriveResponse> drives = dos.DosDriveManager.Values
1157+
.Where(static drive => drive is VirtualDrive)
1158+
.Cast<VirtualDrive>()
11571159
.Select(static drive => new DosDriveResponse {
11581160
Drive = drive.DosVolume,
11591161
CurrentDosDirectory = drive.CurrentDosDirectory,
@@ -1164,7 +1166,7 @@ public CallToolResult QueryDosState() {
11641166
return new DosStateResponse {
11651167
CurrentDrive = dos.DosDriveManager.CurrentDrive.DosVolume,
11661168
CurrentDriveIndex = dos.DosDriveManager.CurrentDriveIndex,
1167-
PotentialDriveLetters = dos.DosDriveManager.NumberOfPotentiallyValidDriveLetters,
1169+
PotentialDriveLetters = dos.DosDriveManager.Count,
11681170
CurrentProgramSegmentPrefix = dos.DosSwappableDataArea.CurrentProgramSegmentPrefix,
11691171
DeviceCount = dos.Devices.Count,
11701172
HasEms = dos.Ems != null,
@@ -1238,7 +1240,7 @@ public CallToolResult DosSetDefaultDrive(string driveLetter) {
12381240
}
12391241

12401242
char normalizedDriveLetter = char.ToUpperInvariant(driveLetter[0]);
1241-
if (!dos.DosDriveManager.TryGetValue(normalizedDriveLetter, out VirtualDrive? mountedDrive) || mountedDrive == null) {
1243+
if (!dos.DosDriveManager.TryGetDrive(normalizedDriveLetter, out VirtualDrive? mountedDrive) || mountedDrive == null) {
12421244
throw new InvalidOperationException($"Drive '{normalizedDriveLetter}' is not mounted");
12431245
}
12441246

@@ -1524,12 +1526,10 @@ private static byte ResolveDosDriveNumber(Dos dos, string driveLetter, out strin
15241526
throw new ArgumentException("Drive letter must be empty or a single character between A and Z");
15251527
}
15261528

1527-
char normalizedDriveLetter = char.ToUpperInvariant(driveLetter[0]);
1528-
if (!DosDriveManager.DriveLetters.TryGetValue(normalizedDriveLetter, out byte driveIndex)) {
1529-
throw new ArgumentException($"Drive letter '{normalizedDriveLetter}' is invalid");
1530-
}
1531-
if (!dos.DosDriveManager.TryGetValue(normalizedDriveLetter, out VirtualDrive? virtualDrive) || virtualDrive == null) {
1532-
throw new InvalidOperationException($"Drive '{normalizedDriveLetter}' is not mounted");
1529+
char driveLetterChar = driveLetter[0];
1530+
int driveIndex = DosDriveManager.GetDriveIndexOrThrow(driveLetterChar, nameof(driveLetter));
1531+
if (!dos.DosDriveManager.TryGetDrive(driveLetterChar, out VirtualDrive? virtualDrive) || virtualDrive == null) {
1532+
throw new InvalidOperationException($"Drive '{driveLetterChar}' is not mounted");
15331533
}
15341534

15351535
resolvedDrive = virtualDrive.DosVolume;

0 commit comments

Comments
 (0)