-- Copyright (C) 1981, 1984, 1985 by Xerox Corporation. All rights reserved.
-- IFSFileControl.mesa, HGM, 16-Sep-85 19:35:42
-- Last edited by Gobbel: 27-Jul-81 19:55:35
-- Last edited by Levin: 1-Jul-81 16:43:27
-- Hankins 25-Jul-84 13:42:58 Klamath update (LOOHOLEs)
DIRECTORY
FileDefs USING [Operations, OperationsRecord],
Heap USING [systemZone],
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],
Storage USING [StringLength],
String USING [WordsForString],
VMDefs USING [Problem, UnableToLogin];
IFSFileControl: MONITOR
IMPORTS
Heap, IFSFilePrivate, LogDefs, PupDefs, Sequin, Storage, String, VMDefs
EXPORTS FileDefs, IFSFilePrivate =
BEGIN OPEN IFSFilePrivate;
-- Global Variables --
loginCount: CARDINAL;
ifsOps: FileDefs.Operations;
-- Miscellaneous --
someWordsForFilename: CARDINAL = 15;
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
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 ← Heap.systemZone.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]]];
RETURN[ifsOps]
END;
FinalizeIFS: PUBLIC PROCEDURE =
BEGIN
IF loginCount # 0 THEN ERROR InsufficientLogouts;
Heap.systemZone.FREE[@ifsOps];
FinalizeFreeList[];
END;
-- Variables Exported to IFSFilePrivate --
ifsFiles: PUBLIC CARDINAL;
-- Internal Procedures --
Login: PROCEDURE [
server, userName, password, secondaryName, secondaryPassword: LONG STRING ← NIL]
RETURNS [fs: FSInstance] =
BEGIN
serverAddr: PupDefs.PupAddress ← [net:, host:, socket: Leaf.leafSocket];
TryForConnection: PROCEDURE =
BEGIN
LeafStringWords: PROCEDURE [s: LONG STRING] RETURNS [CARDINAL] = {
RETURN[String.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;
[] ← PupDefs.PupPackageMake[];
PupDefs.GetPupAddress[
@serverAddr, server !
PupDefs.PupNameTrouble =>
ERROR VMDefs.UnableToLogin[
SELECT code FROM noRoute, noResponse => io, ENDCASE => other]];
TryForConnection[];
fs ← Heap.systemZone.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 Heap.systemZone.FREE[@fs.primaryName];
IF fs.primaryPassword # NIL THEN Heap.systemZone.FREE[@fs.primaryPassword];
IF fs.secondaryName # NIL THEN Heap.systemZone.FREE[@fs.secondaryName];
IF fs.secondaryPassword # NIL THEN Heap.systemZone.FREE[@fs.secondaryPassword];
Heap.systemZone.FREE[@fs];
PupDefs.PupPackageDestroy[];
NoteLogout[];
END;
Checkpoint: PROCEDURE [fs: FSInstance] = {NULL};
Abort: PROCEDURE [fs: FSInstance] = {NULL};
END.