-- 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.