-- Copyright (C) 1984 by Xerox Corporation. All rights reserved. --FloppyImplPublicC.mesa (last edited by JXG on 18-Jan-84 17:25:19) DIRECTORY Environment USING [wordsPerPage], File USING [File, PageCount, PageNumber, Type], Floppy USING [ AlreadyFormatted, BootFilePointer, Close, CopyFromPilotFile, CopyToPilotFile, DataError, Density, Error, ErrorType, FileHandle, FileID, Format, GetAttributes, GetBootFiles, GetFileAttributes, GetNextFile, nullFileID, Open, PageCount, PageNumber, SetBootFiles, SetRootFile, Sides, VolumeHandle], FloppyChannel USING [DiskAddress], FloppyFormat USING [ ConvertPageNumber, DiskAddressToSector, firstDataAddress, nullSector, Sector, SectorToDiskAddress], FloppyImplInterface, Inline USING [LowHalf], Space USING [Interval, Map, Unmap], SpecialFloppy USING [CreateInitialMicrocodeWithID, CreateFileAtAddressWithID, Error, ErrorType, GetFileAtDiskAddress, nullDiskAddress]; FloppyImplPublicC: MONITOR LOCKS volumeDesc USING volumeDesc: FloppyImplInterface.VolumeDesc IMPORTS Floppy, FloppyFormat, FloppyImplInterface, Inline, Space, SpecialFloppy EXPORTS Floppy, SpecialFloppy = BEGIN OPEN FloppyImplInterface; FloppyFileInfo: TYPE = MACHINE DEPENDENT RECORD [ fileID(0): Floppy.FileID, size(2): Floppy.PageCount, fileType(4): File.Type, offset(5): File.PageNumber]; FloppyInfoSeq: TYPE = RECORD [ length: CARDINAL, item: ARRAY [0..0) OF FloppyFileInfo]; FloppyInfoSeqType: TYPE = LONG POINTER TO FloppyInfoSeq; HeaderPage0: TYPE = MACHINE DEPENDENT RECORD [ seal(0): CARDINAL ← ImageSeal, version(1): CARDINAL← ImageVersion, currentNumberOfFiles(2): CARDINAL, maxNumberOfFiles(3): CARDINAL, fileList(4): Floppy.FileHandle, rootFile(8): Floppy.FileHandle, density(12): Floppy.Density, sides(13): Floppy.Sides, initialUCode(14): Floppy.BootFilePointer, pilotUCode(18): Floppy.BootFilePointer, diagUCode(22): Floppy.BootFilePointer, germ(26): Floppy.BootFilePointer, pilotBootFile(30): Floppy.BootFilePointer, pilotUCodeAddress(34): FloppyChannel.DiskAddress, diagUCodeAddress(36): FloppyChannel.DiskAddress, germAddress(38): FloppyChannel.DiskAddress, pilotBootFileAddress(40): FloppyChannel.DiskAddress, sizeOfFile(42): Floppy.PageCount, pseudoRootPageIndex(44): CARDINAL, labelStringBody(45): StringBody]; ImageSeal: CARDINAL = 146363B; ImageVersion: CARDINAL = 1; PseudoPVRootPageAddress: FloppyChannel.DiskAddress = [ cylinder: 4, head: 0, sector: 1]; CreateFileAtAddress: PUBLIC PROCEDURE [ volume: Floppy.VolumeHandle, size: Floppy.PageCount, type: File.Type, location: FloppyChannel.DiskAddress] RETURNS [file: Floppy.FileHandle] = BEGIN volumeDesc: VolumeDesc; file.volume ← volume; volumeDesc ← ValidateHandle[volume]; file.file ← CreateFileAtAddressWithIDInternal[ volumeDesc, Floppy.nullFileID, size, type, location]; END; CreateFileAtAddressWithID: PUBLIC PROCEDURE [ volume: Floppy.VolumeHandle, id: Floppy.FileID, size: Floppy.PageCount, type: File.Type, location: FloppyChannel.DiskAddress] RETURNS [file: Floppy.FileHandle] = BEGIN volumeDesc: VolumeDesc; file.volume ← volume; volumeDesc ← ValidateHandle[volume]; file.file ← CreateFileAtAddressWithIDInternal[ volumeDesc, id, size, type, location]; END; CreateFileAtAddressWithIDInternal: ENTRY PROCEDURE [ volumeDesc: VolumeDesc, id: Floppy.FileID, size: Floppy.PageCount, type: File.Type, location: FloppyChannel.DiskAddress] RETURNS [file: Floppy.FileID] = BEGIN ENABLE BEGIN UNWIND => NULL; END; startSector: FloppyFormat.Sector; IF ~volumeDesc.open THEN RETURN WITH ERROR Floppy.Error[volumeNotOpen]; IF location = SpecialFloppy.nullDiskAddress THEN startSector ← FloppyFormat.nullSector ELSE BEGIN startSector ← FloppyFormat.DiskAddressToSector[ location, volumeDesc.sectorNine.cylinders, volumeDesc.sectorNine.tracksPerCylinder, volumeDesc.sectorNine.sectorsPerTrack]; --check that location is valid IF (FloppyFormat.DiskAddressToSector[ FloppyFormat.firstDataAddress, volumeDesc.sectorNine.cylinders, volumeDesc.sectorNine.tracksPerCylinder, volumeDesc.sectorNine.sectorsPerTrack] > startSector) OR (startSector + size > volumeDesc.numPages - 1) THEN RETURN WITH ERROR SpecialFloppy.Error[invalidDiskAddress]; END; file ← CreateFileInternal[volumeDesc, size, type, startSector, id].fileID; END; CreateFloppyFromImage: PUBLIC PROCEDURE [ floppyDrive: CARDINAL, imageFile: File.File, firstImagePage: File.PageNumber, reformatFloppy: BOOLEAN, floppyDensity: Floppy.Density, floppySides: Floppy.Sides, numberOfFiles: CARDINAL, newLabelString: LONG STRING] = BEGIN floppyFileInfoPerPage: CARDINAL = Environment.wordsPerPage/SIZE[FloppyFileInfo]; headerPage0Ptr: LONG POINTER TO HeaderPage0; floppyHandle: Floppy.VolumeHandle; space1Interval: Space.Interval; space2Interval: Space.Interval; floppyInfoSeqPtr: FloppyInfoSeqType; fileHandle: Floppy.FileHandle; oldLabelString: LONG STRING; index: CARDINAL ← 0; spaceAvailable: Floppy.PageCount; dataErrorFile: Floppy.FileHandle; dataErrorPage: Floppy.PageNumber; BEGIN OPEN hdr:headerPage0Ptr, flptr: floppyInfoSeqPtr; space1Interval ← Space.Map[ [file: imageFile, base: firstImagePage, count: 1]]; headerPage0Ptr ← space1Interval.pointer; IF hdr.seal # ImageSeal OR hdr.version # ImageVersion THEN ERROR Floppy.Error[error: floppyImageInvalid]; IF numberOfFiles # 0 AND hdr.currentNumberOfFiles > numberOfFiles THEN ERROR Floppy.Error[error: fileListLengthTooShort]; oldLabelString ← @hdr.labelStringBody; space2Interval ← Space.Map[ [file: imageFile, base: firstImagePage + 1, count: hdr.currentNumberOfFiles/floppyFileInfoPerPage + 1]]; floppyInfoSeqPtr ← space2Interval.pointer; Floppy.Format[ drive: floppyDrive, maxNumberOfFileListEntries: IF numberOfFiles = 0 THEN hdr.maxNumberOfFiles ELSE numberOfFiles, labelString: IF newLabelString = NIL THEN oldLabelString ELSE IF newLabelString.length = 0 THEN oldLabelString ELSE newLabelString, density: floppyDensity, sides: floppySides ! Floppy.AlreadyFormatted => IF reformatFloppy THEN RESUME ELSE REJECT]; floppyHandle ← Floppy.Open[floppyDrive]; [freeSpace: spaceAvailable] ← Floppy.GetAttributes [ volume: floppyHandle, labelString: NIL]; IF hdr.sizeOfFile > spaceAvailable THEN ERROR Floppy.Error[error: floppySpaceTooSmall]; FOR index IN [0..flptr.length) DO SELECT flptr.item[index].fileID FROM Floppy.nullFileID => EXIT; hdr.initialUCode.file => fileHandle ← SpecialFloppy.CreateInitialMicrocodeWithID[ volume: floppyHandle, id: flptr.item[index].fileID, size: flptr.item[index].size, type: flptr.item[index].fileType, startingPageNumber: hdr.initialUCode.page ! SpecialFloppy.Error => SELECT error FROM IDAlreadyInUse => ERROR Floppy.Error[error: floppyImageInvalid]; ENDCASE]; flptr.item[hdr.pseudoRootPageIndex].fileID => fileHandle ← SpecialFloppy.CreateFileAtAddressWithID[ volume: floppyHandle, id: flptr.item[index].fileID, size: flptr.item[index].size, type: flptr.item[index].fileType, location: PseudoPVRootPageAddress ! SpecialFloppy.Error => SELECT error FROM IDAlreadyInUse => ERROR Floppy.Error[error: floppyImageInvalid]; ENDCASE]; hdr.pilotUCode.file => fileHandle ← SpecialFloppy.CreateFileAtAddressWithID[ volume: floppyHandle, id: flptr.item[index].fileID, size: flptr.item[index].size, type: flptr.item[index].fileType, location: hdr.pilotUCodeAddress ! SpecialFloppy.Error => SELECT error FROM IDAlreadyInUse => ERROR Floppy.Error[error: floppyImageInvalid]; ENDCASE]; hdr.diagUCode.file => fileHandle ← SpecialFloppy.CreateFileAtAddressWithID[ volume: floppyHandle, id: flptr.item[index].fileID, size: flptr.item[index].size, type: flptr.item[index].fileType, location: hdr.diagUCodeAddress ! SpecialFloppy.Error => SELECT error FROM IDAlreadyInUse => ERROR Floppy.Error[error: floppyImageInvalid]; ENDCASE]; hdr.germ.file => fileHandle ← SpecialFloppy.CreateFileAtAddressWithID[ volume: floppyHandle, id: flptr.item[index].fileID, size: flptr.item[index].size, type: flptr.item[index].fileType, location: hdr.germAddress ! SpecialFloppy.Error => SELECT error FROM IDAlreadyInUse => ERROR Floppy.Error[error: floppyImageInvalid]; ENDCASE]; hdr.pilotBootFile.file => fileHandle ← SpecialFloppy.CreateFileAtAddressWithID[ volume: floppyHandle, id: flptr.item[index].fileID, size: flptr.item[index].size, type: flptr.item[index].fileType, location: hdr.pilotBootFileAddress ! SpecialFloppy.Error => SELECT error FROM IDAlreadyInUse => ERROR Floppy.Error[error: floppyImageInvalid]; ENDCASE]; ENDCASE => fileHandle ← SpecialFloppy.CreateFileAtAddressWithID[ volume: floppyHandle, id: flptr.item[index].fileID, size: flptr.item[index].size, type: flptr.item[index].fileType, location: SpecialFloppy.nullDiskAddress ! SpecialFloppy.Error => SELECT error FROM IDAlreadyInUse => ERROR Floppy.Error[error: floppyImageInvalid]; ENDCASE]; fileHandle ← [floppyHandle, flptr.item[index].fileID]; Floppy. CopyFromPilotFile[ pilotFile: imageFile, floppyFile: fileHandle, firstPilotPage: firstImagePage + flptr.item[index].offset, firstFloppyPage: 0, count: flptr.item[index].size ! Floppy.DataError => BEGIN dataErrorFile ← file; dataErrorPage ← page; space2Interval.pointer ← Space.Unmap[space2Interval.pointer]; space1Interval.pointer ← Space.Unmap[space1Interval.pointer]; Floppy.Close[floppyHandle]; GOTO errorExit; END; ]; ENDLOOP; Floppy.SetBootFiles[ volume: floppyHandle, pilotMicrocode: hdr.pilotUCode, diagnosticMicrocode: hdr.diagUCode, germ: hdr.germ, pilotBootFile: hdr.pilotBootFile]; IF hdr.rootFile.file # Floppy.nullFileID THEN Floppy.SetRootFile[hdr.rootFile]; space2Interval.pointer ← Space.Unmap[space2Interval.pointer]; space1Interval.pointer ← Space.Unmap[space1Interval.pointer]; Floppy.Close[floppyHandle]; EXITS errorExit => ERROR Floppy.DataError[file: dataErrorFile, page: dataErrorPage , vm: NIL]; END; END; CreateInitialMicrocodeWithID: PUBLIC PROCEDURE [ volume: Floppy.VolumeHandle, id: Floppy.FileID, size: Floppy.PageCount, type: File.Type, startingPageNumber: Floppy.PageNumber] RETURNS [file: Floppy.FileHandle] = BEGIN volumeDesc: VolumeDesc; file.volume ← volume; volumeDesc ← ValidateHandle[volume]; file.file ← CreateInitialMicrocodeInternal[ volumeDesc, size, type, startingPageNumber, id]; END; GetDiskAddress: PUBLIC PROCEDURE [ file: Floppy.FileHandle, page: Floppy.PageNumber] RETURNS [diskAddress: FloppyChannel.DiskAddress] = BEGIN volumeDesc: VolumeDesc; GetDiskAddressInternal: ENTRY PROCEDURE [ volumeDesc: VolumeDesc, page: Floppy.PageNumber] = BEGIN ENABLE BEGIN UNWIND => NULL; END; sector: FloppyFormat.Sector; IF ~volumeDesc.open THEN RETURN WITH ERROR Floppy.Error[volumeNotOpen]; sector ← FindFile[volumeDesc, file.file].address + FloppyFormat.ConvertPageNumber[ page]; diskAddress ← FloppyFormat.SectorToDiskAddress[ sector, volumeDesc.sectorNine.cylinders, volumeDesc.sectorNine.tracksPerCylinder, volumeDesc.sectorNine.sectorsPerTrack]; END; volumeDesc ← ValidateHandle[file.volume]; GetDiskAddressInternal[volumeDesc, page]; END; GetFileAtDiskAddress: PUBLIC PROCEDURE [ volume: Floppy.VolumeHandle, diskAddress: FloppyChannel.DiskAddress] RETURNS [file: Floppy.FileHandle, pageNumber: Floppy.PageNumber] = BEGIN volumeDesc: VolumeDesc; GetFileAtDiskAddressInternal: ENTRY PROCEDURE [ volumeDesc: VolumeDesc, diskAddress: FloppyChannel.DiskAddress] = BEGIN ENABLE BEGIN UNWIND => NULL; END; sector: FloppyFormat.Sector; file.volume ← volume; IF ~volumeDesc.open THEN RETURN WITH ERROR Floppy.Error[volumeNotOpen]; sector ← FloppyFormat.DiskAddressToSector[ diskAddress, volumeDesc.sectorNine.cylinders, volumeDesc.sectorNine.tracksPerCylinder, volumeDesc.sectorNine.sectorsPerTrack]; IF volumeDesc.allocationMap[sector] ~= allocated THEN BEGIN file.file ← Floppy.nullFileID; pageNumber ← 0; RETURN; END ELSE BEGIN file.file ← Floppy.nullFileID; pageNumber ← 0; FOR i: CARDINAL IN [0..volumeDesc.fileList.count) DO IF sector IN [volumeDesc.fileList.files[ i].location..volumeDesc.fileList.files[i].location + volumeDesc.fileList.files[i].size) THEN BEGIN file.file ← volumeDesc.fileList.files[i].file; pageNumber ← sector - volumeDesc.fileList.files[i].location; EXIT; END; ENDLOOP; END; END; volumeDesc ← ValidateHandle[volume]; GetFileAtDiskAddressInternal[volumeDesc, diskAddress]; END; GetCurrentNumberOfFiles: PROCEDURE [volume: Floppy.VolumeHandle] RETURNS [currentNumberOfFiles: CARDINAL] = BEGIN volumeDesc: VolumeDesc; GetCurrentNumberOfFilesInternal: ENTRY PROCEDURE [volumeDesc: VolumeDesc] = BEGIN ENABLE BEGIN UNWIND => NULL; END; IF ~volumeDesc.open THEN RETURN WITH ERROR Floppy.Error[volumeNotOpen]; currentNumberOfFiles ← volumeDesc.fileList.count; END; volumeDesc ← ValidateHandle[volume]; GetCurrentNumberOfFilesInternal[volumeDesc]; END; GetImageAttributes: PUBLIC PROCEDURE [ imageFile: File.File, firstImagePage: File.PageNumber, name: LONG STRING] RETURNS [ maxNumberOfFiles: CARDINAL, currentNumberOfFiles: CARDINAL, density: Floppy.Density[single..double], sides: Floppy.Sides[one..two]] = BEGIN headerPage0Ptr: LONG POINTER TO HeaderPage0; spaceInterval: Space.Interval; labelString: LONG STRING; spaceInterval ← Space.Map[[file: imageFile, base: firstImagePage, count: 1]]; headerPage0Ptr ← spaceInterval.pointer; labelString ← @headerPage0Ptr.labelStringBody; IF name # NIL THEN BEGIN FOR index: CARDINAL IN [0..MIN[name.maxlength, labelString.length]) DO name.text[index] ← labelString.text[index]; ENDLOOP; name.length ← labelString.length; END; maxNumberOfFiles ← headerPage0Ptr.maxNumberOfFiles; currentNumberOfFiles ← headerPage0Ptr.currentNumberOfFiles; density ← headerPage0Ptr.density; sides ← headerPage0Ptr.sides; spaceInterval.pointer ← Space.Unmap[spaceInterval.pointer]; END; MakeImage: PUBLIC PROCEDURE [ floppyDrive: CARDINAL, imageFile: File.File, firstImagePage: File.PageNumber] = BEGIN floppyFileInfoPerPage: CARDINAL = Environment.wordsPerPage/SIZE[FloppyFileInfo]; headerPage0Ptr: LONG POINTER TO HeaderPage0; floppyHandle: Floppy.VolumeHandle; space1Interval: Space.Interval; space2Interval: Space.Interval; floppyInfoSeqPtr: FloppyInfoSeqType; labelString: LONG STRING; numOfFiles: CARDINAL; fileHandle: Floppy.FileHandle; floppyID: Floppy.FileID ← Floppy.nullFileID; index: CARDINAL ← 0; numOfPages: LONG CARDINAL; pages: Floppy.PageCount; pseudoRootPageHandle: Floppy.FileHandle; dataErrorFile: Floppy.FileHandle; dataErrorPage: Floppy.PageNumber; BEGIN OPEN hdr: headerPage0Ptr, flptr: floppyInfoSeqPtr; floppyHandle ← Floppy.Open[floppyDrive]; [pages: pages, files: numOfFiles] ← PagesForFloppyInfoSeq[ floppyHandle]; numOfPages ← pages; space2Interval ← Space.Map[[file: imageFile, base: firstImagePage + 1, count: pages]]; floppyInfoSeqPtr ← space2Interval.pointer; space1Interval ← Space.Map[[file: imageFile, base: firstImagePage, count: 1]]; headerPage0Ptr ← space1Interval.pointer; flptr.length ← numOfFiles - 1; -- The fileList is not included numOfPages ← numOfPages + 1; [file: pseudoRootPageHandle] ← SpecialFloppy .GetFileAtDiskAddress[ volume: floppyHandle, diskAddress: PseudoPVRootPageAddress]; fileHandle ← [floppyHandle, floppyID]; fileHandle ← Floppy.GetNextFile[fileHandle]; FOR index IN [0..flptr.length) DO SELECT fileHandle.file FROM pseudoRootPageHandle.file => hdr.pseudoRootPageIndex ← index; hdr.pilotUCode.file => hdr.pilotUCodeAddress ← GetDiskAddress[file: fileHandle, page: 0]; hdr.diagUCode.file => hdr.diagUCodeAddress ← GetDiskAddress[file: fileHandle, page: 0]; hdr.germ.file => hdr.germAddress ← GetDiskAddress[file: fileHandle, page: 0]; hdr.pilotBootFile.file => hdr.pilotBootFileAddress ← GetDiskAddress[file: fileHandle, page: 0]; ENDCASE => NULL; [size: flptr.item[index].size, type: flptr.item[index].fileType] ← Floppy.GetFileAttributes[fileHandle]; flptr.item[index].fileID ← fileHandle.file; flptr.item[index].offset ← numOfPages; Floppy.CopyToPilotFile[ floppyFile: fileHandle, pilotFile: imageFile, firstFloppyPage: 0, firstPilotPage: firstImagePage + flptr.item[index].offset, count: flptr.item[index].size ! Floppy.DataError => BEGIN dataErrorFile ← file; dataErrorPage ← page; space1Interval.pointer ← Space.Unmap[space1Interval.pointer]; space2Interval.pointer ← Space.Unmap[space2Interval.pointer]; Floppy.Close[floppyHandle]; GOTO errorExit; END; ]; numOfPages ← numOfPages + flptr.item[index].size; fileHandle ← Floppy.GetNextFile[fileHandle]; ENDLOOP; numOfPages ← numOfPages - flptr.item[0].offset; space2Interval.pointer ← Space.Unmap[space2Interval.pointer]; labelString ← @hdr.labelStringBody; labelString↑ ← StringBody[length: 0, maxlength: 128, text:]; hdr.seal ← ImageSeal; hdr.version ← ImageVersion; hdr.currentNumberOfFiles ← GetCurrentNumberOfFiles[floppyHandle]; [fileList: hdr.fileList, rootFile: hdr.rootFile, density: hdr.density, sides: hdr.sides, maxFileListEntries: hdr.maxNumberOfFiles] ← Floppy.GetAttributes[volume: floppyHandle, labelString: labelString]; [hdr.initialUCode, hdr.pilotUCode, hdr.diagUCode, hdr.germ, hdr.pilotBootFile] ← Floppy.GetBootFiles[floppyHandle]; hdr.sizeOfFile ← numOfPages; space1Interval.pointer ← Space.Unmap[space1Interval.pointer]; Floppy.Close[floppyHandle]; EXITS errorExit => ERROR Floppy.DataError[file: dataErrorFile, page: dataErrorPage, vm: NIL]; END; END; PagesForFloppyInfoSeq: PROCEDURE [ floppyHandle: Floppy.VolumeHandle] RETURNS [pages: File.PageCount, files: CARDINAL] = BEGIN files ← GetCurrentNumberOfFiles[floppyHandle]; pages ← (files*SIZE[FloppyFileInfo] + Environment.wordsPerPage -1)/ Environment.wordsPerPage; END; PagesForImage: PUBLIC PROCEDURE [floppyDrive: CARDINAL] RETURNS [File.PageCount] = BEGIN floppyHandle: Floppy.VolumeHandle; fileHandle: Floppy.FileHandle; floppyID: Floppy.FileID ← Floppy.nullFileID; numOfPages: File.PageCount ← 1; -- for the header sizeOfFile: Floppy.PageCount; pages: File.PageCount; floppyHandle ← Floppy.Open[floppyDrive]; [pages: pages] ← PagesForFloppyInfoSeq[floppyHandle]; numOfPages ← numOfPages + pages; fileHandle ← [floppyHandle, floppyID]; fileHandle ← Floppy.GetNextFile[fileHandle]; WHILE fileHandle.file # Floppy.nullFileID DO [size: sizeOfFile] ← Floppy.GetFileAttributes[fileHandle]; numOfPages ← numOfPages + LOOPHOLE[sizeOfFile, LONG CARDINAL]; fileHandle ← Floppy.GetNextFile[fileHandle]; ENDLOOP; Floppy.Close[floppyHandle]; RETURN[numOfPages]; END; END. LOG Time: 1-Feb-82 15:08:14 by: LXD Created File Time: 9-Feb-82 19:04:53 by: LXD added GetDiskAddress Time: 11-Feb-82 18:05:30 by: LXD added GetFileAtDiskAddress Time: 6-Aug-82 18:47:49 by: AWL Implemented GetFileListAttributes, CreateWithIDAtLocation, CreateInitialMicrocodeWIthID Time: 2-Nov-82 11:15:25 By: EKN Added CreateFloppyFromImage, GetImageAttributes, MakeImage, PagesForImage, PagesForFloppyInfoSeq, FCError. (written by DXG ) Time: 2-Mar-83 15:16:57 By: EKN Updated Space Stuff to Klamath. ChangedGetFileListAttributes to GetCurrentNumberOfFiles. References to SpecialFloppyExtras and FloppyExtras are now SpecialFloppy and Floppy, respectively. Time: 18-Jan-84 15:14:36 By: JXG off by one error Time: 18-Jan-84 17:26:08 By: JXG undid erroneous fix