DIRECTORY CWF: TYPE USING [SWF1, WF0, WF1, WF2, WFCR], DCSFileTypes: TYPE USING [tLeaderPage], Directory: TYPE USING [CreateFile, Error, GetProps, Handle, ignore, Lookup], Environment: TYPE USING [bytesPerPage, wordsPerPage], File: TYPE USING [Capability, SetSize], FileStream: TYPE USING [Create, SetLeaderPropertiesForCapability, SetLength], IFSFile: TYPE USING [AccessFailure, CantOpen, Close, Completer, Error, FileHandle, FSInstance, GetLength, GetTimes, Initialize, Login, Logout, Open, OpenOptions, Problem, SetCreation, SetLength, StartRead, StartWrite, UnableToLogin], Inline: TYPE USING [LowHalf], LeafSubr: TYPE USING [], LongString: TYPE USING [EquivalentString], Space: TYPE USING [CopyIn, CopyOut, Create, Delete, GetAttributes, Handle, Kill, LongPointer, Map, nullHandle, virtualMemory], Stream: TYPE USING [Delete, Handle], Subr: TYPE USING [AbortMyself, AllocateString, Any, CopyString, FileError, FreeString, GetNameandPassword, LongZone, Prefix, TTYProcs], UserCredentialsUnsafe: TYPE USING[GetUserCredentials]; LeafSubrImpl: MONITOR IMPORTS CWF, Directory, File, FileStream, IFSFile, Inline, LongString, Space, Stream, Subr, UserCredentialsUnsafe EXPORTS LeafSubr = { connseq: LONG POINTER TO ConnSeqRecord _ NIL; MAXCONNS: CARDINAL = 8; ConnSeqRecord: TYPE = RECORD[ user2: LONG STRING _ NIL, -- connect name password2: LONG STRING _ NIL, -- connect password size: CARDINAL _ 0, -- # of connections body: SEQUENCE maxsize: CARDINAL OF ConnTable ]; ConnTable: TYPE = RECORD[ fsinstance: IFSFile.FSInstance _ NIL, host: LONG STRING _ NIL ]; Open: PUBLIC PROC [host, sfn: LONG STRING, h: Subr.TTYProcs, openOptions: IFSFile.OpenOptions] RETURNS[fh: IFSFile.FileHandle] = { fsinstance: IFSFile.FSInstance _ Connect[host,h, NIL, NIL, NIL, NIL]; fh _ IFSFile.Open[fsinstance, sfn, openOptions ! IFSFile.CantOpen => SELECT reason FROM ok => NULL -- can't happen -- ; io, alreadyExists, other => ERROR IFSFile.CantOpen[reason]; accessDenied, accessConflict => { SetOtherPass[h, "access Denied or Conflict"L]; fsinstance _ ForceClosed[fsinstance]; fsinstance _ Connect[host, h, NIL, NIL, connseq.user2, connseq.password2]; RETRY; }; notFound, illegalFileName => ERROR Subr.FileError[notFound]; ENDCASE => ERROR ]; }; RemoteMap: PUBLIC PROC[space: Space.Handle, fh: IFSFile.FileHandle, base: CARDINAL] = { problem: IFSFile.Problem; notready: BOOL; finished: CONDITION _ [timeout: 0]; DoRead: ENTRY PROC [bytebase: LONG CARDINAL, bytesize: CARDINAL, buffer: LONG POINTER] = { notready _ TRUE; IFSFile.StartRead[fh, bytebase, bytesize, buffer, CallProc, 0]; WHILE notready DO WAIT finished; ENDLOOP; SELECT problem FROM ok => NULL; io, resources, other, credentials => RETURN WITH ERROR IFSFile.Error[problem]; ENDCASE => ERROR; }; CallProc: ENTRY IFSFile.Completer = { problem _ outcome; notready _ FALSE; NOTIFY finished; }; { bytebase: LONG CARDINAL _ base*Environment.bytesPerPage; buffer: LONG POINTER _ Space.LongPointer[space]; filelength: LONG CARDINAL _ IFSFile.GetLength[fh]; pagesize: CARDINAL; bytesize: LONG CARDINAL; Space.Map[space]; [size: pagesize] _ Space.GetAttributes[space]; bytesize _ LONG[pagesize] * Environment.bytesPerPage; IF bytebase + bytesize > filelength THEN { IF filelength >= bytebase THEN bytesize _ filelength - bytebase ELSE ERROR; -- base is a page number bigger than the file }; WHILE bytesize > 0 DO thisTimeSize: CARDINAL = Inline.LowHalf[MIN[bytesize, LONG[63*512]]]; DoRead[bytebase, thisTimeSize, buffer]; bytesize _ bytesize - thisTimeSize; bytebase _ bytebase + thisTimeSize; buffer _ buffer + (thisTimeSize/2); ENDLOOP; }}; NPages: CARDINAL = 4; NBytes: CARDINAL = NPages * Environment.bytesPerPage; BytesAtATime: PROC[len: LONG CARDINAL] RETURNS[nb: CARDINAL] = INLINE { RETURN[IF len > NBytes THEN NBytes ELSE Inline.LowHalf[len]]; }; RemoteCopy: PUBLIC PROC[fromHost, fromFilename, toHost, toFilename: LONG STRING, h: Subr.TTYProcs] RETURNS[length: LONG CARDINAL] = { createtime, len: LONG CARDINAL; fhRead, fhWrite: IFSFile.FileHandle _ NIL; buffer: ARRAY[0 .. NPages*Environment.wordsPerPage) OF WORD; base: CARDINAL _ 0; problem: IFSFile.Problem; notready: BOOL; finished: CONDITION _ [timeout: 0]; { ENABLE UNWIND => { IF fhRead ~= NIL THEN IFSFile.Close[fhRead]; fhRead _ NIL; IF fhWrite ~= NIL THEN IFSFile.Close[fhWrite]; fhWrite _ NIL; }; DoRead: ENTRY PROC = { notready _ TRUE; IFSFile.StartRead[fhRead, base*Environment.bytesPerPage, BytesAtATime[len], @buffer, CallProc, 0]; WHILE notready DO WAIT finished; ENDLOOP; SELECT problem FROM ok => NULL; io, resources, other, credentials => RETURN WITH ERROR IFSFile.Error[problem]; ENDCASE => ERROR; }; DoWrite: ENTRY PROC = { notready _ TRUE; IFSFile.StartWrite[fhWrite, base*Environment.bytesPerPage, BytesAtATime[len], @buffer, CallProc, 0]; WHILE notready DO WAIT finished; ENDLOOP; SELECT problem FROM ok => NULL; io, resources, other, credentials => RETURN WITH ERROR IFSFile.Error[problem]; ENDCASE => ERROR; }; CallProc: ENTRY IFSFile.Completer = { problem _ outcome; notready _ FALSE; NOTIFY finished; }; fhRead _ Open[fromHost, fromFilename, h, oldReadOnly]; fhWrite _ Open[toHost, toFilename, h, new]; [create: createtime] _ IFSFile.GetTimes[fhRead]; length _ len _ IFSFile.GetLength[fhRead]; IFSFile.SetLength[fhWrite, length]; WHILE len > 0 DO DoRead[]; DoWrite[]; len _ len - BytesAtATime[len]; base _ base + NPages; ENDLOOP; IFSFile.SetCreation[fhWrite, createtime]; IFSFile.Close[fhRead]; fhRead _ NIL; IFSFile.Close[fhWrite]; fhWrite _ NIL; }}; Retrieve: PUBLIC PROC[remoteHost, remoteFilename, localFilename: LONG STRING, h: Subr.TTYProcs] RETURNS[length: LONG CARDINAL, cap: File.Capability] = { npages, base: CARDINAL; buffer: LONG POINTER; len, create, read, write: LONG CARDINAL; sh: Stream.Handle _ NIL; fh: IFSFile.FileHandle _ NIL; space: Space.Handle _ Space.nullHandle; problem: IFSFile.Problem; notready: BOOL; finished: CONDITION _ [timeout: 0]; DoReadAndWrite: ENTRY PROC = { base _ 0; WHILE len > 0 DO notready _ TRUE; IFSFile.StartRead[fh, base*Environment.bytesPerPage, BytesAtATime[len], buffer, CallProc, 0]; WHILE notready DO WAIT finished; ENDLOOP; SELECT problem FROM ok => NULL; io, resources, other, credentials => RETURN WITH ERROR IFSFile.Error[problem]; ENDCASE => ERROR; Space.CopyOut[space, [cap, base+1]]; base _ base + NPages; len _ len - BytesAtATime[len]; Space.Kill[space]; ENDLOOP; }; CallProc: ENTRY IFSFile.Completer = { problem _ outcome; notready _ FALSE; NOTIFY finished; }; {ENABLE UNWIND => { IF sh ~= NIL THEN Stream.Delete[sh]; sh _ NIL; IF space ~= Space.nullHandle THEN Space.Delete[space]; space _ Space.nullHandle; IF fh ~= NIL THEN IFSFile.Close[fh]; fh _ NIL; }; fh _ Open[remoteHost, remoteFilename, h, oldReadOnly]; len _ length _ IFSFile.GetLength[fh]; npages _ Inline.LowHalf[length/Environment.bytesPerPage] + 2; cap _ Directory.CreateFile[localFilename, DCSFileTypes.tLeaderPage, npages ! Directory.Error => { IF type = fileAlreadyExists THEN { cap _ Directory.Lookup[fileName: localFilename, permissions: Directory.ignore]; File.SetSize[cap, npages]; } ELSE ERROR Subr.FileError[notFound]; CONTINUE }]; space _ Space.Create[NPages, Space.virtualMemory]; buffer _ Space.LongPointer[space]; Space.Map[space]; DoReadAndWrite[]; Space.Delete[space]; space _ Space.nullHandle; [read, write, create] _ IFSFile.GetTimes[fh]; sh _ FileStream.Create[cap]; FileStream.SetLength[sh, length]; FileStream.SetLeaderPropertiesForCapability[cap: cap, create: LOOPHOLE[create], write: LOOPHOLE[write], read: LOOPHOLE[read]]; Stream.Delete[sh]; sh _ NIL; IFSFile.Close[fh]; fh _ NIL; }}; Store: PUBLIC PROC[localFilename, remoteHost, remoteFilename: LONG STRING, h: Subr.TTYProcs] RETURNS[length: LONG CARDINAL] = { base: CARDINAL; buffer: LONG POINTER; len, create: LONG CARDINAL; fh: IFSFile.FileHandle _ NIL; space: Space.Handle _ Space.nullHandle; problem: IFSFile.Problem; notready: BOOL; finished: CONDITION _ [timeout: 0]; cap: File.Capability; directoryfilename: LONG STRING _ Subr.AllocateString[100]; DoReadAndWrite: ENTRY PROC = { base _ 0; WHILE len > 0 DO notready _ TRUE; Space.CopyIn[space, [cap, base+1]]; IFSFile.StartWrite[fh, base*Environment.bytesPerPage, BytesAtATime[len], buffer, CallProc, 0]; WHILE notready DO WAIT finished; ENDLOOP; SELECT problem FROM ok => NULL; io, resources, other, credentials => RETURN WITH ERROR IFSFile.Error[problem]; ENDCASE => ERROR; base _ base + NPages; len _ len - BytesAtATime[len]; Space.Kill[space]; ENDLOOP; }; CallProc: ENTRY IFSFile.Completer = { problem _ outcome; notready _ FALSE; NOTIFY finished; }; {ENABLE UNWIND => { IF space ~= Space.nullHandle THEN Space.Delete[space]; space _ Space.nullHandle; IF fh ~= NIL THEN IFSFile.Close[fh]; fh _ NIL; Subr.FreeString[directoryfilename]; }; fh _ Open[remoteHost, remoteFilename, h, new]; space _ Space.Create[NPages, Space.virtualMemory]; buffer _ Space.LongPointer[space]; Space.Map[space]; cap _ Directory.Lookup[fileName: localFilename, permissions: Directory.ignore]; [byteLength: length, createDate: create] _ Directory.GetProps[cap, directoryfilename]; len _ length; IFSFile.SetLength[fh, length]; DoReadAndWrite[]; Space.Delete[space]; space _ Space.nullHandle; IFSFile.SetCreation[fh, create]; IFSFile.Close[fh]; fh _ NIL; }; Subr.FreeString[directoryfilename]; }; PrintLeafProblem: PUBLIC PROC[problem: IFSFile.Problem] = { CWF.WF2["Leaf Error: %s, #%u in IFSFile.Problem.\n"L, (SELECT problem FROM ok => "ok"L, io => "io"L, resources => "resources"L, credentials => "credentials"L, illegalIO => "illegalIO"L, other => "other"L, ENDCASE => ERROR), @problem]; }; PrintLeafAccessFailure: PUBLIC PROC[reason: IFSFile.AccessFailure] = { CWF.WF2["Leaf Error: %s, #%u in IFSFile.AccessFailure.\n"L, (SELECT reason FROM ok => "ok"L, io => "io"L, notFound => "notFound"L, alreadyExists => "alreadyExists"L, accessDenied => "accessDenied"L, accessConflict => "accessConflict"L, illegalFileName => "illegalFileName"L, other => "other"L, ENDCASE => ERROR), @reason]; }; SetOtherPass: PROC[h: Subr.TTYProcs, error: STRING] = { CheckStarted[]; CWF.WF1["Error '%s'\nEnter Connect "L, error]; Subr.GetNameandPassword[connect, connseq.user2, connseq.password2, h]; IF connseq.user2.length = 0 AND connseq.password2.length = 0 THEN { IF h.Confirm[h.in, h.out, h.data, "\nType y to retry with different login name, n to abort ", 'n] = 'n THEN { CWF.WF0["No.\n"L]; SIGNAL Subr.AbortMyself; }; CWF.WF0["Yes.\nEnter "L]; Subr.GetNameandPassword[login, NIL, NIL, h]; CWF.WFCR[]; }; }; Connect: PROC[host: LONG STRING, h: Subr.TTYProcs, defaultUsername, defaultPassword, secondaryName, secondaryPassword: LONG STRING] RETURNS[IFSFile.FSInstance] = { StartLeaf[]; FOR i: CARDINAL IN [0..connseq.size) DO IF connseq[i].host ~= NIL AND LongString.EquivalentString[host, connseq[i].host] THEN RETURN[connseq[i].fsinstance]; ENDLOOP; connseq[connseq.size].fsinstance _ MakeFSInstance[host, h, defaultUsername, defaultPassword, secondaryName, secondaryPassword]; connseq[connseq.size].host _ Subr.CopyString[host]; IF connseq.size >= connseq.maxsize THEN { CWF.WF0["Error - to many conns\n"L]; RETURN[NIL]; }; connseq.size _ connseq.size + 1; RETURN[connseq[connseq.size-1].fsinstance]; }; ForceClosed: PROC[fsinstance: IFSFile.FSInstance] RETURNS[IFSFile.FSInstance] = { FOR i: CARDINAL IN [0 .. connseq.size) DO IF fsinstance = connseq[i].fsinstance THEN CloseAndFree[i]; ENDLOOP; RETURN[NIL]; }; CloseAndFree: PROC[i: CARDINAL] = { CWF.WF1["Closing Leaf connection to %s ... "L, connseq[i].host]; IFSFile.Logout[connseq[i].fsinstance]; CWF.WF0["closed.\n"L]; Subr.FreeString[connseq[i].host]; connseq[i].host _ NIL; connseq[i].fsinstance _ NIL; }; MakeFSInstance: PROC[host: LONG STRING, h: Subr.TTYProcs, defaultUsername, defaultPassword, secondaryName, secondaryPassword: LONG STRING] RETURNS[fsinstance: IFSFile.FSInstance] = { IF host = NIL THEN { CWF.WF0["Error: remote host has not been specified.\n"L]; RETURN[NIL]; }; CWF.WF1["Opening Leaf connection to %s.\n"L, host]; IF defaultUsername ~= NIL THEN { fsinstance _ IFSFile.Login[host, defaultUsername, defaultPassword, secondaryName, secondaryPassword ! IFSFile.UnableToLogin => IF reason = credentials THEN GOTO normal; ]; RETURN[fsinstance]; }; GOTO normal; EXITS normal => { n: LONG STRING _ Subr.AllocateString[50]; p: LONG STRING _ Subr.AllocateString[50]; {ENABLE UNWIND => {Subr.FreeString[n]; Subr.FreeString[p]}; AddUserName[NIL, NIL, h]; UserCredentialsUnsafe.GetUserCredentials[name: n, password: p]; fsinstance _ IFSFile.Login[ host, n, p, secondaryName, secondaryPassword ! IFSFile.UnableToLogin => IF reason = credentials THEN {SetPass[h, NIL]; RETRY} ]; }; -- of ENABLE UNWIND Subr.FreeString[n]; Subr.FreeString[p]; }; }; SetPass: PROC[h: Subr.TTYProcs, error: LONG STRING] = { CheckStarted[]; IF error ~= NIL THEN CWF.WF1["Error '%s'\n"L,error]; CWF.WF0["Enter "L]; Subr.GetNameandPassword[login, NIL, NIL, h]; CWF.WFCR[]; }; AddUserName: PROC[sto: LONG STRING, spat: STRING, h: Subr.TTYProcs] = { u: LONG STRING _ Subr.AllocateString[50]; p: LONG STRING _ Subr.AllocateString[50]; lengthzero: BOOL; {ENABLE UNWIND => {Subr.FreeString[u]; Subr.FreeString[p]}; UserCredentialsUnsafe.GetUserCredentials[name: NIL, password: p]; lengthzero _ p = NIL OR p.length = 0; DO UserCredentialsUnsafe.GetUserCredentials[name: u, password: NIL]; IF u = NIL OR u.length = 0 OR Subr.Any[u,' ] OR Subr.Prefix[u, "CedarUser"L] OR lengthzero THEN { lengthzero _ FALSE; CWF.WF0["Enter "L]; Subr.GetNameandPassword[login, NIL, NIL, h]; CWF.WFCR[]; } ELSE EXIT; ENDLOOP; IF sto ~= NIL THEN CWF.SWF1[sto,spat,u]; }; -- of ENABLE UNWIND Subr.FreeString[u]; Subr.FreeString[p]; }; StartLeaf: PROC = { longzone: UNCOUNTED ZONE; IF connseq ~= NIL THEN RETURN; longzone _ Subr.LongZone[]; connseq _ longzone.NEW[ConnSeqRecord[MAXCONNS]]; connseq.user2 _ Subr.AllocateString[50]; connseq.password2 _ Subr.AllocateString[50]; }; StopLeaf: PUBLIC PROC = { ENABLE UNWIND => connseq _ NIL; longzone: UNCOUNTED ZONE; IF connseq = NIL THEN RETURN; longzone _ Subr.LongZone[]; FOR i: CARDINAL IN [0..connseq.size) DO IF connseq[i].fsinstance ~= NIL THEN CloseAndFree[i]; ENDLOOP; Subr.FreeString[connseq.user2]; Subr.FreeString[connseq.password2]; longzone.FREE[@connseq]; }; CheckStarted: PROC = { IF connseq = NIL THEN ERROR; }; IFSFile.Initialize[]; }. ´LeafSubrImpl.Mesa last edit December 30, 1982 2:11 pm last edit May 23, 1983 3:21 pm, Russ Atkinson MDS USAGE !!! endof MDS USAGE !!! connection table we use the username and password from Profile.userName, userPassword base is # of page to start mapping on; note that here, base = 0 is the first page of data whereas in Pilot base = 1 is the first page; space may have arbitrary size (> 64k words) leaf can handle up to 64K in the protocol the existing leaf servers can only handle up to 32K because of bugs by convention, if username and password are both 0 length, then we just abort the program always returns NIL u _ NameAndPasswordOps.userName; never called IFSFile.Finalize[]; Ê˘šœ™Jšœ#™#Jšœ-™-—J˜šÏk ˜ Jšœœœœ˜,Jšœœœ˜'Jšœ œœ7˜LJšœ œœ˜5Jšœœœ˜'Jšœ œœ7˜Mšœ œœ4˜GJ˜HJ˜?J˜—Jšœœœ ˜Jšœ œœ˜Jšœ œœ˜*šœœœ@˜QJ˜-—Jšœœœ˜$šœœœ;˜KJ˜<—Jšœœœ˜6J˜—šœ˜š˜Jšœf˜i—Jšœ ˜—J˜šœ ™ Jš œ œœœœ˜-Jšœ™—J˜šœ™Jšœœ˜JšœD™Dšœœœ˜JšœœœœÏc˜)Jšœ œœœž˜1Jšœœž˜'Jšœœ œœ ˜-J˜—šœ œœ˜Jšœ!œ˜%Jšœœœœ˜J˜—J˜—šÏnœœ˜Jšœ œœ6˜MJšœ˜#Jš œ1œœœœ˜E˜.˜šœ˜Jšœœžœ˜Jšœœ˜;˜!J˜.J˜%Jšœœœ$˜JJšœ˜J˜—Jšœœ˜