-- CedarSnapshotFile.mesa -- last edited by Levin: November 22, 1982 2:12 pm DIRECTORY Boot USING [BootFileType, Location, LVBootFiles], BootFile USING [Header, MemorySizeToFileSize], CedarSnapshotPrivate USING [ FilePoint, initialSnapshotSize, nullFilePoint, PointAction, SnapshotFile, SnapshotFileDescriptor], DCSFileTypes USING [tLeaderPage], Environment USING [wordsPerPage], File USING [ Capability, Create, delete, Delete, GetAttributes, GetSize, grow, ID, MakePermanent, nullID, PageCount, PageNumber, read, SetSize, Type, Unknown, write], FileTypes USING [tUntypedFile], Heap USING [systemZone], KernelFile USING [GetBootLocation], Runtime USING [GlobalFrame], RuntimeInternal USING [Codebase], Space USING [ Create, Delete, GetAttributes, GetHandle, GetWindow, Handle, LongPointer, Map, PageCount, PageFromLongPointer, virtualMemory], SpecialFile USING [Link, MakeBootable], SpecialSpace USING [realMemorySize], SpecialVolume USING [GetLogicalVolumeBootFiles, SetLogicalVolumeBootFiles], System USING [GetGreenwichMeanTime, GreenwichMeanTime], Volume USING [Close, GetStatus, ID, systemID], VolumeExtras USING [OpenVolume]; CedarSnapshotFile: PROGRAM IMPORTS BootFile, File, Heap, KernelFile, Runtime, RuntimeInternal, Space, SpecialFile, SpecialSpace, SpecialVolume, System, Volume, VolumeExtras EXPORTS CedarSnapshotPrivate SHARES File = BEGIN OPEN CedarSnapshotPrivate; Header: TYPE = LONG POINTER TO SnapshotHeader; SnapshotHeader: TYPE = MACHINE DEPENDENT RECORD [ version(0): CARDINAL ← currentVersion, creation(1): System.GreenwichMeanTime, bootFileCreation(3): System.GreenwichMeanTime, bootFileVolume(5): Volume.ID, bootFilePoint(10): FilePoint ]; currentVersion: CARDINAL = 11082; previousVersion: CARDINAL = 06012; -- Cedar 3.4.1 -- pagesForHeader: Space.PageCount = (SIZE[SnapshotHeader]+Environment.wordsPerPage-1)/Environment.wordsPerPage; snapshotSlot: Boot.BootFileType = hardMicrocode; -- as good as any... snapshotFileType: File.Type = FileTypes.tUntypedFile; -- eventually, our own type InitializeSnapshotFile: PUBLIC PROC [volume: Volume.ID] RETURNS [snapshot: SnapshotFile] = { GetFile: PROC [volume: Volume.ID] RETURNS [file: File.ID] = { IF (file ← GetSnapshotPoint[volume, clear].filePoint.fID) = File.nullID THEN GO TO noFile; [] ← File.GetSize[[file, File.read] ! File.Unknown => GO TO noFile]; EXITS noFile => file ← File.Create[volume, initialSnapshotSize, snapshotFileType].fID; }; file: File.ID = GetFile[volume]; headerSpace: Space.Handle = Space.Create[pagesForHeader, Space.virtualMemory]; header: Header = Space.LongPointer[headerSpace]; snapshot ← Heap.systemZone.NEW[SnapshotFileDescriptor ← [ volume: volume, cap: [file, File.read + File.write + File.grow + File.delete], firstFree: 0]]; EnsureSnapshotFileSize[snapshot, pagesForHeader]; Space.Map[headerSpace, [snapshot.cap, snapshot.firstFree]]; snapshot.firstFree ← snapshot.firstFree + pagesForHeader; header↑ ← [ creation: System.GetGreenwichMeanTime[], bootFileCreation: GetBootFileCreation[GetCurrentBootFilePoint[]], bootFileVolume: Volume.systemID, bootFilePoint: GetCurrentBootFilePoint[] ]; Space.Delete[headerSpace]; }; FinalizeSnapshotFile: PUBLIC PROC [snapshot: SnapshotFile, action: PointAction] = { IF snapshot = NIL THEN RETURN; IF action = clear THEN File.Delete[snapshot.cap]; Heap.systemZone.FREE[@snapshot]; }; EnsureSnapshotFileSize: PUBLIC PROC [snapshot: SnapshotFile, size: File.PageCount] = {IF File.GetSize[snapshot.cap] < size THEN File.SetSize[snapshot.cap, size]}; PrepareForOutload: PUBLIC PROC [snapshot: SnapshotFile] RETURNS [location: disk Boot.Location] = { firstRMPage: File.PageNumber = snapshot.firstFree; pagesForRM: File.PageCount = BootFile.MemorySizeToFileSize[SpecialSpace.realMemorySize]; EnsureSnapshotFileSize[snapshot, firstRMPage + pagesForRM]; [] ← SpecialFile.MakeBootable[ file: snapshot.cap, firstPage: firstRMPage, count: pagesForRM, lastLink: SpecialFile.Link[0]]; location.diskFileID ← [fID: snapshot.cap.fID, firstPage: firstRMPage, da:]; [deviceType: location.deviceType, deviceOrdinal: location.deviceOrdinal, link: LOOPHOLE[location.diskFileID.da, SpecialFile.Link]] ← KernelFile.GetBootLocation[snapshot.cap, firstRMPage]; }; InstallSnapshotFile: PUBLIC PROC [snapshot: SnapshotFile, location: disk Boot.Location] = { bootFiles: Boot.LVBootFiles; SpecialVolume.GetLogicalVolumeBootFiles[snapshot.volume, @bootFiles]; bootFiles[snapshotSlot] ← [snapshot.cap.fID, location.diskFileID.firstPage, LOOPHOLE[location.diskFileID.da]]; SpecialVolume.SetLogicalVolumeBootFiles[snapshot.volume, @bootFiles]; File.MakePermanent[snapshot.cap]; }; GetSnapshotPoint: PUBLIC PROC [volume: Volume.ID, action: PointAction] RETURNS [filePoint: FilePoint, valid: BOOL ← FALSE] = { bootFiles: Boot.LVBootFiles; SpecialVolume.GetLogicalVolumeBootFiles[volume, @bootFiles]; filePoint ← [fID: bootFiles[snapshotSlot].fID, firstPage: bootFiles[snapshotSlot].firstPage]; IF filePoint = nullFilePoint THEN RETURN; valid ← ValidSnapshot[volume]; IF action = keep THEN RETURN; [fID: bootFiles[snapshotSlot].fID, firstPage: bootFiles[snapshotSlot].firstPage] ← nullFilePoint; SpecialVolume.SetLogicalVolumeBootFiles[volume, @bootFiles]; }; ValidSnapshot: PROC [volume: Volume.ID] RETURNS [ok: BOOL ← FALSE] = { headerSpace: Space.Handle = Space.Create[pagesForHeader, Space.virtualMemory]; header: Header = Space.LongPointer[headerSpace]; bootFiles: Boot.LVBootFiles; SpecialVolume.GetLogicalVolumeBootFiles[volume, @bootFiles]; {ENABLE --BogusFilePoint, File.Unknown, Volume.NeedsScavenging-- ANY => {ok ← FALSE; CONTINUE}; snapshotVolumeOpened: BOOL ← FALSE; IF Volume.GetStatus[volume] ~= open THEN { VolumeExtras.OpenVolume[volume: volume, readOnly: TRUE]; snapshotVolumeOpened ← TRUE; }; {ENABLE UNWIND => IF snapshotVolumeOpened THEN Volume.Close[volume]; Space.Map[headerSpace, [[bootFiles[snapshotSlot].fID, File.read], 0]]; SELECT header.version FROM currentVersion => { bootFileVolumeOpened: BOOL ← FALSE; IF Volume.GetStatus[header.bootFileVolume] ~= open THEN { VolumeExtras.OpenVolume[volume: header.bootFileVolume, readOnly: TRUE]; bootFileVolumeOpened ← TRUE; }; ok ← header.bootFileCreation = GetBootFileCreation[header.bootFilePoint]; IF bootFileVolumeOpened THEN Volume.Close[header.bootFileVolume]; }; previousVersion => ok ← header.bootFileCreation = GetBootFileCreation[[bootFiles[pilot].fID, bootFiles[pilot].firstPage]]; ENDCASE; }; IF snapshotVolumeOpened THEN Volume.Close[volume]; }; Space.Delete[headerSpace]; }; BogusFilePoint: ERROR = CODE; GetBootFileCreation: PROC [filePoint: FilePoint] RETURNS [creation: System.GreenwichMeanTime] = { -- This procedure differs from Runtime.GetBuildTime in that it deals with the boot file at -- arm's length. pagesForBootFileHeader: Space.PageCount = (SIZE[BootFile.Header]+Environment.wordsPerPage-1)/Environment.wordsPerPage; bootHeaderSpace: Space.Handle = Space.Create[pagesForBootFileHeader, Space.virtualMemory]; bootHeader: LONG POINTER TO BootFile.Header = Space.LongPointer[bootHeaderSpace]; cap: File.Capability = [filePoint.fID, File.read]; IF File.GetSize[cap] < filePoint.firstPage + pagesForBootFileHeader THEN ERROR BogusFilePoint; Space.Map[bootHeaderSpace, [cap, filePoint.firstPage]]; creation ← LOOPHOLE[bootHeader.creationDate]; Space.Delete[bootHeaderSpace]; }; GetCurrentBootFilePoint: PROC RETURNS [FilePoint] = { -- Pilot should really give us some help here. file: File.ID; someBootFileCode: Space.Handle ← Space.GetHandle[Space.PageFromLongPointer[ RuntimeInternal.Codebase[Runtime.GlobalFrame[Space.GetHandle]]]]; DO parent: Space.Handle; mapped: BOOL; [parent: parent, mapped: mapped] ← Space.GetAttributes[someBootFileCode]; IF mapped THEN {file ← Space.GetWindow[someBootFileCode].file.fID; EXIT}; someBootFileCode ← parent; ENDLOOP; RETURN[ [fID: file, firstPage: SELECT File.GetAttributes[[file, File.read]].type FROM FileTypes.tUntypedFile => 0, -- probably a volume root file DCSFileTypes.tLeaderPage => 1, ENDCASE => 0] -- unexpected: 0 probably isn't right, but... ] }; END.