Server Cache
ServerData: TYPE ~ REF ServerDataObject;
ServerDataObject:
TYPE ~
RECORD [
ttl: CARD,
downMsg: ROPE, -- non-NIL => down
hostName: ROPE,
address: Arpa.Address,
port: ArpaUDP.Port,
mountPort: ArpaUDP.Port,
h: SunRPC.Handle,
c: SunRPCAuth.Conversation,
FS view ...
remoteDirs: RemoteDirHandle
Unix(tm) view ...
nothing!
];
ObtainRPCHandleAndConversation:
PROC [sH: ServerHandle]
RETURNS [h: SunRPC.Handle, c: SunRPCAuth.Conversation];
Obtain SunRPC handle and Unix-flavor credentials for the current logged-in Cedar user (UserCredentials)
ReleaseRPCHandleAndConversation: PROC [sH: ServerHandle, h: SunRPC.Handle, c: SunRPCAuth.Conversation];
Server Procs (FS view)
SunNFSDelete: FSRemoteFileBackdoor.DeleteProc;
SunNFSEnumerateForInfo: FSRemoteFileBackdoor.EnumerateForInfoProc;
SunNFSEnumerateForNames: FSRemoteFileBackdoor.EnumerateForNamesProc;
SunNFSGetInfo: FSRemoteFileBackdoor.GetInfoProc;
SunNFSRename: FSRemoteFileBackdoor.RenameProc;
SunNFSRetrieve: FSRemoteFileBackdoor.RetrieveProc;
SunNFSStore: FSRemoteFileBackdoor.StoreProc;
Server Procs (Unix view)
SunNFSUnixOpen: UnixRemoteFile.OpenProc;
SunNFSUnixClose: UnixRemoteFile.CloseProc;
SunNFSUnixCreate: UnixRemoteFile.CreateProc;
SunNFSUnixDelete: UnixRemoteFile.DeleteProc;
SunNFSUnixMkDir: UnixRemoteFile.MkDirProc;
SunNFSUnixRmDir: UnixRemoteFile.RmDirProc;
SunNFSUnixLink: UnixRemoteFile.LinkProc;
SunNFSUnixSymLink: UnixRemoteFile.SymLinkProc;
SunNFSUnixRename: UnixRemoteFile.RenameProc;
SunNFSUnixEnumerate: UnixRemoteFile.EnumerateProc;
SunNFSUnixGetInfo: UnixRemoteFile.GetInfoProc;
SunNFSUnixSetInfo: UnixRemoteFile.SetInfoProc;
SunNFSUnixRead: UnixRemoteFile.ReadProc;
SunNFSUnixWrite: UnixRemoteFile.WriteProc;
Directories
RemoteDirHandle: TYPE ~ REF RemoteDirObject;
RemoteDirObject:
TYPE ~
RECORD [
parent, child, sibling: RemoteDirHandle,
nameComponent: ROPE, -- u/l case exactly as on server
fHandle: SunNFS.FHandle,
createMode: CARD, -- default mode for files created in this directory
createModeTTL: CARDINAL,
content: DirEntries,
contentMTime: SunNFS.TimeVal,
contentTTL: CARDINAL,
contentLocked: BOOL ← FALSE,
contentAvailable: CONDITION,
useCount: CARDINAL,
ttl: CARDINAL
];
DirEntries: TYPE ~ REF DirEntriesObject;
DirEntriesObject:
TYPE ~
RECORD [
next: DirEntries ← NIL,
count: CARDINAL ← 0,
entries: SEQUENCE maxCount: CARDINAL OF ROPE
];
GetRemoteDirRoot:
PROC [sH: ServerHandle]
RETURNS [dH: RemoteDirHandle];
Return "pinned" RemoteDirHandle for root of file system associated with server.
GetRemoteDirChild:
PROC [sH: ServerHandle, dH: RemoteDirHandle, childName:
ROPE, create:
BOOL]
RETURNS [dHChild: RemoteDirHandle, created:
BOOL];
Return "pinned" RemoteDirHandle for named child of given (pinned) directory.
If create is TRUE, create the subdirectory if necessary.
This is CASE-SENSITIVE!
CreateSubdirectory:
PROC [sH: ServerHandle, dH: RemoteDirHandle, name:
ROPE, desiredMode:
CARD]
RETURNS [fH: SunNFS.FHandle];
Create a subdirectory with the given (case-sensitive) name.
InsertRemoteDirChild:
PROC [dH: RemoteDirHandle, childName:
ROPE, fHandle: SunNFS.FHandle]
RETURNS [dHChild: RemoteDirHandle];
Insert directory cache entry for given file. Caller must be sure that "fHandle" does in fact denote the named directory. Return "pinned" RemoteDirHandle.
PinRemoteDirPath:
PROC [dH: RemoteDirHandle];
Lock ("pin") the given cached remote directory and all its ancestors.
Cached directories are reference counted. For each "pin" operation there must be a corresponding "release" operation. See ReleaseRemoteDir / ReleaseRemoteDirPath, below.
UnPinRemoteDir:
PROC [dH: RemoteDirHandle]
RETURNS [dHParent: RemoteDirHandle];
Release ("unpin") the given cached remote directory. The parent and other ancestors remain "pinned".
UnPinRemoteDirPath:
PROC [dH: RemoteDirHandle];
Release ("unpin") the path leading to the given cached remote directory. The client may not hold any pinned descendants of dH.
SweepRemoteDirCache:
PROC [root: RemoteDirHandle, seconds:
CARD];
Called occasionally by the Sweep proc registered with FSRemoteFileBackdoor.
GetCreateMode:
PROC [sH: ServerHandle, dH: RemoteDirHandle, forDirectory:
BOOL ←
FALSE]
RETURNS [createMode:
CARD];
Get the (nfs) mode to give to (regular or subdirectory) files created in the directory denoted by dH.
FixModeForDirectory: PROC [mode: CARD] RETURNS [CARD];
FixModeForRegularFile: PROC [mode: CARD] RETURNS [CARD];
GetModeAccessBits: PROC [mode: CARD] RETURNS [CARD];
UpdateModeAccessBits:
PROC [mode:
CARD, newAccessBits:
CARD]
RETURNS [
CARD];
EachDirEntryProc: TYPE ~ PROC [entryName: ROPE] RETURNS [continue: BOOL ← TRUE];
EnumerateDirectory:
PROC [sH: ServerHandle, dH: RemoteDirHandle, eachDirEntry: EachDirEntryProc, staleOK:
BOOL ←
FALSE];
Enumerate the directory, applying eachDirEntry to each entry.
Note the name passed to eachDirEntry is in SERVER format, not FS format.
Directory contents may be cached; if "staleOK" is FALSE, always contact the server to verify that the cache is up-to-date.
FollowDirPath:
PROC [sH: ServerHandle, nR: NameReader, case:
BOOL, create:
BOOL]
RETURNS [dH: RemoteDirHandle];
Return a (pinned) RemoteDirHandle for the longest prefix of directory names in nR, leaving nR ready for ReadBaseComponent[nR].
If case is TRUE then this is case-sensitive; otherwise name components are presented to the server in LOWER case.
The client is responsible for calling ReleaseRemoteDirPath[dH].
! FS.Error[...]
Case of file names
This is slightly bogus. A race between programs concurrently creating a new file version and deleting the "last" version may cause the case information to disappear. Fortunately, nobody relies on the case information for anything important.
caseFileNamePrefix: READONLY ROPE;
caseFileNamePrefixLen: READONLY INT;
CreateCaseFile:
PROC [sH: ServerHandle, dH: RemoteDirHandle, base:
ROPE];
Create a case file for file base. The base should have no version part.
CollectCaseFile:
PROC [sH: ServerHandle, dH: RemoteDirHandle, base:
ROPE];
If there are (appear to be) no more versions of the base file, delete any case file. The base should have no version part.
File Name Readers / Writers
VersionInfo: TYPE ~ { missing, bang, bangNumber, bangStar, bangH, bangL };
Parsing
versionPartLeftBracket: READONLY ROPE;
versionPartLeftBracketLen: READONLY INT;
versionPartRightBracket: READONLY CHAR;
versionPartRightBracketLen: READONLY INT;
DecodeVersionFromNFSName:
PROC [name:
ROPE, checkCase:
BOOL ←
FALSE]
RETURNS [nameWithoutVersion:
ROPE, version: Version, caseOK:
BOOL];
If no version part, or version part can't be parsed, returns version=FSBackdoor.noVersion.
The checkCase option checks to see that the name is all lower-case.
EncodeVersionInNFSName:
PROC [name:
ROPE, version: Version]
RETURNS [nameWithVersion:
ROPE];
Like FSName.BangVersionFile, but uses the NFS encoding of versions in file names.
Name Readers
NameReader: TYPE ~ REF NameReaderObject;
NameReaderObject:
TYPE ~
RECORD [
text: REF READONLY TEXT,
index: CARDINAL
];
ReadDirComponent:
PROC [nR: NameReader, case:
BOOL]
RETURNS [component:
ROPE];
The returned component is NIL if all the directory information has already been read. In particular, if the name reader contains "<>foo!17", the first call of ReadDirComponent will return NIL and leave things ready for ReadBaseComponent.
If case is FALSE then the returned component is all LOWER CASE.
ReadBaseComponent:
PROC [nR: NameReader, case:
BOOL, stripVersion:
BOOL ←
FALSE]
RETURNS [base: ROPE, vI: VersionInfo, version: Version, isPattern: BOOL, patternHead: ROPE];
The result "isPattern" is TRUE iff the base component contains a '* before the version part; in this case, "patternHead" goes up to (but does not include) the first '* in the pattern.
If case is FALSE then the returned base and pattern head are all LOWER CASE.
The base contains whatever version info was specified in the nR source, unless "stripVersion" is TRUE.
CreateNameReader: PROC [r: ROPE] RETURNS [nR: NameReader];
ResetNameReader:
PROC [nR: NameReader, position:
INTEGER];
The position is a number of pathname components. A negative position is relative to the current name reader position; a nonnegative position is absolute.
Name Writers
NameWriter: TYPE ~ REF NameWriterObject;
NameWriterObject:
TYPE ~
RECORD [
text: REF TEXT
];
CreateNameWriter:
PROC
RETURNS [nW: NameWriter];
Create an empty name writer.
WriteDirComponent: PROC [nW: NameWriter, component: ROPE];
WriteBaseComponent:
PROC [nW: NameWriter, component:
ROPE];
WriteDirComponent appends ">" if the writer is currently empty, then appends component.
WriteBaseComponent appends ">" unconditionally, then appends component.
The idea is that if you start with an empty name writer, then do zero or more WriteDirComponent calls followed by a WriteBaseComponent call, then Rope.Cat["[server]<", RopeFromNameWriter[nW]] will be a valid name.
RetractComponent: PROC [nW: NameWriter];
RetractAndReturnComponent:
PROC [nW: NameWriter]
RETURNS [r:
ROPE];
"Back up" the last component written to the writer.
RopeFromNameWriter: PROC [nW: NameWriter] RETURNS [ROPE];
Error Reporting (FS View)
These procs raise appropriate FS.Error[...]s.
ReportRPCError: PROC [code: ATOM, sH: ServerHandle ← NIL, name, msg: ROPE ← NIL];
ReportAuthError: PROC [code: ATOM, sH: ServerHandle ← NIL, msg: ROPE ← NIL];
ReportNFSError: PROC [status: SunNFS.Stat, sH: ServerHandle ← NIL, name, msg: ROPE ← NIL];
ReportFSError: PROC [code: FSBackdoor.ErrorCode, sH: ServerHandle ← NIL, name, msg: ROPE ← NIL];
}...