DIRECTORY Commander, CommandTool, Disk, DiskFace, File, FileInternal, IO, RedBlackTree, Rope, VolumeFormat; FileUtil: CEDAR PROGRAM IMPORTS Commander, CommandTool, File, FileInternal, IO, RedBlackTree EXPORTS DiskFace, File = BEGIN VAMStatsStop: BOOL _ FALSE; PrintVAMStats: Commander.CommandProc = { NowPage: FileInternal.EnumeratePagesProc = TRUSTED { attr: VolumeFormat.Attributes = LOOPHOLE[label.attributes]; SELECT TRUE FROM status # Disk.ok => { badStatus _ badStatus + 1; }; attr = header => { IF FileInternal.IsUsed[volume: volume, page: da] THEN headers _ headers + 1 ELSE freeHeaders _ freeHeaders + 1; }; attr = data => { IF FileInternal.IsUsed[volume: volume, page: da] THEN datas _ datas + 1 ELSE freeDatas_ freeDatas + 1; }; attr = freePage => { IF FileInternal.IsUsed[volume: volume, page: da] THEN freeMissings _ freeMissings + 1 ELSE frees _ frees + 1; }; ENDCASE => { IF FileInternal.IsUsed[volume: volume, page: da] THEN others _ others + 1 ELSE freeOthers_ freeOthers + 1; }; exit _ VAMStatsStop; }; argv: CommandTool.ArgumentVector; volume: File.Volume; volumeFree: INT; volumeSize: INT; badStatus: INT _ 0; headers, freeHeaders, datas, freeDatas, freeMissings, frees, others, freeOthers: INT _ 0; argv _ CommandTool.Parse[cmd: cmd ! CommandTool.Failed => { msg _ errorMsg; CONTINUE; }]; IF argv = NIL THEN GOTO Failed; IF argv.argc # 2 THEN GOTO Usage; volume _ File.FindVolumeFromName[argv[1]]; IF volume = NIL THEN GOTO NoVolume; [size: volumeSize, free: volumeFree] _ File.LogicalInfo[volume]; VAMStatsStop _ FALSE; TRUSTED { FileInternal.EnumeratePages[volume: volume, start: [0], skipBadPages: TRUE, work: NowPage]; }; cmd.out.PutF[" Volume %g is %s pages with %g pages free in the VAM\n", IO.rope[argv[1]], IO.int[volumeSize], IO.int[volumeFree] ]; IF badStatus > 0 THEN cmd.out.PutF[" %g pages had read errors\n", IO.int[badStatus]]; cmd.out.PutF[" Headers %g (%g free in VAM), Data %g (%g free in VAM) \n", IO.int[headers], IO.int[freeHeaders], IO.int[datas], IO.int[freeDatas] ]; cmd.out.PutF[" Others %g (%g free in VAM), Free %g (%g not free in VAM) \n", IO.int[others], IO.int[freeOthers], IO.int[frees], IO.int[freeMissings] ]; EXITS Failed => RETURN[$Failure, msg]; Usage => RETURN[$Failure, " Usage: VAMStats volumename\n"]; NoVolume => RETURN[$Failure, " No such volume\n"]; }; StopVAMStats: Commander.CommandProc = { VAMStatsStop _ TRUE; }; ComputeVAMStop: BOOL _ FALSE; ComputeVAMProc: Commander.CommandProc = { NowPage: FileInternal.EnumeratePagesProc = TRUSTED { attr: VolumeFormat.Attributes = LOOPHOLE[label.attributes]; SELECT TRUE FROM status # Disk.ok => { badStatus _ badStatus + 1; }; attr = header => { IF FileInternal.IsUsed[volume: volume, page: da] THEN headers _ headers + 1 ELSE { freeHeaders _ freeHeaders + 1; [] _ FileInternal.SetPageUsed[volume: volume, page: da, inUse: TRUE]; }; }; attr = data => { IF FileInternal.IsUsed[volume: volume, page: da] THEN datas _ datas + 1 ELSE { freeDatas_ freeDatas + 1; [] _ FileInternal.SetPageUsed[volume: volume, page: da, inUse: TRUE]; }; }; attr = freePage => { IF FileInternal.IsUsed[volume: volume, page: da] THEN { freeMissings _ freeMissings + 1; [] _ FileInternal.SetPageUsed[volume: volume, page: da, inUse: FALSE]; } ELSE frees _ frees + 1; }; ENDCASE => { IF FileInternal.IsUsed[volume: volume, page: da] THEN others _ others + 1 ELSE { freeOthers_ freeOthers + 1; [] _ FileInternal.SetPageUsed[volume: volume, page: da, inUse: TRUE]; }; }; exit _ ComputeVAMStop; }; argv: CommandTool.ArgumentVector; volume: File.Volume; volumeFree: INT; volumeSize: INT; badStatus: INT _ 0; headers, freeHeaders, datas, freeDatas, freeMissings, frees, others, freeOthers: INT _ 0; argv _ CommandTool.Parse[cmd: cmd ! CommandTool.Failed => { msg _ errorMsg; CONTINUE; }]; IF argv = NIL THEN GOTO Failed; IF argv.argc # 2 THEN GOTO Usage; volume _ File.FindVolumeFromName[argv[1]]; IF volume = NIL THEN GOTO NoVolume; [size: volumeSize, free: volumeFree] _ File.LogicalInfo[volume]; ComputeVAMStop _ FALSE; TRUSTED { FileInternal.EnumeratePages[volume: volume, start: [0], skipBadPages: TRUE, work: NowPage]; }; cmd.out.PutF[" Volume %g is %s pages with %g pages free in the VAM\n", IO.rope[argv[1]], IO.int[volumeSize], IO.int[volumeFree] ]; IF badStatus > 0 THEN cmd.out.PutF[" %g pages had read errors\n", IO.int[badStatus]]; cmd.out.PutF[" Headers %g (%g free in VAM), Data %g (%g free in VAM) \n", IO.int[headers], IO.int[freeHeaders], IO.int[datas], IO.int[freeDatas] ]; cmd.out.PutF[" Others %g (%g free in VAM), Free %g (%g not free in VAM) \n", IO.int[others], IO.int[freeOthers], IO.int[frees], IO.int[freeMissings] ]; EXITS Failed => RETURN[$Failure, msg]; Usage => RETURN[$Failure, " Usage: ComputeVAM volumename\n"]; NoVolume => RETURN[$Failure, " No such volume\n"]; }; StopComputeVAMProc: Commander.CommandProc = { ComputeVAMStop _ TRUE; }; Handle: TYPE = REF Object; --File.--Object: PUBLIC TYPE = FileInternal.Object; --DiskFace.--RelID: PUBLIC TYPE = VolumeFormat.RelID; DeleteOrphanPagesStop: BOOL _ FALSE; FPRec: TYPE = RECORD [fp: File.FP]; OpenFileRec: TYPE = RECORD [ key: REF FPRec, file: FileInternal.Handle _ NIL ]; getKey: RedBlackTree.GetKey = { myData: REF OpenFileRec = NARROW[data]; RETURN[myData.key]; }; compareKeys: RedBlackTree.Compare = { myData: REF OpenFileRec = NARROW[data]; myKey: REF FPRec = NARROW[k]; KKey: File.FP = NARROW[myData, REF OpenFileRec].key.fp; DKey: File.FP = myKey.fp; KInt: INT = LOOPHOLE[KKey.da]; DInt: INT = LOOPHOLE[DKey.da]; SELECT TRUE FROM KInt < DInt => RETURN [less]; KInt > DInt => RETURN [greater]; KInt = DInt => RETURN [equal]; ENDCASE => ERROR; }; DeleteOrphanPagesProc: Commander.CommandProc = { openFileTable: RedBlackTree.Table _ NIL; { ENABLE UNWIND => { IF openFileTable # NIL THEN RedBlackTree.DestroyTable[openFileTable]; }; NowPage: FileInternal.EnumeratePagesProc = TRUSTED { processPage: PROC [where: FileInternal.WhereLocation] = TRUSTED -- INLINE -- { file: FileInternal.Handle _ NIL; relid: RelID = label.fileID.relID; diskPageFromFile: Disk.PageNumber; IF lastFile # NIL THEN { IF lastFileFP = relid THEN file _ lastFile; }; IF file = NIL THEN { openFP: File.FP _ relid; dataFound: RedBlackTree.UserData; key: REF FPRec _ NEW[FPRec _ [openFP]]; dataFound _ RedBlackTree.Lookup[self: openFileTable, lookupKey: key]; IF dataFound = NIL THEN { insertData: REF OpenFileRec; file _ File.Open[volume: volume, fp: openFP ! File.Error => { SELECT why FROM unknownFile, unknownPage, inconsistent, software => { openFP _ File.nullFP; CONTINUE; }; ENDCASE; }; ]; IF file # NIL THEN { insertData _ NEW [OpenFileRec _ [key, file]]; RedBlackTree.Insert[self: openFileTable, dataToInsert: insertData, insertKey: key]; }; } ELSE { openFileData: REF OpenFileRec = NARROW[dataFound]; file _ openFileData.file; }; lastFileFP _ openFP; lastFile _ file; }; IF file # NIL THEN [diskPage: diskPageFromFile] _ FileInternal.FindRun[ start: IF where = header THEN [-file.logicalRunTable.headerPages+label.filePage] ELSE [label.filePage], nPages: 1, runTable: file.runTable ]; IF (file = NIL) OR (diskPageFromFile # diskPage) THEN { freedPages _ freedPages + 1; FileInternal.FreeRun[logicalRun: [da, 1], volume: volume, verifyLabel: NIL]; }; }; attr: VolumeFormat.Attributes = LOOPHOLE[label.attributes]; pageCounter _ pageCounter + 1; IF pageCounter MOD 1000 = 0 THEN { IF pageCounter MOD 10000 = 0 THEN cmd.out.PutF["(%g) ", IO.int[pageCounter]] ELSE cmd.out.PutRope[". "]; }; SELECT TRUE FROM status # Disk.ok => { badStatus _ badStatus + 1; }; attr = header => { processPage[header]; }; attr = data => { processPage[data]; }; attr = freePage => { }; ENDCASE => { }; exit _ DeleteOrphanPagesStop; }; argv: CommandTool.ArgumentVector; volume: File.Volume; volumeFree: INT; volumeSize: INT; badStatus: INT _ 0; lastFileFP: File.FP ; lastFile: FileInternal.Handle _ NIL; freedPages: INT _ 0; pageCounter: INT _ 0 ; argv _ CommandTool.Parse[cmd: cmd ! CommandTool.Failed => { msg _ errorMsg; CONTINUE; }]; IF argv = NIL THEN GOTO Failed; IF argv.argc # 2 THEN GOTO Usage; volume _ File.FindVolumeFromName[argv[1]]; IF volume = NIL THEN GOTO NoVolume; [size: volumeSize, free: volumeFree] _ File.LogicalInfo[volume]; DeleteOrphanPagesStop _ FALSE; openFileTable _ RedBlackTree.Create[getKey: getKey, compare: compareKeys]; cmd.out.PutRope["Starting disk scan. A dot is printed for every 1000 pages\n"]; TRUSTED { FileInternal.EnumeratePages[volume: volume, start: [0], skipBadPages: TRUE, work: NowPage]; }; cmd.out.PutF["\nFreed %g pages.\n", IO.int[freedPages]]; RedBlackTree.DestroyTable[openFileTable]; EXITS Failed => RETURN[$Failure, msg]; Usage => RETURN[$Failure, " Usage: DeleteOrphanPages volumename\n"]; NoVolume => RETURN[$Failure, " No such volume\n"]; }; }; StopDeleteOrphanPagesProc: Commander.CommandProc = { DeleteOrphanPagesStop _ TRUE; }; CHECKED BEGIN Commander.Register[key: "VAMStats", proc: PrintVAMStats, doc: "Compute and show some accuracy statistics on the VAM for the given volume"]; Commander.Register[key: "StopVAMStats", proc: StopVAMStats, doc: "Stop VAMStats early"]; Commander.Register[key: "ComputeVAM", proc: ComputeVAMProc, doc: "Compute VAM from disk labels for the given volume"]; Commander.Register[key: "StopComputeVAM", proc: StopComputeVAMProc, doc: "Stop Compute VAM from disk labels"]; Commander.Register[key: "DeleteOrphanPages", proc: DeleteOrphanPagesProc, doc: "Mark pages as free that are not in any file, or are not in the file they claim to be in"]; Commander.Register[key: "StopDeleteOrphanPages", proc: StopDeleteOrphanPagesProc, doc: "Stop Delete Orphan Pages"]; END; END. ²FileUtil.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Utilities for the File Package Last Edited by: Bob Hagmann, June 20, 1985 8:58:33 am PDT PROC[status: Disk.Status, da: VolumeFormat.LogicalPage, label: POINTER TO Disk.Label] RETURNS[exit: BOOL _ FALSE]; PROC[status: Disk.Status, da: VolumeFormat.LogicalPage, label: POINTER TO Disk.Label] RETURNS[exit: BOOL _ FALSE]; PROC [data: RedBlackTree.UserData] RETURNS [RedBlackTree.Key]; PROC [k: RedBlackTree.Key, data: RedBlackTree.UserData] RETURNS [Basics.Comparison]; PROC[status: Disk.Status, da: VolumeFormat.LogicalPage, label: POINTER TO Disk.Label, diskPage: INT] RETURNS[exit: BOOL _ FALSE]; Start code Κ $˜codešœ ™ Kšœ Οmœ1™<—K™™K™)—code1šΟk ˜ Jšœ ˜ Jšœ ˜ J˜Jšœ ˜ Lšœ˜Lšœ ˜ Lšžœ˜Lšœ ˜ Lšœ˜Lšœ ˜ —šœ žœž˜Lšžœ-žœ˜DLšžœ˜Lšœž˜L˜Lšœžœžœ˜L˜šΟb œ˜(šŸœ$žœ˜4Lš žœ;žœžœ žœžœžœ™rLšœ žœ˜;šžœžœž˜Jšœ3˜3šœ˜šžœ.˜0Jšžœ˜Jšžœ˜#—Jšœ˜—šœ˜šžœ.˜0Jšžœ˜Jšžœ˜—Jšœ˜—šœ˜šžœ.˜0Jšžœ ˜$Jšžœ˜—Jšœ˜—šžœ˜ šžœ.˜0Jšžœ˜Jšžœ˜ —Jšœ˜——Lšœ˜L˜—Lšœ!˜!Lšœ˜Lšœ žœ˜Lšœ žœ˜Lšœ žœ˜LšœQžœ˜YL˜L˜šœ!˜!Lšœ+žœ˜8—Lšžœžœžœžœ˜Lšžœžœžœ˜!Lšœ*˜*Lšžœ žœžœžœ ˜#Lšœ@˜@Lšœžœ˜šžœ˜ LšœFžœ˜[L˜—šœG˜GLšžœžœžœ˜;—Lšžœžœ.žœ˜VšœJ˜JLšžœžœžœ žœ˜I—šœM˜MLšžœžœžœ žœ˜J—šž˜Lšœ žœ˜ Lšœ žœ.˜=Lšœ žœ"˜4—L˜—L˜L˜L˜šŸ œ˜'Lšœžœ˜L˜—L˜Lšœžœžœ˜L˜šŸœ˜)šŸœ$žœ˜4Lš žœ;žœžœ žœžœžœ™rLšœ žœ˜;šžœžœž˜Jšœ3˜3šœ˜šžœ.˜0Jšžœ˜šžœ˜Jšœ˜Jšœ?žœ˜EJ˜——Jšœ˜—šœ˜šžœ.˜0Jšžœ˜šžœ˜Jšœ˜Jšœ?žœ˜EJ˜——Jšœ˜—šœ˜šžœ.˜0šžœ˜Jšœ ˜ Jšœ?žœ˜FJ˜—Jšžœ˜—Jšœ˜—šžœ˜ šžœ.˜0Jšžœ˜šžœ˜Jšœ˜Jšœ?žœ˜EJ˜——Jšœ˜——Lšœ˜L˜—Lšœ!˜!Lšœ˜Lšœ žœ˜Lšœ žœ˜Lšœ žœ˜LšœQžœ˜YL˜L˜šœ!˜!Lšœ+žœ˜8—Lšžœžœžœžœ˜Lšžœžœžœ˜!Lšœ*˜*Lšžœ žœžœžœ ˜#Lšœ@˜@Lšœžœ˜šžœ˜ LšœFžœ˜[L˜—šœG˜GLšžœžœžœ˜;—Lšžœžœ.žœ˜VšœJ˜JLšžœžœžœ žœ˜I—šœM˜MLšžœžœžœ žœ˜J—šž˜Lšœ žœ˜ Lšœ žœ0˜?Lšœ žœ"˜4—L˜—L˜šŸœ˜-Lšœžœ˜L˜—L˜Lšœžœžœ˜K˜KšΟc œžœžœ˜3K˜Kš  œžœžœ˜5K˜L˜Lšœžœžœ˜$L˜Lšœžœžœ žœ˜#L˜šœ žœžœ˜Lšœžœ˜Lšœž˜L˜—L˜šŸœ˜Lšžœžœ™>Lšœžœžœ˜'Lšžœ ˜L˜—šŸ œ˜%Lšžœ4žœ™TLšœžœžœ˜'Lšœžœ žœ˜Lšœ žœžœ žœ˜7Lšœ žœ ˜Lšœžœžœ ˜Lšœžœžœ ˜šžœžœž˜Lšœžœ˜Lšœžœ ˜ Lšœžœ ˜Lšžœžœ˜—L˜—šŸœ˜0Lšœ$žœ˜(˜šžœžœ˜Lšžœžœžœ*˜EL˜—šŸœ$žœ˜4Lšžœ;žœžœžœžœžœžœ™šŸ œžœ'žœ  œ˜NJšœžœ˜ Jšœ"˜"Jšœ"˜"šžœ žœžœ˜Jšžœžœ˜+J˜—šžœžœžœ˜Jšœ žœ ˜Jšœ!˜!Jšœžœ žœ˜'JšœE˜Ešžœ žœžœ˜Jšœ žœ ˜šœ=˜=šžœž˜šœ5˜5Jšœ˜Jšžœ˜ J˜—Jšžœ˜—Jšœ˜—Jšœ˜šžœžœžœ˜Jšœ žœ˜-JšœS˜SJ˜—J˜—šœžœ˜Jšœžœžœ ˜2Jšœ˜J˜—Jšœ˜Jšœ˜J˜—šžœžœžœ6˜HKšœžœžœ4žœ˜gKšœ ˜ Kšœ˜—Kšœ˜šžœ žœžœžœ˜7J˜JšœGžœ˜LJ˜—L˜—Lšœ žœ˜;L˜šžœ žœ žœ˜"Lšžœ žœ žœžœ˜LLšœžœ˜L˜—L˜šžœžœž˜Jšœ3˜3šœ˜Jšœ˜Jšœ˜—šœ˜Jšœ˜Jšœ˜—šœ˜Jšœ˜—šžœ˜ Jšœ˜——Lšœ˜L˜—Lšœ!˜!Lšœ˜Lšœ žœ˜Lšœ žœ˜Lšœ žœ˜Lšœžœ˜Lšœ žœ˜$Lšœ žœ˜Lšœ žœ˜L˜šœ!˜!Lšœ+žœ˜8—Lšžœžœžœžœ˜Lšžœžœžœ˜!Lšœ*˜*Lšžœ žœžœžœ ˜#Lšœ@˜@Lšœžœ˜LšœJ˜JL˜Pšžœ˜ LšœFžœ˜[L˜—Lšœ8˜8Lšœ)˜)šž˜Lšœ žœ˜ Lšœ žœ7˜FLšœ žœ"˜4—L˜—L˜—L˜šŸœ˜4Lšœžœ˜L˜—L˜L˜L˜L˜L™ šžœž˜ Lšœ‹˜‹LšœX˜XLšœv˜vLšœn˜nLšœͺ˜ͺLšœs˜sL˜Lšžœ˜—Lšžœ˜L™—L˜J˜—…—%¨4~