-- File: IFSFileControl.mesa -- Last edited by Levin: 1-Jul-81 16:43:27 DIRECTORY FileDefs USING [Operations, OperationsRecord], FrameDefs USING [IsBound], IFSFilePrivate USING [ Abandon, Close, CopyString, Destroy, Extend, FinalizeFreeList, FSInstance, FSObject, GetLength, GetTimes, InitializeFreeList, Open, SetCreationTime, SetLength, StartRead, StartWrite, Truncate], Leaf USING [ Answer, AnswerObject, LeafOp, leafSocket, paramsOp, ptLeaf, Request, RequestObject], LogDefs USING [DisplayNumber], PupDefs USING [ GetPupAddress, PupAddress, PupNameTrouble, PupPackageDestroy, PupPackageMake], Sequin USING [ Broken, Buffer, Create, Destroy, Get, GetEmptyBuffer, Handle, Put, ReleaseBuffer, SetZone], Storage USING [StringLength], StringDefs USING [WordsForString], VMDefs USING [Problem, UnableToLogin], VMStorage USING [longTerm, shortTerm]; IFSFileControl: MONITOR IMPORTS FrameDefs, IFSFilePrivate, LogDefs, PupDefs, Sequin, Storage, StringDefs, VMDefs, VMStorage EXPORTS FileDefs, IFSFilePrivate = BEGIN OPEN IFSFilePrivate; -- Global Variables -- loginCount: CARDINAL; ifsOps: FileDefs.Operations; oldZone: MDSZone; -- Miscellaneous -- someWordsForFilename: CARDINAL = 15; CantCommunicateByTelepathy: ERROR = CODE; FilesInUse: ERROR = CODE; InsufficientLogouts: ERROR = CODE; PupBuffersTooSmall: ERROR = CODE; ServerNameMissing: ERROR = CODE; TooManyLogouts: ERROR = CODE; -- Types Exported to FileDefs -- -- Unfortunately, the compiler doesn't support this just yet -- FSInstance: PUBLIC TYPE = IFSFilePrivate.FSInstance; -- Procedures Exported to FileDefs -- InitializeIFS: PUBLIC PROCEDURE RETURNS [ops: FileDefs.Operations] = BEGIN IF (loggingEnabled ← FrameDefs.IsBound[LogDefs.DisplayNumber]) THEN {ifsFiles ← 0; LogDefs.DisplayNumber["Open IFS Files"L, [short[@ifsFiles]]]}; loginCount ← 0; InitializeFreeList[]; -- the LOOPHOLEs below get around non-support for multiple implementors of an -- exported type. ifsOps ← VMStorage.longTerm.NEW[FileDefs.OperationsRecord ← [ login: LOOPHOLE[Login], logout: LOOPHOLE[Logout], checkpoint: LOOPHOLE[Checkpoint], abort: LOOPHOLE[Abort], open: LOOPHOLE[Open], close: LOOPHOLE[Close], abandon: LOOPHOLE[Abandon], destroy: LOOPHOLE[Destroy], getLength: LOOPHOLE[GetLength], setLength: LOOPHOLE[SetLength], extend: LOOPHOLE[Extend], truncate: LOOPHOLE[Truncate], startRead: LOOPHOLE[StartRead], startWrite: LOOPHOLE[StartWrite], getTimes: LOOPHOLE[GetTimes], setCreation: LOOPHOLE[SetCreationTime]]]; oldZone ← Sequin.SetZone[VMStorage.shortTerm]; RETURN[ifsOps] END; FinalizeIFS: PUBLIC PROCEDURE = BEGIN IF loginCount ~= 0 THEN ERROR InsufficientLogouts; VMStorage.longTerm.FREE[@ifsOps]; FinalizeFreeList[]; [] ← Sequin.SetZone[oldZone]; END; -- Variables Exported to IFSFilePrivate -- loggingEnabled: PUBLIC BOOLEAN; ifsFiles: PUBLIC CARDINAL; -- Internal Procedures -- Login: PROCEDURE [ server, userName, password, secondaryName, secondaryPassword: STRING ← NIL] RETURNS [fs: FSInstance] = BEGIN serverAddr: PupDefs.PupAddress ← [net: , host: , socket: Leaf.leafSocket]; TryForConnection: PROCEDURE = BEGIN LeafStringWords: PROCEDURE [s: STRING] RETURNS [CARDINAL] = {RETURN[StringDefs.WordsForString[Storage.StringLength[s]] - 1]}; 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: VMDefs.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: 2*60/5, connectionTimeout: 10*60/5]]; buffer.nBytes ← Leaf.paramsOp.length; BEGIN 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 VMDefs.UnableToLogin[problem]}; END; Sequin.Destroy[sequin]; END; NoteLogin: ENTRY PROCEDURE = INLINE {loginCount ← loginCount + 1}; IF server= NIL OR server.length = 0 THEN ERROR ServerNameMissing; IF FrameDefs.IsBound[PupDefs.PupPackageMake] THEN PupDefs.PupPackageMake[] ELSE ERROR CantCommunicateByTelepathy; PupDefs.GetPupAddress[@serverAddr, server ! PupDefs.PupNameTrouble => ERROR VMDefs.UnableToLogin[ SELECT code FROM noRoute, noResponse => io, ENDCASE => other]]; TryForConnection[]; fs ← VMStorage.shortTerm.NEW[FSObject ← [ primaryName: CopyString[userName], primaryPassword: CopyString[password], secondaryName: CopyString[secondaryName], secondaryPassword: CopyString[secondaryPassword], serverAddr: serverAddr]]; NoteLogin[]; END; Logout: PROCEDURE [fs: FSInstance] = BEGIN NoteLogout: ENTRY PROCEDURE = INLINE {loginCount ← loginCount - 1}; IF loginCount = 0 THEN ERROR TooManyLogouts; IF fs.fileList ~= NIL THEN ERROR FilesInUse; IF fs.primaryName ~= NIL THEN VMStorage.shortTerm.FREE[@fs.primaryName]; IF fs.primaryPassword ~= NIL THEN VMStorage.shortTerm.FREE[@fs.primaryPassword]; IF fs.secondaryName ~= NIL THEN VMStorage.shortTerm.FREE[@fs.secondaryName]; IF fs.secondaryPassword ~= NIL THEN VMStorage.shortTerm.FREE[@fs.secondaryPassword]; VMStorage.shortTerm.FREE[@fs]; PupDefs.PupPackageDestroy[]; NoteLogout[]; END; Checkpoint: PROCEDURE [fs: FSInstance] = {NULL}; Abort: PROCEDURE [fs: FSInstance] = {NULL}; END.