Parameters
initialRemoteDirTTL: CARDINAL ← 600;
initialCreateModeTTL: CARDINAL ← 600;
defaultCreateMode: CARD ← 0640B; -- rw. r.. ...
fsModeFileName: ROPE ← ".~mode~";
dirSearchBlocksize: CARD ← 2048; -- should become 8K when gateways are fixed!
initialDirContentTTL: CARDINAL ← 60;
dirEntriesPerObject: CARDINAL ← 30;
File mode stuff
regularModeBits: CARD ~ 0100000B;
directoryModeBits: CARD ~ 040700B;
accessBits: CARD ~ 07777B; -- includes suid, sgid
ownerRBit: CARD ~ 0400B;
ownerWBit: CARD ~ 0200B;
ownerXBit: CARD ~ 0100B;
groupRWBits: CARD ~ 060B;
groupRBit: CARD ~ 040B;
groupWBit: CARD ~ 020B;
groupXBit: CARD ~ 010B;
otherRBit: CARD ~ 04B;
otherWBit: CARD ~ 02B;
otherXBit: CARD ~ 01B;
FixModeForRegularFile:
PUBLIC PROC [mode:
CARD]
RETURNS [
CARD] ~ {
mode ← LOOPHOLE[Basics.DoubleOr[LOOPHOLE[mode], LOOPHOLE[regularModeBits]]];
RETURN [mode];
};
FixModeForDirectory:
PUBLIC
PROC [mode:
CARD]
RETURNS [
CARD] ~ {
mode ← LOOPHOLE[Basics.DoubleAnd[LOOPHOLE[mode], LOOPHOLE[accessBits]]];
mode ← LOOPHOLE[Basics.DoubleOr[LOOPHOLE[mode], LOOPHOLE[directoryModeBits]]];
IF
LOOPHOLE[Basics.DoubleAnd[
LOOPHOLE[mode],
LOOPHOLE[groupWBit]],
CARD] # 0
THEN mode ← LOOPHOLE[Basics.DoubleOr[LOOPHOLE[mode], LOOPHOLE[groupRBit]]];
IF
LOOPHOLE[Basics.DoubleAnd[
LOOPHOLE[mode],
LOOPHOLE[groupRBit]],
CARD] # 0
THEN mode ← LOOPHOLE[Basics.DoubleOr[LOOPHOLE[mode], LOOPHOLE[groupXBit]]];
IF
LOOPHOLE[Basics.DoubleAnd[
LOOPHOLE[mode],
LOOPHOLE[otherWBit]],
CARD] # 0
THEN mode ← LOOPHOLE[Basics.DoubleOr[LOOPHOLE[mode], LOOPHOLE[otherRBit]]];
IF
LOOPHOLE[Basics.DoubleAnd[
LOOPHOLE[mode],
LOOPHOLE[otherRBit]],
CARD] # 0
THEN mode ← LOOPHOLE[Basics.DoubleOr[LOOPHOLE[mode], LOOPHOLE[otherXBit]]];
RETURN [mode];
};
GetModeAccessBits:
PUBLIC
PROC [mode:
CARD]
RETURNS [
CARD] ~ {
RETURN [LOOPHOLE[Basics.DoubleAnd[LOOPHOLE[mode], LOOPHOLE[accessBits]]] ];
};
UpdateModeAccessBits:
PUBLIC
PROC [mode:
CARD, newAccessBits:
CARD]
RETURNS [
CARD] ~ {
mode ← LOOPHOLE[Basics.DoubleAnd[LOOPHOLE[mode], LOOPHOLE[Basics.DoubleNot[LOOPHOLE[accessBits]]]]];
newAccessBits ← LOOPHOLE[Basics.DoubleAnd[LOOPHOLE[newAccessBits], LOOPHOLE[accessBits]]];
RETURN[ LOOPHOLE[Basics.DoubleOr[LOOPHOLE[mode], LOOPHOLE[newAccessBits]]] ];
};
Cache of remote directory handles
FindRemoteDirChild:
ENTRY
PROC [dH: RemoteDirHandle, childName:
ROPE]
RETURNS [dHChild: RemoteDirHandle] ~ {
ENABLE UNWIND => NULL;
FOR dHChild ← dH.child, dHChild.sibling
WHILE dHChild #
NIL
DO
IF Rope.Equal[dHChild.nameComponent, childName,
TRUE]
THEN {
dHChild.useCount ← dHChild.useCount.SUCC;
RETURN;
};
ENDLOOP;
};
InsertRemoteDirChild:
PUBLIC
ENTRY
PROC [dH: RemoteDirHandle, childName:
ROPE, fHandle: SunNFS.FHandle]
RETURNS [dHChild: RemoteDirHandle] ~ {
ENABLE UNWIND => NULL;
dHChild ← NEW[RemoteDirObject ← [parent~dH, sibling~dH.child, nameComponent~childName, fHandle~fHandle, createMode~0, createModeTTL~0, contentMTime~[0, 0], contentTTL~0, useCount~1, ttl~initialRemoteDirTTL]];
dH.child ← dHChild;
};
PinRemoteDirPath:
PUBLIC
ENTRY
PROC [dH: RemoteDirHandle] ~ {
ENABLE UNWIND => NULL;
WHILE dH #
NIL
DO
dH.useCount ← dH.useCount.SUCC;
dH ← dH.parent;
ENDLOOP;
};
UnPinRemoteDir:
PUBLIC
ENTRY
PROC [dH: RemoteDirHandle]
RETURNS [dHParent: RemoteDirHandle] ~ {
ENABLE UNWIND => NULL;
dH.useCount ← dH.useCount.PRED;
dH.ttl ← initialRemoteDirTTL;
RETURN[dH.parent];
};
UnPinRemoteDirPath:
PUBLIC
ENTRY
PROC [dH: RemoteDirHandle] ~ {
ENABLE UNWIND => NULL;
WHILE dH #
NIL
DO
dH.useCount ← dH.useCount.PRED;
dH.ttl ← initialRemoteDirTTL;
dH ← dH.parent;
ENDLOOP;
};
GetRemoteDirRoot:
PUBLIC
ENTRY
PROC [sH: ServerHandle]
RETURNS [dH: RemoteDirHandle] ~ {
ENABLE UNWIND => NULL;
d: ServerData ← NARROW[sH.data];
dH ← d.remoteDirs;
IF dH = NIL THEN ERROR;
dH.useCount ← dH.useCount.SUCC;
};
VerifySubdirectory:
PROC [sH: ServerHandle, dH: RemoteDirHandle, name:
ROPE]
RETURNS [fH: SunNFS.FHandle] ~ {
Return fHandle for subdirectory if it exists; return NIL if subdirectory doesn't exist, else raise appropriate FS.Error.
reply: SunNFS.DirOpRes;
reply ← LookupThruSymLinks[sH, dH, name];
SELECT reply.status
FROM
ok => {
IF reply.attributes.type # dir THEN ReportNFSError[notdir, sH, name];
fH ← reply.file;
};
ENDCASE => {
ReportNFSError[reply.status, sH, name];
};
};
CreateSubdirectory:
PUBLIC
PROC [sH: ServerHandle, dH: RemoteDirHandle, name:
ROPE, desiredMode:
CARD]
RETURNS [fH: SunNFS.FHandle] ~ {
Create subdirectory in the directory specified by <sH, dH>.
rpcH: SunRPC.Handle;
c: SunRPCAuth.Conversation;
reply: SunNFS.DirOpRes;
[rpcH, c] ← ObtainRPCHandleAndConversation[sH];
{
ENABLE
UNWIND => ReleaseRPCHandleAndConversation[sH, rpcH, c];
reply ← SunNFSClient.Mkdir[rpcH, c, [dH.fHandle, Rope.ToRefText[name]],
SunNFS.SAttr[
mode~FixModeForDirectory[desiredMode],
uid~CARD.LAST, -- => default
gid~CARD.LAST, -- => default
size~CARD.LAST, -- => default
atime~[CARD.LAST, CARD.LAST], -- => default
mtime~[CARD.LAST, CARD.LAST] -- => default
]
! SunRPC.Error => ReportRPCError[code, sH, name]];
SELECT reply.status
FROM
ok => {
fH ← reply.file;
};
ENDCASE => {
ReportNFSError[reply.status, sH, name];
};
};
ReleaseRPCHandleAndConversation[sH, rpcH, c];
};
RefreshRemoteDirContent:
PROC [sH: ServerHandle, dH: RemoteDirHandle, staleOK:
BOOL]
RETURNS [content: DirEntries] ~ {
Read directory content from server if it has changed since oldMTime.
h: SunRPC.Handle;
c: SunRPCAuth.Conversation;
tail: DirEntries ← NIL;
oldMTime, mtime: SunNFS.TimeVal;
EachEntry: SunNFS.EachDirEntryProc
-- [fileid: CARD, filename: FileName] RETURNS [continue: BOOL ← TRUE] -- ~ {
nameRope: ROPE ~ Rope.FromRefText[filename];
IF (tail =
NIL)
OR (tail.count >= tail.maxCount)
THEN {
temp: DirEntries ~ NEW[DirEntriesObject[dirEntriesPerObject]];
IF tail = NIL THEN content ← temp ELSE tail.next ← temp;
tail ← temp;
};
tail.entries[tail.count] ← nameRope;
tail.count ← tail.count + 1;
};
CheckOutContent:
ENTRY
PROC
RETURNS [locked:
BOOL] ~ {
ENABLE UNWIND => NULL;
WHILE dH.contentLocked DO WAIT dH.contentAvailable ENDLOOP;
content ← dH.content;
oldMTime ← dH.contentMTime;
locked ← dH.contentLocked ← ((NOT staleOK) OR (dH.contentTTL = 0));
};
CheckInContent:
ENTRY
PROC ~ {
ENABLE UNWIND => NULL;
dH.content ← content;
dH.contentMTime ← mtime;
dH.contentTTL ← initialDirContentTTL;
dH.contentLocked ← FALSE;
BROADCAST dH.contentAvailable;
};
UnlockContent:
ENTRY
PROC ~ {
ENABLE UNWIND => NULL;
dH.contentLocked ← FALSE;
BROADCAST dH.contentAvailable;
};
IF NOT CheckOutContent[].locked THEN RETURN;
{
ENABLE
UNWIND => {
UnlockContent[];
IF h # NIL THEN ReleaseRPCHandleAndConversation[sH, h, c];
};
{
attrStat: SunNFS.AttrStat;
[h, c] ← ObtainRPCHandleAndConversation[sH];
attrStat ← SunNFSClient.Getattr[h, c, dH.fHandle
! SunRPC.Error => ReportRPCError[code, sH]];
IF attrStat.status # ok THEN ReportNFSError[attrStat.status, sH];
mtime ← attrStat.attributes.mtime;
};
IF CompareSunTimes[mtime, oldMTime] = greater
THEN {
status: SunNFS.Stat;
eof: BOOL ← FALSE;
cookie: SunNFS.Cookie ← NIL;
WHILE
NOT eof
DO
[status, eof, cookie] ← SunNFSClient.Readdir[h, c, dH.fHandle, cookie, dirSearchBlocksize, EachEntry
! SunRPC.Error => ReportRPCError[code, sH]];
IF status # ok THEN ReportNFSError[status, sH];
ENDLOOP;
};
};
CheckInContent[];
ReleaseRPCHandleAndConversation[sH, h, c];
};
GetCreateMode:
PUBLIC
PROC [sH: ServerHandle, dH: RemoteDirHandle, forDirectory:
BOOL]
RETURNS [createMode:
CARD] ~ {
rawMode: CARD ← RefreshCreateMode[sH, dH];
RETURN [IF forDirectory THEN FixModeForDirectory[rawMode] ELSE FixModeForRegularFile[rawMode]];
};
RefreshCreateMode:
PROC [sH: ServerHandle, dH: RemoteDirHandle]
RETURNS [createMode:
CARD] ~ {
The returned create mode has no type bits set ...
CheckOutCreateMode:
ENTRY
PROC
RETURNS [ok:
BOOL] ~
--
INLINE
-- {
ENABLE UNWIND => NULL;
createMode ← dH.createMode;
ok ← (dH.createModeTTL > 0);
};
CheckInCreateMode:
ENTRY
PROC ~
--INLINE-- {
ENABLE UNWIND => NULL;
dH.createMode ← createMode;
dH.createModeTTL ← initialCreateModeTTL;
};
IF dH = NIL THEN RETURN [defaultCreateMode];
IF CheckOutCreateMode[].ok THEN RETURN;
{ reply: SunNFS.DirOpRes ← LookupThruSymLinks[sH, dH, fsModeFileName];
SELECT reply.status
FROM
ok => createMode ← GetModeAccessBits[reply.attributes.mode];
noent => createMode ← RefreshCreateMode[sH, dH.parent];
ENDCASE => ReportNFSError[reply.status, sH];
};
CheckInCreateMode[];
};
EnumerateDirectory:
PUBLIC
PROC [sH: ServerHandle, dH: RemoteDirHandle, eachDirEntry: EachDirEntryProc, staleOK:
BOOL] ~ {
content: DirEntries;
content ← RefreshRemoteDirContent[sH, dH, staleOK];
FOR p: DirEntries ← content, p.next
WHILE p #
NIL
DO
FOR i:
CARDINAL
IN [0 .. p.count)
DO
IF NOT eachDirEntry[p.entries[i]].continue THEN RETURN;
ENDLOOP;
ENDLOOP;
};
FollowDirPath:
PUBLIC
PROC [sH: ServerHandle, nR: NameReader, case:
BOOL, create:
BOOL]
RETURNS [dH: RemoteDirHandle ←
NIL] ~ {
ENABLE
UNWIND => {
IF dH # NIL THEN UnPinRemoteDirPath[dH];
};
dH ← GetRemoteDirRoot[sH];
DO
dHParent: RemoteDirHandle ← dH;
created: BOOL;
component: ROPE ← ReadDirComponent[nR, FALSE];
IF Rope.IsEmpty[component] THEN EXIT;
[dH, created] ← GetRemoteDirChild[sH~sH, dH~dH, childName~component, create~create];
IF created
THEN {
componentWithCase: ROPE;
ResetNameReader[nR, -1];
componentWithCase ← ReadDirComponent[nR, TRUE];
CreateCaseFile[sH, dHParent, componentWithCase ! FS.Error => CONTINUE ];
};
ENDLOOP;
};
GetRemoteDirChild:
PUBLIC
PROC [sH: ServerHandle, dH: RemoteDirHandle, childName:
ROPE, create:
BOOL]
RETURNS [dHChild: RemoteDirHandle, created: BOOL ← FALSE] ~ {
Given a (pinned) RemoteDirHandle, return a (pinned) RemoteDirHandle for the named child, if that child exists and is a directory. Otherwise raise FS.Error[...].
fH: SunNFS.FHandle;
IF (dHChild ← FindRemoteDirChild[dH, childName]) # NIL THEN RETURN;
fH ← VerifySubdirectory[sH, dH, childName];
IF fH =
NIL
THEN {
desiredMode: CARD;
IF NOT create THEN ReportNFSError[noent, sH, childName];
desiredMode ← GetCreateMode[sH, dH, TRUE];
fH ← CreateSubdirectory[sH, dH, childName, desiredMode];
created ← TRUE;
};
dHChild ← InsertRemoteDirChild[dH, childName, fH];
};
SweepRemoteDirCache:
PUBLIC
ENTRY
PROC [root: RemoteDirHandle, seconds:
CARD] ~ {
Note this can't delete the root!
ENABLE UNWIND => NULL;
SweepInner:
PROC [dH: RemoteDirHandle] ~ {
prev: RemoteDirHandle ← NIL;
FOR p: RemoteDirHandle ← dH.child, p.sibling
WHILE p #
NIL
DO
SweepInner[p];
IF (p.ttl = 0)
AND (p.child =
NIL)
AND (p.useCount = 0)
THEN {
IF prev = NIL THEN dH.child ← p.sibling ELSE prev.sibling ← p.sibling;
}
ENDLOOP;
IF dH.ttl > seconds THEN dH.ttl ← dH.ttl - seconds ELSE dH.ttl ← 0;
IF dH.contentTTL > seconds
THEN {
dH.contentTTL ← dH.contentTTL - seconds;
}
ELSE {
dH.contentTTL ← 0;
IF
NOT dH.contentLocked
THEN {
dH.content ← NIL;
dH.contentMTime ← [0, 0];
};
};
IF dH.createModeTTL > seconds
THEN dH.createModeTTL ← dH.createModeTTL - seconds
ELSE dH.createModeTTL ← 0;
};
IF root # NIL THEN SweepInner[root];
};
}...