DIRECTORY BasicTime USING [GMT, Now, Update], Booting USING [Deregister, CheckpointProc, RegisterProcs, RollbackProc], BTree USING [Entry, Error, New, Open, SalvageEntries, SetState, SetUpdateInProgress, Tree, UpdateInProgress], BTreeVM USING [FreeBuffers, Handle, Open, ReferencePage, ReleasePage], File USING [Create, Delete, Error, FindVolumeFromID, FindVolumeFromName, FP, GetRoot, GetVolumeName, GetVolumePages, Handle, Info, NextFile, nullFP, Open, PageCount, PageNumber, Reason, SetFreeboard, SetRoot, SetSize, SystemVolume, Volume, VolumeID], FileExtrasForFS USING [CreateVMBacking], FS USING [Error, ErrorDesc, WordsForPages], FSBackdoor USING [Entry, EntryPtr, EntryType, MakeFName, TextFromTextRep, TextRep, ProduceError, Version], FSDir USING [Compare, EntrySize, UpdateAttachedEntry, UpdateCachedEntry, UpdateLocalEntry], FSFileOps USING [GetNameBodyAndVersion, GetProps, InitializePropertyStorage, RegisterVolumeFlusher, VolumeDesc, VolumeDescObject], FSName USING [IsLocal], FSReport USING [FileError, UnknownVolume], Rope USING [Cat, Equal, Fetch, Length, ROPE, Text]; FSFileOpsImpl: CEDAR MONITOR IMPORTS BasicTime, Booting, BTree, BTreeVM, File, FileExtrasForFS, FS, FSBackdoor, FSDir, FSFileOps, FSName, FSReport, Rope EXPORTS FSBackdoor, FSFileOps = { ScavengeDirectoryAndCache: PUBLIC PROC [volName: Rope.ROPE] = { Activate: ENTRY PROC = { ENABLE UNWIND => NULL; ActivateVolume[vDesc]; }; errorDesc: FS.ErrorDesc; vDesc: FSFileOps.VolumeDesc; Booting.RegisterProcs[c: RejectCheckpoint]; -- mutual exclusion with checkpoints vDesc _ InnerGetVolumeDesc[ volName, TRUE -- suspension occurred only if no FS.Error ! FS.Error => {errorDesc _ error; CONTINUE} ]; IF errorDesc.group = ok THEN { Scavenge[ vDesc.vol ! FS.Error => {errorDesc _ error; CONTINUE} ]; Activate[ ! FS.Error => {IF errorDesc.group = ok THEN errorDesc _ error; CONTINUE} ]; }; Booting.Deregister[c: RejectCheckpoint]; IF errorDesc.group # ok THEN ERROR FS.Error[errorDesc]; }; SetFreeboard: PUBLIC PROC [freeboard: INT] = { vDesc: FSFileOps.VolumeDesc = GetVolumeDesc[NIL]; IF vDesc = NIL THEN FSReport.UnknownVolume[NIL]; File.SetFreeboard[ vDesc.vol, freeboard ! File.Error => FSReport.FileError[why] ]; }; VolumePages: PUBLIC PROC [volName: Rope.ROPE _ NIL] RETURNS [size, free, freeboard: INT] = { vDesc: FSFileOps.VolumeDesc = GetVolumeDesc[volName]; IF vDesc = NIL THEN FSReport.UnknownVolume[NIL]; [size, free, freeboard] _ File.GetVolumePages[ vDesc.vol ! File.Error => FSReport.FileError[why] ]; }; FNameFromHandle: PUBLIC PROC [file: File.Handle] RETURNS [Rope.ROPE] = { nameBody, prefix: Rope.ROPE; version: FSBackdoor.Version; { ENABLE File.Error => FSReport.FileError[why]; volume: File.Volume = File.Info[file].volume; prefix _ IF volume = File.SystemVolume[] THEN NIL ELSE Rope.Cat["[]<", File.GetVolumeName[volume], ">"]; }; [nameBody, version] _ FSFileOps.GetNameBodyAndVersion[file]; RETURN [ FSBackdoor.MakeFName[nameBody, version, prefix] ]; }; CloseVolume: PUBLIC ENTRY PROC [v: File.Volume] = { ENABLE UNWIND => NULL; prev, vDesc: FSFileOps.VolumeDesc _ NIL; FOR vDesc _ volumeDescList, vDesc.next UNTIL vDesc = NIL DO IF vDesc.vol = v THEN { IF prev = NIL THEN volumeDescList _ vDesc.next ELSE prev.next _ vDesc.next; IF vDesc = svDesc THEN svDesc _ NIL; BTree.SetState[vDesc.tree, closed]; IF vDesc.treeVM # NIL THEN { BTreeVM.FreeBuffers[vDesc.treeVM]; vDesc.treeVM _ NIL; }; EXIT; }; prev _ vDesc; ENDLOOP; }; GetVolumeDesc: PUBLIC PROC [vName: Rope.ROPE] RETURNS [vDesc: FSFileOps.VolumeDesc] = { errorDesc: FS.ErrorDesc; vDesc _ InnerGetVolumeDesc[vName, FALSE ! FS.Error => {errorDesc _ error; CONTINUE} ]; IF errorDesc.group # ok THEN ERROR FS.Error[errorDesc]; }; LPCreatedTime: PUBLIC PROC [vol: File.Volume, fp: File.FP] RETURNS [BasicTime.GMT] = { handle: File.Handle; handle _ File.Open[ vol, fp ! File.Error => FSReport.FileError[why] ]; RETURN [ FSFileOps.GetProps[handle].created ]; }; OpenFile: PUBLIC PROC [vol: File.Volume, fp: File.FP] RETURNS [h: File.Handle] = { RETURN [ File.Open[ vol, fp ! File.Error => FSReport.FileError[why] ] ]; }; CreateFile: PUBLIC PROC [vol: File.Volume, pages: INT, VMBackingFile: BOOL _ FALSE] RETURNS [fp: File.FP, h: File.Handle] = { ENABLE File.Error => FSReport.FileError[why]; IF VMBackingFile THEN h _ FileExtrasForFS.CreateVMBacking[vol, pages, FSFileOps.InitializePropertyStorage] ELSE h _ File.Create[vol, pages, FSFileOps.InitializePropertyStorage]; fp _ File.Info[h].fp; }; DeleteFile: PUBLIC PROC [h: File.Handle] = { File.Delete[ h ! File.Error => FSReport.FileError[why] ]; }; SetFilePages: PUBLIC PROC [h: File.Handle, pages: INT] = { File.SetSize[h, pages ! File.Error => FSReport.FileError[why] ]; }; GetFileInfo: PUBLIC PROC [h: File.Handle] RETURNS [pages: INT, fp: File.FP] = { [fp: fp, size: pages] _ File.Info[h ! File.Error => FSReport.FileError[why] ]; }; waitForRollback: BOOL _ FALSE; rollback: CONDITION; svDesc, volumeDescList: FSFileOps.VolumeDesc _ NIL; InnerGetVolumeDesc: ENTRY PROC [vName: Rope.ROPE, suspendVolume: BOOL] RETURNS [FSFileOps.VolumeDesc] = { ENABLE UNWIND => NULL; vDesc: FSFileOps.VolumeDesc; vol: File.Volume _ NIL; WHILE waitForRollback DO WAIT rollback; ENDLOOP; IF Rope.Length[vName] = 0 AND svDesc # NIL THEN { IF suspendVolume THEN SuspendVolume[svDesc]; RETURN [svDesc]; }; SELECT TRUE FROM Rope.Length[vName] = 0 => { -- system volume vol _ File.SystemVolume[]; IF vol = NIL THEN { -- no system volume is available IF suspendVolume THEN FSReport.UnknownVolume[NIL] ELSE RETURN [NIL]; }; vName _ File.GetVolumeName[vol]; }; (Rope.Fetch[vName, 0] = '#) => { -- volume number vol _ File.FindVolumeFromID[ MakeVolumeID[vName] ]; IF vol = NIL THEN FSReport.UnknownVolume[vName]; vName _ File.GetVolumeName[vol]; }; ENDCASE; FOR vDesc _ volumeDescList, vDesc.next UNTIL vDesc = NIL DO IF Rope.Equal[vName, vDesc.vName, FALSE] THEN { IF suspendVolume THEN SuspendVolume[vDesc]; RETURN [vDesc]; }; ENDLOOP; IF vol = NIL THEN { vol _ File.FindVolumeFromName[vName]; IF vol = NIL THEN FSReport.UnknownVolume[vName]; }; vDesc _ NEW[ FSFileOps.VolumeDescObject _ [ NIL, vName, NIL, vol, NIL, NIL ] ]; vDesc.tree _ AllocateBTree[]; IF NOT suspendVolume THEN SetUpBTree[vDesc]; IF vol = File.SystemVolume[] THEN { FSFileOps.RegisterVolumeFlusher[vDesc]; svDesc _ vDesc; } ELSE vDesc.prefix _ Rope.Cat["[]<", vName, ">"]; vDesc.next _ volumeDescList; volumeDescList _ vDesc; RETURN [vDesc]; }; bufferSize: CARDINAL = 4; buffers: CARDINAL = 32; basePage: File.PageNumber = [0]; -- first page of the directory/cache btree initialPages: File.PageCount = basePage + buffers*bufferSize; AllocateBTree: PROC RETURNS [BTree.Tree] = { RETURN [ BTree.New [ repPrim: [compare: FSDir.Compare, entrySize: FSDir.EntrySize], storPrim: [referencePage: BTreeVM.ReferencePage, releasePage: BTreeVM.ReleasePage], minEntrySize: SIZE[FSBackdoor.Entry.local] + SIZE[FSBackdoor.TextRep[1]], -- "a" initialState: suspended ] ]; }; SetUpBTree: PROC [vDesc: FSFileOps.VolumeDesc, scavenge: BOOL _ FALSE] = { newFile: BOOL _ FALSE; treeFile: File.Handle; treeFP: File.FP; treeVM: BTreeVM.Handle; treeFP _ File.GetRoot[vDesc.vol, client ! File.Error => IF why = nonCedarVolume THEN FSBackdoor.ProduceError[nonCedarVolume, Rope.Cat["The local volume \"", vDesc.vName, "\" is not formatted for Cedar."]] ELSE FSReport.FileError[why] ].fp; IF treeFP = File.nullFP THEN { treeFile _ File.Create[vDesc.vol, initialPages, NIL ! File.Error => FSReport.FileError[why] ]; newFile _ TRUE; } ELSE treeFile _ OpenFile[vDesc.vol, treeFP]; treeVM _ BTreeVM.Open[ file: treeFile, filePagesPerPage: bufferSize, cacheSize: buffers, base: basePage ]; { ENABLE UNWIND => { BTreeVM.FreeBuffers[treeVM]; IF newFile THEN DeleteFile[treeFile ! FS.Error => CONTINUE]; }; OpenBTree[vDesc.tree, treeVM, newFile, scavenge]; IF newFile THEN File.SetRoot[client, treeFile ! File.Error => FSReport.FileError[why] ]; }; vDesc.treeVM _ treeVM; }; OpenBTree: PROC [tree: BTree.Tree, treeVM: BTreeVM.Handle, new, scavenge: BOOL] = { BTree.Open[ tree: tree, storage: treeVM, pageSize: FS.WordsForPages[bufferSize], initialize: new, maintainRecomputableState: TRUE ! BTree.UpdateInProgress => IF scavenge THEN RESUME ELSE FSBackdoor.ProduceError[badBTree, "Update discovered to be in progress when opening the directory/cache BTree."]; BTree.Error => FSBackdoor.ProduceError[badBTree, "Error from the BTree package when opening the directory/cache BTree."]; File.Error => FSReport.FileError[why]; ]; }; MakeVolumeID: PROC [vName: Rope.ROPE] RETURNS [id: File.VolumeID] = { FSBackdoor.ProduceError[notImplemented, "Can't handle hex volume ID's yet."]; }; SuspendVolume: INTERNAL PROC [vDesc: FSFileOps.VolumeDesc] = { IF vDesc = svDesc THEN FSFileOps.RegisterVolumeFlusher[NIL]; BTree.SetState[vDesc.tree, suspended]; -- may wait forever IF vDesc.treeVM # NIL THEN { BTreeVM.FreeBuffers[vDesc.treeVM]; vDesc.treeVM _ NIL; }; }; ActivateVolume: INTERNAL PROC [vDesc: FSFileOps.VolumeDesc] = { SetUpBTree[vDesc ! FS.Error => DestroyVolumeDesc[vDesc] ]; IF vDesc = svDesc THEN FSFileOps.RegisterVolumeFlusher[svDesc]; }; DestroyVolumeDesc: INTERNAL PROC [victim: FSFileOps.VolumeDesc] = { prev: FSFileOps.VolumeDesc _ NIL; FOR vDesc: FSFileOps.VolumeDesc _ volumeDescList, vDesc.next UNTIL vDesc = NIL DO IF victim = vDesc THEN EXIT; prev _ vDesc; REPEAT FINISHED => ERROR; ENDLOOP; IF victim = svDesc THEN { FSFileOps.RegisterVolumeFlusher[NIL]; svDesc _ NIL; }; BTree.SetState[victim.tree, closed]; IF prev = NIL THEN volumeDescList _ victim.next ELSE prev.next _ victim.next; }; RejectCheckpoint: Booting.CheckpointProc = { rejection _ "FS scavenge is in progress."; }; FSCheckpointProc: ENTRY Booting.CheckpointProc = { ENABLE UNWIND => NULL; waitForRollback _ TRUE; FOR vDesc: FSFileOps.VolumeDesc _ volumeDescList, vDesc.next UNTIL vDesc = NIL DO SuspendVolume[vDesc]; ENDLOOP; }; FSRollbackProc: ENTRY Booting.RollbackProc = { ENABLE UNWIND => NULL; FOR vDesc: FSFileOps.VolumeDesc _ volumeDescList, vDesc.next UNTIL vDesc = NIL DO ActivateVolume[vDesc ! FS.Error => CONTINUE ]; ENDLOOP; waitForRollback _ FALSE; BROADCAST rollback; }; AttachedEntry: TYPE = RECORD [ next: REF AttachedEntry, nameBody: Rope.Text, version: FSBackdoor.Version, keep: CARDINAL, created: BasicTime.GMT, attachedTo: Rope.Text ]; Scavenge: PROC [vol: File.Volume] = TRUSTED { SaveAttachments: UNSAFE PROC [entry: BTree.Entry] RETURNS [continue: BOOL] = UNCHECKED { entryPtr: FSBackdoor.EntryPtr = LOOPHOLE[entry]; continue _ TRUE; WITH e: entryPtr^ SELECT FROM attached => attHead _ NEW [ AttachedEntry _ [ attHead, FSBackdoor.TextFromTextRep[@entryPtr[e.nameBody]], e.version, e.keep, e.created, FSBackdoor.TextFromTextRep[@entryPtr[e.attachedTo]] ] ]; ENDCASE; }; fakeUsedTime: BasicTime.GMT = BasicTime.Update[BasicTime.Now[], -60*20]; attHead: REF AttachedEntry _ NIL; vDesc: FSFileOps.VolumeDesc = NEW [FSFileOps.VolumeDescObject]; fp: File.FP _ File.nullFP; vDesc.vol _ vol; vDesc.tree _ AllocateBTree[]; SetUpBTree[vDesc, TRUE]; [] _ BTree.SalvageEntries[vDesc.tree, SaveAttachments]; OpenBTree[vDesc.tree, vDesc.treeVM, TRUE, TRUE]; -- reinitialize the BTree BTree.SetUpdateInProgress[vDesc.tree, TRUE]; { ENABLE UNWIND => { BTree.SetUpdateInProgress[vDesc.tree, FALSE]; BTreeVM.FreeBuffers[vDesc.treeVM] }; FOR attHead _ attHead, attHead.next UNTIL attHead = NIL DO IF NOT FSName.IsLocal[attHead.nameBody] THEN LOOP; FSDir.UpdateAttachedEntry[vDesc, attHead.nameBody, attHead.version, attHead.keep, attHead.created, attHead.attachedTo, insertOrReplace]; ENDLOOP; UNTIL (fp _ File.NextFile[vDesc.vol, fp]) = File.nullFP DO nameBody: Rope.Text; version: FSBackdoor.Version; h: File.Handle = OpenFile[vDesc.vol, fp ! FS.Error => IF error.code = $badFP THEN LOOP ]; [nameBody, version] _ FSFileOps.GetNameBodyAndVersion[h ! FS.Error => IF error.code = $invalidPropertyPage THEN LOOP ]; IF Rope.Length[nameBody] = 0 THEN DeleteFile[h] -- creation of this file was not completed ELSE { exists: BOOL _ FALSE; IF FSName.IsLocal[nameBody] THEN FSDir.UpdateLocalEntry[ vDesc, nameBody, version, FSFileOps.GetProps[h].keep, fp, insert ! BTree.Error => IF reason = wrongUpdateType THEN {exists _ TRUE; CONTINUE} ] ELSE FSDir.UpdateCachedEntry[ vDesc, nameBody, version, fakeUsedTime, fp, insert ! BTree.Error => IF reason = wrongUpdateType THEN {exists _ TRUE; CONTINUE} ]; IF exists THEN DeleteFile[h]; }; ENDLOOP; }; BTree.SetUpdateInProgress[vDesc.tree, FALSE]; BTreeVM.FreeBuffers[vDesc.treeVM]; }; Booting.RegisterProcs[c: FSCheckpointProc, r: FSRollbackProc]; }. :FSFileOpsImpl.mesa Copyright c 1984 by Xerox Corporation. All rights reserved. Schroeder, November 30, 1983 9:07 am Levin, September 22, 1983 1:21 pm Bob Hagmann, May 10, 1984 10:14:41 am PDT Russ Atkinson, November 7, 1984 11:07:28 am PST Exported to FSBackdoor Exported to FSFileOps Internal procedures can't make new ones now, so don't even look want system volume and already have descriptor found VolumeDesc in list new tree file, but can't have validation stamp in property page no SIGNALs or ERRORs turn off volume flusher if any; (RRA) must do this before suspending the BTree assumes that tree already is suspended special steps for the system volume; (RRA) must close this before closing the BTree a little earlier so used times always will be updated after scavenge put file in directory/cache Start Code Κα– "Cedar" style˜šœ™Jšœ Οmœ1™˜>J˜šŸ œžœžœ˜,šžœ˜J˜>JšœS˜SJšœžœžœ ˜PJ˜J˜—Jšœ˜—J˜šŸ œžœ)žœžœ˜JJšœ žœžœ˜Jšœ˜Jšœ žœ˜Jšœ˜šœ'˜'šœ˜šžœ˜Kšžœx˜|Jšžœ˜——Jšœ˜—šžœ˜šžœ˜Jšœ?™?šœ0ž˜3Jšœ*˜*—Jšœ žœ˜Jšœ˜—Jšžœ(˜,—šœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜—šœ˜šžœžœ˜Jšœ˜Jšžœ žœžœ žœ˜Jšœ™šžœž˜JšœO™OJšœ žœ˜%—Jšœ' ˜:šžœžœžœ˜Jšœ"˜"Jšœžœ˜Jšœ˜—Jšœ˜—J˜šŸœžœžœ"˜?Jšœžœ%˜:Jšžœžœ)˜?Jšœ˜—J˜šŸœžœžœ#˜CJšœ&™&Jšœžœ˜!šžœ:žœ žœž˜QJšžœžœžœ˜Jšœ ˜ Jšžœžœžœ˜Jšžœ˜—šžœžœ˜JšœT™TJšœ žœ˜%Jšœ žœ˜ Jšœ˜—Jšœ$˜$šžœž˜ Jšžœ˜!Jšžœ˜—Jšœ˜—J˜šœ,˜,Jšœ*˜*Jšœ˜—J˜šœžœ˜2Jšžœžœžœ˜Jšœžœ˜šžœ:žœ žœž˜QJšœ˜Jšžœ˜—Jšœ˜—J˜šΟbœžœ˜.Jšžœžœžœ˜šžœ:žœ žœž˜QJšœžœ žœ˜.Jšžœ˜—Jšœžœ˜Jšž œ ˜Jšœ˜—J˜šœžœžœ˜Jšœžœ˜Jšœ˜J˜Jšœžœ˜Jšœžœ˜J˜J˜—J˜šŸœžœžœ˜-J˜š Ÿœžœžœžœ žœž œ˜XJšœ žœ˜0Jšœ žœ˜šžœžœž˜šœžœ˜+Jšœ”˜”—Jšžœ˜—Jšœ˜—šœžœ-˜HJšœD™D—Jšœ žœžœ˜!Jšœžœ˜?Jšœ žœ˜J˜Jšœ˜Jšœžœ˜Jšœ7˜7Jšœ$žœžœ ˜JJšœ&žœ˜,šœ˜šžœžœ˜Jšœ&žœ˜-Jšœ$˜$—šžœ!žœ žœž˜:Kšžœžœ"žœžœ˜2Kšœˆ˜ˆKšžœ˜—šžœ3ž˜:K˜K˜šœ'˜'Kš œžœ žœžœžœ˜1—˜7Kš œžœ žœ#žœžœ˜?—šžœ˜Kšžœ *˜=šžœ˜Kšœ™Kšœžœžœ˜šžœ˜šžœ˜Kšœ@˜@Kš œžœžœ žœžœ˜KKšœ˜—šžœ˜Kšœ2˜2Kš œžœžœ žœžœ˜KKšœ˜——Kšžœžœ˜Kšœ˜——Kšžœ˜—Jšœ˜—Jšœ&žœ˜-Jšœ"˜"Jšœ˜J˜——™ J˜Jšœ>˜>J˜—Jšœ˜—…—0ξD