FloppyImplPublicB.mesa
Copyright Ó 1983, 1984, 1985, 1986, 1987 by Xerox Corporation. All rights reserved.
Tim Diebert: May 7, 1987 3:34:22 pm PDT
DIRECTORY
Environment USING [wordsPerPage],
File USING [nullFile, Type],
Floppy USING [AlreadyFormatted, Density, Error, FileID, maxCharactersInLabel, nullFileID, PageCount, Sides],
FloppyChannel USING [Attributes, Context, DiskAddress, FormatTracks, GetDeviceAttributes, GetHandle, Handle, Nop, SectorCount, SetContext, Status, WriteSectors],
FloppyExtras USING [ExtrasError, ExtrasErrorType],
FloppyFormat USING [Alternate, badSpotSector, badSpotSectors, BadSpotSectors, Byte, ConvertPageCount, dataContext, FileList, FileListEntry, FileListSeal, FileListVersion, FillTrackOneSector, FillTrackZeroSector, firstDataAddress, FloppySeal, FloppyVersion, Format, ImplementedFileSize, MarkerPage, MarkerSeal, maxBadSectors, nullSector, Sector, SectorNine, SectorToDiskAddress, trackOneAddress, trackOneContext, TrackOneSector, trackZeroAddress, trackZeroContext, TrackZeroSector],
FloppyImplInterface,
VM USING [ defaultBase, Error, Interval, Map, nullInterval, PageCount, Unmap];
FloppyImplPublicB: MONITOR LOCKS volumeDesc USING volumeDesc: FloppyImplInterface.VolumeDesc
IMPORTS Floppy, FloppyChannel, FloppyFormat, FloppyImplInterface, VM
EXPORTS Floppy
SHARES FloppyImplInterface =
BEGIN OPEN FloppyImplInterface;
PUBLIC ERRORs
ExtrasError: PUBLIC ERROR [error: FloppyExtras.ExtrasErrorType] = CODE;
Locals
FormatVerifyPasses: CARDINAL ← 2;
BadSector: SIGNAL [sector: CARDINAL] = CODE;
Bug: ERROR [bugType: BugType] = CODE;
BugType: TYPE = {impossibleEndcase};
FormatType: TYPE = {format, erase};
buffer: Space.Interval ← Space.nullInterval;
PRIVATE operations (must be first to avoid storage overlow in pass 5)
CheckSectorNine: PROCEDURE [sectorNine: LONG POINTER TO FloppyFormat.SectorNine] =
a check by Erase to see if floppy seems to be formatted
BEGIN
IF sectorNine.seal # FloppyFormat.FloppySeal
OR sectorNine.version # FloppyFormat.FloppyVersion
OR sectorNine.labelSize > Floppy.maxCharactersInLabel THEN
RETURN WITH ERROR Floppy.Error[notFormatted];
IF sectorNine.countBadSectors > FloppyFormat.maxBadSectors THEN
RETURN WITH ERROR Floppy.Error[notFormatted];
END; -- CheckSectorNine
CheckBadPageMap: PROCEDURE [
badPageMap: LONG POINTER TO FloppyFormat.BadSpotSectors,
numPages: Floppy.PageCount] =
a check by Erase to see if floppy seems to be formatted
BEGIN
FOR i: CARDINAL IN [0..FloppyFormat.maxBadSectors) DO
IF badPageMap[i].bad > numPages OR badPageMap[i].alternate > numPages
THEN RETURN WITH ERROR Floppy.Error[notFormatted];
ENDLOOP;
END; -- CheckSectorTen
ScanFloppy: PROCEDURE [ -- Checks to see if we can write and read the floppy
volumeDesc: VolumeDesc, handle: FloppyChannel.Handle, buffer: LONG POINTER, context: FloppyChannel.Context, sectorCount: CARDINAL, firstSector: CARDINAL] = BEGIN
countLeft: CARDINAL;
count: CARDINAL;
currentSector: CARDINAL;
status: FloppyChannel.Status;
currentSector ← firstSector;
countLeft ← sectorCount;
IF ~FloppyChannel.SetContext[handle, context] THEN ERROR Floppy.Error[badDisk];
DO -- write out the information
[status, count] ← FloppyChannel.WriteSectors[
handle, FloppyFormat.SectorToDiskAddress[
currentSector, volumeDesc.sectorNine.cylinders,
volumeDesc.sectorNine.tracksPerCylinder,
volumeDesc.sectorNine.sectorsPerTrack], NIL, countLeft, FALSE];
NIL field should really be buffer: cheap hack to work around bug in FloppyChannel ***
IF (countLeft ← countLeft - count) = 0 THEN EXIT;
SIGNAL BadSector[(currentSector ← currentSector + count)];
currentSector ← currentSector + 1;
countLeft ← countLeft - 1;
ENDLOOP;
END; -- ScanFloppy
CountBadPages: PROCEDURE [sector: FloppyFormat.Sector, countBadPages: CARDINAL,
badPageList: LONG POINTER TO FloppyFormat.BadSpotSectors] RETURNS [count: CARDINAL ← 1, nextIndex: CARDINAL] = BEGIN
NOTE THAT sector MUST BE IN badPageList
FOR i: CARDINAL IN [0.. countBadPages) DO
IF sector # badPageList[i].bad THEN LOOP;
FOR nextIndex IN (i.. countBadPages) DO
IF badPageList[nextIndex].bad # badPageList[i].bad + nextIndex - i
THEN RETURN[count, nextIndex];
count ← count.SUCC;
ENDLOOP;
ENDLOOP;
RETURN[count, countBadPages];
END; -- CountBadPages
WriteMarkerPages: PROCEDURE [volumeDesc: VolumeDesc, markerPage: LONG POINTER TO FloppyFormat.MarkerPage, countBadPages: CARDINAL, badPageList: LONG POINTER TO FloppyFormat.BadSpotSectors] = BEGIN
IF countBadPages = 0 THEN BEGIN
markerPage^ ← [
previous: [length: 0, body: free[]],
next: [
length: volumeDesc.numPages - 2 - FirstDataSector[volumeDesc] + 1,
body: free[]]];
WriteFloppy[volumeDesc, markerPage, FirstDataSector[volumeDesc], 1];
markerPage­ ← [
previous: [
length: volumeDesc.numPages - 2 - FirstDataSector[volumeDesc] + 1,
body: free[]], next: [length: 0, body: free[]]];
WriteFloppy[
volumeDesc, markerPage, FloppyFormat.ConvertPageCount[
volumeDesc.numPages], 1];
RETURN;
END
ELSE BEGIN
We must place marker pages around every run of bad pages
sector: FloppyFormat.Sector;
lastSector: FloppyFormat.Sector;
badPageIndex: CARDINAL;
Find the first good sector on the disk
IF badPageList[0].bad = FirstDataSector[volumeDesc] THEN
BEGIN -- Find the initial run of bad pages
count: CARDINAL;
[count, badPageIndex] ← CountBadPages[
FirstDataSector[volumeDesc], countBadPages, badPageList];
lastSector ← FirstDataSector[volumeDesc] + count;
markerPage­ ← [
previous: [length: count, body: badSectors[]],
next: [length: 0, body: free[]]];
END
ELSE -- the first page on the disk is good
BEGIN
badPageIndex ← 0;
lastSector ← FirstDataSector[volumeDesc];
markerPage­ ← [
previous: [length: 0, body: free[]],
next: [length: 0, body: free[]]];
END;
WHILE badPageIndex < countBadPages DO
we will write the X/Free MP at lastSector and Free/Bad MP at sector
count: CARDINAL; -- the length of the bad page run
sector ← badPageList[badPageIndex].bad - 1;
IF lastSector ~= sector THEN
BEGIN -- We have found a run of free pages
markerPage.next.length ← sector - (lastSector + 1);
WriteFloppy[volumeDesc, markerPage, lastSector, 1]; -- X/Free
markerPage.previous ← [
length: sector - (lastSector + 1), body: free[]];
END;
[count, badPageIndex] ← CountBadPages[
sector + 1, countBadPages, badPageList];
markerPage.next ← [length: count, body: badSectors[]];
WriteFloppy[volumeDesc, markerPage, sector, 1]; -- (Bad or Free)/Bad
lastSector ← sector + count + 1;
markerPage­ ← [
previous: [length: count, body: badSectors[]],
next: [length: 0, body: free[]]]; -- setup for bad/free
ENDLOOP;
sector ←
FloppyFormat.ConvertPageCount[volumeDesc.numPages]; -- Last data sector
IF lastSector <= sector THEN -- i.e., the last page is not bad
BEGIN
markerPage.next.length ← sector - (lastSector + 1);
WriteFloppy[volumeDesc, markerPage, lastSector, 1]; -- Bad/Free
IF sector ~= lastSector THEN
BEGIN
markerPage­ ← [
previous: [length: sector - (lastSector + 1), body: free[]],
next: [length: 0, body: free[]]];
WriteFloppy[volumeDesc, markerPage, sector, 1]; -- Free/Free
END;
END;
END; -- Of initializing marker pages on the disk with bad pages present
END; -- WriteMarkerPages
PUBLIC operations
Format: PUBLIC PROCEDURE [drive: CARDINAL, maxNumberOfFileListEntries: CARDINAL, labelString: ROPE, density: Floppy.Density, sides: Floppy.Sides] =
BEGIN
trackBufferLength: CARDINAL = 6*Environment.wordsPerPage; ++not needed
IF ~ValidDrive[drive] THEN ERROR Floppy.Error[noSuchDrive];
FormatInternal[volumeTable[drive], format, drive,
maxNumberOfFileListEntries, labelString, density, sides];
END; -- Format
Erase: PUBLIC PROCEDURE [drive: CARDINAL, maxNumberOfFileListEntries: CARDINAL, labelString: ROPE] = BEGIN
IF ~ValidDrive[drive] THEN ERROR Floppy.Error[noSuchDrive];
we'll get the floppy's density and sides in FormatInternal
FormatInternal[volumeTable[drive], erase, drive, maxNumberOfFileListEntries, labelString,,];
END; --
ENTRY procedures
FormatInternal: ENTRY PROCEDURE [volumeDesc: VolumeDesc, formatMode: FormatType, drive: CARDINAL, maxNumberOfFileListEntries: CARDINAL, labelString: ROPE, density: Floppy.Density, sides: Floppy.Sides] = BEGIN
ENABLE BEGIN
IOError => GOTO dataError;
UNWIND => VM.Free[buffer];
END;
attributes: FloppyChannel.Attributes;
format: FloppyFormat.Format;
trackZeroSector: LONG POINTER TO FloppyFormat.TrackZeroSector;
trackOneSector: LONG POINTER TO FloppyFormat.TrackOneSector;
markerPage: LONG POINTER TO FloppyFormat.MarkerPage;
countBadPages: CARDINAL;
countToFormat: CARDINAL;
requestedSize: Space.PageCount;
address: FloppyFormat.Sector;
diskAddress: FloppyChannel.DiskAddress;
status: FloppyChannel.Status;
sectors, trackZeroSectors: FloppyChannel.SectorCount;
trackOneDensity: Floppy.Density;
First create the buffer space that we need to work in
requestedSize ←
WordsToPages[SIZE[FloppyFormat.TrackZeroSector]] + WordsToPages[
SIZE[FloppyFormat.TrackOneSector]] + WordsToPages[
SIZE[FloppyFormat.MarkerPage]];
buffer ← CreateBuffer[requestedSize];
IF buffer.count ~= requestedSize THEN ERROR; -- Insufficient VM to work in
trackZeroSector ← LOOPHOLE[buffer.pointer];
markerPage ←
LOOPHOLE[trackZeroSector +
Environment.wordsPerPage * WordsToPages[
SIZE[FloppyFormat.TrackZeroSector]]];
trackOneSector ←
LOOPHOLE[markerPage +
Environment.wordsPerPage * WordsToPages[
SIZE[FloppyFormat.BadSpotSectors]]];
check volumeDesc.open; get handle, attributes, status
IF volumeDesc.open THEN
BEGIN
IF formatMode = format THEN
BEGIN
label: STRING ← [Floppy.maxCharactersInLabel];
label.length ← 0;
FOR i: CARDINAL IN [0..volumeDesc.sectorNine.labelSize) DO
label[i] ← volumeDesc.sectorNine.label[i];
label.length ← label.length + 1;
ENDLOOP;
This doesn't look right - Swap next 2 and RET w/ERROR instead?
SIGNAL Floppy.AlreadyFormatted[label];
CloseVolume[volumeDesc];
END
ELSE IF formatMode = erase THEN CloseVolume[volumeDesc];
END;
volumeDesc.handle ← FloppyChannel.GetHandle[drive];
attributes ←
FloppyChannel.GetDeviceAttributes[volumeDesc.handle].attributes;
status ← FloppyChannel.Nop[volumeDesc.handle];
IF status = notReady THEN {
buffer.pointer ← Space.Unmap[buffer.pointer];
RETURN WITH ERROR Floppy.Error[notReady]};
IF status = writeFault THEN {
buffer.pointer ← Space.Unmap[buffer.pointer];
RETURN WITH ERROR Floppy.Error[writeInhibited]};
discover sides and density
IF formatMode = format THEN
BEGIN
SELECT attributes.twoSided FROM
FALSE =>
IF sides = one OR sides = default THEN volumeDesc.sides ← one
ELSE {
buffer.pointer ← Space.Unmap[buffer.pointer];
RETURN WITH ERROR Floppy.Error[onlyOneSide]};
TRUE =>
IF sides = two OR sides = default THEN volumeDesc.sides ← two
ELSE {
buffer.pointer ← Space.Unmap[buffer.pointer];
RETURN WITH ERROR Floppy.Error[invalidFormat]};
Should be new error, say, [formatConflict], not invalidFormat
ENDCASE;
SELECT density FROM
single => volumeDesc.density ← single;
double =>
BEGIN
IF FloppyChannel.SetContext[
volumeDesc.handle, FloppyFormat.dataContext[double]]
THEN volumeDesc.density ← double
ELSE
BEGIN
buffer.pointer ← Space.Unmap[buffer.pointer];
RETURN WITH ERROR Floppy.Error[onlySingleDensity];
END;
END;
default =>
volumeDesc.density ←
IF FloppyChannel.SetContext[
volumeDesc.handle, FloppyFormat.dataContext[double]]
THEN double ELSE single;
ENDCASE =>
BEGIN
buffer.pointer ← Space.Unmap[buffer.pointer];
Bug[impossibleEndcase];
END;
END
ELSE IF formatMode = erase THEN -- get sides and density off floppy
BEGIN
byte: FloppyFormat.Format;
diskAddress ← [
head: FloppyFormat.trackZeroAddress.head,
cylinder: FloppyFormat.trackZeroAddress.cylinder, sector: 7];
AccessFloppy[
volumeDesc: volumeDesc, buffer: trackZeroSector, count: 1,
address: diskAddress, access: read];
byte ←
LOOPHOLE[trackZeroSector[71]]; -- reflects FloppyFormat.Format type
SELECT byte FROM -- 64 (' ), 212 ('M), 242 ('2) are valid
singleSidedSingleDensity =>
BEGIN
volumeDesc.sides ← one;
volumeDesc.density ← single;
attributes.numberOfHeads ← 1;
END;
doubleDensity =>
BEGIN
volumeDesc.sides ← two;
volumeDesc.density ← double;
END;
doubleSidedSingleDensity =>
BEGIN
volumeDesc.sides ← two;
volumeDesc.density ← single;
END;
ENDCASE => RETURN WITH ERROR FloppyExtras.ExtrasError[notFormatted];
END;
IF ~FloppyChannel.SetContext[
volumeDesc.handle, FloppyFormat.dataContext[volumeDesc.density]] THEN
BEGIN
buffer.pointer ← Space.Unmap[buffer.pointer];
RETURN WITH ERROR Floppy.Error[badDisk];
END;
sectors ←
FloppyChannel.GetDeviceAttributes[volumeDesc.handle].maxSectorsPerTrack;
Finish initializing volumeDesc
volumeDesc.open ← FALSE;
volumeDesc.writeProtected ← FALSE;
volumeDesc.numPages ←
attributes.numberOfHeads * attributes.numberOfCylinders * sectors;
IF formatMode = format THEN -- start initializing volumeDesc.sectorNine
volumeDesc.sectorNine­ ← [
cylinders: attributes.numberOfCylinders,
tracksPerCylinder: attributes.numberOfHeads,
sectorsPerTrack: sectors,
firstAlternateSector: FloppyFormat.nullSector
We don't allocate alternates for now
]
ELSE IF formatMode = erase THEN
retrieve sector 9 & bad page map from floppy
BEGIN -- and check them to see if they seem reasonable
diskAddress ← [
head: FloppyFormat.trackZeroAddress.head,
cylinder: FloppyFormat.trackZeroAddress.cylinder, sector: 9];
AccessFloppy[
volumeDesc: volumeDesc, buffer: volumeDesc.sectorNine, count: 1,
address: diskAddress, access: read];
CheckSectorNine[volumeDesc.sectorNine];
countBadPages ← volumeDesc.sectorNine.countBadSectors;
diskAddress.sector ← FloppyFormat.badSpotSector;
AccessFloppy[
volumeDesc: volumeDesc, buffer: volumeDesc.badPageMap,
count: FloppyFormat.badSpotSectors, address: diskAddress,
access: read];
CheckBadPageMap[volumeDesc.badPageMap, volumeDesc.numPages];
re-initialize some sectorNine fields
BEGIN OPEN volumeDesc.sectorNine;
keep seal through sectorsPerTrack, label & size, countBadSectors
fileList ← FloppyFormat.nullSector;
fileListID ← Floppy.nullFileID;
fileListSize ← 0;
rootFile ← Floppy.nullFileID;
pilotMicrocode ← FloppyFormat.nullSector;
diagnosticMicrocode ← FloppyFormat.nullSector;
germ ← FloppyFormat.nullSector;
pilotBootFile ← FloppyFormat.nullSector;
firstAlternateSector ←
FloppyFormat.nullSector; -- We don't allocate alternates for now
nextUnusedFileID ← 1;
changing ← FALSE;
END; -- of OPEN
END;
IF labelString ~= NIL THEN -- Copy our client's label, if any
BEGIN
volumeDesc.sectorNine.labelSize ← MIN[
Floppy.maxCharactersInLabel, labelString.length];
FOR i: CARDINAL IN [0..volumeDesc.sectorNine.labelSize) DO
volumeDesc.sectorNine.label[i] ← labelString[i];
ENDLOOP;
FOR i: CARDINAL IN
[volumeDesc.sectorNine.labelSize..Floppy.maxCharactersInLabel) DO
volumeDesc.sectorNine.label[i] ← ' ;
ENDLOOP;
END;
volumeDesc is initialized at this point except for allocationMap
and allocationMapSpace which will be handled later
IF formatMode = format THEN -- this block only if are formatting
BEGIN
Format the floppy
First the data sectors.
countToFormat ←
(attributes.numberOfCylinders - 1) * attributes.numberOfHeads;
IF FloppyChannel.FormatTracks[
volumeDesc.handle, FloppyFormat.firstDataAddress,
countToFormat].countDone ~= countToFormat THEN
BEGIN
buffer.pointer ← Space.Unmap[buffer.pointer];
RETURN WITH ERROR Floppy.Error[badDisk];
END;
The data area formatted okay, but lets see if we can read/write it:
find bad sectors
countBadPages ← 0;
FOR i: CARDINAL IN [0..LENGTH[volumeDesc.badPageMap­]) DO
volumeDesc.badPageMap[i] ← [
bad: FloppyFormat.nullSector, alternate: FloppyFormat.nullSector];
ENDLOOP;
FOR i: CARDINAL IN [0..FormatVerifyPasses) DO
cylinderZeroSectors: CARDINAL =
sectors * attributes.numberOfHeads;
SetBlock[buffer.pointer, Environment.wordsPerPage, 0];
ScanFloppy[
volumeDesc, volumeDesc.handle, buffer.pointer,
FloppyFormat.dataContext[volumeDesc.density],
FloppyFormat.ConvertPageCount[
volumeDesc.numPages - cylinderZeroSectors], FirstDataSector[
volumeDesc] !
BadSector =>
BEGIN
FOR i: CARDINAL IN [0..countBadPages) DO
eliminate duplicates
temp: FloppyFormat.Alternate;
IF volumeDesc.badPageMap[i].bad = sector THEN RESUME
;
IF volumeDesc.badPageMap[i].bad < sector THEN LOOP;
temp ← volumeDesc.badPageMap[i];
volumeDesc.badPageMap[i] ← [
bad: sector, alternate: FloppyFormat.nullSector];
sector ← temp.bad;
ENDLOOP;
IF countBadPages >= FloppyFormat.maxBadSectors THEN
GO TO tooManyBadPages;
volumeDesc.badPageMap[countBadPages] ← [
bad: sector, alternate: FloppyFormat.nullSector];
countBadPages ← countBadPages + 1;
RESUME
END];
REPEAT
tooManyBadPages => RETURN WITH ERROR Floppy.Error[badDisk];
ENDLOOP;
Now format cylinder zero
First track zero
IF ~FloppyChannel.SetContext[
volumeDesc.handle, FloppyFormat.trackZeroContext] THEN
BEGIN
buffer.pointer ← Space.Unmap[buffer.pointer];
RETURN WITH ERROR Floppy.Error[badDisk];
END;
IF FloppyChannel.FormatTracks[
volumeDesc.handle, FloppyFormat.trackZeroAddress, 1].countDone ~= 1
THEN
BEGIN
buffer.pointer ← Space.Unmap[buffer.pointer];
RETURN WITH ERROR Floppy.Error[badDisk];
END;
trackZeroSectors ←
FloppyChannel.GetDeviceAttributes[
volumeDesc.handle].maxSectorsPerTrack;
Now see if we can read/write track 0
FOR i: CARDINAL IN [0..FormatVerifyPasses) DO
SetBlock[buffer.pointer, Environment.wordsPerPage, 0];
ScanFloppy[
volumeDesc, volumeDesc.handle, buffer.pointer,
FloppyFormat.trackZeroContext, trackZeroSectors, 1 !
BadSector => GO TO badCylinderZero; ];
REPEAT
badCylinderZero => RETURN WITH ERROR Floppy.Error[badDisk];
ENDLOOP;
If two sided, then format track one
IF volumeDesc.sides = two THEN
BEGIN
SELECT TRUE FROM
FloppyChannel.SetContext[
volumeDesc.handle,
FloppyFormat.trackOneContext[
trackOneDensity ← volumeDesc.density]]
=> NULL;
FloppyChannel.SetContext[
volumeDesc.handle,
FloppyFormat.trackOneContext[
trackOneDensity ←
IF trackOneDensity = single THEN double ELSE single]]
=> NULL;
ENDCASE =>
BEGIN
buffer.pointer ← Space.Unmap[buffer.pointer];
RETURN WITH ERROR Floppy.Error[badDisk];
END;
IF FloppyChannel.FormatTracks[
volumeDesc.handle, FloppyFormat.trackOneAddress, 1].countDone ~= 1
THEN
BEGIN
buffer.pointer ← Space.Unmap[buffer.pointer];
RETURN WITH ERROR Floppy.Error[badDisk];
END;
For now we don't care if we can read/write track one
END;
Now fill in cylinder zero with correct values
format ←
SELECT volumeDesc.density FROM
double => doubleDensity,
single =>
SELECT volumeDesc.sides FROM
one => singleSidedSingleDensity,
two => doubleSidedSingleDensity
ENDCASE => ERROR,
ENDCASE => ERROR;
Fill in track zero, cylinder zero
FOR address IN [1..trackZeroSectors] DO
IF address = 9 THEN LOOP; -- We will fill in sector nine later
FloppyFormat.FillTrackZeroSector[trackZeroSector, format, address];
diskAddress ← FloppyFormat.trackZeroAddress;
diskAddress.sector ← address;
AccessFloppy[volumeDesc, trackZeroSector, diskAddress, 1, write];
ENDLOOP;
IF volumeDesc.sides = two THEN
BEGIN -- Fill in track one, cylinder zero
trackOneSectors: CARDINAL;
IF ~FloppyChannel.SetContext[
volumeDesc.handle, FloppyFormat.trackOneContext[trackOneDensity]]
THEN
BEGIN
buffer.pointer ← Space.Unmap[buffer.pointer];
RETURN WITH ERROR Floppy.Error[badDisk];
END;
trackOneSectors ←
FloppyChannel.GetDeviceAttributes[
volumeDesc.handle].maxSectorsPerTrack;
diskAddress ← FloppyFormat.trackOneAddress;
FOR address IN [1..trackOneSectors] DO
FloppyFormat.FillTrackOneSector[trackOneSector, format, address];
diskAddress.sector ← address;
AccessFloppy[volumeDesc, trackOneSector, diskAddress, 1, write];
ENDLOOP;
END;
At this point cylinder zero has mostly correct data.
We now must fill in those parts of track zero that belong to
the floppy file system
First initialize the bad spot table on track zero
volumeDesc.sectorNine.countBadSectors ← countBadPages;
diskAddress ← FloppyFormat.trackZeroAddress;
diskAddress.sector ← FloppyFormat.badSpotSector;
AccessFloppy[ -- Write out the bad page list
volumeDesc, volumeDesc.badPageMap, diskAddress,
FloppyFormat.badSpotSectors, write];
END; --- of block if only formatting
write the marker pages for both formats and erases
WriteMarkerPages[
volumeDesc, markerPage, countBadPages, volumeDesc.badPageMap];
Allocate the fileListSpace now so that InitializeAllocationMap works
volumeDesc.sectorNine.fileListSize ← WordsToPages[
SIZE[FloppyFormat .FileList[maxNumberOfFileListEntries]]];
volumeDesc.fileListSpace ← Space.Map[
[File.nullFile, Space.defaultBase, volumeDesc.sectorNine.fileListSize]];
really should catch errors and do something reasonable
volumeDesc.fileList ← volumeDesc.fileListSpace.pointer;
volumeDesc.fileList.seal ← FloppyFormat.FileListSeal;
volumeDesc.fileList.version ← FloppyFormat.FileListVersion;
volumeDesc.fileList.count ← 0;
volumeDesc.fileList.maxEntries ← maxNumberOfFileListEntries;
FOR i: CARDINAL IN [0..maxNumberOfFileListEntries) DO
volumeDesc.fileList.files[i] ← []; ENDLOOP;
InitializeAllocationMap[volumeDesc];
Finish initializing volumeDesc.sectorNine
[volumeDesc.sectorNine.fileList, volumeDesc.sectorNine.fileListID] ←
AllocateFile[
volumeDesc, volumeDesc.sectorNine.fileListSize,
FloppyImplInterface.FileListType, FloppyFormat.nullSector];
WriteSectorNine[volumeDesc];
volumeDesc.fileList.count ← 1;
volumeDesc.fileList.files[0] ← [
file: volumeDesc.sectorNine.fileListID,
type: FloppyImplInterface.FileListType,
location: volumeDesc.sectorNine.fileList,
size: volumeDesc.sectorNine.fileListSize];
WriteFileList[volumeDesc];
CloseVolume[volumeDesc]; -- To clear out the temporary spaces
buffer.pointer ← Space.Unmap[buffer.pointer];
EXITS
dataError => RETURN WITH ERROR Floppy.Error[badDisk];
END; -- FormatInternal
END...