<> <> <> DIRECTORY Basics USING [DoubleAnd, DoubleOr], BasicTime USING [GMT], FS USING [Error], FSRemoteFileBackdoor USING [ServerObject], Rope USING [Cat, Equal, FromRefText, IsEmpty, ROPE, ToRefText], SunMountClient USING [Mnt, Umnt], SunNFS USING [AttrStat, Cookie, DirOpRes, EachDirEntryProc, FHandle, FileName, SAttr, Stat, TimeVal], SunNFSClient USING [Getattr, Lookup, Mkdir, Readdir], SunNFSFSRemoteFile USING [CompareSunTimes, CreateCaseFile, DirEntries, DirEntriesObject, EachDirEntryProc, NameReaderObject, NameWriterObject, ObtainRPCHandleAndConversation, ReleaseRPCHandleAndConversation, ReadDirComponent, RemoteDirObject, ReportNFSError, ReportRPCError, ResetNameReader, ServerDataObject], SunRPC USING [Error, Handle, SetRemote], SunRPCAuth USING [Conversation] ; SunNFSFSRemoteDirImpl: CEDAR MONITOR IMPORTS Basics, Rope, FS, SunMountClient, SunNFSClient, SunNFSFSRemoteFile, SunRPC EXPORTS SunNFSFSRemoteFile ~ { OPEN SunNFSFSRemoteFile; <> FHandle: TYPE ~ SunNFS.FHandle; GMT: TYPE ~ BasicTime.GMT; NameReader: TYPE ~ REF NameReaderObject; <> NameWriter: TYPE ~ REF NameWriterObject; <> RemoteDirHandle: TYPE ~ REF RemoteDirObject; <> ROPE: TYPE ~ Rope.ROPE; ServerData: TYPE ~ REF ServerDataObject; <> ServerHandle: TYPE ~ REF ServerObject; ServerObject: TYPE ~ FSRemoteFileBackdoor.ServerObject; <> initialRemoteDirTTL: CARDINAL _ 600; initialCreateModeTTL: CARDINAL _ 600; defaultCreateMode: CARD _ ownerRWBits; fsModeFileName: ROPE _ ".fsmode"; dirSearchBlocksize: CARD _ 1024; -- should be 8K??? initialDirContentTTL: CARDINAL _ 60; dirEntriesPerObject: CARDINAL _ 30; <> regularModeBits: CARD ~ 0100000B; directoryModeBits: CARD ~ 040700B; accessBits: CARD ~ 0777B; ownerRWBits: CARD ~ 0600B; ownerSearchBit: CARD ~ 0100B; groupRWBits: CARD ~ 060B; groupSearchBit: CARD ~ 010B; otherRWBits: CARD ~ 06B; otherSearchBit: CARD ~ 01B; GetModeAccessBits: PROC [mode: CARD] RETURNS [CARD] ~ INLINE { RETURN [LOOPHOLE[Basics.DoubleAnd[LOOPHOLE[mode], LOOPHOLE[accessBits]]] ]; }; FixModeForRegularFile: PROC [mode: CARD] RETURNS [CARD] ~ INLINE { mode _ LOOPHOLE[Basics.DoubleOr[LOOPHOLE[mode], LOOPHOLE[regularModeBits]]]; RETURN [mode]; }; FixModeForDirectory: PROC [mode: CARD] RETURNS [CARD] ~ { mode _ GetModeAccessBits[mode]; mode _ LOOPHOLE[Basics.DoubleOr[LOOPHOLE[mode], LOOPHOLE[directoryModeBits]]]; IF LOOPHOLE[Basics.DoubleAnd[LOOPHOLE[mode], LOOPHOLE[groupRWBits]], CARD] # 0 THEN mode _ LOOPHOLE[Basics.DoubleOr[LOOPHOLE[mode], LOOPHOLE[groupSearchBit]]]; IF LOOPHOLE[Basics.DoubleAnd[LOOPHOLE[mode], LOOPHOLE[otherRWBits]], CARD] # 0 THEN mode _ LOOPHOLE[Basics.DoubleOr[LOOPHOLE[mode], LOOPHOLE[otherSearchBit]]]; RETURN [mode]; }; <> 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] ~ { <> 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; }; noent => { fH _ NIL; }; ENDCASE => { ReportNFSError[reply.status, sH, name]; }; }; CreateSubdirectory: PUBLIC PROC [sH: ServerHandle, dH: RemoteDirHandle, name: ROPE, desiredMode: CARD] RETURNS [fH: SunNFS.FHandle] ~ { <.>> 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] ~ { <> 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] ~ { <> 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] ~ { <> 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] ~ { <> 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; } ELSE { prev _ p; }; 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]; }; <> LookupThruSymLinks: PUBLIC PROC [sH: ServerHandle, dH: RemoteDirHandle, name: ROPE] RETURNS [dirOpRes: SunNFS.DirOpRes] ~ { rpcH, rpcHForMount: SunRPC.Handle; c: SunRPCAuth.Conversation; data: ServerData _ NARROW[sH.data]; { ENABLE { UNWIND => { IF rpcHForMount # NIL THEN rpcH _ SunRPC.SetRemote[rpcHForMount, data.address, data.port]; IF rpcH # NIL THEN ReleaseRPCHandleAndConversation[sH, rpcH, c]; }; SunRPC.Error => { ReportRPCError[code, sH]; }; }; fullPathName: ROPE; fullPathNameRefText: REF TEXT; attrStat: SunNFS.AttrStat; fH: REF TEXT; [rpcH, c] _ ObtainRPCHandleAndConversation[sH]; dirOpRes _ SunNFSClient.Lookup[rpcH, c, [dH.fHandle, Rope.ToRefText[name]] ]; SELECT dirOpRes.status FROM ok => NULL; ENDCASE => GOTO Out; SELECT dirOpRes.attributes.type FROM lnk => NULL; ENDCASE => GOTO Out; <> fullPathName _ name; FOR finger: RemoteDirHandle _ dH, finger.parent WHILE finger # NIL DO fullPathName _ Rope.Cat[finger.nameComponent, "/", fullPathName]; ENDLOOP; fullPathNameRefText _ Rope.ToRefText[fullPathName]; rpcHForMount _ SunRPC.SetRemote[rpcH, data.address, data.mountPort]; rpcH _ NIL; fH _ SunMountClient.Mnt[rpcHForMount, c, fullPathNameRefText].directory; IF fH = NIL THEN { dirOpRes.status _ noent; GOTO Out }; SunMountClient.Umnt[rpcHForMount, c, fullPathNameRefText ! SunRPC.Error => CONTINUE ]; rpcH _ SunRPC.SetRemote[rpcHForMount, data.address, data.port]; rpcHForMount _ NIL; attrStat _ SunNFSClient.Getattr[rpcH, c, fH]; dirOpRes _ [attrStat.status, fH, attrStat.attributes]; EXITS Out => NULL; }; IF rpcHForMount # NIL THEN rpcH _ SunRPC.SetRemote[rpcHForMount, data.address, data.port]; IF rpcH # NIL THEN ReleaseRPCHandleAndConversation[sH, rpcH, c]; }; << LookupThruSymLinks: PUBLIC PROC [sH: ServerHandle, dH: RemoteDirHandle, name: ROPE] RETURNS [dirOpRes: SunNFS.DirOpRes] ~ { <> rpcH: SunRPC.Handle; c: SunRPCAuth.Conversation; dH2: RemoteDirHandle; { ENABLE UNWIND => { IF rpcH # NIL THEN ReleaseRPCHandleAndConversation[sH, rpcH, c]; IF dH2 # NIL THEN UnPinRemoteDirPath[dH2]; }; nameRefText: REF TEXT _ Rope.ToRefText[name]; status: SunNFS.Stat; iStart, i: CARDINAL; component: ROPE; linkValue: REF TEXT; [rpcH, c] _ ObtainRPCHandleAndConversation[sH]; dirOpRes _ SunNFSClient.Lookup[rpcH, c, [dH.fHandle, nameRefText] ! SunRPC.Error => ReportRPCError[code, sH]]; SELECT dirOpRes.status FROM ok => NULL; ENDCASE => GOTO Out; SELECT dirOpRes.attributes.type FROM lnk => NULL; ENDCASE => GOTO Out; [status, linkValue] _ SunNFSClient.Readlink[rpcH, c, dirOpRes.file]; SELECT status FROM ok => NULL; ENDCASE => { dirOpRes.status _ status; GOTO Out }; ReleaseRPCHandleAndConversation[sH, rpcH, c]; rpcH _ NIL; <> SELECT linkValue[0] FROM '/ => { dH2 _ GetRemoteDirRoot[sH]; i _ 1 }; ENDCASE => { PinRemoteDirPath[dH2 _ dH]; i _ 0 }; DO iStart _ i; WHILE (i < linkValue.length) AND (linkValue[i] # '/) DO i _ i + 1 ENDLOOP; IF i >= linkValue.length THEN EXIT; IF (i+1) = linkValue.length -- trailing slash THEN { linkValue.length _ linkValue.length-1; EXIT }; component _ Rope.FromRefText[linkValue, iStart, i-iStart]; SELECT TRUE FROM Rope.Equal[component, "."] => NULL; Rope.Equal[component, ".."] => dH2 _ UnPinRemoteDir[dH2]; ENDCASE => [dHChild~dH2] _ GetRemoteDirChild[sH, dH2, component, FALSE]; i _ i + 1; ENDLOOP; component _ Rope.FromRefText[linkValue, iStart]; dirOpRes _ LookupThruSymLinks[sH, dH2, component]; UnPinRemoteDirPath[dH2]; dH2 _ NIL; GOTO Out; EXITS Out => IF rpcH # NIL THEN ReleaseRPCHandleAndConversation[sH, rpcH, c]; }; }; >> }...