DIRECTORY Ascii, Basics USING [BytePair, LongDivMod], Convert USING [Error, IntFromRope], Disk USING [Channel, DoIO, DriveAttributes, Label, PageCount, PageNumber, Request, Status], DiskFace USING [DeviceHandle, DiskAddress, GetDeviceAttributes], ExtraIagoOps, File USING [Delete, Error, FindVolumeFromID, FP, GetVolumeName, Handle, Info, nullFP, nullVolumeID, Open, PageCount, PageNumber, Read, Volume, VolumeFile, VolumeID, wordsPerPage], FileBackdoor USING [GetRoot, PhysicalPageBad], FileInternal USING [Handle, Alloc, Commit, FindRun, Free, GetBadPages, TranslateLogicalRun], FS USING [Close, Error, FileInfo, nullOpenFile, Open, OpenFile], FSBackdoor USING [GetFileHandle, Version], FSFileOps USING [GetNameBodyAndVersion], FormatDisk USING [altoRegionJargon, altoRegionsSize, hardUCodeSize], IagoOps USING [Confirm, FileError, GetArg, GetDrive, GetFile, GetLogical, GetNumber, GetPhysical, PutID], IO, PhysicalVolume USING [GetSubVolumes, NextPhysical, Physical, PhysicalInfo, PhysicalRC, SubVolumeDetails, SubVolumeDetailsObject, SubVolumes], Rope, SystemVersion USING [machineType], VM USING [AddressForPageNumber, Allocate, Free, Interval, nullInterval, PagesForBytes, PagesForWords, SwapIn, Unpin], VolumeFormat USING [Attributes, BadPageList, LogicalPage, LogicalRun, PhysicalRoot, RelID]; ExtraIagoOpsImpl: CEDAR PROGRAM IMPORTS Basics, Convert, Disk, DiskFace, File, FileBackdoor, FileInternal, FormatDisk, FS, FSBackdoor, FSFileOps, IagoOps, IO, PhysicalVolume, Rope, SystemVersion, VM EXPORTS ExtraIagoOps = { OPEN IO; STREAM: TYPE = IO.STREAM; ROPE: TYPE = Rope.ROPE; HowToShowData: TYPE = {none, all, text, stop}; pagePrompt: ROPE = "\nPage number: "; logicalPagePrompt: ROPE = "\nLogicalPage number: "; pageHelp: ROPE = "? type the page number (in decimal)"; numPagesPrompt: ROPE = "\nNumber of pages: "; numPagesHelp: ROPE = "? type the number of pages (in decimal)"; howToPrompt: ROPE = "\nHow to show the data: "; howToHelp: ROPE = "? type one of {n (none), a (all), t (text), s (stop)}"; GetDrive: PROC[in, out: STREAM] RETURNS[d: Disk.Channel, drive: INT] = { d _ IagoOps.GetDrive[in, out]; drive _ IF d # NIL THEN Disk.DriveAttributes[d].ordinal ELSE -1; }; GetPageNumber: PROC[in, out: STREAM, max: INT] RETURNS[page: INT] = { page _ 0; page _ IagoOps.GetNumber[ in: in, out: out, default: page, max: max, prompt: pagePrompt, help: pageHelp]; }; GetLogicalPageNumber: PROC[in, out: STREAM, max: INT] RETURNS[logicalPage: VolumeFormat.LogicalPage] = { page: INT _ 0; page _ IagoOps.GetNumber[ in: in, out: out, default: page, max: max, prompt: logicalPagePrompt, help: pageHelp]; RETURN[[page]]; }; GetNumberOfPages: PROC[in, out: STREAM] RETURNS[count: INT] = { count _ 1; count _ IagoOps.GetNumber[ in: in, out: out, default: count, max: 7, prompt: numPagesPrompt, help: numPagesHelp]; }; GetHowToShow: PROC[in, out: STREAM] RETURNS[howToShowData: HowToShowData] = { howTo: ROPE _ "n (none)"; HowToHelp: PROC = {out.PutRope[howToHelp]}; DO howTo _ IagoOps.GetArg[ in: in, out: out, default: howTo, prompt: howToPrompt, help: HowToHelp]; SELECT howTo.Fetch[0] FROM 'n, 'N => RETURN[none]; 'a, 'A => RETURN[all]; 't, 'T => RETURN[text]; 's, 'S => RETURN[stop]; ENDCASE => out.PutF["%g is not a legal value; try again", rope[howTo]]; ENDLOOP; }; Loophole: PUBLIC PROC[in, out: IO.STREAM] = { Help: PROC = { IO.PutRope[out, "type a number, ending in B or H"] }; ok: BOOL _ TRUE; sizeRope: ROPE _ IagoOps.GetArg[ in: in, out: out, prompt: "(xxxB) ", default: "0", help: Help]; size: INT; size _ Convert.IntFromRope[sizeRope ! Convert.Error => { ok _ FALSE; CONTINUE } ]; IF ok THEN out.PutF[" in decimal is %g", IO.int[size]] ELSE out.PutRope["\nNot a number"]; }; GetAddress: PUBLIC PROC[d: DiskFace.DeviceHandle, page: INT] RETURNS[addr: DiskFace.DiskAddress] = { ENABLE UNWIND => NULL; thisCylinder: CARDINAL; temp: CARDINAL; cylinders, movingHeads, fixedHeads, sectorsPerTrack: CARDINAL; [cylinders, movingHeads, fixedHeads, sectorsPerTrack]_ DiskFace.GetDeviceAttributes[d]; IF cylinders = 0 THEN RETURN[[LAST[CARDINAL], 0, 0]]; [quotient: thisCylinder, remainder: temp] _ Basics.LongDivMod[ num: page, den: sectorsPerTrack * movingHeads]; IF (LOOPHOLE[d, CARDINAL] = 0) AND (SystemVersion.machineType = dorado) THEN RETURN[[cylinder: thisCylinder MOD 815, sector: temp MOD sectorsPerTrack, head: thisCylinder/815 ] ] ELSE RETURN[ [cylinder: thisCylinder, sector: temp MOD sectorsPerTrack, head: temp/sectorsPerTrack ] ] }; PrintPageAndDiskAddr: PROC[page: Disk.PageNumber, d: DiskFace.DeviceHandle, out: STREAM] = { addr: DiskFace.DiskAddress _ 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]]; }; StatusToRope: 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: PROC[out: STREAM, status: Disk.Status, dontReportOK: BOOL _ TRUE] = { 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: 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: PROC[c: Disk.Channel] RETURNS[d: DiskFace.DeviceHandle] = { ordinal: CARDINAL _ Disk.DriveAttributes[c].ordinal; d _ LOOPHOLE[ordinal, DiskFace.DeviceHandle]; }; VolumeFileToRope: 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: 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"]; }; AddPageToBadPageTable: PUBLIC PROC[in, out: STREAM] = { p: PhysicalVolume.Physical _ IagoOps.GetPhysical[in, out]; page: INT = GetPageNumber[in, out, LAST[INT]]; name: ROPE = PhysicalVolume.PhysicalInfo[p].name; out.PutF["\nAdding physical page %g to bad page table for %g", int[page], rope[name]]; []_ FileBackdoor.PhysicalPageBad[p, [page]]; }; DescribeAllocated: PUBLIC PROC[in, out: STREAM] = { FOR p: PhysicalVolume.Physical _ PhysicalVolume.NextPhysical[NIL], PhysicalVolume.NextPhysical[p] UNTIL p = NIL DO channel: Disk.Channel; rootStatus: PhysicalVolume.PhysicalRC; id: File.VolumeID; name: Rope.ROPE; size: Disk.PageCount; free: Disk.PageCount; inUse: INT _ 0; reserved: INT; [channel: channel, rootStatus: rootStatus, id: id, name: name, size: size, free: free] _ PhysicalVolume.PhysicalInfo[p]; out.PutF["\n\nID: "]; IagoOps.PutID[out, id]; out.PutF["\nOn drive RD%g", [integer[Disk.DriveAttributes[channel].ordinal]] ]; SELECT rootStatus FROM ok => NULL--drop through to after ENDCASE--; wentOffline => { out.PutRope["\nVolume went offline"]; LOOP }; inconsistent => { out.PutRope["\nRoot page is inconsistent (wrong version?)"]; LOOP }; software => { out.PutRope["\nCan't find the volume root page (label-check)"]; LOOP }; hardware => { out.PutRope["\nHard disk error reading the volume root page"]; LOOP }; ENDCASE => ERROR File.Error[rootStatus]; out.PutF["\nName: %g\nSize: %g\n Logical sub-volumes:", [rope[name]], [integer[size]] ]; { sv: PhysicalVolume.SubVolumes = PhysicalVolume.GetSubVolumes[p]; FOR i: CARDINAL IN [0..sv.count) DO out.PutF["\n At physical page %g, logical id: ", [integer[sv[i].address]] ]; IagoOps.PutID[out, sv[i].id]; out.PutF[", pages [%g..%g)", [integer[sv[i].start]], [integer[sv[i].start+sv[i].size]] ]; inUse _ inUse + sv[i].size; ENDLOOP; reserved _ size - inUse - free; IF reserved # 0 THEN { num: INT _ reserved - FormatDisk.hardUCodeSize; IF num >= FormatDisk.altoRegionsSize THEN out.PutF["\n%g pages (%g %g) reserved for alto allocations", [integer[num]], [integer[num/FormatDisk.altoRegionsSize]], [rope[FormatDisk.altoRegionJargon]] ]; }; IF free # 0 THEN out.PutF["\n%g pages (%g %g) for potential alto allocations", [integer[free]], [integer[(free+1)/FormatDisk.altoRegionsSize]], [rope[FormatDisk.altoRegionJargon]] ]; }; ENDLOOP; }; BadPagesRec: TYPE = RECORD[ ls: LIST OF VolumeFormat.LogicalPage, subV: PhysicalVolume.SubVolumeDetails, vol: File.Volume, drive: DiskFace.DeviceHandle ]; BadPagesListProc: TYPE = PROC[ls: LIST OF VolumeFormat.LogicalPage, subV: PhysicalVolume.SubVolumeDetails, vol: File.Volume, drive: DiskFace.DeviceHandle]; DescribeBadPages: PUBLIC PROC[in, out: IO.STREAM] = TRUSTED { badPagesInfo: LIST OF BadPagesRec _ NIL; count: INT _ 0; Dbp: BadPagesListProc = TRUSTED { badPagesInfo _ CONS[ [ls, subV, vol, drive], badPagesInfo] }; DoBadPages[in, out, Dbp, FALSE]; IF badPagesInfo = NIL THEN RETURN; FOR bp: LIST OF BadPagesRec _ badPagesInfo, bp.rest UNTIL bp = NIL DO out.PutF["\n\nBad Pages for %g\n", rope[File.GetVolumeName[bp.first.vol]]]; FOR ls: LIST OF VolumeFormat.LogicalPage _ bp.first.ls, ls.rest UNTIL ls=NIL DO DescribeOnePage[ls.first, bp.first.vol, in, out]; IF (count _ count + 1) MOD 10 = 0 THEN { out.PutRope["\nContinue?"]; IF ~IagoOps.Confirm[in, out] THEN RETURN; }; ENDLOOP; ENDLOOP; }; DescribeVolumePage: PUBLIC PROC[in, out: IO.STREAM] = { vol: File.Volume = IagoOps.GetLogical[in, out]; logicalPage: VolumeFormat.LogicalPage = GetLogicalPageNumber[in, out, LAST[INT]]; DescribeOnePage[logicalPage, vol, in, out]; }; DescribeDiskPage: PUBLIC PROC[in, out: IO.STREAM] = { p: PhysicalVolume.Physical _ IagoOps.GetPhysical[in, out]; page: INT = GetPageNumber[in, out, LAST[INT]]; name: ROPE = PhysicalVolume.PhysicalInfo[p].name; logicalPage: VolumeFormat.LogicalPage; vol: File.Volume; [logicalPage, vol] _ PhysicalToLogicalPage[p, [page]]; IF vol = NIL THEN { out.PutF["\nPage %g not valid for %g", IO.int[page], IO.rope[name]]; RETURN; }; DescribeOnePage[logicalPage, vol, in, out]; }; DescribeOnePage: 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.FP _ LOOPHOLE[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]; }; }; EnsureBadPagesInVAM: PUBLIC PROC[in, out: IO.STREAM] = { Ensure: BadPagesListProc = TRUSTED { FOR vls: LIST OF VolumeFormat.LogicalPage _ ls, vls.rest UNTIL vls=NIL DO AllocatePageInVAM[out, vol, vls.first]; ENDLOOP; }; DoBadPages[in, out, Ensure, TRUE]; }; ListBadPages: PUBLIC PROC[in, out: IO.STREAM] = { Print: BadPagesListProc = TRUSTED { FOR vls: LIST OF VolumeFormat.LogicalPage _ ls, vls.rest UNTIL vls=NIL DO PrintBadPageInfo[out, subV, vls.first, drive]; ENDLOOP; }; DoBadPages[in, out, Print, TRUE]; }; MarkPageAllocated: PUBLIC PROC[in, out: STREAM] = { vol: File.Volume = IagoOps.GetLogical[in, out]; logicalPage: VolumeFormat.LogicalPage = GetLogicalPageNumber[in, out, LAST[INT]]; AllocatePageInVAM[out, vol, logicalPage]; }; ReadDiskPages: PUBLIC PROC[in, out: STREAM] = { page, drive, count: INT; d: Disk.Channel; howToShowData: HowToShowData; [d, drive] _ GetDrive[in, out]; IF d = NIL THEN RETURN; page _ GetPageNumber[in, out, LAST[INT]]; count _ GetNumberOfPages[in, out]; IF count = 0 THEN RETURN; howToShowData _ GetHowToShow[in, out]; IF howToShowData = stop THEN RETURN; out.PutF["\nReading %g pages starting at %g on RD%g ...", int[count], int[page], int[drive]]; ReadAndReport[in, out, page, count, d, howToShowData]; }; ReadFilePages: PUBLIC PROC[in, out: STREAM] = { name: ROPE _ IagoOps.GetFile[in: in, out: out]; openFile: FS.OpenFile; handle: File.Handle; fiHandle: FileInternal.Handle; fullName: ROPE _ NIL; diskPage: Disk.PageNumber; channel: Disk.Channel; bytes, pagesInFile, startingPage, count: INT; howToShowData: HowToShowData _ none; [fullName, , , bytes, ]_ FS.FileInfo[name: name ! FS.Error => SELECT error.code FROM $unknownServer, $unknownVolume, $unknownFile, $illegalName, $patternNotAllowed => { out.PutRope[" ... "]; out.PutRope[error.explanation]; CONTINUE }; ENDCASE => NULL ]; IF fullName.Length[] = 0 THEN RETURN; pagesInFile _ VM.PagesForBytes[bytes]; startingPage _ GetPageNumber[in, out, pagesInFile]; count _ GetNumberOfPages[in, out]; IF count = 0 THEN RETURN; IF (count + startingPage) > pagesInFile THEN count _ pagesInFile - startingPage - 1; howToShowData _ GetHowToShow[in, out]; IF howToShowData = stop THEN RETURN; handle _ FSBackdoor.GetFileHandle[openFile _ FS.Open[fullName]]; TRUSTED {fiHandle _ LOOPHOLE[handle]}; FOR i: INT IN [0 .. count) DO [diskPage, , channel]_ FileInternal.FindRun[[startingPage+i], 1, fiHandle.runTable]; ReadAndReport[in, out, diskPage, count, channel, howToShowData]; ENDLOOP; IF openFile # FS.nullOpenFile THEN FS.Close[openFile]; }; ReadLogicalPages: PUBLIC PROC[in, out: IO.STREAM] = { count: INT; d: Disk.Channel; diskPage: Disk.PageNumber; howToShowData: HowToShowData; run: VolumeFormat.LogicalRun; volume: File.Volume = IagoOps.GetLogical[in, out]; logicalPage: VolumeFormat.LogicalPage; IF volume = NIL THEN RETURN; logicalPage _ GetLogicalPageNumber[in, out, LAST[INT]]; count _ GetNumberOfPages[in, out]; IF count = 0 THEN RETURN; howToShowData _ GetHowToShow[in, out]; IF howToShowData = stop THEN RETURN; run _ [logicalPage, 1]; [d, diskPage]_ FileInternal.TranslateLogicalRun[run, volume]; out.PutF["\nReading %g pages starting at (logical) %g on volume: %g ...", int[count], int[logicalPage], rope[File.GetVolumeName[volume]]]; ReadAndReport[in, out, diskPage, count, d, howToShowData]; }; ReadNamedFile: PUBLIC PROC[in, out: IO.STREAM] = { name: ROPE = IagoOps.GetFile[in: in, out: out]; openFile: FS.OpenFile; handle: File.Handle = FSBackdoor.GetFileHandle[openFile _ FS.Open[name]]; IF handle # NIL THEN CheckPages[handle, name, out]; IF openFile # FS.nullOpenFile THEN FS.Close[openFile]; }; ShowDiskAddress: PUBLIC PROC[in, out: IO.STREAM] = { d: Disk.Channel = GetDrive[in: in, out: out].d; page: INT = GetPageNumber[in, out, LAST[INT]]; out.PutChar['\n]; PrintPageAndDiskAddr[[page], ChannelToDeviceHandle[d], out]; }; UpdateVAM: PUBLIC PROC[in, out: STREAM] = {}; WriteDiskPage: PUBLIC PROC[in, out: STREAM] = TRUSTED { diskPage, drive: INT; d: Disk.Channel; useOldData: BOOL; pageSpace: VM.Interval; [d, drive] _ GetDrive[in, out]; IF d = NIL THEN RETURN; diskPage _ GetPageNumber[in, out, LAST[INT]]; out.PutRope["\nDo you want to try to rewrite the old data? "]; useOldData _ IagoOps.Confirm[in, out]; { ENABLE UNWIND => FreeSpace[pageSpace]; data: LONG POINTER; initLabel: Disk.Label; label: Disk.Label _ initLabel; request: Disk.Request; status: Disk.Status; [pageSpace, data]_ GetSpace[1]; request _ [diskPage: [diskPage], data: data, incrementDataPtr: FALSE, command: [verify, read, read], count: 1]; [status, ]_ Disk.DoIO[channel: d, label: @label, request: @request]; IF OKStatusForWrite[status, in, out] THEN { IF ~useOldData THEN FOR i: INT IN [0 .. File.wordsPerPage) DO (data+i)^_ 0; ENDLOOP; request _ [diskPage: [diskPage], data: data, incrementDataPtr: FALSE, command: [verify, verify, write], count: 1]; [status, ]_ Disk.DoIO[channel: d, label: @label, request: @request]; ReportStatus[out, status, FALSE]; } ELSE { ReportStatus[out, status]; out.PutRope["\n Write NOT done\n"]; }; FreeSpace[pageSpace]; }; }; DeleteSystemFile: PUBLIC PROC[in, out: IO.STREAM, which: File.VolumeFile] = { volume: File.Volume _ IagoOps.GetLogical[in, out]; fp: File.FP; file: File.Handle; name: ROPE _ VolumeFileToRope[which]; fp _ FileBackdoor.GetRoot[volume, which].fp; IF fp = File.nullFP THEN { out.PutF["\n%g file doesn't exist", rope[name]]; RETURN}; file _ File.Open[volume, fp ! File.Error => { out.PutRope[" ... "]; out.PutRope[IagoOps.FileError[why]]; file _ NIL; CONTINUE } ]; IF file # NIL THEN { out.PutF["Confirm deletion of %g file: ", rope[name]]; IF IagoOps.Confirm[in, out] THEN { out.PutF["\nDeleting %g file", rope[name]]; File.Delete[file]; out.PutF["\n%g file has been deleted", rope[name]] }; }; }; ReadAndReport: 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 CARDINAL _ LOOPHOLE[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: 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] }; ReadSystemFile: PUBLIC PROC[in, out: STREAM, which: File.VolumeFile] = { volume: File.Volume _ IagoOps.GetLogical[in, out]; fp: File.FP; page: File.PageNumber; handle: File.Handle; name: ROPE _ VolumeFileToRope[which]; [fp, page]_ FileBackdoor.GetRoot[volume, which]; IF fp = File.nullFP THEN RETURN; handle _ File.Open[volume, fp ! File.Error => { out.PutRope[" ... "]; out.PutRope[IagoOps.FileError[why]]; handle _ NIL; CONTINUE } ]; IF handle # NIL THEN CheckPages[handle, name, out]; }; CheckPages: 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: BOOL _ FALSE; 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]; }; }; AllocatePageInVAM: PROC[ out: STREAM, vol: File.Volume, logicalPage: VolumeFormat.LogicalPage] = { given: VolumeFormat.LogicalRun _ FileInternal.Alloc[volume: vol, first: logicalPage, size: 1, min: 1]; IF given.first = logicalPage THEN { FileInternal.Commit[vol]; out.PutF["\n Logical page %g has been added to the VAM for volume: %g", IO.int[logicalPage], IO.rope[File.GetVolumeName[vol]]] } ELSE { FileInternal.Free[vol, given]; out.PutF["\n Logical page %g was already in the VAM", IO.int[logicalPage]]; }; }; PhysicalToLogicalPage: 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 start: INT = sv[i].start; IF page >= start AND page < start+sv[i].size THEN { logicalPage _ [page-start]; vol _ File.FindVolumeFromID[sv[i].id]; RETURN }; ENDLOOP; RETURN[[0], File.FindVolumeFromID[File.nullVolumeID]]; }; ReservedList: TYPE = LIST OF RECORD[start: Disk.PageNumber, size: Disk.PageCount]; P2: TYPE = REF PhysicalObject; PhysicalObject: TYPE = RECORD[ channel: Disk.Channel, rootStatus: PhysicalVolume.PhysicalRC _ ok, root: LONG POINTER TO VolumeFormat.PhysicalRoot _ NIL, bad: LONG POINTER TO VolumeFormat.BadPageList _ NIL, name: Rope.ROPE _ NIL, reserved: ReservedList _ NIL, rest: REF PhysicalObject _ NIL ]; DoBadPages: PROC[in, out: IO.STREAM, proc: BadPagesListProc, doOut: BOOL] = { p: PhysicalVolume.Physical _ IagoOps.GetPhysical[in, out]; anyBad: BOOL _ FALSE; sv: PhysicalVolume.SubVolumes; drive: DiskFace.DeviceHandle; subV: PhysicalVolume.SubVolumeDetails; vol: File.Volume; badList: LIST OF VolumeFormat.LogicalPage; IF p = NIL THEN RETURN; TRUSTED { p2: P2 _ LOOPHOLE[p]; p2.bad _ NIL; }; drive _ ChannelToDeviceHandle[PhysicalVolume.PhysicalInfo[p].channel]; sv _ PhysicalVolume.GetSubVolumes[p]; FOR i: CARDINAL IN [0..sv.count) DO KeepList: PROC[logicalPage: VolumeFormat.LogicalPage] = { badList _ CONS[logicalPage, badList]; }; badList _ NIL; subV _ NEW[PhysicalVolume.SubVolumeDetailsObject _ sv[i]]; FileInternal.GetBadPages[subVolume: subV, work: KeepList]; IF badList = NIL THEN LOOP; anyBad _ TRUE; vol _ File.FindVolumeFromID[subV.id]; IF doOut THEN out.PutF["\n\nBad Pages for %g {subvolume %g}:", rope[File.GetVolumeName[vol]], card[i]]; IF proc # NIL THEN proc[badList, subV, vol, drive]; ENDLOOP; IF ~anyBad THEN IF doOut THEN out.PutRope["\nNo bad pages listed"]; }; PrintBadPageInfo: PROC[out: STREAM, subV: PhysicalVolume.SubVolumeDetails, logicalPage: VolumeFormat.LogicalPage, drive: DiskFace.DeviceHandle] = { bad: Disk.PageNumber _ [logicalPage + subV.address + subV.start]; out.PutF["\n Logical page: %g (%bB)", int[logicalPage], int[logicalPage]]; PrintPageAndDiskAddr[bad, drive, out]; }; 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; }; }. ζExtraIagoOpsImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Willie-Sue, October 30, 1985 4:34:31 pm PST Russ Atkinson (RRA) March 11, 1985 8:39:34 pm PST * * * * * * * * * * * * * * * * * Utility Procedures * * * * * * * * * * * * * * * kludge for funny RD0 formatting on dorado * * * * * * * * commands implementation * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * force reading of BadPageTable from disk Κ (˜codešœ™Kšœ Οmœ1™žœžœ˜RKšžœžœžœ žœ˜ZKšœ˜—K˜š Ÿ œžœžœ!žœžœ ˜dKšžœžœžœ˜Kšœžœ˜Kšœžœ˜Kšœ5žœ˜>KšœW˜WK˜Kš žœžœžœžœžœ ˜5K˜šœ>˜>Kšœ/˜/—šžœžœžœžœ%˜GKšž˜šœ)™)šžœžœ˜'Kšœ žœ,˜<——šž˜šžœ˜ Kšœ žœ0˜@———Kšœ˜—K˜šœ˜Kšœžœ7žœ˜GKšœ1˜1šžœžœžœž˜&Kšœ*žœžœžœ˜J—Kšœ6˜6šœ2˜2K˜N—Kšœ˜—K˜š Ÿ œžœžœžœ žœ˜IKšœžœ˜šžœ žœž˜Kšœ>˜>šœ žœ ž˜!Kšœ˜Kšœ2žœ˜8Kšœ˜Kšœ+˜+Kšœ!˜!Kšœ'˜'Kšœ%˜%Kšœ#˜#Kšœ'˜'Kšœ+˜+Kšœ)˜)Kšœ#˜#Kšœ˜Kšœ!˜!Kšœ!˜!Kšœ!˜!Kšœ'˜'Kšœ˜—Kšžœ˜—Kšžœ˜K˜—K˜š Ÿ œžœžœ%žœžœ˜SKšœžœ˜Kšœžœ˜ Kšœ!˜!Kšžœžœžœžœ˜&K˜FKšœ˜—K˜š Ÿœžœžœžœžœ˜Ršžœ žœž˜Kšœ žœžœ˜šœ žœ ž˜!Kšœžœ˜Kšœ1žœžœ˜>K˜KšœD˜DKšœH˜HKšœ8žœžœ˜F—Kšžœ˜—Kšžœ˜K˜DK˜Kšœ˜—K˜šŸœžœžœ˜RKšœ žœ#˜4Kšœžœ!˜-Kšœ˜—K˜šŸœžœžœžœ˜@šžœžœž˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšžœ ˜ Kšžœ ˜ Kšœ˜Kšœ˜Kšžœ˜—Kšœ˜—K˜šŸœžœ&žœžœ˜Mšžœžœ ž˜Kšœ˜Kšœ˜Kšœ˜Kšœ%˜%Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ"˜"Kšžœ˜—Kšœ˜—K˜K˜Kšœ7™7K˜šŸœžœžœ žœ˜7Kšœ:˜:Kšœžœžœžœ˜.Kšœžœ'˜1K˜KšœV˜VKšœ,˜,Kšœ˜—K˜šŸœžœžœ žœ˜3š žœ:žœ"žœžœž˜rKšœ˜Kšœ&˜&Kšœ˜Kšœ žœ˜Kšœ˜Kšœ˜Kšœžœ˜Kšœ žœ˜Kšœx˜xKšœ-˜-KšœO˜Ošžœ ž˜KšœžΟc!œ˜,šœ˜Kšœ%˜%Kšžœ˜—šœ˜Kšœ<˜˜>Kšžœ˜—Kšžœžœ˜(—šœ7˜7Kšœ ˜ Kšœ˜Kšœ˜—šœ˜K˜@šžœžœžœž˜#KšœO˜OKšœ˜šœ˜Kšœ˜Kšœ!˜!Kšœ˜—Kšœ˜Kšžœ˜—Kšœ˜šžœžœ˜Kšœžœ'˜/Kšžœ#ž˜)˜˜Jšœ˜KšœG˜G—šžœ˜šžœ˜K˜˜HKšžœžœ˜6—Kšœ˜—šžœ˜K˜Kšœ7žœ˜LKšœ˜——Kšœ˜—K˜šŸœžœ3˜NKšžœ=˜DKšœ@˜@šžœžœžœž˜#Kšœžœ˜šžœžœžœ˜3Kšœ˜Kšœ&˜&Kšž˜K˜—Kšžœ˜—Kšžœ0˜6Kšœ˜—K˜Kš œžœžœžœžœ/˜RKšœžœžœ˜šœžœžœ˜K˜Kšœ+˜+Kš œžœžœžœžœ˜6Kš œžœžœžœžœ˜4Kšœ žœžœ˜Kšœžœ˜Kšœžœžœ˜!—K˜š Ÿ œžœ žœžœ!žœ˜MKšœ:˜:Kšœžœžœ˜Kšœ˜K˜Kšœ&˜&K˜Kšœ žœžœ˜*Kšžœžœžœžœ˜K˜šžœ˜ Kšœ žœ˜šœ žœ˜ Kšœ'™'—K˜—K˜KšœF˜FKšœ%˜%šžœžœžœž˜#šŸœžœ+˜9Kšœ žœ˜%Kšœ˜—Kšœ žœ˜Kšœžœ0˜:Kšœ:˜:Kšžœ žœžœžœ˜Kšœ žœ˜Kšœ%˜%šžœž˜ KšœY˜Y—Kšžœžœžœ!˜3Kšžœ˜—Kšžœ žœžœžœ&˜CKšœ˜—K˜šŸœžœžœq˜“KšœA˜AKšœJ˜JK˜&Kšœ˜—K˜šŸœžœžœžœžœžœžœžœ˜TKšœžœ žœ'˜=Kšœžœ"˜+Kšžœžœžœ˜2Kšœ˜—K˜šŸ œžœžœ žœ˜/Kšžœ žœžœžœ˜'Kšžœ˜Kšžœ ˜Kšœžœ˜Kšœ˜—K˜K™Kšœ˜—…—l Ž