<> <> <> <> <> <> <> <<>> DIRECTORY Basics USING [bytesPerWord, LongNumber, SwapHalves], BasicTime USING [GMT, nullGMT, ToPupTime, Update], CedarProcess USING [Abort, CheckAbort, Fork, ForkableProc, Process], FS USING [ComponentPositions, Error, ExpandName, FileInfo], PupDefs USING [GetHopsToNetwork, GetPupContentsBytes, PupBuffer, PupSocket, PupSocketDestroy, PupSocketMake, ReturnPup, SendErrorPup, veryLongWait], PupTypes USING [fillInPupAddress, Pair, PupAddress, PupSocketID, PupType], Rope USING [Cat, Find, FromRefText, Index, Length, Replace, ROPE, Substr], RuntimeError USING [UNCAUGHT], STPServerFileTranslation USING [FindNamedTranslator, NamedTranslator], STPServerPrivate USING [CurrentVersion, FileName, NameMapDirection, NameMapList], UserProfile USING [CallWhenProfileChanges, ListOfTokens, ProfileChangeReason]; STPServerAuxImpl: CEDAR MONITOR IMPORTS Basics, BasicTime, CedarProcess, FS, PupDefs, Rope, RuntimeError, STPServerPrivate, UserProfile, STPServerFileTranslation EXPORTS STPServerPrivate ~ BEGIN OPEN STPServerPrivate; <> nameMaps: NameMapList _ NIL; GMT: TYPE ~ BasicTime.GMT; LongNumber: TYPE ~ Basics.LongNumber; ROPE: TYPE ~ Rope.ROPE; LOR: TYPE ~ LIST OF ROPE; BothFromOne: PUBLIC PROC [oneName: ROPE, direction: NameMapDirection] RETURNS [both: FileName] ~ { otherName: ROPE _ oneName; otherLength: INT _ otherName.Length[]; FOR nms: NameMapList _ nameMaps, nms.rest WHILE nms # NIL DO find: ROPE ~ SELECT direction FROM localToRemote => nms.first.local, remoteToLocal => nms.first.remote, ENDCASE => ERROR; repl: ROPE ~ SELECT direction FROM localToRemote => nms.first.remote, remoteToLocal => nms.first.local, ENDCASE => ERROR; start: INT ~ otherName.Find[s2: find, case: FALSE]; cutLength: INT ~ find.Length[]; IF start >= 0 THEN { otherName _ otherName.Replace[start: start, len: cutLength, with: repl]; EXIT; }; ENDLOOP; both _ SELECT direction FROM localToRemote => [local: oneName, remote: otherName], remoteToLocal => [local: otherName, remote: oneName], ENDCASE => ERROR; }; RealName: PROC [remoteName: ROPE] RETURNS [realName: ROPE _ NIL, translated: BOOL _ FALSE] ~ { fullFName: ROPE _ NIL; cp: FS.ComponentPositions; namedTranslator: STPServerFileTranslation.NamedTranslator _ NIL; hostNameLength: INT _ 0; [fullFName, cp] _ FS.ExpandName[remoteName]; namedTranslator _ STPServerFileTranslation.FindNamedTranslator[fullFName, cp.dir.start, cp.dir.length]; IF namedTranslator = NIL OR cp.subDirs.length = 0 THEN RETURN [realName: BothFromOne[remoteName, remoteToLocal].local, translated: FALSE]; hostNameLength _ Rope.Index[s1: fullFName, pos1: cp.subDirs.start, s2: ">"] - cp.subDirs.start; realName _ Rope.Cat["[", Rope.Substr[fullFName, cp.subDirs.start, hostNameLength], "]<", Rope.Substr[fullFName, cp.subDirs.start+hostNameLength+1]]; translated _ TRUE; }; NoteProfile: PROC [reason: UserProfile.ProfileChangeReason] --UserProfile.ChangeProc-- ~ { maps: LOR _ UserProfile.ListOfTokens["STPServer.NameMappings", NIL]; newMaps: NameMapList _ NIL; FOR maps _ maps, maps.rest.rest WHILE maps # NIL AND maps.rest # NIL DO remote: ROPE ~ maps.first; local: ROPE ~ maps.rest.first; newMaps _ CONS[[local: local, remote: remote], newMaps]; ENDLOOP; IF maps # NIL THEN ERROR; nameMaps _ newMaps; }; <> <<>> LookupFileType: PupTypes.PupType = LOOPHOLE[200B]; LookupFileReplyType: PupTypes.PupType = LOOPHOLE[201B]; LookupFileErrorType: PupTypes.PupType = LOOPHOLE[202B]; LookupFileSocket: PupTypes.PupSocketID = [0, 61B]; singleSocket: PupDefs.PupSocket _ NIL; singleProcess: CedarProcess.Process _ NIL; StartSingle: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; IF singleProcess = NIL THEN { singleSocket _ PupDefs.PupSocketMake [local: LookupFileSocket, remote: PupTypes.fillInPupAddress, ticks: PupDefs.veryLongWait ]; singleProcess _ CedarProcess.Fork[ SinglePacketListener, NIL, [priority: foreground, usePriority: TRUE]]; }; }; StopSingle: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; IF singleProcess # NIL THEN { CedarProcess.Abort[singleProcess]; PupDefs.PupSocketDestroy[singleSocket ! RuntimeError.UNCAUGHT => CONTINUE]; singleSocket _ NIL; }; }; ReplyRecord: TYPE = MACHINE DEPENDENT RECORD[v: CARDINAL, c, l: LongNumber]; ReplyRecordBytes: CARDINAL = SIZE[ReplyRecord]*Basics.bytesPerWord; SinglePacketListener: CedarProcess.ForkableProc = TRUSTED { ENABLE UNWIND => singleProcess _ NIL; text: REF TEXT _ NEW[TEXT[256]]; DO receiver: PupDefs.PupBuffer = singleSocket.get[]; replyType: PupTypes.PupType _ error; replyBytes: CARDINAL _ 0; IF receiver # NIL THEN { addr: PupTypes.PupAddress _ receiver.source; msWait: CARDINAL = 2000+500*MIN[8, PupDefs.GetHopsToNetwork[addr.net]]; IF receiver.pupType = LookupFileType THEN { id: PupTypes.Pair _ receiver.pupID; len: INT _ PupDefs.GetPupContentsBytes[receiver]; IF len IN [1..256] THEN { ENABLE RuntimeError.UNCAUGHT => GO TO dropIt; sLen: NAT _ len; name: ROPE _ NIL; fileLen: INT _ 0; fileDate: GMT _ BasicTime.nullGMT; rPtr: LONG POINTER TO ReplyRecord = LOOPHOLE[@receiver.pupBody]; translated: BOOL _ FALSE; text[0] _ '[; text[1] _ ']; FOR i: NAT IN [0 .. sLen) DO text[i+2] _ receiver.pupChars[i]; ENDLOOP; text.length _ sLen+2; name _ Rope.FromRefText[text]; [name, translated] _ RealName[name]; [fullFName: name, created: fileDate, bytes: fileLen] _ FS.FileInfo[name: name ! FS.Error => { SELECT error.code FROM $nonCedarVolume, $unknownVolume, $unknownFile, $unknownCreatedTime, $illegalName, $patternNotAllowed => replyType _ LookupFileErrorType; ENDCASE => NULL; CONTINUE }; ]; IF fileDate # BasicTime.nullGMT AND fileLen >= 0 THEN { IF translated THEN { fileLen _ (fileLen+999)/1000*1000; fileDate _ BasicTime.Update[fileDate, 1]; }; rPtr.v _ CurrentVersion[name]; rPtr.c _ Basics.SwapHalves[[lc[BasicTime.ToPupTime[fileDate]]]]; rPtr.l _ Basics.SwapHalves[[li[fileLen]]]; replyType _ LookupFileReplyType; replyBytes _ ReplyRecordBytes; }; }; EXITS dropIt => {}; }; receiver.pupType _ replyType; IF replyType = error THEN PupDefs.SendErrorPup[receiver, noProcessPupErrorCode, "Can't lookup file"] ELSE PupDefs.ReturnPup[receiver, replyType, replyBytes]; }; CedarProcess.CheckAbort[singleProcess]; ENDLOOP; }; <<>> <> Init: PROC ~ { UserProfile.CallWhenProfileChanges[NoteProfile]; }; Init[]; END.