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; }; }. 8IFSFileImplA.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Levin - 13-Oct-81 9:09:48 Russ Atkinson, March 7, 1985 3:02:46 pm PST Global Variables Miscellaneous Procedures and Types Exported to IFSFile Handle translations of host names. This is a kludge, since we don't know whether we will read or write. We assume that we should try for the write translation first, then settle for the first listed read translation. Procedures and Variables Exported to IFSFilePrivate we cache the newest one to minimize the chance of subsequent timeout Ê£˜codešœ™Kšœ Ïmœ1™Kšžœ˜#K˜Kšžœ˜K˜Kšžœžœžœ˜K˜—šœ™K˜Kšœ žœ˜K˜—šœ ™ K˜Kšœžœ˜$K˜Kšœ žœžœ˜Kšœžœžœ˜"Kšœžœžœ˜!Kšœžœžœ˜ Kšœžœžœ˜K˜—šœ(™(K˜Kšœ žœžœ˜0K˜šÏn œžœžœ˜K˜K˜Kšœ˜K˜—šŸœžœžœ˜Kšžœžœžœ˜2K˜Kšœ˜K˜—š Ÿœžœžœžœžœ˜6Kšžœ˜!Kšœ˜K˜—š Ÿœžœžœ@žœžœžœ˜zK˜PK˜K˜šŸœžœžœ˜:K˜0šœ žœ˜šœžœžœžœ˜?K˜7K˜EK˜——K˜Kšžœžœžœ˜Kšžœžœžœ˜%K˜—K˜K˜—Kšžœžœžœ˜8K˜K˜K˜K˜šœžœ ˜K˜1K˜K˜%K˜Kšœ"žœ˜)—K˜ Kšœ˜K˜—Kšœžœžœžœ˜=K˜šŸœžœžœ˜(K˜KšŸ œžœžœžœ˜>K˜Kšžœžœžœ˜,Kšžœžœžœžœ ˜,Kšžœžœžœžœ˜3Kšžœžœžœžœ˜;Kšžœžœžœžœ˜7Kšžœžœžœžœ˜?Kšžœžœ5žœ˜OK˜K˜ Kšœ˜K˜——šœ3™3K˜šŸœžœžœžœ˜2Kšžœ$žœž˜4šžœž˜#Kšœžœ˜1—KšžœC˜GKšžœ˜K˜—šŸœžœžœžœ˜$Kšœ0žœžœ˜@KšœD™DKšžœ žœžœ˜2Kšžœžœ!˜6Kšœ*žœ˜/Kšœ˜K˜—Kšžœ˜K˜——…—Ò­