<> <> <> <> DIRECTORY FSPseudoServers USING [TranslateForRead, TranslateForWrite], IFSFile USING [Problem], IFSFilePrivate USING [connectionTimeout, fileLockTimeout, FinalizeFreeList, FSInstance, FSObject, InitializeFreeList], Leaf USING [Answer, AnswerObject, LeafOp, leafSocket, paramsOp, ptLeaf, Request, RequestObject], PupDefs USING [GetPupAddress, PupAddress, PupNameTrouble, PupPackageDestroy, PupPackageMake], Rope USING [Equal, Length, ROPE], Sequin USING [Broken, Buffer, Create, Destroy, Get, GetEmptyBuffer, Handle, Put, ReleaseBuffer]; IFSFileImplA: MONITOR IMPORTS FSPseudoServers, IFSFilePrivate, PupDefs, Rope, Sequin EXPORTS IFSFile, IFSFilePrivate = { OPEN IFSFilePrivate; ROPE: TYPE = Rope.ROPE; <> loginCount: CARDINAL; <> someWordsForFilename: CARDINAL = 15; FilesInUse: ERROR = CODE; InsufficientLogouts: ERROR = CODE; PupBuffersTooSmall: ERROR = CODE; ServerNameMissing: ERROR = CODE; TooManyLogouts: ERROR = CODE; <> FSObject: PUBLIC TYPE = IFSFilePrivate.FSObject; Initialize: PUBLIC PROC = { loginCount _ 0; InitializeFreeList[]; }; Finalize: PUBLIC PROC = { IF loginCount ~= 0 THEN ERROR InsufficientLogouts; FinalizeFreeList[]; }; LeafStringWords: PROC [r: ROPE] RETURNS [CARDINAL] = { RETURN[((Rope.Length[r])+1)/2+1]; }; Login: PUBLIC PROC [server, userName, password, secondaryName, secondaryPassword: ROPE _ NIL] RETURNS [fs: FSInstance] = { serverAddr: PupDefs.PupAddress _ [net: [0], host: [0], socket: Leaf.leafSocket]; sequin: Sequin.Handle; TryForConnection: PROC RETURNS [sequin: Sequin.Handle] = { buffer: Sequin.Buffer _ Sequin.GetEmptyBuffer[]; adequate: CARDINAL = 2*(MAX[SIZE[Leaf.RequestObject], SIZE[Leaf.AnswerObject]] + 1 + LeafStringWords[userName] + LeafStringWords[password] + LeafStringWords[secondaryName] + LeafStringWords[secondaryPassword] + someWordsForFilename); problem: IFSFile.Problem; IF buffer.maxBytes < adequate THEN ERROR PupBuffersTooSmall; sequin _ Sequin.Create[dest: serverAddr, pupType: Leaf.ptLeaf]; LOOPHOLE[buffer.data, Leaf.Request]^ _ [ Leaf.paramsOp, params[packetDataBytes: buffer.maxBytes, fileLockTimeout: fileLockTimeout/5, connectionTimeout: connectionTimeout/5]]; buffer.nBytes _ Leaf.paramsOp.length; {ENABLE Sequin.Broken => {problem _ io; GO TO serverDead}; answerOp: Leaf.LeafOp; Sequin.Put[sequin, buffer]; buffer _ Sequin.Get[sequin]; answerOp _ LOOPHOLE[buffer.data, Leaf.Answer].op; Sequin.ReleaseBuffer[buffer]; IF answerOp.type ~= params OR answerOp.sense ~= reply THEN {problem _ other; GO TO serverDead}; EXITS serverDead => {Sequin.Destroy[sequin]; ERROR UnableToLogin[problem]}; }; }; GetPupAddress: PROC = { serverAddr _ PupDefs.GetPupAddress[Leaf.leafSocket, server ! PupDefs.PupNameTrouble => { ERROR UnableToLogin[SELECT code FROM noRoute, noResponse => io, ENDCASE => other]; }]; }; NoteLogin: ENTRY PROC = INLINE {loginCount _ loginCount + 1}; { <> name: ROPE _ FSPseudoServers.TranslateForWrite[server]; IF Rope.Equal[server, "$"] THEN { list: LIST OF ROPE _ FSPseudoServers.TranslateForRead[server]; IF list # NIL THEN name _ list.first; }; server _ name; }; IF Rope.Length[server] = 0 THEN ERROR ServerNameMissing; PupDefs.PupPackageMake[]; GetPupAddress[]; sequin _ TryForConnection[]; fs _ NEW[FSObject _ [ primaryName: userName, primaryPassword: password, secondaryName: secondaryName, secondaryPassword: secondaryPassword, serverAddr: serverAddr, cachedSequin: sequin, haveSequin: TRUE]]; NoteLogin[]; }; UnableToLogin: PUBLIC ERROR [reason: IFSFile.Problem] = CODE; Logout: PUBLIC PROC [fs: FSInstance] = { NoteLogout: ENTRY PROC = INLINE {loginCount _ loginCount - 1}; IF loginCount = 0 THEN ERROR TooManyLogouts; IF fs.fileList ~= NIL THEN ERROR FilesInUse; IF fs.primaryName ~= NIL THEN fs.primaryName _ NIL; IF fs.primaryPassword ~= NIL THEN fs.primaryPassword _ NIL; IF fs.secondaryName ~= NIL THEN fs.secondaryName _ NIL; IF fs.secondaryPassword ~= NIL THEN fs.secondaryPassword _ NIL; IF fs.haveSequin THEN {Sequin.Destroy[fs.cachedSequin]; fs.cachedSequin _ NIL}; PupDefs.PupPackageDestroy[]; NoteLogout[]; }; <> GetSequinForFS: PUBLIC ENTRY PROC [fs: FSInstance] RETURNS [sequin: Sequin.Handle, fromCache: BOOL] = { IF (fromCache _ fs.haveSequin) THEN {fs.haveSequin _ FALSE; sequin _ fs.cachedSequin} ELSE sequin _ Sequin.Create[dest: fs.serverAddr, pupType: Leaf.ptLeaf]; }; FreeSequinForFS: PUBLIC ENTRY PROC [ fs: FSInstance, sequin: Sequin.Handle, toCache: BOOL _ TRUE] = { <> IF ~toCache THEN {Sequin.Destroy[sequin]; RETURN}; IF fs.haveSequin THEN Sequin.Destroy[fs.cachedSequin]; fs.cachedSequin _ sequin; fs.haveSequin _ TRUE; }; }.