DIRECTORY BasicTime USING [GMT], File USING [FP, Handle, Volume], FS USING [ComponentPositions, InfoProc, Lock, OpenFile], Rope USING [ROPE, Text]; FSBackdoor: CEDAR DEFINITIONS = BEGIN ROPE: TYPE = Rope.ROPE; FileProcs: TYPE; CreateFileProcs: PROC [ GetClass: PROC [clientFile: REF] RETURNS [ATOM] _ NIL, SameFile: PROC [clientFile1, clientFile2: REF] RETURNS [BOOLEAN] _ NIL, GetName: PROC [clientFile: REF] RETURNS [fullFName, attachedTo: Rope.ROPE] _ NIL, GetInfo: PROC [clientFile: REF] RETURNS [keep: CARDINAL, pages, bytes: INT, created: BasicTime.GMT, lock: FS.Lock] _ NIL, SetPageCount: PROC [clientFile: REF, pages: INT] _ NIL, SetByteCountAndCreatedTime: PROC [clientFile: REF, bytes: INT, created: BasicTime.GMT] _ NIL, Read: UNSAFE PROC [clientFile: REF, from, nPages: INT, to: LONG POINTER] _ NIL, Write: PROC [clientFile: REF, to: INT, nPages: INT, from: LONG POINTER] _ NIL, Close: PROC [clientFile: REF] _ NIL ] RETURNS [REF FileProcs]; CreateProcsOpenFile: PROC [clientFile: REF, fileProcs: REF FileProcs] RETURNS [FS.OpenFile]; GetClientFileAndProcs: PROC [file: FS.OpenFile] RETURNS [clientFile: REF, fileProcs: REF FileProcs]; ErrorCode: TYPE = {ok -- used internally-- , inconsistent, software, badFP, wentOffline, hardware, volumeFull, fragmented, noMoreVersions, serverInaccessible, connectionRejected, connectionTimedOut, badCredentials, accessDenied, quotaExceeded, invalidPropertyPage, badBTree, lockConflict, fileBusy, noCache, wrongLock, globalWriteLock, zeroKeep, badByteCount, unknownPage, invalidOpenFile, notImplemented, nonCedarVolume, unknownServer, unknownVolume, unknownFile, unknownCreatedTime, illegalName, patternNotAllowed, versionSpecified, globalCreation, badWorkingDir, noKeeps, cantUpdateTiogaFile}; ProduceError: PROC [code: ErrorCode, explanation: Rope.ROPE]; SetFreeboard: PROC [freeboard: INT]; VolumePages: PROC [volName: ROPE _ NIL] RETURNS [size, free, freeboard: INT]; InfoProc: TYPE = PROC [ fullGName: ROPE, created: BasicTime.GMT, bytes: INT, keep: CARDINAL ] RETURNS [continue: BOOLEAN]; EnumerateCacheForInfo: PROC [proc: InfoProc, volName, pattern: ROPE _ NIL]; NameProc: TYPE = PROC [fullGName: ROPE] RETURNS [continue: BOOLEAN]; EnumerateCacheForNames: PROC [proc: NameProc, volName, pattern: ROPE _ NIL]; Flush: PROC [fullGName: ROPE, volName: ROPE _ NIL]; Version: TYPE = RECORD [CARDINAL]; noVersion: Version = [LAST[CARDINAL]]; highestVersion: Version = noVersion; lowestVersion: Version = [0]; EntryType: TYPE = {local, attached, cached, notFound}; -- notFound is for internal use only EntryPtr: TYPE = LONG BASE POINTER TO Entry; TextRP: TYPE = EntryPtr RELATIVE POINTER TO TextRep; TextRep: TYPE = MACHINE DEPENDENT RECORD [PACKED SEQUENCE length: CARDINAL OF CHAR]; Entry: TYPE = MACHINE DEPENDENT RECORD [ size(0): CARDINAL, -- size in words of entire entry, including TextRep's at end version(1): Version, -- version part of FName nameBody(2): TextRP, -- FName w/o version rest(3): SELECT type(3): EntryType FROM local => [ keep(4): CARDINAL, fp(5): File.FP ], attached => [ keep(4): CARDINAL, created(5): BasicTime.GMT, attachedTo(5+SIZE[BasicTime.GMT]): TextRP -- includes version part ], cached => [ used(4): BasicTime.GMT, fp(4+SIZE[BasicTime.GMT]): File.FP ] ENDCASE -- here follows the TextRep for nameBody and possibly for attachedTo ]; Enumerate: PROC [volName: ROPE, nameBodyPattern: Rope.Text, localOnly, allVersions: BOOLEAN, version: Version, matchProc: UNSAFE PROC [entry: EntryPtr] RETURNS [accept, stop: BOOLEAN], acceptProc: PROC RETURNS [stop: BOOLEAN] ]; TextFromTextRep: PROCEDURE [nameBody: LONG POINTER TO TextRep] RETURNS [Rope.Text]; MakeFName: PROCEDURE [nameBody: ROPE, version: Version _ noVersion, prefix: ROPE _ NIL] RETURNS [ROPE]; ScavengeDirectoryAndCache: PROC [ volName: ROPE _ NIL ]; CloseVolume: PROC [v: File.Volume]; GetFileHandle: PROC [file: FS.OpenFile] RETURNS [File.Handle]; CreateVMBacking: PROC [name: ROPE, setPages: BOOLEAN _ TRUE, pages: INT _ 0, setKeep: BOOLEAN _ FALSE, keep: CARDINAL _ 1, wDir: ROPE _ NIL] RETURNS [FS.OpenFile]; FNameFromHandle: PROC [file: File.Handle] RETURNS [ROPE]; RemoteOp: TYPE = {startRetrieving, endRetrieving, startStoring, endStoring, startDeleting, endDeleting, startRenaming, endRenaming, startFlushing, endFlushing}; RemoteEvent: TYPE = RECORD [ op: RemoteOp, -- remote operation that has occurred fName: Rope.ROPE, -- full GName of the remote file operated upon chain: REF RemoteEvent -- used internally to chain events together ]; NextRemoteEvent: PROC [REF READONLY RemoteEvent _ NIL] RETURNS [REF READONLY RemoteEvent]; CreateOp: TYPE = {writeClose, renameTo, copyTo}; CreateEvent: TYPE = RECORD [ op: CreateOp, -- creation operation that has occurred fName: Rope.ROPE, -- full LName of the local file that has been created chain: REF CreateEvent -- used internally to chain events together ]; NextCreateEvent: PROC [REF READONLY CreateEvent _ NIL] RETURNS [REF READONLY CreateEvent]; GuestProcsRec: TYPE = RECORD [ IsGuestProcess: PROC [] RETURNS [isGuest: BOOL], SetDefaultWDir: PROC [dir: ROPE _ NIL], GetDefaultWDir: PROC RETURNS [ROPE], ExpandName: PROC[name: ROPE, wDir: ROPE ] RETURNS [useDefault: BOOL, fullFName: ROPE, cp: FS.ComponentPositions, dirOmitted: BOOLEAN], FileInfo: PROC [name: ROPE, wantedCreatedTime: BasicTime.GMT, remoteCheck: BOOLEAN, wDir: ROPE] RETURNS [fullFName, attachedTo: ROPE, keep: CARDINAL, bytes: INT, created: BasicTime.GMT], EnumerateForInfo: PROC [pattern: ROPE, proc: FS.InfoProc, wDir: ROPE], EnumerateForNames: PROC [pattern: ROPE, proc: NameProc, wDir: ROPE], Open: PROC [name: ROPE, lock: FS.Lock, wantedCreatedTime: BasicTime.GMT, remoteCheck: BOOLEAN, wDir: ROPE] RETURNS [FS.OpenFile], Create: PROC [name: ROPE, setPages: BOOLEAN, pages: INT, setKeep: BOOLEAN, keep: CARDINAL, wDir: ROPE] RETURNS [FS.OpenFile], Copy: PROC [from, to: ROPE, setKeep: BOOLEAN, keep: CARDINAL, wantedCreatedTime: BasicTime.GMT, remoteCheck: BOOLEAN, attach: BOOLEAN, wDir: ROPE] RETURNS [toFName: ROPE], Delete: PROC [name: ROPE, wantedCreatedTime: BasicTime.GMT, wDir: ROPE], Rename: PROC [from, to: ROPE, setKeep: BOOLEAN, keep: CARDINAL, wantedCreatedTime: BasicTime.GMT, wDir: ROPE], SetKeep: PROC [name: ROPE, keep: CARDINAL, wDir: ROPE] ]; RegisterGuestProcs: PROC [newProcs: REF GuestProcsRec]; GuestProcs: REF GuestProcsRec ; END. %°FSBackdoor.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Created by M. D. Schroeder Schroeder, September 15, 1983 1:56 pm Bob Hagmann March 15, 1985 4:25:18 pm PST Doug Wyatt, February 27, 1985 11:26:24 am PST Backdoors to the Cedar File System Client-provided open files FS provides a way for clients to implement objects with the TYPE FS.OpenFile. The client provides procedures that implement the operations on an FS.OpenFile. Refer to FS.mesa for the semantics of these procedures. The client procedures should raise FS.Error as appropriate. Client procedures can generate code ATOM's used by FS and can produce additional code ATOM's if needed. FS.Error's with existing code ATOM's should be generated using FSBackdoor.ProduceError (see below). The client is responsible for associating any new code ATOM's with the appropriate FS.ErrorGroup. Note that no locking is done by FS on client-provided FS.OpenFile's. FS produces FS.Error[client, $notImplemented] when an attempt is make to use any client procedures that are NIL. SameFile will only get called for two clientFiles with equal "REF FileProcs". Client errors: none User errors: none Whenever any of the procedures above are called for the FS.OpenFile returned by FSBackdoor.CreateProcsOpenFile, the "clientFile" argument to CreateProcsOpenFile is passed on as the identification of the open file that is to be operated upon. Client errors: none User errors: none If "file" is a client-provided FS.OpenFile then the "clientFile" and "fileProcs" are returned, otherwise NIL is returned for both results. Client errors: $invalidOpenFile User error: none Raises FS.Error for the code ATOM that corresponds lexically to the "code". The FS.ErrorGroup in the error is properly set. The error will contain "explanation". Clients should use this procedure to generate FS.Error's for existing codes to avoid spelling the ATOM's wrong and getting the wrong FS.ErrorGroup. Volume space management FS provides access to the File package procedures for setting the volume freeboard on the system volume and reading the size, free and freeboard counts from a named volume. Client errors: none User errors: $unknownVolume "volName" = NIL means the system volume. Client errors: none User errors: $nonCedarVolume, $unknownVolume Manual cache management Like FS.EnumerateForInfo and FS.EnumerateForNames, except that only cached GNames in the named volume are enumerated. "volName" = NIL means the system volume. "pattern" = NIL means to match all names. Client errors: $noCache User errors: $nonCedarVolume, $unknownVolume, $illegalName The specified GName is removed from the directory/cache on the named volume and any associated file on that volume is deleted. "volName" = NIL means the system volume. Locking is done only for the system volume. In this case FS.Error[lock, $lockConflict] is generated when a "write" lock connot be obtained. Flushing a cached file from other than the system volume is done independent of any locks that may be set, so BE SURE YOU KNOW WHAT YOU ARE DOING. No FS.Error occurs if the "fullGName" is not in the cache on the indicated volume Client errors: none User errors: $nonCedarVolume, $unknownVolume Direct access to the directory/cache on any volume The directory of LNames and the cache for GName are implemented together as a BTree on a local volume. The following procedures and TYPES allow direct access to this BTree. A "nameBody" is an FName without a version part. LNames are recorded in the directory/cache without the "[]<>" prefix. Thus the nameBody for the LName "[]<>foo.mesa!5" will be "foo.mesa", and the nameBody for the GName "[indigo]Top>FS.df!47" will be "[indigo]Top>FS.df". The version part is represented as a scalar. The version for a GName that includes no version is "noVersion", which value otherwise will not occur. "highestVersion" and "lowestVersion" are used internally as the representation of !L and !H. An entry in the directory/cache can be gotten at directly via FSBackdoor.Enumerate and the following TYPEs. ******************************************************************************* WARNING: You should treat Entry's as READONLY, though the compiler won't let me say it. ******************************************************************************* "volName" is the name of a disk volume. A NIL "volName" means the system volume. The directory/cache is enumerated. The order of enumeration is lexical by nameBody (lower case letters are mapped to upper case) then numerical by version. Because LNames in the directory/cache do not have the "[]<>" prefix, and because of the constraints on the characters allowed in FNames, all LNames appear in the directory/cache earlier in the enumeration order than all GNames. The scope of the enumeration is constrained by the "localOnly" argument: if TRUE then only the LNames are enumerated; otherwise the enumeration spans all entries in the directory/cache. If "allVersions" is TRUE then the enumeration includes all versions of entries; otherwise it includes on the version specified by "version". The name body pattern is applied literally, without consideration of any working directories. If you want to enumerate only global names, then be sure the "nameBodyPattern" starts with "[". "matchProc" is called for each entry that matches the "pattern". A NIL "pattern" means to start at the beginning of the directory/cache and match everything. If "stop" is returned as TRUE then the enumeration terminates. Otherwise, if "accept" is returned as TRUE then "acceptProc" is called. The "acceptProc" can also stop the enumeration. The directory/cache is read locked while "matchProc" is called, so other operations on the directory/cache and tasks involving indefinite waits should not be done from this procedure. Do these from the "acceptProc" instead. Client errors: none User errors: $nonCedarVolume, $unknownVolume If "e" is an "EntryPtr", and "e.t" is a contained "TextRP", then "@e[e.t]" is a "LONG POINTER TO TextRep". Client errors: none User errors: none Makes an FName out of a "nameBody" and "version", and a "prefix". Does not do a syntax check. The prefix is prepended if the nameBody does not start with the character "[". If the nameBody comes from the directory of some named volume other than the system volume, then a prefix of "[]" should be supplied. If a prefix is needed and NIL is supplied, then "[]<>" is used. For use in converting the "attachedTo" name from a directory entry to a ROPE, just leave "version" and "prefix" defaulted, since "attachedTo" already starts with "[" and includes the version part. Client errors: none User errors: none Directory/cache reconstruction The directory/cache BTree for the named volume is rebuilt by enumerating the leader pages of all files on the volume and merging in any attached LNames that can be recovered from an existing BTree. "volName" = NIL means the system volume. While scavenging is occuring all FS operations that access the directory will wait. DO NOT call FSBackdoor.CloseVolume first. Client errors: none User errors: $nonCedarVolume, $unknownVolume Miscellaneous operations For experts only!!! Tells FS to close any directory/cache BTree it has open for the volume. May cause FS operations in progress to raise various strange BTree and File ERROR's. After CloseVolume returns, new FS operations will try to reopen a directory/cache BTree for the volume. Should be called AFTER a volume is erased. Client errors: none User errors: none For experts only!!! Returns the File.Handle that goes with an FS.OpenFile. Client errors: $invalidOpenFile, $notImplemented (for client-provided FS.OpenFile's) User errors: none A variant of FS.Create for the VM backing file. Errors: same as FS.Create Returns the full FName of the named "file". Will raise FS.Error[environment, $invalidPropertyPage] if the handle is not for an FS file. Client errors: none User errors: none A remote event is the start or conclusion of retrieving, storing, deleting, renaming or flushing (from the cache) a global file. NextRemoteEvent returns the next event that occurs after the argument RemoteEvent. When the argument RemoteEvent is NIL then NextRemoteEvent returns the first event to occur after the time of the call. NextRemoteEvent will WAIT if another event has not occurred yet. Storing, retrieving and flushing of several files can be in progress simultaneously. Client errors: none User errors: none A creation event is the closing of a local file that was open for write (was just created or overwritten), the completion of an FS.Rename call where "to" is an LName, or the completion of an FS.Copy call where "to" is an LName. NextCreateEvent returns the next event that occurs after the argument CreateEvent. When the argument CreateEvent is NIL then NextCreateEvent returns the first event to occur after the time of the call. NextCreateEvent will WAIT if another event has not occurred yet. Client errors: none User errors: none Guest processes Register procedures to determine if a process is a guest, and procedures to handle SetDefaultWDir, GetDefaultWDir, ExpandName, FileInfo, EnumerateForInfo, EnumerateForNames, Open, Create, OpenOrCreate, Copy, Delete, Rename, and SetKeep for guests. Current record of guest procedures. Bob Hagmann February 4, 1985 9:24:18 am PST Cedar 6.0 interface changes changes to: CreateVMBacking, FNameFromHandle, RemoteEvent, CreateOp, CreateEvent, NextCreateEvent, GuestProcsRec Ê ÿ– "cedar" style˜codešœ™Kšœ Ïmœ1™žœ ™MK™Kšœ™Kšœ™K˜—K˜š  œžœžœ žœ žœžœ ˜\K™Kšœ8žœ·™ñK™Kšœ™Kšœ™K˜—K˜š  œžœžœ žœžœ žœ ˜dK™KšœžœHžœ™ŠK™Kšœ ™ Kšœ™K™—K™Kšœ žœÏcœ©˜ÔK˜š  œžœ%žœ˜=K™Kš œžœžœ0žœ€žœ2žœžœ™»—K™—™Kšœ¬™¬K˜š  œžœ žœ˜$K™Kšœ™Kšœ™K™—K™š   œžœ ž œžœžœ˜MK™Kšœ žœ™(K™Kšœ™Kšœ¡œ™-K™——šœ™Kšœ žœžœžœžœ žœ ž œžœ žœ˜}K˜Kš œžœ$žœžœ˜KK˜Kš œ žœžœ žœžœ žœ˜DK˜š œžœ$žœžœ˜LK˜Kš œžœžœdžœ'žœ™ÊK™Kšœ™Kšœ¡œ¡œ ™;K˜—K˜š  œžœ žœ žœžœ˜3K˜KšœŒžœUžœÀžœžœžœžœžœžœžœžœžœM™žK™Kšœ™Kšœ¡œ™-K™——™2™­K™—šžœ³™´K™—Kšœ žœžœžœ˜"Kšœžœžœ˜&Kšœ$˜$šœ˜K™Kšœ\™\—K™K™kK™K™OK™XK™OK˜Kšœ žœ(¡$˜[K˜Kš œ žœžœžœžœžœ˜,K˜Kš œžœ žœžœžœ ˜4Kšœ žœžœž œžœžœžœ žœžœžœ˜TK˜Kš0œžœžœž œžœ ž œ¡<œžœ¡œ¡œ žœžœžœžœžœžœžœ žœ ¡œ%žœžœ žœ žœž¡Eœ˜ÍK˜š  œžœ žœ8žœ!žœžœžœžœžœžœžœ˜éK™Kšœ)žœžœôžœžœøžœžœržœIžœ°™™ K™Kšœ™Kšœ¡œ™-K™—K˜š  œž œ žœžœžœ žœ ˜SK™KšœQžœžœžœ ™jK™Kšœ™Kšœ™K™—K™š  œž œ žœ)žœžœžœžœ˜hK™KšœÝžœlžœx™ÈK™Kšœ™Kšœ™K™——™š œžœ žœžœ˜8K˜Kš œÓžœ<žœ2žœžœ#™ïK™Kšœ™Kšœ-™-K™——šœ™š  œžœ˜#K˜Kš œžœKžœ@žœ$žœYžœ™ÈK™Kšœ™Kšœ™K™—K™š  œžœžœ žœ˜>K˜Kšœ?žœ ™KK™Kšœ ¡œ%žœ ™UKšœ™K™—K˜š œžœžœ žœžœ žœžœžœžœ žœžœžœ˜£Kšœ/™/Kšœ™K˜—š œžœžœžœ˜9K˜Kšœ8žœFžœ™ˆK™Kšœ™Kšœ™K˜—K˜Kšœ žœ’˜ K˜šœ žœžœ˜Kšœ¡%˜3Kšœ žœ¡.˜@Kšœžœ ¡+˜BKšœ˜K˜—š œžœžœžœžœžœžœžœ˜[KšÏièœ ¢Ðik¢i£¢}™äKšœ™Kšœ™—K˜K˜Kšœ žœ"˜0K˜šœ žœžœ˜Kšœ¡'˜5Kšœ žœ¡5˜GKšœžœ ¡+˜BKšœ˜K˜—š œžœžœžœžœžœžœžœ˜[Kš¢éœ¢<œ¢œ ¢£¢ œ¢Hœ¢ £¢'™ñKšœ™Kšœ™K™——™šœžœžœ˜Kš œžœžœ žœ˜0KšÐbnœžœžœžœ˜'Kš œžœžœžœ˜$Kš  œžœžœžœžœžœ žœžœ!žœ˜†Kš œžœžœžœžœžœžœžœžœ žœžœ˜ºKš  œžœ žœžœžœ˜FKš œžœ žœžœ˜DKš œžœžœžœ$žœžœžœžœžœ ˜Kš œžœžœ žœ žœ žœžœžœžœžœ ˜}Kš œžœ žœ žœžœžœžœ žœžœžœ žœ˜«Kš  œžœžœžœžœ˜HKš œžœ žœ žœžœžœžœ˜nKš  œžœžœžœžœ˜6K˜K˜—K˜š œžœ žœ˜7K™Kšœ÷™÷—K˜šœ žœ˜Kšœ#™#—K™K˜—K˜šžœ˜K˜™+K™Kšœ Ïrd™p—K™——…—úJ©