-- FileMgr>FileImpl.mesa (December 9, 1982 11:37 am by Levin) -- Note on monitors in this module: All procedures in this module that must read or change entries in the FileMgr's caches do their actual work through LogicalVolume.VolumeAccess, and are thus protected by VolumeImpl's monitor lock from inconsistencies that might otherwise result if cache accesses were interleaved. Simply (I hope) stated: VolumeImpl's monitor is used to insure the consistency of individual cache entries, FileCacheImpl's monitor insures consistency of the global state of the caches, and FileImpl's monitor is used to serialize access to files at a higher level (i.e., above the level of the caches). There is at least one procedure, GetFileDescriptor, which must be outside of FileImpl's monitor (because it is used by the FileHelper), but which must access the FileMgr caches. DIRECTORY Boot USING [Location, LVBootFiles], Device USING [Type], DiskChannel USING [Address, Handle, Drive, GetAttributes, GetDriveAttributes, GetDriveTag], Environment USING [PageCount, PageNumber, wordsPerPage], File USING [Capability, delete, ErrorType, grow, ID, lastPageNumber, nullCapability, nullID, PageCount, PageNumber, Permissions, read, shrink, Type, write], FileCache USING [FlushFile, GetFilePtrs, GetPageGroup, SetFile, SetPageGroup, ReturnFilePtrs], FileInternal USING [Descriptor, FilePtr, LocalFilePtr, maxPermissions, PageGroup], FilePageTransfer USING [Initiate, Request], FilerException USING [Await], FMPrograms USING [MarkerPageImpl, PhysicalVolumeImpl, VolAllocMapImpl, VolFileMapImpl], Inline USING [BITAND, LowHalf], KernelFile USING [defaultPageCount, GetNextFile, GetRootFile], LabelTransfer USING [ReadLabel, VerifyLabels, WriteLabelAndData], LogicalVolume USING [CloseLogicalVolume, FileVolumeStatus, FreeVolumePages, Handle, nullVolumePage, OpenLogicalVolume, PageNumber, PutRootFile, VolumeAccess, VolumeAccessProc, VolumeAccessStatus], PilotDisk USING [Address, GetLabelFilePage, Label, LabelCheckSum, SetLabelFilePage], PilotFileTypes USING [PilotRootFileType, PilotVFileType, tTempFileList], PilotSwitches USING [switches --.f--], Process USING [GetPriority, Priority, SetPriority], ProcessPriorities USING [priorityPageFaultHigh], Runtime USING [CallDebugger], SimpleSpace USING [Create, ForceOut, Handle, Map, Page, Unmap], Space USING [defaultWindow], SpecialFile USING [Link], SpecialVolume USING [GetLogicalVolumeBootFiles, SetLogicalVolumeBootFiles], StoragePrograms, SubVolume USING [Find, GetPageAddress, Handle], System USING [GetUniversalID, VolumeID], SystemInternal USING [ --altoFPSeries,--Unimplemented], Transaction USING [Handle, InvalidHandle, nullHandle], TransactionState USING [FileOps, Log, LogEntry], Utilities USING [LongPointerFromPage], VMMapLog USING [Entry], VolAllocMap USING [AllocPageGroup, FreePageGroup], VolFileMap USING [DeletePageGroup, GetPageGroup, InsertPageGroup], Volume USING [GetNext, ID, InsufficientSpace, NeedsScavenging, NotOpen, nullID, systemID, TypeSet, Unknown]; FileImpl: MONITOR IMPORTS DiskChannel, FileCache, FilePageTransfer, FilerException, FMPrograms, Inline, KernelFile, LabelTransfer, LogicalVolume, PilotDisk, PilotSwitches, Process, Runtime, SimpleSpace, SpecialVolume, SubVolume, System, SystemInternal, Transaction, TransactionState, Utilities, VolAllocMap, VolFileMap, Volume EXPORTS File, LogicalVolume, KernelFile, SpecialFile, StoragePrograms SHARES DiskChannel, File, System, SystemInternal = BEGIN OPEN File, FileInternal; VolProc: TYPE = LogicalVolume.VolumeAccessProc; -- One-page buffer used by MakePermanent, MakeImmutable, MakeBootable: pageBuffer: SimpleSpace.Handle = SimpleSpace.Create[1, hyperspace]; bufferPage: Environment.PageNumber = SimpleSpace.Page[pageBuffer]; bufferPointer: LONG POINTER = Utilities.LongPointerFromPage[bufferPage]; -- Temporary File list used by DeleteTemps and EnterInTempFileList -- (these values assume list entries do not overlap pages) tmpsBuffer: SimpleSpace.Handle ← SimpleSpace.Create[1, hyperspace]; tmpsVolume: Volume.ID ← Volume.nullID; tmpsFile: File.Capability; tmpsFileSize: File.PageCount; tmpStart: LONG POINTER TO File.ID = Utilities.LongPointerFromPage[SimpleSpace.Page[tmpsBuffer]]; tmpsLast: LONG POINTER TO File.ID = tmpStart+(Environment.wordsPerPage/SIZE[File.ID])*SIZE[File.ID]; tmps: LONG POINTER TO File.ID; nullTransaction: Transaction.Handle = Transaction.nullHandle; AttributeAction: TYPE = {immutable, permanent, mutable, temporary}; Error: PUBLIC ERROR [type: ErrorType] = CODE; InvalidParameters: PUBLIC ERROR = CODE; LabelError: SIGNAL = CODE; Unknown: PUBLIC ERROR [file: Capability] = CODE; ExistingFile: PUBLIC ERROR = CODE; FileImplError: ERROR [{disappearedOrRemoteTempFile, fileWithHole, illegalAttributeAction, impossibleFileType, makeBootablePageGroupNotFound, makeBootableImpossibleError, missingPage0, missingPageGroupSetSize, missingPinnedPageGroup, remoteTmpsFile, remoteTxLog, SubvolumeNotFoundInGetFilePoint, tmpsFileProblem, tmpsFileWentAway, tmpsVolumeWentAway, volumeWentAwayDuringDeleteTemps, setSizeImpossibleError}] = CODE; -- MONITOR EXTERNAL PROCEDURES Create: PUBLIC SAFE PROCEDURE [volume: System.VolumeID, initialSize: PageCount, type: Type, transaction: Transaction.Handle] RETURNS [file: Capability] = TRUSTED BEGIN IF type IN PilotFileTypes.PilotVFileType THEN ERROR Error[reservedType]; file ← [[System.GetUniversalID[]], FileInternal.maxPermissions]; CreateWithIDExternal[volume, initialSize, type, file.fID, transaction]; END; CreateWithID: PUBLIC PROCEDURE [volume: System.VolumeID, initialSize: PageCount, type: Type, id: ID] = -- Create file given the file identifier {CreateWithIDExternal[volume, initialSize, type, id]}; Delete: PUBLIC PROCEDURE [file: Capability, transaction: Transaction.Handle] = {DeleteCommon[@file, NIL, transaction]}; DeleteImmutable: PUBLIC PROCEDURE [file: Capability, volume: System.VolumeID, transaction: Transaction.Handle] = {DeleteCommon[@file, @volume, transaction]}; FileHelperProcess: PROCEDURE = BEGIN helpCount: CARDINAL ← 0; -- for perfomance monitoring. fileD: FileInternal.Descriptor; req: FilePageTransfer.Request; DO --FOREVER-- req ← FilerException.Await[]; GetFileDescriptorSignals[@req.file, @fileD]; -- file cache updated as side effect WITH fileD SELECT FROM local => BEGIN Helper1: VolProc = BEGIN fPtr: FileInternal.FilePtr; success: BOOLEAN; group: FileInternal.PageGroup; updateMarkers ← FALSE; [success, fPtr] ← FileCache.GetFilePtrs[1, fileD.fileID]; IF ~success THEN RETURN; -- fell out of cache, let exception happen again [success, group] ← VolFileMap.GetPageGroup[volume, @fileD, req.filePage]; IF (success ← (success AND req.filePage<group.nextFilePage)) THEN FileCache.SetPageGroup[req.file.fID, group, FALSE]; -- page is within file? FileCache.ReturnFilePtrs[1, fPtr]; IF ~success THEN Runtime.CallDebugger["Mapped off File (Helper)"L]; END; SELECT LogicalVolume.VolumeAccess[@fileD.volumeID, Helper1] FROM ok => NULL; ENDCASE => Runtime.CallDebugger[ "Volume vanished between Descriptor and PageGroup (Helper)"]; END; --Helper1-- remote => NULL; ENDCASE; FilePageTransfer.Initiate[req]; helpCount ← helpCount+1; ENDLOOP END; GetAttributes: PUBLIC SAFE PROCEDURE [file: Capability, transaction: Transaction.Handle] RETURNS [type: Type, immutable, temporary: BOOLEAN, volume: System.VolumeID] = TRUSTED BEGIN f: FileInternal.Descriptor; GetFileDescriptorSignals[@file, @f]; WITH f SELECT FROM local => RETURN[type, immutable, temporary, f.volumeID]; ENDCASE => --RETURN[File.Type[0], FALSE, FALSE, VolumeInternal.altoVolume] ERROR SystemInternal.Unimplemented END; GetBootLocation: PUBLIC PROCEDURE [ file: File.Capability, filePage: File.PageNumber] RETURNS [deviceType: Device.Type, deviceOrdinal: CARDINAL, link: SpecialFile.Link] = BEGIN v: Volume.ID; grp: FileInternal.PageGroup; channel: DiskChannel.Handle; GetVIDAndGroup[@v, @grp, @file, filePage]; -- set vID, group [channel, LOOPHOLE[link, DiskChannel.Address]] ← SubVolume.GetPageAddress[v, grp.volumePage+(filePage-grp.filePage)]; [deviceType: deviceType, deviceOrdinal: deviceOrdinal] ← DiskChannel.GetDriveAttributes[DiskChannel.GetAttributes[channel].drive]; END; GetFileDescriptor: PROCEDURE [ file: POINTER TO READONLY File.Capability, fileD: FileInternal.FilePtr, vP: POINTER TO READONLY Volume.ID ← NIL] RETURNS [found: BOOLEAN] = -- Look up file in cache and then in given volume or all volumes (vP=NIL), -- and set the descriptor. Return success BEGIN fPtr: FileInternal.FilePtr; success: BOOLEAN; v: Volume.ID; getAll: Volume.TypeSet = [normal: TRUE, debugger: TRUE, debuggerDebugger: TRUE]; GetFileDescriptor1: VolProc = BEGIN group: FileInternal.PageGroup; label: PilotDisk.Label; lf: local FileInternal.Descriptor ← [file.fID, v, local[, , , ]]; updateMarkers ← FALSE; [success, group] ← VolFileMap.GetPageGroup[volume, @lf, 0]; IF ~success THEN RETURN; label ← LabelTransfer.ReadLabel[lf, 0, group.volumePage].label; IF label.fileID#lf.fileID OR PilotDisk.GetLabelFilePage[@label]#0 THEN SIGNAL LabelError; lf.body ← local[ immutable: label.immutable, temporary: label.temporary, size: VolFileMap.GetPageGroup[ volume, LONG[@lf], File.lastPageNumber].group.filePage, type: label.type]; -- success?? fileD↑ ← lf; DO FileCache.SetFile[lf, FALSE]; [success, fPtr] ← FileCache.GetFilePtrs[1, lf.fileID]; IF success THEN BEGIN FileCache.SetPageGroup[lf.fileID, group, FALSE]; FileCache.ReturnFilePtrs[1, fPtr]; RETURN; END; ENDLOOP; END; IF file.fID = File.nullID THEN RETURN[FALSE]; --IF LOOPHOLE[file.fID, SystemInternal.UniversalID].series=SystemInternal.altoFPSeries THEN --IF GetAltoSize[file]=0 THEN ERROR Unknown[file↑] ELSE RETURN[[file.fID, VolumeInternal.altoVolume, remote[]]]; [success, fPtr] ← FileCache.GetFilePtrs[1, file.fID]; IF success THEN BEGIN fileD↑ ← fPtr↑; FileCache.ReturnFilePtrs[1, fPtr]; IF vP=NIL OR fileD.volumeID=vP↑ THEN RETURN[TRUE]; END; v ← IF vP=NIL THEN Volume.GetNext[Volume.nullID, getAll] ELSE vP↑; WHILE v#Volume.nullID DO IF LogicalVolume.VolumeAccess[@v, GetFileDescriptor1]=ok AND success THEN RETURN[TRUE]; IF vP#NIL THEN EXIT ELSE v ← Volume.GetNext[v, getAll]; ENDLOOP; RETURN[FALSE]; END; GetFileDescriptorSignals: PROCEDURE [ file: POINTER TO READONLY File.Capability, fileD: FileInternal.FilePtr, vP: POINTER TO READONLY Volume.ID ← NIL] = BEGIN IF ~GetFileDescriptor[file, fileD, vP].found THEN ERROR Unknown[file↑]; END; GetFilePoint: PUBLIC PROCEDURE [ pEntry: LONG POINTER TO VMMapLog.Entry, pFile: POINTER TO File.Capability, filePage: File.PageNumber] = BEGIN countMax: CARDINAL = 4096; vID: Volume.ID; group: FileInternal.PageGroup; lvPage: LogicalVolume.PageNumber; success: BOOLEAN; svH: SubVolume.Handle; label: PilotDisk.Label; GetVIDAndGroup[@vID, @group, pFile, filePage]; lvPage ← filePage-group.filePage+group.volumePage; -- file => logical vol page [success, svH] ← SubVolume.Find[vID, lvPage]; IF ~success THEN ERROR FileImplError[SubvolumeNotFoundInGetFilePoint]; label.fileID ← pFile.fID; PilotDisk.SetLabelFilePage[@label, filePage]; pEntry↑ ← [page:, writeProtected:, fill:, count: MIN[countMax, Inline.LowHalf[group.nextFilePage-filePage]], filePoint: disk[ driveTag: DiskChannel.GetDriveTag[DiskChannel.GetAttributes[svH.channel].drive], diskPage: lvPage-svH.lvPage+svH.pvPage, -- logical vol => physical vol page, labelCheck: PilotDisk.LabelCheckSum[@label, 0]]]; END; GetSize: PUBLIC SAFE PROCEDURE [file: Capability, transaction: Transaction.Handle] RETURNS [size: PageCount] = TRUSTED BEGIN fileD: FileInternal.Descriptor; GetFileDescriptorSignals[@file, @fileD]; RETURN[ WITH fileD SELECT FROM local => size, ENDCASE => --GetAltoSize[@file]--ERROR SystemInternal.Unimplemented] END; IsOnVolume: PUBLIC SAFE PROCEDURE [file: Capability, volume: System.VolumeID] = TRUSTED BEGIN fileD: FileInternal.Descriptor; IF ~GetFileDescriptor[@file, @fileD] THEN FileCache.SetFile[[file.fID, volume, remote[]], FALSE]; END; MakeBootable: PUBLIC PROCEDURE [ file: File.Capability, firstPage: File.PageNumber, count: File.PageCount, lastLink: SpecialFile.Link] RETURNS [firstLink: SpecialFile.Link] = BEGIN RETURN[LOOPHOLE[MakeBootableOrUnbootable[ bootable, @file, firstPage, count, LOOPHOLE[lastLink]]]]; END; MakeImmutable: PUBLIC PROCEDURE [file: Capability, transaction: Transaction.Handle] = {ChangeAttributes[@file, immutable, transaction]}; MakeMutable: PUBLIC PROCEDURE [file: Capability] = {ChangeAttributes[@file, mutable]}; MakePermanent: PUBLIC SAFE PROCEDURE [file: Capability, transaction: Transaction.Handle] = TRUSTED {ChangeAttributes[@file, permanent, transaction]}; MakeTemporary: PUBLIC PROCEDURE [file: Capability] = BEGIN fileD: FileInternal.Descriptor; IF ~GetFileDescriptor[@file, @fileD] THEN ERROR Unknown[file]; TmpsEnter[@file, @fileD.volumeID]; ChangeAttributes[@file, temporary]; END; MakeUnbootable: PUBLIC PROCEDURE [ file: File.Capability, firstPage: File.PageNumber, count: File.PageCount] = {[] ← MakeBootableOrUnbootable[unbootable, @file, firstPage, count, ]}; Move: PUBLIC PROCEDURE [ file: Capability, volume: System.VolumeID, transaction: Transaction.Handle] = {SIGNAL SystemInternal.Unimplemented}; ReplicateImmutable: PUBLIC SAFE PROCEDURE [ file: Capability, volume: System.VolumeID, transaction: Transaction.Handle] = TRUSTED {SIGNAL SystemInternal.Unimplemented}; SetDebuggerFiles: PUBLIC PROCEDURE [debugger, debuggee: File.Capability] = BEGIN bootFiles: Boot.LVBootFiles; fileD: FileInternal.Descriptor; dTEr, dTEe: Device.Type; dOEr, dOEe: CARDINAL; linkEr, linkEe: SpecialFile.Link; id: Volume.ID = Volume.systemID; [deviceType: dTEr, deviceOrdinal: dOEr, link: linkEr] ← GetBootLocation[debugger, 0]; [deviceType: dTEe, deviceOrdinal: dOEe, link: linkEe] ← GetBootLocation[debuggee, 0]; GetFileDescriptorSignals[@debugger, @fileD]; IF dTEr#dTEe OR dOEr#dOEe OR fileD.volumeID#id THEN ERROR InvalidParameters; SpecialVolume.GetLogicalVolumeBootFiles[id, @bootFiles]; bootFiles[debugger] ← [debugger.fID, 0, LOOPHOLE[linkEr]]; bootFiles[debuggee] ← [debuggee.fID, 0, LOOPHOLE[linkEe]]; SpecialVolume.SetLogicalVolumeBootFiles[id, @bootFiles]; END; SufficientPermissions: PROCEDURE [given, needed: Permissions] RETURNS [BOOLEAN] = INLINE {RETURN[Inline.BITAND[given, needed]=needed]}; -- ENTRY PROCEDURES ChangeAttributes: ENTRY PROCEDURE [ file: POINTER TO READONLY File.Capability, action: AttributeAction, transaction: Transaction.Handle ← nullTransaction] = BEGIN fileD: FileInternal.Descriptor; IF ~GetFileDescriptor[file, @fileD] THEN RETURN WITH ERROR Unknown[file↑]; WITH f: fileD SELECT FROM local => BEGIN IF f.immutable AND action#mutable THEN RETURN WITH ERROR Error[immutable]; IF action=permanent AND ~f.temporary THEN RETURN; IF transaction#nullTransaction THEN BEGIN OPEN TransactionState; entry: LogEntry ← SELECT action FROM immutable => [makeMutable[id: file.fID]], permanent => [makeTemporary[id: file.fID]], ENDCASE => ERROR FileImplError[illegalAttributeAction]; Log[transaction, @entry, txFileProcs ! Volume.InsufficientSpace => GOTO InsufficientSpace; Transaction.InvalidHandle => GOTO InvalidTxHandle]; EXITS InsufficientSpace => RETURN WITH ERROR Volume.InsufficientSpace; InvalidTxHandle => RETURN WITH ERROR Transaction.InvalidHandle; END; SELECT ChangeAttributesInternal[@f, action] FROM ok => NULL; volumeUnknown => RETURN WITH ERROR Volume.Unknown[f.volumeID]; volumeNotOpen => RETURN WITH ERROR Volume.NotOpen[f.volumeID]; ENDCASE; END ENDCASE => RETURN WITH ERROR SystemInternal.Unimplemented; END; CloseVolumeAndFlushFiles: PUBLIC ENTRY PROCEDURE [ v: POINTER TO READONLY Volume.ID] = BEGIN -- Someday, flush file caches & make sure nobody is mapped to the bugger IF tmpsVolume=v↑ THEN TmpsUnmap[]; LogicalVolume.CloseLogicalVolume[v ! Volume.Unknown => GOTO unknown]; EXITS unknown => RETURN WITH ERROR Volume.Unknown[v↑]; END; CreateWithIDExternal: PROCEDURE [ volume: System.VolumeID, initialSize: PageCount, type: Type, id: ID, transaction: Transaction.Handle ← nullTransaction] = BEGIN file: Capability ← [id, FileInternal.maxPermissions]; fileD: FileInternal.Descriptor; CreateWithIDEntry: ENTRY PROCEDURE = INLINE BEGIN IF type IN PilotFileTypes.PilotVFileType THEN ERROR FileImplError[impossibleFileType]; IF GetFileDescriptor[@file, @fileD, @volume] THEN RETURN WITH ERROR ExistingFile; IF transaction#nullTransaction THEN BEGIN OPEN TransactionState; entry: LogEntry ← [delete[id: file.fID]]; Log[transaction, @entry, txFileProcs ! Volume.InsufficientSpace => GOTO InsufficientSpace; Transaction.InvalidHandle => GOTO InvalidTxHandle]; EXITS InsufficientSpace => RETURN WITH ERROR Volume.InsufficientSpace; InvalidTxHandle => RETURN WITH ERROR Transaction.InvalidHandle; END; SELECT CreateWithIDInternal[@volume, @initialSize, type, @id] FROM ok => NULL; insufficientSpace => RETURN WITH ERROR Volume.InsufficientSpace; ENDCASE; END; TmpsEnter[@file, @volume]; CreateWithIDEntry[]; END; DeleteCommon: ENTRY PROCEDURE [ file: POINTER TO READONLY File.Capability, volume: POINTER TO READONLY Volume.ID, -- NIL if Delete, volume if DeleteImmutable-- transaction: Transaction.Handle] = BEGIN fileD: FileInternal.Descriptor; IF ~GetFileDescriptor[file, @fileD, volume] THEN RETURN WITH ERROR Unknown[file↑]; IF ~SufficientPermissions[file.permissions, File.delete] THEN RETURN WITH ERROR Error[insufficientPermissions]; WITH f: fileD SELECT FROM local => BEGIN IF volume = NIL THEN {IF f.immutable THEN RETURN WITH ERROR Error[immutable]} ELSE IF ~f.immutable THEN RETURN WITH ERROR Error[notImmutable]; IF transaction#nullTransaction THEN BEGIN OPEN TransactionState; ENABLE { Volume.InsufficientSpace => GOTO InsufficientSpace; Transaction.InvalidHandle => GOTO InvalidTxHandle}; entry: LogEntry ← [setContents[ id: f.fileID, base: 0, size: f.size, makePermanent: ~f.temporary, makeImmutable: f.immutable]]; Log[transaction, @entry, txFileProcs]; entry ← [create[id: f.fileID, volume: f.volumeID, size: f.size, type: f.type]]; Log[transaction, @entry, txFileProcs]; EXITS InsufficientSpace => RETURN WITH ERROR Volume.InsufficientSpace; InvalidTxHandle => RETURN WITH ERROR Transaction.InvalidHandle; END; SELECT DeleteFileOnVolumeInternal[@f] FROM ok => NULL; volumeUnknown => RETURN WITH ERROR Volume.Unknown[f.volumeID]; volumeNotOpen => RETURN WITH ERROR Volume.NotOpen[f.volumeID]; ENDCASE; IF f.temporary THEN TmpsRemove[file, @f.volumeID]; END; ENDCASE => RETURN WITH ERROR SystemInternal.Unimplemented; END; GetFileAttributes: PUBLIC ENTRY PROCEDURE [file: Capability] RETURNS [size: PageCount, immutable: BOOLEAN, readOnly: BOOLEAN] = BEGIN f: FileInternal.Descriptor; IF ~GetFileDescriptor[@file, @f] THEN RETURN WITH ERROR Unknown[file]; WITH f SELECT FROM local => RETURN[size, immutable, ~SufficientPermissions[file.permissions, write]]; ENDCASE => RETURN WITH ERROR SystemInternal.Unimplemented END; --DeleteTemps: PUBLIC PROCEDURE [volume: Volume.ID] = --BEGIN --DeleteTempsEntry: ENTRY PROCEDURE = --BEGIN --SELECT DeleteTempsInternal[ --@volume] FROM --ok => NULL; --volumeUnknown => RETURN WITH ERROR Volume.Unknown[volume]; --volumeNotOpen => RETURN WITH ERROR Volume.NotOpen[volume]; --ENDCASE; --END; --DeleteTempsEntry[]; --END; -- Maintained by AltoSize -- cacheA, cacheB: RECORD[file: File.ID, size: PageCount] ← [File.nullID, 0]; -- Access file attributes in label given fileID keeping 2 element MRU cache --GetAltoSize: ENTRY PROCEDURE [file: POINTER TO READONLY File.Capability] RETURNS[size: PageCount] = --BEGIN --faP: LONG POINTER TO AltoFileDefs.FA = @LOOPHOLE[bufferPointer, LONG POINTER TO AltoFileDefs.LD].eofFA; --IF file.fID=cacheA.file THEN RETURN[cacheA.size]; --IF file.fID=cacheB.file THEN size ← cacheB.size ELSE --BEGIN --SimpleSpace.Map[pageBuffer, Space.WindowOrigin[file↑, 0], FALSE]; --size ← faP.page+MIN[faP.byte, 1]; --SimpleSpace.Unmap[pageBuffer] --END; --cacheB ← cacheA; cacheA ← [file.fID, size] --END; -- Look up file in cache and then in all vfm's, set vID and page group descriptor or signal error. GetVIDAndGroup: ENTRY PROCEDURE [ pVID: POINTER TO Volume.ID, pGroup: POINTER TO FileInternal.PageGroup, pFile: POINTER TO READONLY File.Capability, filePage: File.PageNumber] = BEGIN fileD: FileInternal.Descriptor; IF ~GetFileDescriptor[pFile, @fileD] THEN RETURN WITH ERROR Unknown[pFile↑]; WITH fileD SELECT FROM local => BEGIN GetVIDAndGroup1: VolProc = BEGIN success: BOOLEAN; updateMarkers ← FALSE; [success, pGroup↑] ← FileCache.GetPageGroup[fileD.fileID, filePage]; IF ~success THEN [success, pGroup↑] ← VolFileMap.GetPageGroup[volume, @fileD, filePage]; IF ~(success AND filePage<pGroup.nextFilePage) THEN ERROR FileImplError[fileWithHole]; END; pVID↑ ← fileD.volumeID; SELECT LogicalVolume.VolumeAccess[pVID, GetVIDAndGroup1] FROM ok => NULL; volumeUnknown => RETURN WITH ERROR Volume.Unknown[pVID↑]; volumeNotOpen => RETURN WITH ERROR Volume.NotOpen[pVID↑]; ENDCASE; END; remote => RETURN WITH ERROR SystemInternal.Unimplemented; ENDCASE; END; LogContents: PUBLIC ENTRY PROCEDURE [ transaction: Transaction.Handle, file: Capability, base: PageNumber, count: PageCount] = BEGIN OPEN TransactionState; ENABLE UNWIND => NULL; entry: LogEntry ← [setContents[id: file.fID, base: base, size: count]]; Log[transaction, @entry, txFileProcs]; END; MakeBootableOrUnbootable: ENTRY PROCEDURE [ op: {bootable, unbootable}, file: POINTER TO READONLY File.Capability, firstPage: File.PageNumber, count: File.PageCount, lastLink: DiskChannel.Address] RETURNS [firstLink: DiskChannel.Address] = BEGIN fileD: FileInternal.Descriptor; group: FileInternal.PageGroup; limitPage: File.PageNumber = firstPage+count; nextLink: DiskChannel.Address; page: File.PageNumber ← firstPage; success: BOOLEAN; GetStuff: VolProc = BEGIN updateMarkers ← FALSE; [success, group] ← VolFileMap.GetPageGroup[volume, @fileD, page]; IF ~success THEN ERROR FileImplError[makeBootablePageGroupNotFound]; IF firstPage=page THEN firstLink ← SubVolume.GetPageAddress[fileD.volumeID, group.volumePage+(firstPage-group.filePage)].address; SELECT TRUE FROM op=unbootable => nextLink ← [0, 0, 0]; group.nextFilePage>=limitPage => {group.nextFilePage ← limitPage; nextLink ← lastLink}; ENDCASE => -- should check success of GetPageGroup in next statement nextLink ← SubVolume.GetPageAddress[fileD.volumeID, VolFileMap.GetPageGroup[volume, @fileD, group.nextFilePage].group.volumePage].address; IF group.filePage>=group.nextFilePage THEN ERROR FileImplError[makeBootableImpossibleError]; group.volumePage ← group.volumePage+(group.nextFilePage-group.filePage)-1; group.filePage ← group.nextFilePage-1; END; TransferLabels: PROCEDURE = INLINE BEGIN SimpleSpace.Map[pageBuffer, [[fileD.fileID, File.read], group.filePage], TRUE, 1]; [] ← LabelTransfer.WriteLabelAndData[ fileD, group.filePage, group.volumePage, bufferPage, nextLink]; SimpleSpace.Unmap[pageBuffer]; END; IF ~GetFileDescriptor[file, @fileD] THEN RETURN WITH ERROR Unknown[file↑]; IF (WITH fD: fileD SELECT FROM local => limitPage>fD.size, ENDCASE => TRUE) THEN RETURN WITH ERROR InvalidParameters; WHILE page<limitPage DO SELECT LogicalVolume.VolumeAccess[@fileD.volumeID, GetStuff] FROM ok => NULL; volumeUnknown => RETURN WITH ERROR Volume.Unknown[fileD.volumeID]; volumeNotOpen => RETURN WITH ERROR Volume.NotOpen[fileD.volumeID]; ENDCASE; IF success THEN TransferLabels[]; page ← group.nextFilePage; ENDLOOP; END; OpenVolumeAndDeleteTemps: PUBLIC ENTRY PROCEDURE [ volume: POINTER TO READONLY Volume.ID] = BEGIN SELECT LogicalVolume.OpenLogicalVolume[volume] FROM wasOpen => RETURN; ok => NULL; Unknown => RETURN WITH ERROR Volume.Unknown[volume↑]; VolumeNeedsScavenging => RETURN WITH ERROR Volume.NeedsScavenging; ENDCASE; IF PilotSwitches.switches.u=up THEN IF DeleteTempsInternal[volume]#ok THEN ERROR FileImplError[volumeWentAwayDuringDeleteTemps]; END; Pin: PUBLIC ENTRY PROCEDURE [ file: File.Capability, page: File.PageNumber, count: File.PageCount] = BEGIN fileD: FileInternal.Descriptor; after: File.PageNumber; IF ~GetFileDescriptor[@file, @fileD] THEN RETURN WITH ERROR Unknown[file]; WITH f: fileD SELECT FROM local => BEGIN p: FileInternal.LocalFilePtr ← @f; -- FOR COMPILER BUG Pin1: VolProc = BEGIN success: BOOLEAN; group: FileInternal.PageGroup ← [, , page]; FileCache.SetFile[fileD, TRUE]; updateMarkers ← FALSE; WHILE group.nextFilePage<after DO [success, group] ← VolFileMap.GetPageGroup[volume, p, group.nextFilePage]; IF ~success THEN ERROR FileImplError[missingPinnedPageGroup]; FileCache.SetPageGroup[file.fID, group, TRUE] ENDLOOP; END; after ← IF count=KernelFile.defaultPageCount THEN p.size ELSE page+count; SELECT LogicalVolume.VolumeAccess[@f.volumeID, Pin1] FROM ok => NULL; volumeUnknown => RETURN WITH ERROR Volume.Unknown[f.volumeID]; volumeNotOpen => RETURN WITH ERROR Volume.NotOpen[f.volumeID]; ENDCASE; END; remote => RETURN WITH ERROR SystemInternal.Unimplemented; ENDCASE; END; SetSize: PUBLIC ENTRY PROCEDURE [ file: Capability, size: PageCount, transaction: Transaction.Handle] = BEGIN ENABLE UNWIND => NULL; fileD: FileInternal.Descriptor; IF ~GetFileDescriptor[@file, @fileD] THEN RETURN WITH ERROR Unknown[file]; IF ~SufficientPermissions[file.permissions, File.write] THEN RETURN WITH ERROR Error[insufficientPermissions]; WITH f: fileD SELECT FROM local => BEGIN IF f.immutable THEN RETURN WITH ERROR Error[immutable]; IF transaction#nullTransaction THEN IF size#f.size THEN BEGIN OPEN TransactionState; entry: LogEntry ← (SELECT size FROM >f.size => [shrink[id: file.fID, size: f.size]], ENDCASE => [setContents[ id: file.fID, base: size, size: f.size-size]]); Log[transaction, @entry, txFileProcs ! Volume.InsufficientSpace => GOTO InsufficientSpace; Transaction.InvalidHandle => GOTO InvalidTxHandle]; EXITS InsufficientSpace => RETURN WITH ERROR Volume.InsufficientSpace; InvalidTxHandle => RETURN WITH ERROR Transaction.InvalidHandle; END; SELECT SetSizeInternal[@f, @size, file.permissions] FROM ok => RETURN; insufficientSpace => RETURN WITH ERROR Volume.InsufficientSpace; insufficientPermissions => RETURN WITH ERROR Error[insufficientPermissions]; ENDCASE; END; remote => RETURN WITH ERROR SystemInternal.Unimplemented; ENDCASE; END; -- this is its own entry procedure since it can get many nasty errors TmpsEnter: ENTRY PROCEDURE [ f: POINTER TO READONLY File.Capability, v: POINTER TO READONLY Volume.ID] = BEGIN FindIt: INTERNAL PROCEDURE RETURNS [BOOLEAN] = INLINE BEGIN tOriginal: LONG POINTER TO File.ID ← tmps; DO IF tmps↑=File.nullID THEN RETURN[TRUE]; IF (tmps ← tmps+SIZE[File.ID])=tmpsLast THEN tmps ← tmpStart; IF tmps=tOriginal THEN EXIT; ENDLOOP; RETURN[FALSE]; END; SELECT TmpsGet[v, last] FROM ok => NULL; volumeUnknown => RETURN WITH ERROR Volume.Unknown[v↑]; notOpen => RETURN WITH ERROR Volume.NotOpen[v↑]; noFile => RETURN; -- next delete tmps will be hard way ENDCASE; IF ~FindIt[] THEN IF ~TmpsGrow[] THEN RETURN WITH ERROR Volume.InsufficientSpace; tmps↑ ← f.fID; SimpleSpace.ForceOut[tmpsBuffer]; END; -- INTERNAL PROCEDURES ChangeAttributesInternal: INTERNAL PROCEDURE [ fileD: LocalFilePtr, action: AttributeAction] RETURNS [s: LogicalVolume.VolumeAccessStatus] = BEGIN file: Capability ← [fileD.fileID, maxPermissions]; link: DiskChannel.Address ← LOOPHOLE[LONG[0]]; volumePage: LogicalVolume.PageNumber; volID: Volume.ID ← fileD.volumeID; -- FOR COMPILER BUG GetGroup0: VolProc = BEGIN group: FileInternal.PageGroup; success: BOOLEAN; updateMarkers ← FALSE; [success, group] ← VolFileMap.GetPageGroup[volume, fileD, 0]; IF ~success THEN ERROR FileImplError[missingPage0]; volumePage ← group.volumePage; END; SELECT s ← LogicalVolume.VolumeAccess[@volID, GetGroup0] FROM ok => NULL; volumeUnknown, volumeNotOpen => RETURN; ENDCASE; IF LabelTransfer.VerifyLabels[ fileD↑, [0, volumePage, 1], FALSE, FALSE].status ~= goodCompletion THEN SIGNAL LabelError; -- smash time, folks. Watch out for zero size file IF action=permanent OR action=temporary THEN BEGIN IF fileD.type IN PilotFileTypes.PilotRootFileType THEN LogicalVolume.PutRootFile[@volID, fileD.type, @file ! Volume.Unknown => GOTO VUnknown; Volume.NotOpen => GOTO VNotOpen]; fileD.temporary ← action=temporary; EXITS VUnknown => RETURN[volumeUnknown]; VNotOpen => RETURN[volumeNotOpen]; END ELSE fileD.immutable ← action=immutable; SimpleSpace.Map[ pageBuffer, IF fileD.size=0 THEN Space.defaultWindow ELSE [file, 0], TRUE]; -- There's a small race here, since the label on the disk is now inconsistent with -- the information in the FileCache. If someone tries to access page 0 before we -- get the file cache updated, they will get a label check. The only fix for this -- is to do the label transfer inside the FileCache monitor (ugh) or arrange for the -- a recomputation of the label info and a retry of the i/o. Neither is easy, so -- we'll leave the race in until Klamath. Note that calling FileCache.FlushFile is -- bad too (that's what used to be done), because it flushes pinned page groups, causing -- disaster elsewhere. That problem is more severe than the remaining one. LOOPHOLE[link, PilotDisk.Address] ← LabelTransfer.ReadLabel[fileD↑, 0, volumePage].label.bootChainLink; [] ← LabelTransfer.WriteLabelAndData[ fileD↑, 0, volumePage, SimpleSpace.Page[pageBuffer], link]; FileCache.SetFile[fileD↑, FALSE]; SimpleSpace.Unmap[pageBuffer]; IF action=permanent THEN TmpsRemove[@file, @volID]; END; CreateWithIDInternal: INTERNAL PROCEDURE [ volume: POINTER TO READONLY System.VolumeID, initialSize: POINTER TO READONLY PageCount, type: File.Type, file: POINTER TO READONLY File.ID] RETURNS [s: LogicalVolume .FileVolumeStatus[ok..insufficientSpace]] = -- Create file given the file identifier (called by CreateWithIDExternal, -- OpenVolumeAndDeleteTemps). Expect to see Volume.Unknown, -- Volume.NotOpen, Volume.InsufficientSpace BEGIN fileD: local FileInternal.Descriptor ← [file↑, volume↑, local[FALSE, TRUE, 0, type]]; CreateInner: VolProc = BEGIN group: FileInternal.PageGroup ← [, 0, 0]; updateMarkers ← FALSE; IF LogicalVolume.FreeVolumePages[volume] <= initialSize↑ THEN s ← insufficientSpace ELSE BEGIN DO group ← [group.nextFilePage, group.volumePage+group.nextFilePage-group.filePage, initialSize↑]; VolAllocMap.AllocPageGroup[volume, LONG[@fileD], @group, TRUE]; -- results in modified group and FilePtr.size VolFileMap.InsertPageGroup[volume, LONG[@fileD], @group]; IF fileD.size=initialSize↑ THEN EXIT; ENDLOOP; FileCache.SetFile[fileD, FALSE]; END; END; s ← ok; SELECT LogicalVolume.VolumeAccess[@fileD.volumeID, CreateInner, TRUE] FROM ok => NULL; volumeUnknown => s ← volumeUnknown; volumeNotOpen => s ← volumeNotOpen; ENDCASE; END; DeleteFileOnVolumeInternal: INTERNAL PROCEDURE [ fileD: FileInternal.LocalFilePtr] RETURNS [s: LogicalVolume.VolumeAccessStatus] = BEGIN vID: Volume.ID ← fileD.volumeID; DeleteIt: VolProc = BEGIN g: FileInternal.PageGroup; success: BOOLEAN; FileCache.FlushFile[fileD.fileID]; updateMarkers ← FALSE; DO [success, g] ← VolFileMap.GetPageGroup[volume, fileD, File.lastPageNumber]; -- group.nextFile page is last page in file IF ~success THEN EXIT; g ← [0, LogicalVolume.nullVolumePage, g.nextFilePage]; VolFileMap.DeletePageGroup[volume, fileD, @g]; -- results in modified group VolAllocMap.FreePageGroup[volume, fileD, @g, TRUE]; -- results in modified fileD ENDLOOP; END; RETURN[LogicalVolume.VolumeAccess[@vID, DeleteIt, TRUE]]; END; DeleteTempsInternal: INTERNAL PROCEDURE [v: POINTER TO READONLY Volume.ID] RETURNS [s: LogicalVolume.VolumeAccessStatus] = BEGIN one: File.PageCount ← 1; SELECT TmpsGet[v, first] FROM noFile => s ← DeleteTmpsInternalOld[v]; ok => s ← DeleteTmpsInternalNew[v]; -- also deletes tempFile volumeUnknown => RETURN[volumeUnknown]; notOpen => RETURN[volumeNotOpen]; ENDCASE; IF s#ok THEN RETURN; -- Create a tmps file. tmpsFile ← [[System.GetUniversalID[]], FileInternal.maxPermissions]; SELECT CreateWithIDInternal[v, @one, PilotFileTypes.tTempFileList, @tmpsFile.fID] FROM insufficientSpace => RETURN; -- there will be no temp file; that's Ok volumeUnknown, volumeNotOpen => FileImplError[tmpsVolumeWentAway]; ENDCASE; LogicalVolume.PutRootFile[v, PilotFileTypes.tTempFileList, @tmpsFile ! Volume.Unknown, Volume.NotOpen => FileImplError[tmpsVolumeWentAway]]; END; DeleteTmpsInternalNew: INTERNAL PROCEDURE [v: POINTER TO READONLY Volume.ID] RETURNS [s: LogicalVolume.VolumeAccessStatus] = BEGIN cap: File.Capability ← [File.nullID, File.delete]; fileD: FileInternal.Descriptor; p: File.PageNumber; t: LONG POINTER TO File.ID; FOR p ← 0, p+1 WHILE p<tmpsFileSize DO TmpsMap[p]; FOR t ← tmpStart, t+SIZE[File.ID] WHILE t#tmpsLast DO IF t↑=File.nullID THEN LOOP; cap.fID ← t↑; IF GetFileDescriptor[@cap, @fileD, v] THEN WITH f: fileD SELECT FROM local => IF f.temporary THEN IF (s ← DeleteFileOnVolumeInternal[@f])#ok THEN RETURN ELSE LOOP; ENDCASE; -- ingore remote files (can't happen), and delete errors ENDLOOP; ENDLOOP; TmpsUnmap[]; -- finally, delete the file itself. IF GetFileDescriptor[@tmpsFile, @fileD, v] THEN WITH f: fileD SELECT FROM local => RETURN[DeleteFileOnVolumeInternal[@f]]; ENDCASE; ERROR FileImplError[disappearedOrRemoteTempFile]; END; DeleteTmpsInternalOld: INTERNAL PROCEDURE [v: POINTER TO READONLY Volume.ID] RETURNS [s: LogicalVolume.VolumeAccessStatus] = BEGIN lastCap: File.Capability ← File.nullCapability; thisCap: File.Capability; fileD: FileInternal.Descriptor; DO thisCap ← KernelFile.GetNextFile[v↑, lastCap ! Volume.Unknown => GOTO unknown; Volume.NotOpen => GOTO notOpen]; IF thisCap=File.nullCapability THEN EXIT; IF GetFileDescriptor[@thisCap, @fileD, v] THEN WITH f: fileD SELECT FROM local => IF f.temporary THEN IF (s ← DeleteFileOnVolumeInternal[@f])#ok THEN RETURN ELSE LOOP; ENDCASE; -- ignore remote files (can't happen) lastCap ← thisCap; ENDLOOP; RETURN[ok]; EXITS unknown => RETURN[volumeUnknown]; notOpen => RETURN[volumeNotOpen]; END; SetSizeInternal: INTERNAL PROCEDURE [ fileD: FileInternal.LocalFilePtr, size: POINTER TO READONLY File.PageCount, permissions: File.Permissions] RETURNS [s: LogicalVolume.FileVolumeStatus] = BEGIN vID: Volume.ID ← fileD.volumeID; vs: LogicalVolume.VolumeAccessStatus; SizeIt: VolProc = BEGIN success: BOOLEAN; group: FileInternal.PageGroup; -- if the file has pinned cache entries, the following is bad, but we don't have -- any other good way to deal with it unless the FileCache interface is changed. Better -- to wait for Klamath. FileCache.FlushFile[fileD.fileID]; updateMarkers ← FALSE; SELECT fileD.size FROM <size↑ => BEGIN IF ~SufficientPermissions[permissions, File.write+File.grow] THEN s ← insufficientPermissions ELSE IF LogicalVolume.FreeVolumePages[volume]<size↑-fileD.size THEN s ← insufficientSpace ELSE BEGIN [success, group] ← VolFileMap.GetPageGroup[volume, fileD, fileD.size-MIN[fileD.size, 1]]; IF ~success THEN ERROR FileImplError[missingPageGroupSetSize]; WHILE fileD.size<size↑ DO group ← [group.nextFilePage, group.volumePage+(group.nextFilePage-group.filePage), size↑]; VolAllocMap.AllocPageGroup[volume, fileD, @group, FALSE]; -- change group+fileD VolFileMap.InsertPageGroup[volume, fileD, @group]; ENDLOOP END END; >size↑ => BEGIN IF ~SufficientPermissions[permissions, File.write+File.shrink] THEN s ← insufficientPermissions ELSE BEGIN WHILE fileD.size>size↑ DO group ← [size↑, LogicalVolume.nullVolumePage, fileD.size]; VolFileMap.DeletePageGroup[volume, fileD, @group]; -- changes group VolAllocMap.FreePageGroup[volume, fileD, @group, FALSE]; -- changes FilePtr ENDLOOP; END; END; ENDCASE; IF s = ok THEN FileCache.SetFile[fileD↑, FALSE]; END; s ← ok; IF (vs ← LogicalVolume.VolumeAccess[@vID, SizeIt, TRUE]) ~= ok THEN RETURN [vs]; RETURN[s] END; TmpsGet: INTERNAL PROCEDURE [ v: POINTER TO READONLY Volume.ID, pg: {first, last}] RETURNS [{ok, volumeUnknown, notOpen, noFile}] = BEGIN IF v↑=Volume.nullID THEN RETURN[volumeUnknown]; IF tmpsVolume#v↑ THEN BEGIN fileD: FileInternal.Descriptor; TmpsUnmap[]; tmpsFile ← KernelFile.GetRootFile[PilotFileTypes.tTempFileList, v↑ ! Volume.Unknown => GOTO unknown; Volume.NotOpen => GOTO notOpen]; IF ~GetFileDescriptor[@tmpsFile, @fileD, v] THEN RETURN[noFile]; WITH fileD SELECT FROM local => tmpsFileSize ← size; ENDCASE => ERROR FileImplError[remoteTmpsFile]; TmpsMap[IF pg=first THEN 0 ELSE tmpsFileSize-1]; tmpsVolume ← v↑; EXITS unknown => RETURN[volumeUnknown]; notOpen => RETURN[notOpen]; END; RETURN[ok]; END; TmpsGrow: INTERNAL PROCEDURE RETURNS [BOOLEAN] = BEGIN fileD: FileInternal.Descriptor; newSize: File.PageCount ← tmpsFileSize+1; IF ~GetFileDescriptor[@tmpsFile, @fileD, @tmpsVolume] THEN ERROR FileImplError[tmpsFileWentAway]; WITH f: fileD SELECT FROM local => SELECT SetSizeInternal[@f, @newSize, File.grow+File.write] FROM insufficientSpace => RETURN[FALSE]; ok => NULL; ENDCASE => FileImplError[tmpsFileProblem]; ENDCASE => ERROR FileImplError[remoteTmpsFile]; TmpsMap[tmpsFileSize]; tmpsFileSize ← tmpsFileSize+1; RETURN[TRUE]; END; TmpsMap: INTERNAL PROCEDURE [page: File.PageNumber] = INLINE BEGIN IF tmpsVolume#nullID THEN SimpleSpace.Unmap[tmpsBuffer]; SimpleSpace.Map[tmpsBuffer, [tmpsFile, page], FALSE]; tmps ← tmpStart; END; TmpsRemove: INTERNAL PROCEDURE [ f: POINTER TO READONLY File.Capability, v: POINTER TO READONLY Volume.ID] = BEGIN t: LONG POINTER TO File.ID ← tmps; IF v↑#Volume.nullID -- impossible, he says-- AND tmpsVolume=v↑ THEN DO -- only cheap wins IF t↑=f.fID THEN BEGIN t↑ ← File.nullID; RETURN; END; IF t=tmpStart THEN t ← tmpsLast; IF (t ← t-SIZE[File.ID])=tmps THEN EXIT; ENDLOOP; END; TmpsUnmap: INTERNAL PROCEDURE = INLINE BEGIN IF tmpsVolume#Volume.nullID THEN BEGIN SimpleSpace.Unmap[tmpsBuffer]; tmpsVolume ← Volume.nullID; END; END; -- Here follows a gross kludge to allow the transaction machinery to sneak -- past our monitor lock. txFileProcs: TransactionState.FileOps = [TxCreate, TxMakePerm, TxSetSize]; TxCreate: INTERNAL PROCEDURE [size: PageCount, type: Type] RETURNS [file: ID] = BEGIN volID: Volume.ID ← Volume.systemID; file ← [System.GetUniversalID[]]; SELECT CreateWithIDInternal[@volID, @size, type, @file] FROM ok => NULL; insufficientSpace => ERROR Volume.InsufficientSpace; ENDCASE; END; TxMakePerm: INTERNAL PROCEDURE [file: ID] = BEGIN fileC: Capability ← [file, maxPermissions]; fileD: FileInternal.Descriptor; IF ~GetFileDescriptor[@fileC, @fileD] THEN ERROR Unknown[fileC]; WITH f: fileD SELECT FROM local => BEGIN SELECT ChangeAttributesInternal[@f, permanent] FROM volumeUnknown => ERROR Volume.Unknown[f.volumeID]; volumeNotOpen => ERROR Volume.NotOpen[f.volumeID]; ENDCASE; END; ENDCASE => ERROR FileImplError[remoteTxLog]; END; TxSetSize: INTERNAL PROCEDURE [file: ID, size: PageCount] = BEGIN fileC: Capability ← [file, maxPermissions]; fileD: FileInternal.Descriptor; IF ~GetFileDescriptor[@fileC, @fileD] THEN ERROR Unknown[fileC]; WITH f: fileD SELECT FROM local => BEGIN SELECT SetSizeInternal[@f, @size, maxPermissions] FROM insufficientSpace => ERROR Volume.InsufficientSpace; volumeUnknown => ERROR Volume.Unknown[f.volumeID]; volumeNotOpen => ERROR Volume.NotOpen[f.volumeID]; ENDCASE; END; ENDCASE => ERROR FileImplError[remoteTxLog]; END; -- Initialization InitializeFileMgr: PUBLIC PROCEDURE [ bootFile: LONG POINTER TO disk Boot.Location, pLVBootFiles: POINTER TO Boot.LVBootFiles] RETURNS [debuggerDeviceType: Device.Type, debuggerDeviceOrdinal: CARDINAL] = BEGIN priorityPrev: Process.Priority; throwAway: PROCESS; IF PilotSwitches.switches.f=down THEN Runtime.CallDebugger["Key Stop F"L]; priorityPrev ← Process.GetPriority[]; Process.SetPriority[ProcessPriorities.priorityPageFaultHigh]; throwAway ← FORK FileHelperProcess[]; -- (no profit in Detaching) Process.SetPriority[priorityPrev]; START FMPrograms.VolAllocMapImpl; START FMPrograms.VolFileMapImpl; START FMPrograms.MarkerPageImpl; [debuggerDeviceType, debuggerDeviceOrdinal] ← START FMPrograms.PhysicalVolumeImpl[bootFile, pLVBootFiles]; -- ..also starts VolumeImpl and ScavengeImpl. END; END. (For earlier log entries, see Pilot 4.0 archive version.) April 1, 1980 2:47 PM Gobbel Added transaction handles April 15, 1980 4:37 PM Gobbel Added nullTransactionHandle April 17, 1980 10:08 PM Luniewski Added TransactionHandle argument to GetSize and GetAttributes April 18, 1980 2:59 PM Luniewski Temporary exportation of transaction.nullHandle added May 15, 1980 6:11 PM McJones Add page and count parameters to Pin May 30, 1980 3:07 PM Luniewski PhysicalVolume removed from DIRECTORY. Made compatible with FileInternal.FileDescriptors being LONG POINTERs. STARTed PhysicalVolumeImpl. Removed START of VolumeImpl as it is now started by PhysicalVolumeImpl. LogicalVolume.{Open Close}Volume => LogicalVolume.{Open Close}LogicalVolume. June 10, 1980 1:20 AM Gobbel Added MakeTemporary and MakeMutable June 10, 1980 3:10 PM Gobbel Added transaction logging code July 19, 1980 11:15 AM McJones Deleted nullTransactionHandle and (Transaction.)nullHandle; adapted for new PilotDisk.Label; removed dependency in initialization of tmpsLast on SIZE[File.ID] July 25, 1980 3:32 PM Luniewski SpecialVolume.(NotOpen VolumeNeedsScavenging) => Volume.(NotOpen NeedsScavenging) August 11, 1980 5:24 PM Gobbel/Knutsen Restructure Create to allow export of CreateWithID to KernelFile for transaction crash recovery August 14, 1980 11:15 AM McJones Delete dependencies on tBootFile; FilePageLabel=>PilotDisk; require File.write in SetSizeInternal August 21, 1980 2:10 PM Gobbel Restructure transactional operations to use new interface for managing log files September 12, 1980 12:07 PM Gobbel Make GetFileDescriptor look at all volume types September 17, 1980 3:07 PM Luniewski Mods for new priocedure type passed to LogicalVolume.VolumeAccess. September 26, 1980 4:29 PM McJones GetBootLocation forgot to add offset to volume page December 31, 1980 12:18 PM Gobbel Changed tx log entries to have ids instead of capabilities. January 12, 1981 12:18 PM Luniewski New LabelTransfer interface. January 12, 1981 12:18 PM Knutsen Changed process priorities. January 26, 1981 Knutsen Renamed nullTransactionHandle to nullTransaction (export name conflict). February 11, 1981 5:28 PM Knutsen FilePageTransfer.Initiate now MStore.Promises itself. February 24, 1981 6:15 PM Gobbel Changed all procs that take transaction handles to be sure that monitor lock will not be held in client catch phrase. August 26, 1982 9:11 am Levin Make things SAFE. November 11, 1982 3:01 pm Levin Move all relevant FileCache operations inside volume access lock to ensure proper atomicity of file cache. December 8, 1982 5:11 pm Levin Correct access to FileCache in ChangeAttributesInternal. December 9, 1982 11:37 am Levin Replace lost "s ← ok" in SetSizeInternal.