<> <> DIRECTORY CachedSpace USING [Desc], Environment USING [wordsPerPage], File USING [ Capability, Delete, GetAttributes, GetSize, ID, nullID, PageCount, Permissions, Unknown], Hierarchy USING [GetDescriptor], Inline USING [LowHalf], IO USING [int, Handle, NewLine, PutChar, PutF, PutRope], KernelFile USING [GetRootFile], PilotFileTypes USING [tTempFileList], Rope USING [ROPE], Space USING [ CopyIn, Create, Delete, GetAttributes, Handle, LongPointer, Map, nullHandle, PageCount, virtualMemory], SpaceImplInternal USING [EnterSpace], UserExec USING [CommandProc, Confirm, GetExecHandle, GetStreams, RegisterCommand], Volume USING [systemID]; FlushUnneededTempFiles: PROGRAM IMPORTS File, Hierarchy, Inline, IO, KernelFile, Space, SpaceImplInternal, UserExec, Volume SHARES File = BEGIN FlushTempFiles: UserExec.CommandProc = TRUSTED { out: IO.Handle; tempFiles, recoverableFiles, tempPages, recoverablePages: INT _ 0; CheckSpace: PROC [space: Space.Handle] = { IF Space.GetAttributes[space].mapped THEN { CheckIfThisFile: PROC [file: File.Capability] RETURNS [stop, zap: BOOL _ FALSE] = { CheckBackingFile: PROC = { desc: CachedSpace.Desc; validSpace, validSwapUnit: BOOL; [validSpace, validSwapUnit] _ Hierarchy.GetDescriptor[@desc, LOOPHOLE[space]]; IF ~(validSpace OR validSwapUnit) THEN RETURN; IF desc.window.file.fID = file.fID THEN stop _ zap _ TRUE; }; SpaceImplInternal.EnterSpace[CheckBackingFile]; }; EnumerateTempFiles[CheckIfThisFile]; } ELSE EnumerateChildren[space, CheckSpace]; }; GetBeforeStats: PROC [file: File.Capability] RETURNS [stop, zap: BOOL _ FALSE] = { size: File.PageCount = File.GetSize[file ! File.Unknown => GO TO notInteresting]; IF File.GetAttributes[file].temporary THEN { tempFiles _ tempFiles + 1; tempPages _ tempPages + size; } ELSE GO TO notInteresting; EXITS notInteresting => zap _ TRUE; }; GetAfterStats: PROC [file: File.Capability] RETURNS [stop, zap: BOOL _ FALSE] = { size: File.PageCount = File.GetSize[file ! File.Unknown => GO TO notAFile]; recoverableFiles _ recoverableFiles + 1; recoverablePages _ recoverablePages + size; EXITS notAFile => NULL; }; DoOneFile: PROC [file: File.Capability] RETURNS [stop, zap: BOOL _ FALSE] = { File.Delete[file ! File.Unknown => GO TO notAFile]; out.PutChar['#]; EXITS notAFile => NULL; }; [out: out] _ UserExec.GetStreams[exec]; out.PutRope["Enumerating temp files..."]; EnumerateTempFiles[GetBeforeStats]; out.PutRope["enumerating spaces..."]; EnumerateChildren[Space.virtualMemory, CheckSpace]; out.PutRope["done\N"]; EnumerateTempFiles[GetAfterStats]; out.PutF[ "There are %g temporary files comprising %g total pages.\NOf these, %g can be deleted to recover %g pages.\N", IO.int[tempFiles], IO.int[tempPages], IO.int[recoverableFiles], IO.int[recoverablePages] ]; IF recoverableFiles > 0 AND UserExec.Confirm[msg: "Shall I delete them", exec: exec] THEN { out.PutRope["Deleting..."]; EnumerateTempFiles[DoOneFile]; out.NewLine[]; }; Cleanup[]; }; idsPerPage: NAT = Environment.wordsPerPage/SIZE[File.ID]; TempsPage: TYPE = MACHINE DEPENDENT RECORD [ ids: ARRAY [0..idsPerPage) OF File.ID, fill: ARRAY [0..Environment.wordsPerPage-idsPerPage*SIZE[File.ID]) OF WORD ]; TempsFile: TYPE = RECORD [pages: SEQUENCE COMPUTED Space.PageCount OF TempsPage]; tempFile: File.Capability; tempFilePages: File.PageCount; tempsSpace: Space.Handle; temps: LONG POINTER TO TempsFile _ NIL; EnumerateTempFiles: PROC [proc: PROC [File.Capability] RETURNS [stop, zap: BOOL]] = { IF temps = NIL THEN { tempFile _ KernelFile.GetRootFile[PilotFileTypes.tTempFileList, Volume.systemID]; tempFilePages _ File.GetSize[tempFile]; tempsSpace _ Space.Create[size: Inline.LowHalf[tempFilePages], parent: Space.virtualMemory]; temps _ Space.LongPointer[tempsSpace]; <> <> Space.Map[tempsSpace]; Space.CopyIn[tempsSpace, [tempFile, 0]]; }; FOR page: Space.PageCount IN [0..tempFilePages) DO tempPage: LONG POINTER TO TempsPage = @temps.pages[page]; FOR i: [0..idsPerPage) IN [0..idsPerPage) DO id: File.ID = tempPage.ids[i]; IF id ~= File.nullID THEN { stop, zap: BOOL; [stop, zap] _ proc[[id, LAST[File.Permissions]]]; IF zap THEN tempPage.ids[i] _ File.nullID; IF stop THEN EXIT; }; ENDLOOP; ENDLOOP; }; Cleanup: PROC = { Space.Delete[tempsSpace]; temps _ NIL; }; EnumerateChildren: PROC [space: Space.Handle, proc: PROC [Space.Handle]] = { FOR child: Space.Handle _ Space.GetAttributes[space].lowestChild, Space.GetAttributes[child].nextSibling UNTIL child = Space.nullHandle DO proc[child]; ENDLOOP; }; UserExec.RegisterCommand[ name: "FlushUnneededTempFiles", proc: FlushTempFiles, briefDoc: "Eliminates unnecessary temporary files from the local disk." ]; [] _ FlushTempFiles[event: NIL, exec: UserExec.GetExecHandle[]]; END.