<> <> <> DIRECTORY Basics USING [HighHalf], FS USING [OpenFile, GetInfo, Read, Write], Floppy USING [BootFilePointer, defaultPageCount, Density, ErrorType, FileHandle, FileID, nullBootFilePointer, nullFileID, nullIndex, PageCount, PageNumber, Sides, VolumeHandle], FloppyChannel USING [Error, GetDeviceAttributes, GetHandle, Nop, SetContext, Status], FloppyFormat USING [badSpotSector, BadSpotSectors, ConvertPageCount, ConvertPageNumber, dataContext, DiskAddressToSector, FileList, FileListEntry, FileListSeal, FileListVersion, FloppySeal, FloppyVersion, ImplementedFileSize, InitialMicrocodeDiskAddress, MarkerPage, MarkerSeal, maxBadSectors, minTrackZeroSectors, nullSector, Sector, SectorNine, TrackZero, trackZeroAddress, TrackZeroSector], FloppyImplInterface, PrincOps USING [PageCount, wordsPerPage], Rope USING [FromProc, ROPE], SpecialFloppy USING [Error], VM USING [AddressForPageNumber, Free, Interval, nullInterval]; FloppyImplPublicA: MONITOR LOCKS volumeDesc USING volumeDesc: FloppyImplInterface.VolumeDesc IMPORTS Basics, FS, FloppyChannel, FloppyFormat, FloppyImplInterface, Rope, SpecialFloppy, VM EXPORTS Floppy, FloppyImplInterface SHARES FloppyImplInterface = BEGIN OPEN FloppyImplInterface, Floppy; <> ROPE: TYPE ~ Rope.ROPE; AlreadyFormatted: PUBLIC SAFE SIGNAL [labelString: ROPE] = CODE; DataError: PUBLIC SAFE ERROR [file: Floppy.FileHandle, page: Floppy.PageNumber, vm: LONG POINTER] = CODE; Error: PUBLIC SAFE ERROR [error: Floppy.ErrorType] = CODE; VolumeHandle: PUBLIC TYPE = RECORD [deviceIndex: CARDINAL, changeCount: CARDINAL]; nullVolumeHandle: PUBLIC VolumeHandle _ [LAST[CARDINAL], LAST[CARDINAL]]; <> <> MaxBufferSize: PrincOps.PageCount _ 32; FormatVerifyPasses: CARDINAL _ 2; <> Close: PUBLIC SAFE PROCEDURE [volume: VolumeHandle] = TRUSTED BEGIN CloseVolumeInternal: ENTRY PROCEDURE [volumeDesc: VolumeDesc] = TRUSTED BEGIN ENABLE UNWIND => NULL; CloseVolume[volumeDesc]; END; []_ValidateHandle[volume]; CloseVolumeInternal[volumeTable[volume.deviceIndex]]; END; Compact: PUBLIC SAFE PROCEDURE [volume: VolumeHandle] = TRUSTED BEGIN []_ValidateHandle[volume]; END; CopyFromFSFile: PUBLIC SAFE PROCEDURE [pilotFile: FS.OpenFile, floppyFile: FileHandle, firstFSPage: INT, firstFloppyPage: PageNumber, count: PageCount _ defaultPageCount] = TRUSTED BEGIN buffer: VM.Interval _ VM.nullInterval; CopyPilotFile: ENTRY PROCEDURE [volumeDesc: VolumeDesc, pilotFile: FS.OpenFile, floppyFile: Floppy.FileHandle, firstPilotPage: INT, firstFloppyPage: Floppy.PageNumber, count: Floppy.PageCount] = TRUSTED BEGIN ENABLE {DiskChanged => {CloseVolume[volumeDesc]; GO TO diskChanged}; UNWIND => VM.Free[buffer]}; floppyFileAddress: FloppyFormat.Sector; floppyFileSize: FloppyFormat.ImplementedFileSize; pilotFileSize: LONG CARDINAL; filePageNumber: FloppyFormat.ImplementedFileSize; pageCount: FloppyFormat.ImplementedFileSize; done: LONG CARDINAL; <> IF NOT volumeDesc.open THEN RETURN WITH ERROR Error[volumeNotOpen]; pilotFileSize _ FS.GetInfo[pilotFile].pages; IF volumeDesc.writeProtected THEN RETURN WITH ERROR Error[writeInhibited]; [address: floppyFileAddress, size: floppyFileSize] _ FindFile[volumeDesc, floppyFile.file]; IF floppyFileAddress = FloppyFormat.nullSector THEN RETURN WITH ERROR Error[fileNotFound]; IF (firstFloppyPage >= floppyFileSize) OR (CARD[firstPilotPage] >= pilotFileSize) THEN RETURN WITH ERROR Error[invalidPageNumber]; IF count = Floppy.defaultPageCount THEN BEGIN count _ pilotFileSize - firstPilotPage; IF count > floppyFileSize - firstFloppyPage THEN RETURN WITH ERROR Error [incompatibleSizes]; END ELSE IF (count > pilotFileSize - CARD[firstPilotPage]) OR (count > floppyFileSize - firstFloppyPage) THEN RETURN WITH ERROR Error[incompatibleSizes]; floppyFileAddress _ floppyFileAddress + FloppyFormat.ConvertPageNumber[firstFloppyPage]; IF Basics.HighHalf[count] # 0 THEN RETURN WITH ERROR Error[insufficientSpace]; pageCount _ FloppyFormat.ConvertPageCount[count]; <> buffer _ CreateBuffer[MIN[count, MaxBufferSize]]; IF buffer.count = 0 THEN ERROR; -- insufficient VM to operate FOR filePageNumber _ 0, filePageNumber + CARDINAL[buffer.count] WHILE filePageNumber < pageCount DO FS.Read[pilotFile, firstPilotPage+filePageNumber, buffer.count, VM.AddressForPageNumber[buffer.page]]; WriteFloppy[volumeDesc, VM.AddressForPageNumber[buffer.page], floppyFileAddress+filePageNumber, MIN[CARDINAL[buffer.count], FloppyFormat.ConvertPageNumber[count-filePageNumber]] ! IOError => {done _ filePageNumber+countDone; GO TO dataError}; UNWIND => VM.Free[buffer]]; REPEAT dataError => RETURN WITH ERROR DataError[floppyFile, done, NIL]; FINISHED => VM.Free[buffer]; ENDLOOP; EXITS diskChanged => RETURN WITH ERROR Error[volumeNotOpen]; END; volume: VolumeHandle = floppyFile.volume; [] _ ValidateHandle[volume]; CopyPilotFile[volumeTable[volume.deviceIndex], pilotFile, floppyFile, firstFSPage, firstFloppyPage, count]; END; CopyToFSFile: PUBLIC SAFE PROCEDURE [floppyFile: FileHandle, pilotFile: FS.OpenFile, firstFloppyPage: PageNumber, firstFSPage: INT, count: PageCount _ defaultPageCount] = TRUSTED BEGIN buffer: VM.Interval _ VM.nullInterval; CopyFloppyFile: ENTRY PROCEDURE [volumeDesc: VolumeDesc, floppyFile: Floppy.FileHandle, pilotFile: FS.OpenFile, firstFloppyPage: Floppy.PageNumber, firstPilotPage: INT, count: Floppy.PageCount] = TRUSTED BEGIN ENABLE BEGIN DiskChanged => {CloseVolume[volumeDesc]; GO TO diskChanged}; UNWIND => VM.Free[buffer]; END; floppyFileAddress: FloppyFormat.Sector; floppyFileSize: FloppyFormat.ImplementedFileSize; pilotFileSize: CARD; filePageNumber: FloppyFormat.ImplementedFileSize; pageCount: FloppyFormat.ImplementedFileSize; done: LONG CARDINAL; <> IF ~ volumeDesc.open THEN RETURN WITH ERROR Error[volumeNotOpen]; pilotFileSize _ FS.GetInfo[pilotFile].pages; [address: floppyFileAddress, size: floppyFileSize] _ FindFile[volumeDesc, floppyFile.file]; IF floppyFileAddress = FloppyFormat.nullSector THEN RETURN WITH ERROR Error[fileNotFound]; IF (firstFloppyPage >= floppyFileSize) OR (CARD[firstPilotPage] >= pilotFileSize) THEN RETURN WITH ERROR Error[invalidPageNumber]; IF count = Floppy.defaultPageCount THEN BEGIN count _ floppyFileSize - firstFloppyPage; IF count > pilotFileSize - firstPilotPage THEN RETURN WITH ERROR Error[incompatibleSizes]; END ELSE IF (count > pilotFileSize - firstPilotPage) OR (count > floppyFileSize - firstFloppyPage) THEN RETURN WITH ERROR Error[incompatibleSizes]; floppyFileAddress _ floppyFileAddress + FloppyFormat.ConvertPageNumber[firstFloppyPage]; pageCount _ FloppyFormat.ConvertPageCount[count]; <> buffer _ CreateBuffer[MIN[pageCount, MaxBufferSize]]; FOR filePageNumber _ 0, filePageNumber+CARDINAL[buffer.count] WHILE filePageNumber < pageCount DO pages: CARDINAL = MIN[CARDINAL[buffer.count], pageCount-filePageNumber]; ReadFloppy[ volumeDesc, VM.AddressForPageNumber[buffer.page], floppyFileAddress+filePageNumber, pages ! IOError => {done _ filePageNumber+countDone; GO TO dataError}; UNWIND => VM.Free[buffer]]; FS.Write[file: pilotFile, to: firstPilotPage+filePageNumber, nPages: pages, from: VM.AddressForPageNumber[buffer.page]]; REPEAT dataError => RETURN WITH ERROR DataError[floppyFile, done, NIL]; FINISHED => VM.Free[buffer]; ENDLOOP; EXITS diskChanged => RETURN WITH ERROR Error[volumeNotOpen]; END; -- CopyFloppyFile volume: VolumeHandle = floppyFile.volume; [] _ ValidateHandle[volume]; CopyFloppyFile[volumeTable[volume.deviceIndex], floppyFile, pilotFile, firstFloppyPage, firstFSPage, count]; END; CreateFile: PUBLIC SAFE PROCEDURE [volume: VolumeHandle, size: Floppy.PageCount, type: -- File.Type -- CARDINAL] RETURNS [file: Floppy.FileHandle] = TRUSTED BEGIN volumeDesc: VolumeDesc; CreateFileEntryInternal: ENTRY PROCEDURE[volumeDesc: VolumeDesc, size: Floppy.PageCount, type: -- File.Type -- CARDINAL, startSector: FloppyFormat.Sector] RETURNS[file: Floppy.FileID]= TRUSTED BEGIN ENABLE UNWIND => NULL; IF ~volumeDesc.open THEN RETURN WITH ERROR Error[volumeNotOpen]; IF volumeDesc.writeProtected THEN RETURN WITH ERROR Error[writeInhibited]; file _ CreateFileInternal[volumeDesc, size, type, startSector, Floppy.nullFileID].fileID; END; file.volume _ volume; volumeDesc _ ValidateHandle[volume]; file.file _ CreateFileEntryInternal[volumeDesc, size, type, FloppyFormat.nullSector]; END; CreateInitialMicrocodeFile: PUBLIC SAFE PROCEDURE [volume: VolumeHandle, size: Floppy.PageCount, type: -- File.Type -- CARDINAL, startingPageNumber: Floppy.PageNumber] RETURNS [file: Floppy.FileHandle] = TRUSTED BEGIN volumeDesc: VolumeDesc; file.volume _ volume; volumeDesc _ ValidateHandle[volume]; file.file _ CreateInitialMicrocodeInternal[volumeDesc, size, type, startingPageNumber, Floppy.nullFileID]; END; CreateInitialMicrocodeInternal: PUBLIC ENTRY SAFE PROCEDURE[volumeDesc: VolumeDesc, size: Floppy.PageCount, type: -- File.Type -- CARDINAL, startingPageNumber: Floppy.PageNumber, id: Floppy.FileID] RETURNS[file: Floppy.FileID]= TRUSTED BEGIN ENABLE UNWIND => NULL; alignmentSector, startSector: FloppyFormat.Sector; --physical pages for file IF ~volumeDesc.open THEN RETURN WITH ERROR Error[volumeNotOpen]; IF volumeDesc.writeProtected THEN RETURN WITH ERROR Error[writeInhibited]; IF startingPageNumber >= size THEN RETURN WITH ERROR Error[invalidPageNumber]; alignmentSector _ FloppyFormat.DiskAddressToSector[ FloppyFormat.InitialMicrocodeDiskAddress, volumeDesc.sectorNine.cylinders, volumeDesc.sectorNine.tracksPerCylinder, volumeDesc.sectorNine.sectorsPerTrack]; <> startSector _ alignmentSector - FloppyFormat.ConvertPageNumber[startingPageNumber]; file _ CreateFileInternal[volumeDesc, size, type, startSector, id ! SpecialFloppy.Error => GOTO noRoom].fileID; EXITS noRoom => RETURN WITH ERROR Error[initialMicrocodeSpaceNotAvailable]; END; CreateFileInternal: PUBLIC SAFE PROCEDURE [volumeDesc: VolumeDesc, size: Floppy.PageCount, type: -- File.Type -- CARDINAL, startSector: FloppyFormat.Sector, id: Floppy.FileID] RETURNS[fileID: Floppy.FileID, startPage: FloppyFormat.Sector] = TRUSTED BEGIN ENABLE BEGIN DiskChanged => {CloseVolume[volumeDesc]; GO TO diskChanged}; IOError => {CloseVolume[volumeDesc]; GO TO needsScavenging;}; END; <> IF volumeDesc.fileList.count = volumeDesc.fileList.maxEntries THEN ERROR Error[fileListFull]; VolumeChanging[volumeDesc]; [startPage, fileID] _ AllocateFile[volumeDesc, size, type, startSector, id]; AddFile[volumeDesc, fileID, FloppyFormat.ConvertPageCount[size], type, startPage]; VolumeStable[volumeDesc]; -- The volume is now stable EXITS needsScavenging => ERROR Error[needsScavenging]; diskChanged => ERROR Error[volumeNotOpen]; END; DeleteFile: PUBLIC SAFE PROCEDURE [file: Floppy.FileHandle] = TRUSTED BEGIN buffer: VM.Interval _ VM.nullInterval; DeleteFileInternal: ENTRY PROCEDURE [volumeDesc: VolumeDesc, fileID: Floppy.FileID] = TRUSTED BEGIN ENABLE BEGIN DiskChanged => {CloseVolume[volumeDesc]; GO TO diskChanged}; IOError => {CloseVolume[volumeDesc]; GO TO needsScavenging}; UNWIND => VM.Free[buffer]; END; zerothMarkerPage: LONG POINTER TO FloppyFormat.MarkerPage; firstMarkerPage: LONG POINTER TO FloppyFormat.MarkerPage; secondMarkerPage: LONG POINTER TO FloppyFormat.MarkerPage; thirdMarkerPage: LONG POINTER TO FloppyFormat.MarkerPage; zerothMarkerPageAddress: FloppyFormat.Sector _ FloppyFormat.nullSector; firstMarkerPageAddress: FloppyFormat.Sector; secondMarkerPageAddress: FloppyFormat.Sector; thirdMarkerPageAddress: FloppyFormat.Sector _ FloppyFormat.nullSector; address: FloppyFormat.Sector; firstDeletion, lastDeletion: FloppyFormat.Sector; size: FloppyFormat.ImplementedFileSize; IF ~volumeDesc.open THEN RETURN WITH ERROR Error[volumeNotOpen]; IF volumeDesc.writeProtected THEN RETURN WITH ERROR Error[writeInhibited]; [address: address, size: size] _ FindFile[volumeDesc, fileID]; IF address = FloppyFormat.nullSector THEN RETURN WITH ERROR Error[fileNotFound]; IF fileID = volumeDesc.sectorNine.fileListID THEN RETURN; <> buffer _ CreateBuffer[4]; IF buffer.count < 4 THEN ERROR; -- Insufficient VM to operate zerothMarkerPage _ VM.AddressForPageNumber[buffer.page]; firstMarkerPage _ zerothMarkerPage+PrincOps.wordsPerPage; secondMarkerPage _ firstMarkerPage+PrincOps.wordsPerPage; thirdMarkerPage _ secondMarkerPage+PrincOps.wordsPerPage; firstMarkerPageAddress _ address-1; secondMarkerPageAddress _ address+size; ReadFloppy[volumeDesc, firstMarkerPage, firstMarkerPageAddress, 1]; IF secondMarkerPageAddress # firstMarkerPageAddress+firstMarkerPage.next.length+1 THEN BEGIN volumeDesc.open _ FALSE; VM.Free[buffer]; RETURN WITH ERROR Error[needsScavenging]; END; ReadFloppy[volumeDesc, secondMarkerPage, secondMarkerPageAddress, 1]; IF secondMarkerPageAddress-secondMarkerPage.previous.length-1 # firstMarkerPageAddress THEN BEGIN CloseVolume[volumeDesc]; VM.Free[buffer]; RETURN WITH ERROR Error[needsScavenging]; END; VolumeChanging[volumeDesc]; IF firstMarkerPage.previous.type = free THEN BEGIN zerothMarkerPageAddress _ firstMarkerPageAddress - FloppyFormat.ConvertPageCount[firstMarkerPage.previous.length] -1; firstDeletion _ firstMarkerPageAddress; ReadFloppy[volumeDesc, zerothMarkerPage, zerothMarkerPageAddress, 1]; IF zerothMarkerPageAddress+zerothMarkerPage.next.length+1 # firstMarkerPageAddress THEN BEGIN CloseVolume[volumeDesc]; VM.Free[buffer]; RETURN WITH ERROR Error[needsScavenging]; END; END ELSE firstDeletion _ address; IF (secondMarkerPage.next.type = free) AND (secondMarkerPageAddress~=volumeDesc.numPages) THEN BEGIN thirdMarkerPageAddress _ secondMarkerPageAddress + FloppyFormat.ConvertPageCount[secondMarkerPage.next.length]+1; lastDeletion _ secondMarkerPageAddress; ReadFloppy[volumeDesc, thirdMarkerPage, thirdMarkerPageAddress, 1]; IF thirdMarkerPageAddress-thirdMarkerPage.previous.length-1 # secondMarkerPageAddress THEN BEGIN CloseVolume[volumeDesc]; VM.Free[buffer]; RETURN WITH ERROR Error[needsScavenging]; END; END ELSE lastDeletion _ secondMarkerPageAddress -1; <> IF zerothMarkerPageAddress = FloppyFormat.nullSector THEN BEGIN firstMarkerPage.next.body _ free[]; IF thirdMarkerPageAddress = FloppyFormat.nullSector THEN secondMarkerPage.previous.body _ free[] ELSE BEGIN firstMarkerPage.next.length _ size + 1 + secondMarkerPage.next.length; thirdMarkerPage.previous.length _ firstMarkerPage.next.length; END; END ELSE BEGIN IF thirdMarkerPageAddress = FloppyFormat.nullSector THEN BEGIN secondMarkerPage.previous.body _ free[]; zerothMarkerPage.next.length _ size + 1 + zerothMarkerPage.next.length; secondMarkerPage.previous.length _ zerothMarkerPage.next.length; END ELSE BEGIN zerothMarkerPage.next.length _ zerothMarkerPage.next.length + 2 + size + secondMarkerPage.next.length; thirdMarkerPage.previous.length _ zerothMarkerPage.next.length; END; END; <> IF zerothMarkerPageAddress = FloppyFormat.nullSector THEN WriteFloppy[volumeDesc, firstMarkerPage, firstMarkerPageAddress, 1] ELSE WriteFloppy[volumeDesc, zerothMarkerPage, zerothMarkerPageAddress, 1]; IF thirdMarkerPageAddress = FloppyFormat.nullSector THEN WriteFloppy[volumeDesc, secondMarkerPage, secondMarkerPageAddress, 1] ELSE WriteFloppy[volumeDesc, thirdMarkerPage, thirdMarkerPageAddress, 1]; FOR i: FloppyFormat.Sector IN [firstDeletion..lastDeletion] DO volumeDesc.allocationMap[i] _ free; ENDLOOP; RemoveFile[volumeDesc, fileID]; VolumeStable[volumeDesc]; VM.Free[buffer]; EXITS diskChanged => RETURN WITH ERROR Error[volumeNotOpen]; needsScavenging => RETURN WITH ERROR Error[needsScavenging] END; volume: VolumeHandle = file.volume; [] _ ValidateHandle[volume]; DeleteFileInternal[volumeTable[volume.deviceIndex], file.file]; END; GetAttributes: PUBLIC SAFE PROCEDURE [volume: VolumeHandle] RETURNS [freeSpace: Floppy.PageCount, largestBlock: Floppy.PageCount, fileList: Floppy.FileHandle, rootFile: Floppy.FileHandle, density: Floppy.Density[single..double], sides: Floppy.Sides[one..two], maxFileListEntries: CARDINAL, labelString: ROPE] = TRUSTED BEGIN GetAttrributesInternal: ENTRY PROCEDURE [volumeDesc: VolumeDesc] = TRUSTED BEGIN startRun: FloppyFormat.Sector; inRun: BOOLEAN; firstDataSector: FloppyFormat.Sector = FirstDataSector[volumeDesc]; lastDataSector: FloppyFormat.Sector = FloppyFormat.ConvertPageCount[volumeDesc.numPages]; IF ~volumeDesc.open THEN RETURN WITH ERROR Error[volumeNotOpen]; inRun _ FALSE; startRun _ 0; largestBlock _ 0; freeSpace _ 0; maxFileListEntries _ volumeDesc.fileList.maxEntries; fileList _ [volume, volumeDesc.sectorNine.fileListID]; rootFile _ [volume, volumeDesc.sectorNine.rootFile]; density _ volumeDesc.density; sides _ volumeDesc.sides; BEGIN i: CARDINAL _ 0; P: SAFE PROC RETURNS [c: CHAR] = TRUSTED {c _ volumeDesc.sectorNine.label[i]; i _ i + 1}; labelString _ Rope.FromProc[len: volumeDesc.sectorNine.labelSize, p: P]; END; FOR i: FloppyFormat.Sector IN [firstDataSector..lastDataSector) DO IF volumeDesc.allocationMap[i] = free THEN BEGIN freeSpace _ freeSpace+1; IF ~inRun THEN {inRun _ TRUE; startRun _ i} ELSE NULL; END ELSE IF inRun THEN {inRun _ FALSE; largestBlock _ MAX[largestBlock, i-startRun]}; ENDLOOP; IF inRun THEN largestBlock _ MAX[largestBlock, volumeDesc.numPages-startRun]; END; -- GetAttributesInternal [] _ ValidateHandle[volume]; GetAttrributesInternal[volumeTable[volume.deviceIndex]]; END; <> GetDrive: PUBLIC SAFE PROC [volumeHandle: VolumeHandle] RETURNS [drive: CARDINAL] = TRUSTED { drive _ volumeHandle.deviceIndex; IF ~ValidDrive[drive] THEN ERROR Error[invalidVolumeHandle] }; GetBootFiles: PUBLIC SAFE PROCEDURE [volume: VolumeHandle] RETURNS [initialMicrocode, pilotMicrocode, diagnosticMicrocode, germ, pilotBootFile: Floppy.BootFilePointer] = TRUSTED BEGIN GetBootFilesInternal: ENTRY PROCEDURE [volumeDesc: VolumeDesc, page: FloppyFormat.Sector] RETURNS [floppyBootFileData: Floppy.BootFilePointer] = TRUSTED BEGIN FOR index: CARDINAL IN [0..volumeDesc.fileList.count) DO IF page IN [volumeDesc.fileList.files[index].location .. volumeDesc.fileList.files[index].location + volumeDesc.fileList.files[index].size) THEN BEGIN floppyBootFileData.file _ volumeDesc.fileList.files[index].file; floppyBootFileData.page _ page - volumeDesc.fileList.files[index].location; EXIT; END; REPEAT FINISHED => floppyBootFileData _ Floppy.nullBootFilePointer; ENDLOOP; END; -- GetBootFilesInternal volumeDesc: VolumeDesc; volumeDesc _ ValidateHandle[volume]; IF ~volumeDesc.open THEN ERROR Error[volumeNotOpen]; initialMicrocode _ GetBootFilesInternal[volumeDesc, FloppyFormat.DiskAddressToSector[ FloppyFormat.InitialMicrocodeDiskAddress,volumeDesc.sectorNine.cylinders, volumeDesc.sectorNine.tracksPerCylinder, volumeDesc.sectorNine.sectorsPerTrack]]; pilotMicrocode _ GetBootFilesInternal[volumeDesc, volumeDesc.sectorNine.pilotMicrocode]; diagnosticMicrocode _ GetBootFilesInternal[volumeDesc, volumeDesc.sectorNine.diagnosticMicrocode]; germ _ GetBootFilesInternal[volumeDesc, volumeDesc.sectorNine.germ]; pilotBootFile _ GetBootFilesInternal[volumeDesc, volumeDesc.sectorNine.pilotBootFile]; END; GetFileAttributes: PUBLIC SAFE PROCEDURE [file: Floppy.FileHandle] RETURNS [size: Floppy.PageCount, type: -- File.Type -- CARDINAL] = TRUSTED BEGIN GetFileAttributesInternal: ENTRY PROCEDURE [volumeDesc: VolumeDesc] = TRUSTED BEGIN IF ~volumeDesc.open THEN RETURN WITH ERROR Error[volumeNotOpen]; FOR i: CARDINAL IN [0..volumeDesc.fileList.count) DO IF volumeDesc.fileList.files[i].file = file.file THEN BEGIN size _ volumeDesc.fileList.files[i].size; type _ volumeDesc.fileList.files[i].type; RETURN; END; ENDLOOP; RETURN WITH ERROR Error[fileNotFound]; END; volume: VolumeHandle = file.volume; []_ValidateHandle[volume]; GetFileAttributesInternal[volumeTable[volume.deviceIndex]]; END; GetNextFile: PUBLIC SAFE PROCEDURE [file: Floppy.FileHandle] RETURNS [nextFile: Floppy.FileHandle] = TRUSTED BEGIN GetNextFileInternal: ENTRY PROCEDURE [volumeDesc: VolumeDesc] = TRUSTED BEGIN IF ~volumeDesc.open THEN RETURN WITH ERROR Error[volumeNotOpen]; IF file.file = Floppy.nullFileID THEN <> FOR i: CARDINAL IN [0..volumeDesc.fileList.count) DO IF volumeDesc.fileList.files[i].file ~= volumeDesc.sectorNine.fileListID THEN BEGIN nextFile _ [file.volume, volumeDesc.fileList.files[i].file]; RETURN; END; REPEAT FINISHED => BEGIN nextFile _ [file.volume, Floppy.nullFileID]; RETURN; END; ENDLOOP ELSE --go find such a file FOR i:CARDINAL IN [0..volumeDesc.fileList.count) DO IF volumeDesc.fileList.files[i].file = file.file THEN BEGIN IF (i = volumeDesc.fileList.count-1) OR ((i = volumeDesc.fileList.count-2) AND (volumeDesc.fileList.files[i+1].file = volumeDesc.sectorNine.fileListID)) THEN nextFile _ [file.volume, Floppy.nullFileID] ELSE nextFile _ IF volumeDesc.fileList.files[i+1].file = volumeDesc.sectorNine.fileListID THEN [file.volume, volumeDesc.fileList.files[i+2].file] ELSE [file.volume, volumeDesc.fileList.files[i+1].file]; RETURN; END; ENDLOOP; RETURN WITH ERROR Error[fileNotFound]; END; volume: VolumeHandle = file.volume; [] _ ValidateHandle[volume]; GetNextFileInternal[volumeTable[volume.deviceIndex]]; END; GetNextBadSector: PUBLIC SAFE PROCEDURE [volume: VolumeHandle, oldIndex: CARDINAL] RETURNS [newIndex: CARDINAL, file: Floppy.FileHandle, page: Floppy.PageNumber] = TRUSTED BEGIN []_ValidateHandle[volume]; RETURN[Floppy.nullIndex, [nullVolumeHandle, Floppy.nullFileID], 0]; END; Open: PUBLIC SAFE PROCEDURE [drive: CARDINAL _ 0] RETURNS [volume: Floppy.VolumeHandle] = TRUSTED BEGIN buffer: VM.Interval _ VM.nullInterval; OpenInternal: ENTRY PROCEDURE [volumeDesc: VolumeDesc] RETURNS [volume: VolumeHandle] = TRUSTED BEGIN ENABLE BEGIN IOError => GO TO needsScavenging; UNWIND => VM.Free[buffer]; END; markerPage: LONG POINTER TO FloppyFormat.MarkerPage; requestedSize: PrincOps.PageCount; bound: CARDINAL; lastMoved: CARDINAL; temp: FloppyFormat.FileListEntry; trackZero: FloppyFormat.TrackZero; IF volumeDesc.open THEN BEGIN [] _ FloppyChannel.Nop[volumeDesc.handle ! FloppyChannel.Error => GO TO close]; EXITS close => CloseVolume[volumeDesc ! Error => CONTINUE]; END; IF volumeDesc.open THEN RETURN [[drive, volumeDesc.changeCount]]; requestedSize _ WordsToPages[(SIZE[FloppyFormat.TrackZeroSector] * FloppyFormat.minTrackZeroSectors)] + WordsToPages[SIZE[FloppyFormat.MarkerPage]]; buffer _ CreateBuffer[requestedSize]; IF requestedSize ~= buffer.count THEN ERROR; <> trackZero.BASE _ VM.AddressForPageNumber[buffer.page]; markerPage _ LOOPHOLE[BASE[trackZero] + PrincOps.wordsPerPage * (WordsToPages[FloppyFormat.minTrackZeroSectors * SIZE[FloppyFormat.TrackZeroSector]])]; volumeDesc.handle _ FloppyChannel.GetHandle[drive]; <> AccessFloppy[volumeDesc, BASE[trackZero], FloppyFormat.trackZeroAddress, FloppyFormat.minTrackZeroSectors, read]; volumeDesc.sectorNine^ _ LOOPHOLE[trackZero[9]]; IF volumeDesc.sectorNine.changing THEN GOTO needsScavenging; IF volumeDesc.sectorNine.seal ~= FloppyFormat.FloppySeal THEN GOTO needsScavenging; IF volumeDesc.sectorNine.version ~= FloppyFormat.FloppyVersion THEN GOTO needsScavenging; FOR i: CARDINAL IN [0..FloppyFormat.maxBadSectors) DO volumeDesc.badPageMap^[i] _ LOOPHOLE[BASE[trackZero]+(FloppyFormat.badSpotSector-1)* SIZE[FloppyFormat.TrackZeroSector], LONG POINTER TO FloppyFormat.BadSpotSectors]^[i]; ENDLOOP; volumeDesc.writeProtected _ IsDriveWriteProtected[volumeDesc]; SELECT TRUE FROM FloppyChannel.SetContext[volumeDesc.handle, FloppyFormat.dataContext[single]] AND FloppyChannel.GetDeviceAttributes[volumeDesc.handle].maxSectorsPerTrack = volumeDesc.sectorNine.sectorsPerTrack => volumeDesc.density _ single; FloppyChannel.SetContext [volumeDesc.handle, FloppyFormat.dataContext[double]] AND FloppyChannel.GetDeviceAttributes[volumeDesc.handle].maxSectorsPerTrack = volumeDesc.sectorNine.sectorsPerTrack => volumeDesc.density _ double; ENDCASE => GOTO needsScavenging; IF volumeDesc.sectorNine.tracksPerCylinder = 1 THEN volumeDesc.sides _ one ELSE IF volumeDesc.sectorNine.tracksPerCylinder = 2 THEN volumeDesc.sides _ two ELSE GO TO needsScavenging; IF volumeDesc.sectorNine.cylinders = 0 THEN GOTO needsScavenging; volumeDesc.numPages _ volumeDesc.sectorNine.sectorsPerTrack * volumeDesc.sectorNine.tracksPerCylinder * volumeDesc.sectorNine.cylinders; <> ReadFloppy[volumeDesc, markerPage, volumeDesc.sectorNine.fileList-1, 1]; IF markerPage.seal ~= FloppyFormat.MarkerSeal THEN GOTO needsScavenging; WITH mp: markerPage.next SELECT FROM free, file => GOTO needsScavenging; fileList => BEGIN IF mp.file ~= volumeDesc.sectorNine.fileListID THEN GOTO needsScavenging; IF mp.length ~= volumeDesc.sectorNine.fileListSize THEN GOTO needsScavenging; IF mp.type ~= FloppyImplInterface.FileListType THEN GOTO needsScavenging; END; ENDCASE => GOTO needsScavenging; ReadFloppy[volumeDesc: volumeDesc, buffer: markerPage, count: 1, address: volumeDesc.sectorNine.fileList + volumeDesc.sectorNine.fileListSize]; IF markerPage.seal ~= FloppyFormat.MarkerSeal THEN GOTO needsScavenging; WITH mp: markerPage.previous SELECT FROM free, file => GOTO needsScavenging; fileList => BEGIN IF mp.file ~= volumeDesc.sectorNine.fileListID OR mp.length ~= volumeDesc.sectorNine.fileListSize OR mp.type ~= FloppyImplInterface.FileListType THEN GOTO needsScavenging; END; ENDCASE => GOTO needsScavenging; volumeDesc.fileListSpace _ CreateBuffer[volumeDesc.sectorNine.fileListSize]; volumeDesc.fileList _ VM.AddressForPageNumber[volumeDesc.fileListSpace.page]; ReadFloppy[volumeDesc, volumeDesc.fileList, volumeDesc.sectorNine.fileList, volumeDesc.sectorNine.fileListSize]; IF volumeDesc.fileList.seal ~= FloppyFormat.FileListSeal OR volumeDesc.fileList.version ~= FloppyFormat.FileListVersion OR volumeDesc.fileList.maxEntries = 0 OR volumeDesc.fileList.maxEntries < volumeDesc.fileList.count OR volumeDesc.fileList.count = 0 OR FindFile[volumeDesc, volumeDesc.sectorNine.fileListID].address = FloppyFormat.nullSector THEN GOTO needsScavenging; <> bound _ volumeDesc.fileList.count; DO lastMoved _ 0; FOR i: CARDINAL IN [0..bound-1) DO IF volumeDesc.fileList.files[i].location > volumeDesc.fileList.files[i+1].location THEN BEGIN temp _ volumeDesc.fileList.files[i]; volumeDesc.fileList.files[i] _ volumeDesc.fileList.files[i+1]; volumeDesc.fileList.files[i+1] _ temp; lastMoved _ i; END; ENDLOOP; IF lastMoved = 0 THEN EXIT ELSE bound _ lastMoved+1; ENDLOOP; InitializeAllocationMap[volumeDesc]; volumeDesc.open _ TRUE; VM.Free[buffer]; RETURN [[drive, volumeDesc.changeCount]]; EXITS needsScavenging => BEGIN VM.Free[buffer]; RETURN WITH ERROR Error[needsScavenging]; END; END; IF ~ValidDrive[drive] THEN ERROR Error[noSuchDrive]; RETURN[OpenInternal[volumeTable[drive] ! DiskChanged => RETRY]]; END; Read: PUBLIC PROCEDURE [file: Floppy.FileHandle, first: Floppy.PageNumber, count: Floppy.PageCount, vm: LONG POINTER] = BEGIN done: Floppy.PageCount; ReadInternal: ENTRY PROCEDURE [volumeDesc: VolumeDesc] = BEGIN ENABLE BEGIN IOError => {done _ countDone; GO TO dataError;}; DiskChanged => {CloseVolume[volumeDesc]; GO TO diskChanged}; UNWIND => NULL; END; address: FloppyFormat.Sector; size: FloppyFormat.ImplementedFileSize; localFirst: FloppyFormat.ImplementedFileSize; <> IF ~volumeDesc.open THEN RETURN WITH ERROR Error[volumeNotOpen]; [address: address, size: size] _ FindFile[volumeDesc, file.file]; IF address = FloppyFormat.nullSector THEN RETURN WITH ERROR Error[fileNotFound]; IF first >= size OR first+count > size THEN RETURN WITH ERROR Error[endOfFile]; localFirst _ FloppyFormat.ConvertPageNumber[first]; ReadFloppy[ volumeDesc, vm, address+localFirst, FloppyFormat.ConvertPageCount[count]]; EXITS dataError => RETURN WITH ERROR DataError [file, first+done, NIL]; diskChanged => RETURN WITH ERROR Error[volumeNotOpen]; END; volume: VolumeHandle = file.volume; []_ValidateHandle[volume]; ReadInternal[volumeTable[volume.deviceIndex]]; END; ReplaceBadSector: PUBLIC SAFE PROCEDURE [file: Floppy.FileHandle, page: Floppy.PageNumber] RETURNS [readError: BOOLEAN] = TRUSTED {ERROR}; SetBootFiles: PUBLIC SAFE PROCEDURE [volume: VolumeHandle, pilotMicrocode, diagnosticMicrocode, germ, pilotBootFile: Floppy.BootFilePointer] = TRUSTED BEGIN SetBootFilesInternal: ENTRY PROCEDURE [volumeDesc: VolumeDesc] = TRUSTED BEGIN ENABLE BEGIN DiskChanged => {CloseVolume[volumeDesc]; GO TO diskChanged}; IOError => {CloseVolume[volumeDesc]; GO TO needsScavenging}; UNWIND => NULL; END; pilotMicrocodeSector, diagnosticMicrocodeSector, germSector, pilotBootFileSector: FloppyFormat.Sector; IF ~volumeDesc.open THEN RETURN WITH ERROR Error[volumeNotOpen]; IF volumeDesc.writeProtected THEN RETURN WITH ERROR Error[writeInhibited]; pilotMicrocodeSector _ GetBootFileAddress[volumeDesc, pilotMicrocode]; diagnosticMicrocodeSector _ GetBootFileAddress[volumeDesc, diagnosticMicrocode]; germSector _ GetBootFileAddress[volumeDesc, germ]; pilotBootFileSector _ GetBootFileAddress[volumeDesc, pilotBootFile]; volumeDesc.sectorNine.pilotMicrocode _ pilotMicrocodeSector; volumeDesc.sectorNine.diagnosticMicrocode _ diagnosticMicrocodeSector; volumeDesc.sectorNine.germ _ germSector; volumeDesc.sectorNine.pilotBootFile _ pilotBootFileSector; VolumeChanging[volumeDesc]; WriteSectorNine[volumeDesc]; VolumeStable[volumeDesc]; EXITS diskChanged => RETURN WITH ERROR Error[volumeNotOpen]; needsScavenging => RETURN WITH ERROR Error[needsScavenging]; END; []_ValidateHandle[volume]; SetBootFilesInternal[volumeTable[volume.deviceIndex]]; END; SetRootFile: PUBLIC SAFE PROCEDURE [file: Floppy.FileHandle] = TRUSTED BEGIN SetRootFileInternal: ENTRY PROCEDURE [volumeDesc: VolumeDesc] = TRUSTED BEGIN ENABLE BEGIN DiskChanged => {CloseVolume[volumeDesc]; GO TO diskChanged}; IOError => {CloseVolume[volumeDesc]; GO TO needsScavenging} END; IF ~volumeDesc.open THEN RETURN WITH ERROR Error[volumeNotOpen]; IF volumeDesc.writeProtected THEN RETURN WITH ERROR Error[writeInhibited]; volumeDesc.sectorNine.rootFile _ file.file; WriteSectorNine[volumeDesc]; EXITS diskChanged => RETURN WITH ERROR Error[volumeNotOpen]; needsScavenging => RETURN WITH ERROR Error[needsScavenging]; END; volume: VolumeHandle = file.volume; []_ValidateHandle[volume]; SetRootFileInternal[volumeTable[volume.deviceIndex]]; END; Write: PUBLIC PROCEDURE [file: Floppy.FileHandle, first: Floppy.PageNumber, count: Floppy.PageCount, vm: LONG POINTER] = BEGIN done: Floppy.PageCount; WriteInternal: ENTRY PROCEDURE [volumeDesc: VolumeDesc] = BEGIN ENABLE BEGIN DiskChanged => {CloseVolume[volumeDesc]; GO TO diskChanged}; IOError => {done _ countDone; GO TO dataError;}; UNWIND => NULL; END; address: FloppyFormat.Sector; size: FloppyFormat.ImplementedFileSize; localFirst: FloppyFormat.ImplementedFileSize; <> IF ~volumeDesc.open THEN RETURN WITH ERROR Error[volumeNotOpen]; IF volumeDesc.writeProtected THEN RETURN WITH ERROR Error[writeInhibited]; [address: address, size: size] _ FindFile[volumeDesc, file.file]; IF address = FloppyFormat.nullSector THEN RETURN WITH ERROR Error[fileNotFound]; IF first >= size OR first+count > size THEN RETURN WITH ERROR Error[endOfFile]; localFirst _ FloppyFormat.ConvertPageNumber[first]; WriteFloppy[volumeDesc, vm, address+localFirst, FloppyFormat.ConvertPageCount[count]]; EXITS dataError => RETURN WITH ERROR DataError [file, first+done, NIL]; diskChanged => RETURN WITH ERROR Error[volumeNotOpen]; END; volume: VolumeHandle = file.volume; []_ValidateHandle[volume]; WriteInternal[volumeTable[volume.deviceIndex]]; END; ValidateHandle: PUBLIC SAFE PROCEDURE [volume: VolumeHandle] RETURNS[volumeDesc: VolumeDesc]= TRUSTED BEGIN CheckChangeCount: ENTRY PROCEDURE [volumeDesc: VolumeDesc] = TRUSTED BEGIN status: FloppyChannel.Status; IF volume.changeCount ~= volumeDesc.changeCount THEN RETURN WITH ERROR Error[invalidVolumeHandle]; [status] _ FloppyChannel.Nop[volumeDesc.handle ! FloppyChannel.Error => {CloseVolume[volumeDesc]; GO TO diskChanged}]; IF status = diskChange THEN {CloseVolume[volumeDesc]; RETURN WITH ERROR Error[invalidVolumeHandle]}; EXITS diskChanged => RETURN WITH ERROR Error[invalidVolumeHandle]; END; IF ~ValidDrive[volume.deviceIndex] THEN ERROR Error[invalidVolumeHandle]; CheckChangeCount[volumeDesc _ volumeTable[volume.deviceIndex]]; END; END..