DIRECTORY BasicTime USING [earliestGMT, GMT, Now, Period], FS USING [Error, ErrorDesc, FileType], FSBackdoor USING [ErrorCode, ProduceError, Version], FSPseudoServers USING [AvoidRemoteCheck, TranslateForRead, TranslateForWrite], FSRemoteFileExtras USING [ConfirmProc, ConfirmRetrieveProc, GetServerProc, InfoProc, NameProc, ServerHandle, ServerObject, ServerProcs, ServerProcsObject, SweepProc, ValidateProc], IO USING [STREAM], Process USING [Abort, CheckForAbort, Detach, EnableAborts, MsecToTicks, PauseMsec, SetTimeout], Rope USING [Cat, Flatten, Length, Match, ROPE], SymTab USING [Create, Delete, EachPairAction, Fetch, Pairs, Ref, Store] ; FSRemoteFileExtrasImpl: CEDAR MONITOR IMPORTS BasicTime, FS, FSBackdoor, FSPseudoServers, Process, Rope, SymTab EXPORTS FSRemoteFileExtras ~{ ConfirmProc: TYPE ~ FSRemoteFileExtras.ConfirmProc; ConfirmRetrieveProc: TYPE ~ FSRemoteFileExtras.ConfirmRetrieveProc; FileType: TYPE ~ FS.FileType; GetServerProc: TYPE ~ FSRemoteFileExtras.GetServerProc; GMT: TYPE ~ BasicTime.GMT; InfoProc: TYPE ~ FSRemoteFileExtras.InfoProc; NameProc: TYPE ~ FSRemoteFileExtras.NameProc; ROPE: TYPE ~ Rope.ROPE; ServerHandle: TYPE ~ FSRemoteFileExtras.ServerHandle; Version: TYPE ~ FSBackdoor.Version; msecBetweenSweeps: CARD _ 60000; nonexistentServerTTL: CARD _ 300; waitForServerTimeout: CARD _ 20000; Delete: PUBLIC PROC [server, file: ROPE, wantedCreatedTime: GMT, proc: ConfirmProc] ~ { uServer: ROPE _ UnbracketServer[server]; h: ServerHandle _ GetServer[FSPseudoServers.TranslateForWrite[uServer]]; h.procs.delete[h, file, wantedCreatedTime, proc]; }; EnumerateForInfo: PUBLIC PROC [server, pattern: ROPE, proc: InfoProc] ~ { uServer: ROPE _ UnbracketServer[server]; servers: LIST OF ROPE _ FSPseudoServers.TranslateForRead[uServer]; replicated: BOOL = FSPseudoServers.AvoidRemoteCheck[server]; gotOne: BOOL _ FALSE; savedErrorDesc: FS.ErrorDesc; procInner: InfoProc ~ { gotOne _ TRUE; Process.CheckForAbort[]; RETURN [proc[fullFName, attachedTo, created, bytes, keep, fileType]]; }; FOR each: LIST OF ROPE _ servers, each.rest WHILE (each # NIL) DO ENABLE FS.Error => { IF gotOne OR ((error.code = $unknownFile) AND replicated) THEN REJECT; IF each = servers THEN savedErrorDesc _ error; LOOP; }; h: ServerHandle _ GetServer[each.first]; h.procs.enumerateForInfo[h, pattern, procInner]; IF gotOne OR replicated THEN RETURN; ENDLOOP; IF savedErrorDesc.code # NIL THEN ERROR FS.Error[savedErrorDesc]; }; EnumerateForNames: PUBLIC PROC [server, pattern: ROPE, proc: NameProc] ~ { uServer: ROPE _ UnbracketServer[server]; servers: LIST OF ROPE _ FSPseudoServers.TranslateForRead[uServer]; replicated: BOOL = FSPseudoServers.AvoidRemoteCheck[server]; gotOne: BOOL _ FALSE; savedErrorDesc: FS.ErrorDesc; procInner: NameProc ~ { gotOne _ TRUE; Process.CheckForAbort[]; RETURN [proc[fullFName]]; }; FOR each: LIST OF ROPE _ servers, each.rest WHILE (each # NIL) DO ENABLE FS.Error => { IF gotOne OR ((error.code = $unknownFile) AND replicated) THEN REJECT; IF each = servers THEN savedErrorDesc _ error; LOOP; }; h: ServerHandle _ GetServer[each.first]; h.procs.enumerateForNames[h, pattern, procInner]; IF gotOne OR replicated THEN RETURN; ENDLOOP; IF savedErrorDesc.code # NIL THEN ERROR FS.Error[savedErrorDesc]; }; Info: PUBLIC PROC [server, file: ROPE, wantedCreatedTime: GMT] RETURNS [version: Version, bytes: INT, created: GMT, fileType: FileType] ~ { uServer: ROPE _ UnbracketServer[server]; servers: LIST OF ROPE _ FSPseudoServers.TranslateForRead[uServer]; replicated: BOOL = FSPseudoServers.AvoidRemoteCheck[server]; savedErrorDesc: FS.ErrorDesc; FOR each: LIST OF ROPE _ servers, each.rest WHILE (each # NIL) DO ENABLE FS.Error => { IF (error.code = $unknownFile) AND replicated THEN REJECT; IF each = servers THEN savedErrorDesc _ error; LOOP; }; h: ServerHandle _ GetServer[each.first]; [version, bytes, created, fileType] _ h.procs.getInfo[h, file, wantedCreatedTime]; RETURN; ENDLOOP; ERROR FS.Error[savedErrorDesc]; }; Rename: PUBLIC PROC [server, fromFile: ROPE, fromCreated: GMT, toFile: ROPE, proc: ConfirmProc] ~ { uServer: ROPE _ UnbracketServer[server]; h: ServerHandle _ GetServer[FSPseudoServers.TranslateForWrite[uServer]]; h.procs.rename[h, fromFile, fromCreated, toFile, proc]; }; Retrieve: PUBLIC PROC [server, file: ROPE, wantedCreatedTime: GMT, proc: ConfirmRetrieveProc, checkFileType: BOOL, fileType: FileType] ~ { uServer: ROPE _ UnbracketServer[server]; servers: LIST OF ROPE _ FSPseudoServers.TranslateForRead[uServer]; replicated: BOOL = FSPseudoServers.AvoidRemoteCheck[server]; savedErrorDesc: FS.ErrorDesc; FOR each: LIST OF ROPE _ servers, each.rest WHILE (each # NIL) DO ENABLE FS.Error => { IF (error.code = $unknownFile) AND replicated THEN REJECT; IF each = servers THEN savedErrorDesc _ error; LOOP; }; h: ServerHandle _ GetServer[each.first]; h.procs.retrieve[h, file, wantedCreatedTime, proc, checkFileType, fileType]; RETURN; ENDLOOP; ERROR FS.Error[savedErrorDesc]; }; Store: PUBLIC PROC [server, file: ROPE, str: IO.STREAM, created: GMT, proc: ConfirmProc] ~ { uServer: ROPE _ UnbracketServer[server]; h: ServerHandle _ GetServer[FSPseudoServers.TranslateForWrite[uServer]]; h.procs.store[h, file, str, created, proc]; }; Registration: TYPE ~ REF RegistrationObject; RegistrationObject: TYPE ~ RECORD [ next: Registration, flavor: ATOM, getServer: GetServerProc ]; registrations: Registration _ NIL; Register: PUBLIC ENTRY PROC [flavor: ATOM, getServer: GetServerProc] ~ { p, prev: Registration; FOR p _ registrations, p.next DO IF p.flavor = flavor THEN { IF prev = NIL THEN registrations _ p.next ELSE prev.next _ p.next; EXIT; }; prev _ p; ENDLOOP; IF getServer # NIL THEN registrations _ NEW[RegistrationObject _ [registrations, flavor, getServer]]; }; serverTab: SymTab.Ref _ SymTab.Create[]; lastSweepTime: BasicTime.GMT _ BasicTime.earliestGMT; Daemon: PROC ~ { thisSweepTime: BasicTime.GMT; seconds: INT; CallSweep: SymTab.EachPairAction -- [key, val] RETURNS [quit] -- ~ { h: ServerHandle ~ NARROW[val]; h.procs.sweep[h, seconds]; RETURN [FALSE]; }; DO Process.PauseMsec[msecBetweenSweeps]; thisSweepTime _ BasicTime.Now[]; seconds _ BasicTime.Period[from~lastSweepTime, to~thisSweepTime]; [] _ SymTab.Pairs[serverTab, CallSweep]; lastSweepTime _ thisSweepTime; ENDLOOP; }; GetServerResponse: TYPE ~ REF GetServerResponseObject; GetServerResponseObject: TYPE ~ RECORD [ gotServer: CONDITION, handle: ServerHandle ]; GetServer: PROC [server: ROPE] RETURNS [h: ServerHandle] ~ { h _ NARROW[SymTab.Fetch[serverTab, server].val]; IF (h = NIL) OR (NOT h.procs.validate[h]) THEN { kids: LIST OF PROCESS _ NIL; response: GetServerResponse; response _ NEW [GetServerResponseObject]; FOR each: Registration _ registrations, each.next WHILE each # NIL DO kids _ CONS[ (FORK DoGetServer[each, server, response]), kids ]; ENDLOOP; h _ WaitForResponse[response]; FOR child: LIST OF PROCESS _ kids, child.rest WHILE child # NIL DO TRUSTED { Process.Abort[child.first] }; TRUSTED { Process.Detach[child.first] }; ENDLOOP; IF h = NIL THEN h _ MakeNonexistentServer[server]; [] _ SymTab.Store[serverTab, server, h]; }; IF h.flavor = $nonexistentServer THEN ErrorNonexistentServer[h]; }; DoGetServer: PROC [r: Registration, server: ROPE, response: GetServerResponse] ~ { ENABLE FS.Error => CONTINUE; h: ServerHandle; NotifyGotHandle: ENTRY PROC ~ { IF response.handle # NIL THEN RETURN; response.handle _ h; NOTIFY response.gotServer; }; IF (h _ r.getServer[server]) # NIL THEN NotifyGotHandle[]; }; WaitForResponse: ENTRY PROC [response: GetServerResponse] RETURNS [ServerHandle] ~ { IF response.handle = NIL THEN TRUSTED { Process.EnableAborts[@response.gotServer]; Process.SetTimeout[@response.gotServer, Process.MsecToTicks[waitForServerTimeout]]; WAIT response.gotServer; }; RETURN [response.handle]; }; SetCachedServer: PUBLIC PROC [server: ROPE, flavor: ATOM] ~ { r: Registration; h: ServerHandle; ClearCachedServer[server]; FOR r _ registrations, r.next WHILE (r # NIL) AND (r.flavor # flavor) DO NULL ENDLOOP; IF r = NIL THEN RETURN; h _ r.getServer[server]; IF h = NIL THEN h _ MakeNonexistentServer[server]; [] _ SymTab.Store[serverTab, server, h]; }; ClearCachedServer: PUBLIC PROC [server: ROPE] ~ { [] _ SymTab.Delete[serverTab, server]; }; NonexistentServerData: TYPE ~ REF NonexistentServerDataObject; NonexistentServerDataObject: TYPE ~ RECORD [ ttl: CARD _ nonexistentServerTTL ]; nonexistentServerProcs: FSRemoteFileExtras.ServerProcs _ NEW[FSRemoteFileExtras.ServerProcsObject _ [ sweep~SweepNonexistentServer, validate~ValidateNonexistentServer, delete~NIL, enumerateForInfo~NIL, enumerateForNames~NIL, getInfo~NIL, rename~NIL, retrieve~NIL, store~NIL ] ]; MakeNonexistentServer: PROC [name: ROPE] RETURNS [h: ServerHandle] ~ { d: NonexistentServerData _ NEW[NonexistentServerDataObject]; h _ NEW[FSRemoteFileExtras.ServerObject _ [$nonexistentServer, name, nonexistentServerProcs, d]]; }; SweepNonexistentServer: FSRemoteFileExtras.SweepProc -- [h: ServerHandle, seconds: INT] -- ~ { d: NonexistentServerData _ NARROW[h.data]; IF d.ttl > CARD[seconds] THEN d.ttl _ d.ttl - seconds; }; ValidateNonexistentServer: FSRemoteFileExtras.ValidateProc -- [h: ServerHandle] RETURNS [ok: BOOL] -- ~ { d: NonexistentServerData _ NARROW[h.data]; RETURN[d.ttl > 0]; }; ErrorNonexistentServer: PROC [h: ServerHandle, file: ROPE _ NIL] ~ { FSBackdoor.ProduceError[FSBackdoor.ErrorCode.unknownServer, Rope.Cat["Couldn't find the server for \"", BracketServer[h.name], file, "\""]]; }; BracketServer: PROC[server: ROPE] RETURNS [ROPE] = { IF Rope.Match["[*", server] THEN RETURN [server] ELSE RETURN [ Rope.Cat[ "[", server, "]" ] ]; }; UnbracketServer: PROC[server: ROPE] RETURNS [ROPE] = { IF Rope.Match["[*", server] THEN RETURN [ Rope.Flatten[server, 1, Rope.Length[server]-2]] ELSE RETURN [ server ]; }; TRUSTED { Process.Detach[ FORK Daemon[] ] }; }... jFSRemoteFileExtrasImpl.mesa Demers, September 19, 1987 3:40:59 pm PDT Copied Types Parameters Exported to FSRemoteFile Should I raise FS.Error if NOT gotOne? Should I raise FS.Error if NOT gotOne? Registration Server Handle Cache Finding a server Controlling the flavor of a cached server Nonexistent Server Implementation Name manipulation Initialization Κ ˆ˜codešœ™K™)K˜—šΟk ˜ Kšœ œœ˜0Kšœœ˜&Kšœ œ$˜4Kšœœ9˜NKšœœœ˜΄Kšœœœ˜KšœœR˜_Kšœœœ˜/Kšœœ;˜GK˜K˜—šΟnœœ˜%Kšœ œ4˜IKšœ˜K˜Ihead™ Kšœ œ"˜3Kšœœ*˜CKšœ œœ ˜Kšœœ$˜7Kšœœ œ˜Kšœ œ˜-Kšœ œ˜-Kšœœœ˜Kšœœ#˜5Kšœ œ˜#™ Kšœœ ˜ Kšœœ˜!Kšœœ ˜#—™š žœœœœœ˜WKšœ œ˜(KšœH˜HK˜1K˜K˜—šžœœœœ˜IKšœ œ˜(Kšœ œœœ-˜BIcode2šœ œ,˜Kšœœ œ˜LKšœ œ˜(Kšœ œœœ-˜BMšœ œ,˜šœœœ˜,Kšœœ˜ K˜K˜—šœ8˜8šœ)˜,Kšœ˜Kšœ#˜#Kšœœ˜ Kšœœ˜Kšœœ˜Kšœœ˜ Kšœœ˜ Kšœ œ˜ Kšœ˜ Kšœ˜—Kšœ˜K˜—šžœœœœ˜FKšœœ˜