ExtraIagoUtilsImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Willie-Sue, May 21, 1986 4:13:07 pm PDT
Russ Atkinson (RRA) March 11, 1985 8:39:34 pm PST
DIRECTORY
Ascii,
Basics USING [BytePair],
Disk USING [Channel, DoIO, DriveAttributes, Label, PageCount, PageNumber, Request, Status],
DiskFace USING [DeviceHandle, DiskAddress],
ExtraIagoOps USING [GetAddress],
ExtraIagoUtils,
File USING [Error, FindVolumeFromID, FindVolumeFromName, FP, Handle, Info, nullVolumeID, Open, PageCount, PageNumber, Read, Volume, VolumeFile, VolumeID, wordsPerPage],
FileInternal USING [Handle, FindRun, TranslateLogicalRun],
FS USING [Error],
FSBackdoor USING [Version],
FSFileOps USING [GetNameBodyAndVersion],
IagoOps USING [Confirm, FileError],
IO,
PhysicalVolume USING [GetSubVolumes, Physical, SubVolumeDetailsObject, SubVolumes],
Rope,
VM USING [AddressForPageNumber, Allocate, Free, Interval, nullInterval, PagesForWords, SwapIn, Unpin],
VolumeFormat USING [Attributes, LogicalPage, LogicalRun, RelID];
ExtraIagoUtilsImpl: CEDAR PROGRAM
IMPORTS Basics, Disk, ExtraIagoOps, File, FileInternal, FS, FSFileOps, IagoOps, IO, PhysicalVolume, VM
EXPORTS ExtraIagoUtils =
BEGIN OPEN IO, ExtraIagoUtils;
STREAM: TYPE = IO.STREAM;
ROPE: TYPE = Rope.ROPE;
* * * * * * * * * * * * * * * * * Utility Procedures * * * * * * * * * * * * * * *
StatusToRope: PUBLIC PROC[status: Disk.Status] RETURNS[r: ROPE, wasOK: BOOL] = {
wasOK ← FALSE;
WITH s: status SELECT FROM
changed => r ← "drive's ChangeCount changed; no IO performed";
unchanged => SELECT s.status FROM
inProgress => r ← "inProgress";
goodCompletion => {r ← "good Completion"; wasOK ← TRUE};
notReady => r ← "notReady";
recalibrateError => r ← "recalibrateError";
seekTimeout => r ← "seekTimeout";
headerCRCError => r ← "headerCRCError";
labelCRCError => r ← "labelCRCError";
dataCRCError => r ← "dataCRCError";
headerNotFound => r ← "headerNotFound";
labelVerifyError => r ← "labelVerifyError";
dataVerifyError => r ← "dataVerifyError";
overrunError => r ← "overrunError";
writeFault => r ← "writeFault";
memoryError => r ← "memoryError";
memoryFault => r ← "memoryFault";
clientError => r ← "clientError";
operationReset => r ← "operationReset";
otherError => r ← "otherError";
ENDCASE;
ENDCASE;
};
ReportStatus: PUBLIC PROC[out: STREAM, status: Disk.Status, dontReportOK: BOOLTRUE] = {
r: ROPE;
wasOK: BOOL;
[r, wasOK]← StatusToRope[status];
IF dontReportOK AND wasOK THEN RETURN;
out.PutF["\n\n **********Status reported as: %g **********", rope[r]];
};
OKStatusForWrite: PUBLIC PROC[status: Disk.Status, in, out: STREAM] RETURNS[ok: BOOL] = {
WITH s: status SELECT FROM
changed => RETURN[FALSE];
unchanged => SELECT s.status FROM
labelCRCError => NULL;
goodCompletion, dataCRCError, dataVerifyError => RETURN[TRUE];
inProgress, notReady, recalibrateError, seekTimeout, headerCRCError,
headerNotFound, labelVerifyError, overrunError, writeFault, memoryError,
memoryFault, clientError, operationReset, otherError => RETURN[FALSE];
ENDCASE;
ENDCASE;
out.PutRope["\n LabelCRCError reported; attempt the write anyway?"];
ok ← IagoOps.Confirm[in, out];
};
ChannelToDeviceHandle: PUBLIC PROC[c: Disk.Channel]
RETURNS[d: DiskFace.DeviceHandle] = {
ordinal: CARDINAL ← Disk.DriveAttributes[c].ordinal;
d ← LOOPHOLE[ordinal, DiskFace.DeviceHandle];
};
VolumeFileToRope: PUBLIC PROC[which: File.VolumeFile] RETURNS[ROPE] = {
RETURN[SELECT which FROM
checkpoint => "Checkpoint",
microcode => "Microcode",
germ => "Germ",
bootFile => "BootFile",
debugger => "Debugger",
debuggee => "Debuggee",
VM => "VM",
VAM => "VAM",
client => "FS-root",
alpine => "Alpine-root",
ENDCASE => "Other-root"];
};
AttributesToRope: PUBLIC PROC[attributes: VolumeFormat.Attributes] RETURNS[ROPE] = {
RETURN[SELECT attributes FROM
physicalRoot => "PhysicalRoot",
badPageList => "BadPageList",
badPage => "BadPage",
subVolumeMarker => "SubVolumeMarker",
logicalRoot => "LogicalRoot",
freePage => "FreePage",
header => "HeaderPage",
data => "DataPage",
lastCedar => "LastCedarAttribute",
ENDCASE => "UnknownType"];
};
* * * * * * * * commands implementation * * * * * * * *
DescribeOnePage: PUBLIC PROC[
logicalPage: VolumeFormat.LogicalPage, vol: File.Volume, in, out: STREAM] = TRUSTED {
pageSpace: VM.Interval ← VM.nullInterval;
{ ENABLE UNWIND => FreeSpace[pageSpace];
initLabel: Disk.Label;
data: LONG POINTER;
label: Disk.Label ← initLabel;
request: Disk.Request;
status: Disk.Status;
attr: VolumeFormat.Attributes;
realPage: Disk.PageNumber;
val: WORD;
run: VolumeFormat.LogicalRun;
channel: Disk.Channel;
[pageSpace, data]← GetSpace[1];
run ← [[logicalPage], 1];
[channel, realPage]← FileInternal.TranslateLogicalRun[run, vol ! File.Error => {
out.PutF["\nFile.Error (%g) during TranslateLogicalRun of logical page %g\n",
IO.rope[IagoOps.FileError[why]], IO.int[logicalPage]];
GOTO doQuit;
};
];
BEGIN ENABLE File.Error => {
out.PutF["\n File.Error (%g) reading page %g (physical page %g)\n",
rope[IagoOps.FileError[why]], int[logicalPage], int[realPage]];
GOTO keepGoing;
};
request ← [diskPage: [realPage], data: data, incrementDataPtr: FALSE,
command: [verify, read, read], count: 1];
[status, ]← Disk.DoIO[channel: channel, label: @label, request: @request];
attr ← LOOPHOLE[label.attributes];
IF attr = freePage THEN {
out.PutF["\n Page %g (physical page %g) is free, with status %g",
int[logicalPage], int[realPage], rope[StatusToRope[status].r]];
RETURN
};
IF attr = data OR attr = header THEN {
fp: File.FPLOOPHOLE[label.fileID.relID];
handle: File.Handle ← File.Open[vol, fp];
nameBody: Rope.Text;
version: FSBackdoor.Version;
[nameBody, version]← FSFileOps.GetNameBodyAndVersion[f: handle ! FS.Error => {
out.PutF["\n Page %g (physical page %g),\n\t***FS error: \"%g\"\n",
int[logicalPage], int[realPage], rope[error.explanation] ];
out.PutF["\tFile.FP is: [id: %g (%bB), da: %g (%bB)]\n",
IO.card[LOOPHOLE[fp.id]], IO.card[LOOPHOLE[fp.id]],
IO.card[LOOPHOLE[fp.da]], IO.card[LOOPHOLE[fp.da]]];
out.PutF["\tIs %g page %g of some file",
IF attr = data THEN rope["data"] ELSE rope["header"],
IO.int[label.filePage] ];
CONTINUE}];
IF nameBody # NIL THEN {
out.PutF["\n Page %g (physical page %g), with status %g\n",
int[logicalPage], int[realPage], rope[StatusToRope[status].r]];
out.PutF[" *** is %g page %g of file %g, version %g",
IF attr = data THEN rope["data"] ELSE rope["header"],
int[label.filePage],
rope[nameBody],
int[version]];
};
RETURN;
};
val ← LOOPHOLE[label.attributes];
out.PutF["\nOther type of page: logical: %g (physical %g), attributes: %g (%06b)\n",
IO.int[logicalPage], int[realPage], IO.rope[AttributesToRope[attr]], IO.card[val]];
EXITS
keepGoing => NULL;
END;
FreeSpace[pageSpace];
EXITS
doQuit => FreeSpace[pageSpace];
};
};
CheckPages: PUBLIC PROC[handle: File.Handle, name: ROPE, out: STREAM] = {
ENABLE FS.Error => {
out.PutRope[" ... "];
IF error.code = $invalidPropertyPage
THEN out.PutRope["not an FS file"]
ELSE out.PutRope[error.explanation];
CONTINUE
};
size: File.PageCount ← File.Info[handle].size;
didStop: BOOLFALSE;
diskPage: Disk.PageNumber;
channel: Disk.Channel;
pageSpace: VM.Interval ← VM.nullInterval;
numPages: INT = 25;
{
ENABLE UNWIND => FreeSpace[pageSpace];
data: LONG POINTER;
[pageSpace, data]← GetSpace[numPages];
out.PutF["\nReading pages from %g file (%g pages)\n", IO.rope[name], IO.int[size]];
TRUSTED {
i: File.PageCount ← 0;
WHILE i < size DO
IF i # 0 THEN IF i MOD 100 = 0 THEN
IF i MOD 1000 = 0 THEN out.PutF["(%g)", IO.int[i]] ELSE out.PutChar['~];
File.Read[handle, [i], numPages, data ! File.Error =>
{IF why # unknownPage THEN didStop ← TRUE; EXIT}];
i ← i + numPages;
ENDLOOP;
IF didStop THEN {
ff: FileInternal.Handle;
badPage: INT ← -1;
FOR j: File.PageCount IN [i..i+numPages) DO
File.Read[handle, [j], 1, data
! File.Error => {
out.PutF["\nFile error reading page %g\n", IO.int[j]];
out.PutRope[" ... "]; out.PutRope[IagoOps.FileError[why]];
badPage ← j;
EXIT}];
ENDLOOP;
ff ← LOOPHOLE[handle];
[diskPage, , channel]← FileInternal.FindRun[[badPage], 1, ff.runTable];
out.PutChar['\n];
PrintPageAndDiskAddr[diskPage, ChannelToDeviceHandle[channel], out];
ReadAndReport[NIL, out, diskPage, 1, channel, none];
};
};
FreeSpace[pageSpace];
};
};
LogicalToPhysicalPage: PUBLIC PROC[logicalPage: VolumeFormat.LogicalPage, volName: ROPE]
RETURNS[page: Disk.PageNumber] = {
vol: File.Volume = File.FindVolumeFromName[volName];
IF vol = NIL THEN RETURN[[-1]];
[ , page] ← FileInternal.TranslateLogicalRun[[logicalPage, 1], vol];
};
PhysicalToLogicalPage: PUBLIC PROC[p: PhysicalVolume.Physical, page: Disk.PageNumber]
RETURNS[logicalPage: VolumeFormat.LogicalPage, vol: File.Volume] = {
sv: PhysicalVolume.SubVolumes = PhysicalVolume.GetSubVolumes[p];
FOR i: CARDINAL IN [0..sv.count) DO
addr: INT = sv[i].address;
IF page >= addr AND page < addr+sv[i].size THEN {
logicalPage ← [page-addr];
vol ← File.FindVolumeFromID[sv[i].id];
RETURN
};
ENDLOOP;
RETURN[[0], File.FindVolumeFromID[File.nullVolumeID]];
};
PrintPageAndDiskAddr: PUBLIC PROC[
 page: Disk.PageNumber, d: DiskFace.DeviceHandle, out: STREAM] = {
addr: DiskFace.DiskAddress ← ExtraIagoOps.GetAddress[d, page];
IF addr.cylinder = LAST[CARDINAL] THEN
{ out.PutF[" Drive %g doesn't exist", int[LOOPHOLE[d, INTEGER]]]; RETURN};
out.PutF[" Page: %g (%bB),", int[page], card[page]];
out.PutF[" [cyl: %g (%bB), head: %g, sector: %g]",
card[addr.cylinder], card[addr.cylinder], card[addr.head], card[addr.sector]];
};
ReadAndReport: PUBLIC PROC[in, out: STREAM, first, count: INT, d: Disk.Channel, howToShowData: HowToShowData] = TRUSTED {
pageSpace: VM.Interval ← VM.nullInterval;
{
ENABLE UNWIND => FreeSpace[pageSpace];
origin: Disk.PageNumber;
initLabel: Disk.Label;
data: LONG POINTER;
[pageSpace, data]← GetSpace[1];
FOR i: INT IN [0 .. count) DO
label: Disk.Label ← initLabel;
val: WORD;
request: Disk.Request;
status: Disk.Status;
countDone: INT;
attr: VolumeFormat.Attributes;
origin ← [first + i];
request ← [diskPage: origin, data: data, incrementDataPtr: FALSE,
command: [verify, read, read], count: 1];
[status, countDone]← Disk.DoIO[channel: d, label: @label, request: @request];
ReportStatus[out, status];
out.PutF["\n\n *******Label for disk page %g is:\nFileID: ", int[first+i]];
FOR i: INT IN [0..5) DO
val ← LOOPHOLE[@label + i, LONG POINTER TO CARDINAL]^;
out.PutF[" %06b", IO.card[val]];
ENDLOOP;
attr ← LOOPHOLE[label.attributes];
IF attr = data OR attr = header THEN {
relID: VolumeFormat.RelID ← LOOPHOLE[label.fileID.relID];
da: VolumeFormat.LogicalPage ← LOOPHOLE[relID.da];
out.PutF["\n Logical Address of Header: %g", int[da]];
};
val ← LOOPHOLE[label.attributes];
out.PutF["\nfilePage: %g, attributes: %g (%06b)\n",
IO.int[label.filePage], IO.rope[AttributesToRope[attr]], IO.card[val]];
IF howToShowData # none THEN {
ptr: LONG POINTER TO CARDINALLOOPHOLE[data];
valsPerLine: INT = 8;  -- so its easy to change
numLines: INT ← 256/valsPerLine;
out.PutF["\n *****Data for that page is:\n"];
IF howToShowData = all
THEN {
FOR i: INT IN [0..numLines) DO
out.PutF["%03b/ ", IO.int[i*valsPerLine]];
FOR j: INT IN [0..valsPerLine) DO
val ← (ptr+ j)^; out.PutF[" %06b", IO.card[val]];
ENDLOOP;
out.PutRope[" "];  -- some white space
FOR j: INT IN [0..valsPerLine) DO
bytes: Basics.BytePair;
val ← (ptr+ j)^;
bytes ← LOOPHOLE[val, Basics.BytePair];
out.PutChar[CheckChar[LOOPHOLE[bytes.high, CHAR]]];
out.PutChar[CheckChar[LOOPHOLE[bytes.low, CHAR]]];
ENDLOOP;
out.PutChar['\n];
ptr ← ptr + valsPerLine;
ENDLOOP;
}
ELSE
FOR i: INT IN [0 .. 256) DO
bytes: Basics.BytePair;
val ← (ptr+ i)^;
bytes ← LOOPHOLE[val, Basics.BytePair];
out.PutChar[CheckChar[LOOPHOLE[bytes.high, CHAR]]];
out.PutChar[CheckChar[LOOPHOLE[bytes.low, CHAR]]];
ENDLOOP;
};
ENDLOOP;
FreeSpace[pageSpace];
};
};
CheckChar: PUBLIC PROC[ch: CHAR] RETURNS[CHAR] = {
OPEN Ascii;
xx: CARDINAL [0 .. 377B];
IF ch = NUL THEN RETURN[' ];
IF ch IN [ControlA .. ControlZ] THEN RETURN['*];
IF (xx ← LOOPHOLE[ch]) IN [200B .. 377B] THEN RETURN['!];
RETURN[ch]
};
GetSpace: PROC[num: INT] RETURNS[space: VM.Interval, data: LONG POINTER] = TRUSTED {
space ← VM.Allocate[VM.PagesForWords[num*File.wordsPerPage]];
data ← VM.AddressForPageNumber[space.page];
VM.SwapIn[interval: space, kill: TRUE, pin: TRUE];
};
FreeSpace: PROC[space: VM.Interval] = TRUSTED {
IF space = VM.nullInterval THEN RETURN;
VM.Unpin[space];
VM.Free[space];
space ← VM.nullInterval;
};
END.