FSBackdoor.mesa
Copyright © 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
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;
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.
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];
SameFile will only get called for two clientFiles with equal "REF FileProcs".
Client errors: none
User errors: none
CreateProcsOpenFile: PROC [clientFile: REF, fileProcs: REF FileProcs] RETURNS [FS.OpenFile];
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
GetClientFileAndProcs: PROC [file: FS.OpenFile] RETURNS [clientFile: REF, fileProcs: REF FileProcs];
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
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];
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.
SetFreeboard: PROC [freeboard: INT];
Client errors: none
User errors: $unknownVolume
VolumePages: PROC [volName: ROPE ← NIL] RETURNS [size, free, freeboard: INT];
"volName" = NIL means the system volume.
Client errors: none
User errors: $nonCedarVolume, $unknownVolume
Manual cache management
InfoProc: TYPE = PROC [
fullGName: ROPE,
created: BasicTime.GMT,
bytes: INT,
keep: CARDINAL
] RETURNS [continue: BOOLEAN];
EnumerateCacheForInfo: PROC [proc: InfoProc, volName, pattern: ROPENIL];
NameProc: TYPE = PROC [fullGName: ROPE] RETURNS [continue: BOOLEAN];
EnumerateCacheForNames: PROC [proc: NameProc, volName, pattern: ROPENIL];
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
Flush: PROC [fullGName: ROPE, volName: ROPENIL];
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]<Cedar>Top>FS.df!47" will be "[indigo]<Cedar>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.
Version: TYPE = RECORD [CARDINAL];
noVersion: Version = [LAST[CARDINAL]];
highestVersion: Version = noVersion;
lowestVersion: Version = [0];
"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.
*******************************************************************************
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]
];
"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
TextFromTextRep: PROCEDURE [nameBody: LONG POINTER TO TextRep] RETURNS [Rope.Text];
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
MakeFName: PROCEDURE [nameBody: ROPE,
version: Version ← noVersion, prefix: ROPENIL] RETURNS [ROPE];
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 "[]<volumeName>" 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
ScavengeDirectoryAndCache: PROC [ volName: ROPENIL ];
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
CloseVolume: PROC [v: File.Volume];
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
GetFileHandle: PROC [file: FS.OpenFile] RETURNS [File.Handle];
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
CreateVMBacking: PROC [name: ROPE, setPages: BOOLEANTRUE, pages: INT ← 0, setKeep: BOOLEANFALSE, keep: CARDINAL ← 1, wDir: ROPENIL] RETURNS [FS.OpenFile];
A variant of FS.Create for the VM backing file.
Errors: same as FS.Create
FNameFromHandle: PROC [file: File.Handle] RETURNS [ROPE];
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
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];
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
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];
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
GuestProcsRec: TYPE = RECORD [
IsGuestProcess: PROC [] RETURNS [isGuest: BOOL],
SetDefaultWDir: PROC [dir: ROPENIL],
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];
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.
GuestProcs: REF GuestProcsRec ;
Current record of guest procedures.
END.
Bob Hagmann February 4, 1985 9:24:18 am PST
Cedar 6.0 interface changes
changes to: CreateVMBacking, FNameFromHandle, RemoteEvent, CreateOp, CreateEvent, NextCreateEvent, GuestProcsRec