IFSFileImplA.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Levin - 13-Oct-81 9:09:48
Russ Atkinson, March 7, 1985 3:02:46 pm PST
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;
Global Variables
loginCount: CARDINAL;
Miscellaneous
someWordsForFilename: CARDINAL = 15;
FilesInUse: ERROR = CODE;
InsufficientLogouts: ERROR = CODE;
PupBuffersTooSmall: ERROR = CODE;
ServerNameMissing: ERROR = CODE;
TooManyLogouts: ERROR = CODE;
Procedures and Types Exported to IFSFile
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: ROPENIL] 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};
{
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.
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[];
};
Procedures and Variables Exported to IFSFilePrivate
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: BOOLTRUE] = {
we cache the newest one to minimize the chance of subsequent timeout
IF ~toCache THEN {Sequin.Destroy[sequin]; RETURN};
IF fs.haveSequin THEN Sequin.Destroy[fs.cachedSequin];
fs.cachedSequin ← sequin; fs.haveSequin ← TRUE;
};
}.