DIRECTORY Basics USING [HighHalf], Floppy USING [BootFilePointer, Error, ErrorType, FileID, nullFileID, PageCount, Sides], FloppyChannel USING [Attributes, Context, DiskAddress, Error, GetDeviceAttributes, GetHandle, GetNextDrive, Handle, Nop, nullDrive, ReadSectors, SectorCount, SetContext, Status, WriteSectors], FloppyFormat USING [BadSpotSectors, ConvertPageCount, ConvertPageNumber, dataContext, FileList, FileListEntry, ImplementedFileSize, MarkerPage, MarkerSeal, MarkerPageVersion, nullSector, Sector, SectorNine, SectorToDiskAddress, trackOneContext, trackZeroAddress, trackZeroContext], FloppyImplInterface, PrincOps USING [PageCount, wordsPerPage], SpecialFloppy USING [Error, ErrorType], VM USING [AddressForPageNumber, Allocate, CantAllocate, Free, Interval, nullInterval]; FloppyImplPrivate: PROGRAM IMPORTS Basics, Floppy, FloppyChannel, FloppyFormat, FloppyImplInterface, SpecialFloppy, VM EXPORTS FloppyImplInterface, SpecialFloppy = BEGIN OPEN FloppyImplInterface; IOError: PUBLIC ERROR[countDone: CARDINAL] = CODE; DiskChanged: PUBLIC ERROR = CODE; Bug: PUBLIC ERROR[type: BugType] = CODE; Error: PUBLIC ERROR[error: SpecialFloppy.ErrorType] = CODE; FormatVerifyPasses: CARDINAL = 1; MaxVolumes: CARDINAL = 1; actualVolumes: CARDINAL _ 0; volumeTable: PUBLIC LONG POINTER TO ARRAY [0..0) OF VolumeDesc; VolumeTable: ARRAY [0..MaxVolumes) OF VolumeDesc; -- indexed by device indexes. volumeTableObjects: ARRAY [0..MaxVolumes) OF VolumeDescObject; FileListType: -- File.Type -- CARDINAL = 0 -- CommonSoftwareFileTypes.tFileList --; AccessFloppy: PUBLIC PROCEDURE [volumeDesc: VolumeDesc, buffer: LONG POINTER, address: FloppyChannel.DiskAddress, count: CARDINAL, access: AccessMode] = BEGIN status: FloppyChannel.Status; countDone: CARDINAL; context: FloppyChannel.Context; context _ IF address.cylinder > 0 THEN FloppyFormat.dataContext[volumeDesc.density] ELSE IF address.head = 0 THEN FloppyFormat.trackZeroContext ELSE IF FloppyChannel.SetContext[ volumeDesc.handle, FloppyFormat.trackOneContext[volumeDesc.density]] THEN FloppyFormat.trackOneContext[volumeDesc.density] ELSE FloppyFormat.trackOneContext[ IF volumeDesc.density = single THEN double ELSE single]; IF ~ FloppyChannel.SetContext[volumeDesc.handle, context] THEN ERROR Floppy.Error[hardwareError]; -- Is this really the right error? [status, countDone] _ (SELECT access FROM read => FloppyChannel.ReadSectors, write => FloppyChannel.WriteSectors ENDCASE => ERROR)[volumeDesc.handle, address, buffer, count, TRUE ! FloppyChannel.Error => IF type = invalidHandle THEN GO TO diskChanged]; IF status = goodCompletion THEN RETURN; IF status = diskChange THEN ERROR DiskChanged; IF status = notReady THEN ERROR Floppy.Error[notReady]; IF status = cylinderError THEN ERROR Floppy.Error[invalidFormat]; IF status = recordNotFound THEN ERROR Floppy.Error[invalidFormat]; IF status = deletedData THEN ERROR Floppy.Error[needsScavenging]; IF status = headerError THEN ERROR IOError[countDone]; IF status = dataError THEN ERROR IOError[countDone]; IF status = dataLost THEN ERROR Floppy.Error[needsScavenging]; IF status = writeFault THEN ERROR Floppy.Error[writeInhibited]; IF status = otherError THEN Floppy.Error[hardwareError]; EXITS diskChanged => ERROR DiskChanged; END; AddFile: PUBLIC PROCEDURE [volumeDesc: VolumeDesc, file: Floppy.FileID, size: FloppyFormat.ImplementedFileSize, type: -- File.Type -- CARDINAL, location: FloppyFormat.Sector] = BEGIN addLocation: CARDINAL _ 0; IF volumeDesc.fileList.count = volumeDesc.fileList.maxEntries THEN RETURN WITH ERROR Floppy.Error[fileListFull]; FOR i: CARDINAL IN [0..volumeDesc.fileList.count) DO IF (volumeDesc.fileList.files[i].location > location) THEN {addLocation _ i; EXIT}; REPEAT FINISHED => addLocation _ volumeDesc.fileList.count; ENDLOOP; FOR i: CARDINAL DECREASING IN [addLocation..volumeDesc.fileList.count) DO volumeDesc.fileList.files[i+1] _ volumeDesc.fileList.files[i]; ENDLOOP; volumeDesc.fileList.files[addLocation] _[file: file, size: size, type: type, location: location]; volumeDesc.fileList.count _ volumeDesc.fileList.count+1; WriteFileList[volumeDesc]; END; AllocateFile: PUBLIC PROCEDURE [volumeDesc: VolumeDesc, bigSize: Floppy.PageCount, type: -- File.Type -- CARDINAL, startPage: FloppyFormat.Sector, id: Floppy.FileID] RETURNS [startingSector: FloppyFormat.Sector, file: Floppy.FileID] = BEGIN ValidMarkerPage: PROCEDURE [mp: LONG POINTER TO FloppyFormat.MarkerPage] RETURNS [BOOLEAN] = { RETURN[mp.seal = FloppyFormat.MarkerSeal AND mp.version = FloppyFormat.MarkerPageVersion]}; RejectInvalidMarkerPage: PROCEDURE = BEGIN CloseVolume[volumeDesc]; ERROR Floppy.Error[needsScavenging]; END; runFound: BOOLEAN _ FALSE; buffer: VM.Interval; 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; size: FloppyFormat.ImplementedFileSize = FloppyFormat.ConvertPageCount[bigSize]; isFileList: BOOLEAN = (type = FloppyImplInterface.FileListType); IF Basics.HighHalf[bigSize] ~= 0 THEN {VolumeStable[volumeDesc]; ERROR Floppy.Error[insufficientSpace]}; IF size = 0 THEN {VolumeStable[volumeDesc]; ERROR Floppy.Error[zeroSizeFile]}; IF (startPage = FloppyFormat.nullSector) THEN -- file goes anywhere it will fit -- BEGIN startingSector _ FirstDataSector[volumeDesc]; WHILE startingSector < volumeDesc.numPages DO IF startingSector+size > volumeDesc.numPages THEN {VolumeStable[volumeDesc]; ERROR Floppy.Error[insufficientSpace]}; runFound _ TRUE; FOR page: FloppyFormat.ImplementedFileSize IN [startingSector..startingSector+size) DO IF volumeDesc.allocationMap[page] ~= free THEN {runFound _ FALSE; startingSector _ page+1; EXIT}; ENDLOOP; IF runFound THEN EXIT; REPEAT FINISHED => {VolumeStable[volumeDesc]; ERROR Floppy.Error[insufficientSpace]}; ENDLOOP; END ELSE --file is to go at specified location: if it doesn't fit, we have an error -- BEGIN IF startPage+size > volumeDesc.numPages THEN {VolumeStable[volumeDesc]; ERROR Floppy.Error[insufficientSpace]}; FOR page: FloppyFormat.ImplementedFileSize IN [startPage..startPage+size) DO IF ((volumeDesc.allocationMap[page] = allocated ) OR (volumeDesc.allocationMap[page] = markerPage)) THEN {VolumeStable[volumeDesc]; ERROR SpecialFloppy.Error[spaceNotAvailable]}; IF (volumeDesc.allocationMap[page] = badPage) THEN {VolumeStable[volumeDesc]; ERROR Floppy.Error[badSectors]}; ENDLOOP; startingSector _ startPage; END; [buffer: buffer] _ CreateBuffer[4]; zerothMarkerPage _ VM.AddressForPageNumber[buffer.page]; firstMarkerPage _ zerothMarkerPage+PrincOps.wordsPerPage; secondMarkerPage _ firstMarkerPage+PrincOps.wordsPerPage; thirdMarkerPage _ secondMarkerPage+PrincOps.wordsPerPage; IF id = Floppy.nullFileID THEN file _ GetFileID[volumeDesc] ELSE BEGIN FOR i: CARDINAL IN [0..volumeDesc.fileList.count) DO IF id = volumeDesc.fileList.files[i].file THEN ERROR SpecialFloppy.Error[IDAlreadyInUse]; ENDLOOP; file _ id; END; firstMarkerPageAddress _ startingSector-1; -- this may or may not already be a marker page IF (volumeDesc.allocationMap[firstMarkerPageAddress] ~= markerPage) THEN BEGIN -- it better be free IF (volumeDesc.allocationMap[firstMarkerPageAddress] ~=free) THEN ERROR Floppy.Error[needsScavenging]; FOR page: FloppyFormat.ImplementedFileSize DECREASING IN [0..firstMarkerPageAddress) DO IF volumeDesc.allocationMap[page] = markerPage THEN {zerothMarkerPageAddress _ page; EXIT}; REPEAT FINISHED => ERROR Floppy.Error[needsScavenging]; ENDLOOP; ReadFloppy[volumeDesc, zerothMarkerPage, zerothMarkerPageAddress, 1]; IF ~ValidMarkerPage[zerothMarkerPage] THEN RejectInvalidMarkerPage; END ELSE BEGIN --there is a marker page at firstMarkerPageAddress ReadFloppy[volumeDesc, firstMarkerPage, firstMarkerPageAddress, 1 !]; IF ~ValidMarkerPage[firstMarkerPage] THEN RejectInvalidMarkerPage; END; secondMarkerPageAddress _ startingSector+size; IF (volumeDesc.allocationMap[secondMarkerPageAddress] ~= markerPage) THEN BEGIN -- it better be free IF (volumeDesc.allocationMap[secondMarkerPageAddress] ~= free) THEN ERROR Floppy.Error[needsScavenging]; FOR page: FloppyFormat.ImplementedFileSize IN (secondMarkerPageAddress..FloppyFormat.ConvertPageCount[volumeDesc.numPages]] DO IF volumeDesc.allocationMap[page] = markerPage THEN {thirdMarkerPageAddress _ page; EXIT}; REPEAT FINISHED => ERROR Floppy.Error[needsScavenging]; ENDLOOP; ReadFloppy[volumeDesc, thirdMarkerPage, thirdMarkerPageAddress, 1]; IF ~ValidMarkerPage[thirdMarkerPage] THEN RejectInvalidMarkerPage; END ELSE BEGIN --one is there, go check it ReadFloppy[volumeDesc, secondMarkerPage, secondMarkerPageAddress, 1]; IF ~ValidMarkerPage[secondMarkerPage] THEN RejectInvalidMarkerPage; END; IF zerothMarkerPageAddress ~= FloppyFormat.nullSector THEN BEGIN --check zerothMarkerPage IF thirdMarkerPageAddress ~= FloppyFormat.nullSector THEN BEGIN IF (zerothMarkerPageAddress ~= thirdMarkerPageAddress-thirdMarkerPage.previous.length-1) OR (zerothMarkerPageAddress+zerothMarkerPage.next.length+1 ~= thirdMarkerPageAddress) THEN RejectInvalidMarkerPage; END ELSE BEGIN IF(zerothMarkerPageAddress ~= secondMarkerPageAddress-secondMarkerPage.previous.length-1) OR (zerothMarkerPageAddress+zerothMarkerPage.next.length+1 ~= secondMarkerPageAddress) THEN RejectInvalidMarkerPage; END; END ELSE BEGIN --check firstMarkerPage IF thirdMarkerPageAddress ~= FloppyFormat.nullSector THEN BEGIN IF (firstMarkerPageAddress ~= thirdMarkerPageAddress-thirdMarkerPage.previous.length-1) OR (firstMarkerPageAddress+firstMarkerPage.next.length+1 ~= thirdMarkerPageAddress) THEN RejectInvalidMarkerPage; END ELSE BEGIN IF(firstMarkerPageAddress ~= secondMarkerPageAddress-secondMarkerPage.previous.length-1) OR (firstMarkerPageAddress+firstMarkerPage.next.length+1 ~= secondMarkerPageAddress) THEN RejectInvalidMarkerPage; END; END; IF (zerothMarkerPageAddress ~= FloppyFormat.nullSector) THEN BEGIN --we need to write a new marker page for the file zerothMarkerPage.next _ [length: firstMarkerPageAddress-zerothMarkerPageAddress-1, body: free[]]; firstMarkerPage^ _ [seal: FloppyFormat.MarkerSeal, version: FloppyFormat.MarkerPageVersion , next: , previous: [length: firstMarkerPageAddress-zerothMarkerPageAddress-1, body: free[]]]; volumeDesc.allocationMap[firstMarkerPageAddress] _ markerPage; WriteFloppy[volumeDesc, zerothMarkerPage, zerothMarkerPageAddress, 1]; END; IF isFileList THEN BEGIN -- link first and second marker pages to each other firstMarkerPage.next _ [length: size, body: fileList [file: file, type: type]]; secondMarkerPage.previous _ [length: size, body: fileList [file: file, type: type]]; END ELSE BEGIN firstMarkerPage.next _ [length: size, body: file [file: file, type: type]]; secondMarkerPage.previous _ [length: size, body: file [file: file, type: type]]; END; IF (thirdMarkerPageAddress ~= FloppyFormat.nullSector) THEN BEGIN -- handle thirdMarkerPage thirdMarkerPage.previous _ [length: thirdMarkerPageAddress-secondMarkerPageAddress-1, body: free[]]; secondMarkerPage.seal _ FloppyFormat.MarkerSeal; secondMarkerPage.version _ FloppyFormat.MarkerPageVersion; secondMarkerPage.next _ [length: thirdMarkerPageAddress-secondMarkerPageAddress-1, body: free[]]; volumeDesc.allocationMap[secondMarkerPageAddress] _ markerPage; WriteFloppy[volumeDesc, thirdMarkerPage, thirdMarkerPageAddress, 1]; END; WriteFloppy[volumeDesc,firstMarkerPage, firstMarkerPageAddress, 1]; WriteFloppy[volumeDesc, secondMarkerPage, secondMarkerPageAddress,]; FOR i: FloppyFormat.Sector IN [startingSector..startingSector+size) DO volumeDesc.allocationMap[i] _ allocated ENDLOOP; RETURN; END; CloseVolume: PUBLIC PROCEDURE [volumeDesc: VolumeDesc] = BEGIN volumeDesc.open _ FALSE; volumeDesc.changeCount _ volumeDesc.changeCount + 1; VM.Free[volumeDesc.trackZeroSpace]; END; CreateBuffer: PUBLIC PROCEDURE [size: PrincOps.PageCount] RETURNS [buffer: VM.Interval] = BEGIN buffer _ VM.nullInterval; IF size = 0 THEN RETURN; buffer _ VM.Allocate[size ! VM.CantAllocate => IF (size _ size-1) > 0 THEN RETRY]; END; FindFile: PUBLIC PROCEDURE [volumeDesc: VolumeDesc, file: Floppy.FileID] RETURNS [address: FloppyFormat.Sector, type: -- File.Type -- CARDINAL, size: FloppyFormat.ImplementedFileSize] = BEGIN FOR i: CARDINAL IN [0..volumeDesc.fileList.count) DO IF volumeDesc.fileList.files[i].file = file THEN RETURN [volumeDesc.fileList.files[i].location, volumeDesc.fileList.files[i].type, volumeDesc.fileList.files[i].size]; ENDLOOP; RETURN [FloppyFormat.nullSector, -- FileTypes.tUntypedFile -- 0, 0]; END; FirstDataSector: PUBLIC PROCEDURE [volumeDesc: VolumeDesc] RETURNS [FloppyFormat.Sector] = BEGIN RETURN[volumeDesc.sectorNine.sectorsPerTrack*volumeDesc.sectorNine.tracksPerCylinder+1]; END; GetBootFileAddress: PUBLIC PROCEDURE [volumeDesc: VolumeDesc, bootFile: Floppy.BootFilePointer] RETURNS [address: FloppyFormat.Sector] = BEGIN size, offset: FloppyFormat.ImplementedFileSize; IF bootFile.file = Floppy.nullFileID THEN RETURN[FloppyFormat.nullSector] ELSE BEGIN [address,,size] _ FindFile[volumeDesc, bootFile.file]; offset _ FloppyFormat.ConvertPageNumber[bootFile.page]; IF address = FloppyFormat.nullSector THEN ERROR Floppy.Error[fileNotFound] ELSE IF offset > size-1 THEN ERROR Floppy.Error[invalidPageNumber] ELSE RETURN[address + offset]; END; END; GetFileID: PUBLIC PROCEDURE [volumeDesc: VolumeDesc] RETURNS [fileID: Floppy.FileID] = BEGIN fileID _ LOOPHOLE[volumeDesc.sectorNine.nextUnusedFileID]; volumeDesc.sectorNine.nextUnusedFileID _ volumeDesc.sectorNine.nextUnusedFileID+1; IF volumeDesc.sectorNine.nextUnusedFileID = 0 THEN ERROR Bug[wrappedAroundFileIDs]; END; InitializeAllocationMap: PUBLIC PROCEDURE [volumeDesc: VolumeDesc] = BEGIN size: CARDINAL _ 1+WordsToPages[(volumeDesc.numPages+allocationsPerPage-1)/allocationsPerPage]; volumeDesc.allocationMapSpace _ VM.Allocate[size]; volumeDesc.allocationMap _ VM.AddressForPageNumber[volumeDesc.allocationMapSpace.page]; IF volumeDesc.numPages > LAST[CARDINAL] THEN ERROR Bug[floppyVolumeTooLarge]; FOR i: CARDINAL IN [0..FloppyFormat.ConvertPageCount[volumeDesc.numPages]] DO volumeDesc.allocationMap[i] _ free; ENDLOOP; volumeDesc.allocationMap[FirstDataSector[volumeDesc]] _ markerPage; volumeDesc.allocationMap[FloppyFormat.ConvertPageCount[volumeDesc.numPages]] _ markerPage; FOR i: CARDINAL IN [0..volumeDesc.sectorNine.countBadSectors) DO volumeDesc.allocationMap[volumeDesc.badPageMap[i].bad] _ badPage; IF volumeDesc.allocationMap[volumeDesc.badPageMap[i].bad-1] = free THEN volumeDesc.allocationMap[volumeDesc.badPageMap[i].bad-1] _ markerPage; IF volumeDesc.allocationMap[volumeDesc.badPageMap[i].bad+1] = free THEN volumeDesc.allocationMap[volumeDesc.badPageMap[i].bad+1] _ markerPage; ENDLOOP; FOR i: CARDINAL IN [0..FirstDataSector[volumeDesc]) DO volumeDesc.allocationMap[i] _ allocated; -- Sector 0 and cylinder zero is always in use ENDLOOP; FOR i: CARDINAL IN [0..volumeDesc.fileList.count) DO file: FloppyFormat.FileListEntry = volumeDesc.fileList.files[i]; IF ~(volumeDesc.allocationMap[file.location-1] = free OR volumeDesc.allocationMap[file.location-1] = markerPage) THEN GO TO needsScavenging; volumeDesc.allocationMap[file.location-1] _ markerPage; IF ~ (volumeDesc.allocationMap[file.location+file.size] = free OR volumeDesc.allocationMap[file.location+file.size] = markerPage) THEN GO TO needsScavenging; volumeDesc.allocationMap[file.location+file.size] _ markerPage; FOR j: CARDINAL IN [file.location..file.location+file.size) DO IF volumeDesc.allocationMap[j] ~= free THEN GOTO needsScavenging; volumeDesc.allocationMap[j] _ allocated; ENDLOOP; ENDLOOP; EXITS needsScavenging => BEGIN CloseVolume[volumeDesc]; volumeDesc.allocationMap _ NIL; ERROR Floppy.Error[needsScavenging]; END; END; IsDriveWriteProtected: PUBLIC PROCEDURE [volumeDesc: VolumeDesc] RETURNS [writeProtected: BOOLEAN] = BEGIN status: FloppyChannel.Status; IF ~ FloppyChannel.SetContext[volumeDesc.handle, FloppyFormat.trackZeroContext] THEN ERROR; status _ FloppyChannel.Nop[volumeDesc.handle]; RETURN[status = writeFault]; END; ReadFloppy: PUBLIC PROCEDURE [volumeDesc: VolumeDesc, buffer: LONG POINTER, address: FloppyFormat.Sector, count: FloppyFormat.ImplementedFileSize] = BEGIN AccessFloppy[ volumeDesc, buffer, FloppyFormat.SectorToDiskAddress[ address, volumeDesc.sectorNine.cylinders, volumeDesc.sectorNine.tracksPerCylinder, volumeDesc.sectorNine.sectorsPerTrack], count, read]; END; RemoveFile: PUBLIC PROCEDURE [volumeDesc: VolumeDesc, file: Floppy.FileID] = BEGIN FOR i: CARDINAL IN [0..volumeDesc.fileList.count) DO IF volumeDesc.fileList.files[i].file = file THEN BEGIN IF i = volumeDesc.fileList.count-1 THEN BEGIN -- Deleting the last file in the list volumeDesc.fileList.count _ volumeDesc.fileList.count-1; volumeDesc.fileList.files[i] _ []; END ELSE BEGIN -- There are files later in the list whose entries must be copied FOR j: CARDINAL IN [i..volumeDesc.fileList.count-1) DO volumeDesc.fileList.files[j] _ volumeDesc.fileList.files[j+1]; ENDLOOP; volumeDesc.fileList.count _ volumeDesc.fileList.count-1; volumeDesc.fileList.files[volumeDesc.fileList.count] _ []; END; WriteFileList[volumeDesc]; END; ENDLOOP; END; SectorsPerTrack: PUBLIC PROCEDURE [handle: FloppyChannel.Handle, context: FloppyChannel.Context] RETURNS [sectorsPerTrack: FloppyChannel.SectorCount] = BEGIN attributes: FloppyChannel.Attributes; [] _ FloppyChannel.SetContext[handle, context]; attributes _ FloppyChannel.GetDeviceAttributes[handle]; RETURN[attributes.maxSectorsPerTrack]; END; SetBlock: PUBLIC PROCEDURE [p: LONG POINTER, length: CARDINAL, value: CARDINAL] = {FOR i: CARDINAL IN [0..length) DO (p+i)^ _ value ENDLOOP}; ValidDrive: PUBLIC PROCEDURE [drive: CARDINAL] RETURNS [exists: BOOLEAN] = {RETURN[drive IN [0..actualVolumes]]}; VolumeChanging: PUBLIC PROCEDURE [volumeDesc: VolumeDesc] = BEGIN volumeDesc.sectorNine.changing _ TRUE; WriteSectorNine[volumeDesc]; END; VolumeStable: PUBLIC PROCEDURE [volumeDesc: VolumeDesc] = BEGIN volumeDesc.sectorNine.changing _ FALSE; WriteSectorNine[volumeDesc]; END; WriteFileList: PUBLIC PROCEDURE [volumeDesc: VolumeDesc] = BEGIN WriteFloppy[ volumeDesc, volumeDesc.fileList, volumeDesc.sectorNine.fileList, volumeDesc.sectorNine.fileListSize]; END; WriteFloppy: PUBLIC PROCEDURE [volumeDesc: VolumeDesc, buffer: LONG POINTER, address: FloppyFormat.Sector, count: FloppyFormat.ImplementedFileSize] = BEGIN AccessFloppy[ volumeDesc, buffer, FloppyFormat.SectorToDiskAddress[ address, volumeDesc.sectorNine.cylinders, volumeDesc.sectorNine.tracksPerCylinder, volumeDesc.sectorNine.sectorsPerTrack], count, write]; END; WriteSectorNine: PUBLIC PROCEDURE [volumeDesc: VolumeDesc] = BEGIN AccessFloppy[ volumeDesc: volumeDesc, access: write, buffer: volumeDesc.sectorNine, count: 1, address: [head: FloppyFormat.trackZeroAddress.head, cylinder: FloppyFormat.trackZeroAddress.cylinder, sector: 9]]; END; FOR i: CARDINAL _ FloppyChannel.GetNextDrive[FloppyChannel.nullDrive], FloppyChannel.GetNextDrive[i] UNTIL i = FloppyChannel.nullDrive DO actualVolumes _ i; VolumeTable[actualVolumes] _ @volumeTableObjects[actualVolumes]; volumeTableObjects[actualVolumes].open _ FALSE; volumeTableObjects[actualVolumes].handle _ FloppyChannel.GetHandle[actualVolumes]; volumeTableObjects[actualVolumes].changeCount _ 0; volumeTableObjects[actualVolumes].trackZeroSpace _ CreateBuffer[WordsToPages[SIZE[FloppyFormat.SectorNine]]+ WordsToPages[SIZE[FloppyFormat.BadSpotSectors]]]; volumeTableObjects[actualVolumes].sectorNine _ VM.AddressForPageNumber[volumeTableObjects[actualVolumes].trackZeroSpace.page]; volumeTableObjects[actualVolumes].badPageMap _ LOOPHOLE[volumeTableObjects[actualVolumes].sectorNine+ PrincOps.wordsPerPage*WordsToPages[SIZE[FloppyFormat.SectorNine]]]; volumeTableObjects[actualVolumes].fileList _ NIL; volumeTableObjects[actualVolumes].allocationMap _ NIL; ENDLOOP; volumeTable _ LOOPHOLE[LONG[@VolumeTable]]; END.... XFloppyImplPrivate.mesa Copyright Σ 1983, 1984, 1985, 1987 by Xerox Corporation. All rights reserved. Tim Diebert: May 7, 1987 2:11:55 pm PDT Eventually, we should allocate this array dynamically to make it variable length and to get it out of the MDS. An error has occurred. Translate the error into something that the clients of Floppy are ready to catch. WARNING: This procedure is used for ALL I/O by this module. Thus some of the signals that it raises are inappropriate in some cases. The higher level modules should catch these signals and translate them! We now have a run of usable pages: [startingSector..startingSector+size) Since we zero pages at Delete time, we do not zero the file at this time. find the preceding marker page now check the trailing marker page go find the next one now check existing links among marker pages now set links and write out to disk Now update our local allocation map File ID's have wrapped around - a case not covered by this implementation this calculation is flakey so allocate an extra page for safety We should really catch the signals and convert them into something else The first and last pages of the disk have marker pages unless they are bad. If so, the loop over the bad page list will mark them as such Module initialization Find all of the Floppy drives out there and initialize the volume table Κί˜codešœ™KšœO™OK™'—K˜šΟk ˜ Kšœœ ˜KšœœK˜WKšœœ­˜ΐKšœ œ‰˜›K˜Kšœ œ˜)Kšœœ˜'KšœœN˜VK˜—šΠlnœ˜KšœR˜[Kšœ%œœ˜L—˜Kš Οnœœœ œœ˜2KšŸ œœœœ˜!KšŸœœœœ˜(KšŸœœœ#œ˜;K˜KšŸœœ˜!K˜KšŸ œœ˜Kšœœ˜Kš œ œœœœœœ ˜?šŸ œœœ Οc˜OKšœP™PKšœ™—Kšœœœ˜>K˜K˜KšŸ œ œœ 'œ˜SK˜š Ÿ œœ œ"œœ-œ˜žK˜Kšœ œ˜K˜K˜˜ šœ˜Kšœ-˜1šœœ˜Kšœ˜"š˜šœ˜K˜K˜1—Kšœ1˜5šœ˜"Kšœœœ ˜8—————šœ8˜>Kšœ "˜E—˜šœœ˜K˜"K˜#šœœ˜-K˜Kšœ˜˜Kšœœœœ˜0————Kšœœœ˜'K˜KšœΈ™ΈK˜Kšœœœ ˜.Kšœœœ˜7Kšœœœ˜AKšœœœ˜BKšœœœ˜AKšœœœ˜6Kšœœœ˜4Kšœœœ˜>Kšœœœ˜?Kšœœ˜8Kš˜Kšœœ ˜!Kšœ˜—K˜š Ÿœœ œ] œœ"˜ΆKšœ œ˜šœ<˜BKšœœœ˜-—šœœœ ˜4Kšœ4œœ˜SKš˜Kšœ,˜4Kšœ˜—š œœ œœ*˜IK˜>Kšœ˜—K˜aK˜8K˜Kšœ˜—K˜š Ÿ œœ œ; œœ4œ=˜πšŸœ œœœœœœ˜^Kšœ#œ/˜[—K˜šŸœ œ˜*K˜Kšœ˜$Kšœ˜——˜Kšœ œœ˜Kšœœ ˜Kšœœœœ˜:Kšœœœœ˜9Kšœœœœ˜:Kšœœœœ˜9K˜GK˜,K˜-K˜FK˜PKšœ œ-˜@K˜šœ˜ Kšœœ"˜G—Kšœ œœ˜N—˜šœ&˜(šœ $œ˜/K˜-šœ&˜-šœ+˜1Kšœœ"˜B—Kšœ œ˜šœ(œ'˜Všœ(˜.Kšœ œœ˜2—Kšœ˜ —Kšœ œœ˜Kš˜Kšœœ"˜NKšœ˜—Kš˜—šœ Mœ˜Yšœ&˜,Kšœœ"˜B—šœ(œ˜Lšœ0œ/˜cšœ˜Kšœœ)˜I——šœ+˜-Kšœœ˜@—Kšœ˜—K˜Kšœ˜K˜——šœ“™“K˜—K˜#Kšœœ#˜8K˜9K˜9K˜9K˜šœ˜Kšœ˜!š ˜ šœœœ ˜4Kšœ( œ%˜YKšœ˜—K˜ Kšœ˜———˜Kšœ+ /˜ZšœA˜Cšœœ ˜šœ;˜AKšœ˜$—Kšœ™šœ( œœ˜Xšœ-˜3Kšœ!œ˜'—Kš˜Kšœœ˜0Kšœ˜—K˜EKšœ$œ˜CKš˜—š œ 2˜>K˜Ešœ#˜)K˜—Kšœ˜———˜Kšœ"™"K˜.šœB˜Dšœœ ˜šœ=˜CKšœ˜$—Kšœ™šœ(˜-KšœN˜Pšœ-˜3Kšœ œ˜&—Kš˜Kšœœ˜0Kšœ˜—K˜Cšœ#˜)K˜—Kš˜—šœœ ˜&K˜EKšœ$œ˜CKšœ˜———˜Kšœ+™+šœ3˜5š œ ˜#šœ3 ˜?KšœVœTœ˜ΜKš˜—š ˜ KšœWœUœ˜ΞKšœ˜—Kš˜—šœœ ˜"šœ3 ˜?KšœUœRœ˜ΙKš˜—š ˜ KšœVœSœ˜ΛKšœ˜—Kšœ˜——K˜šœ#™#šœ6œœ 1˜tK˜aK˜ΉK˜>K˜FKšœ˜—šœ ˜ šœœ 3˜>K˜OK˜TKš˜—š ˜ K˜KK˜PKšœ˜——K˜šœ5 œ ˜\K˜dK˜0K˜:K˜aK˜?K˜DKšœ˜———˜KšœC˜CKšœD˜DKšœ#™#šœœ'˜FK˜'Kšœ˜—Kšœ˜Kšœ˜—K˜šŸ œœ œ˜>Kšœœ˜K˜4Kšœ!˜#Kšœ˜—K˜K˜š Ÿ œœ œœ œ ˜_Kšœ œ˜Kšœ œœ˜Kš œ œœœœœ˜RKšœ˜K˜—K˜š Ÿœœ œ. œ& œœ+˜ΐšœœœ ˜4Kšœ* œo˜¦Kšœ˜—Kšœ œ˜DKšœ˜—K˜š Ÿœœ œœ˜`KšœR˜XKšœ˜—K˜š Ÿœœ œ;œ!˜ŽK˜/šœ"˜$Kš œ˜$š ˜ K˜6K˜7Kšœ#œœ˜JKšœœœœ ˜BKšœœ˜Kšœ˜——Kšœ˜—K˜š Ÿ œœ œœ˜\Kšœ œ)˜:K˜Ršœ, œ˜SKšœI™I—Kšœ˜—K˜šŸœœ œ˜JKšœœQ˜_Kšœ?™?šœ œ˜3KšœG™G—Kšœœ:˜WKš œœœœœ˜Mšœœœ9˜MK˜#Kšœ˜—K˜KšœŠ™ŠK˜C˜NK˜ —K˜šœœœ,˜@K˜AKšœAœG˜ŽKšœAœG˜ŽKšœ˜—K˜šœœœ"˜6Kšœ) .˜WKšœ˜—K˜šœœœ ˜4K˜@Kš œ4œ8œœœ˜ŒK˜7Kš œ=œ@œœœ˜K˜?šœœœ*˜>Kšœ% œ˜AK˜(Kšœ˜—Kšœ˜—Kš˜šœ˜K˜Kšœœ˜Kšœ˜$Kšœ˜—Kšœ˜—K˜š Ÿœœ œœœ˜jK˜šœM˜OKšœœ˜ —K˜.Kšœ˜Kšœ˜—K˜š Ÿ œœ œ"œœJ˜š˜ K˜˜!K˜K˜ K˜(K˜'—K˜ —Kšœ˜—K˜šŸ œœ œ0˜Ršœœœ ˜4šœ* ˜6šœ ˜"š œ %˜0K˜8K˜"Kš˜—š œ A˜Lšœœœ"˜6K˜>Kšœ˜—K˜8K˜:Kšœ˜——K˜Kšœ˜—Kšœ˜ —Kšœ˜—K˜š Ÿœœ œ?œ/˜K˜%K˜/K˜7Kšœ ˜&šœ˜K˜——šŸœœ œœœ œ œ˜RKš œœœœ œœ˜;—K˜š Ÿ œœ œ œœ œ˜JKšœœœ˜&—K˜šŸœœ œ˜AKšœ!œ˜&K˜Kšœ˜—K˜šŸ œœ œ˜?Kšœ!œ˜'K˜Kšœ˜K˜—šŸ œœ œ˜@˜ K˜@K˜$—Kšœ˜—K˜š Ÿ œœ œ"œœJ˜›˜ K˜˜!K˜K˜ K˜(K˜'—K˜—Kšœ˜—K˜šŸœœ œ˜B˜ K˜&K˜(˜3K˜1K˜ ——Kšœ˜—K˜Kšœ™K˜KšœG™GK˜šœœUœ˜‰K˜K˜@Kšœ)œ˜/K˜RK˜2˜2Kšœœ)œ ˜k—Kšœ/œM˜~Kšœ. œRœ˜©Kšœ-œ˜1Kšœ2œ˜6Kšœ˜—šœœœ˜+˜K˜——Kšœ˜——…—Nθf