<<>> <> <> <> <> <> <<>> DIRECTORY BasicTime, BridgeComm, BridgeFTPOps, Convert, IO, NetworkStream, Process, Rope ; BridgeFTPOpsImpl: CEDAR PROGRAM IMPORTS BasicTime, BridgeComm, Convert, IO, NetworkStream, Process, Rope EXPORTS BridgeFTPOps ~ { ROPE: TYPE ~ Rope.ROPE; STREAM: TYPE ~ IO.STREAM; NetworkStreamPair: TYPE ~ BridgeComm.NetworkStreamPair; ActionProc: TYPE ~ BridgeFTPOps.ActionProc; RetrieveStream: PUBLIC PROC [nsp: NetworkStreamPair, remoteName: ROPE, action: ActionProc, clientData: REF ¬ NIL, msgStream: STREAM ¬ NIL] RETURNS [excuse: ROPE ¬ NIL] ~ { ENABLE { ABORTED => { excuse ¬ "aborted"; CONTINUE }; BridgeComm.Error => { PutMsg[msgStream, "Communication error: %g\n", msg]; excuse ¬ "Bridge communication error"; CONTINUE }; IO.Error, NetworkStream.Error => { PutMsg[msgStream, "I/O error\n"]; excuse ¬ "I/O error"; CONTINUE }; }; ansMsg: CHAR; ansArg: ROPE; ansArgNumeric: CARD; actionProcQuit: BOOL; PutMsg[msgStream, "Retrieving from %g ... ", remoteName]; [ansMsg, ansArg] ¬ BridgeComm.PutMsgWithReply[nsp, 'I, remoteName]; -- Open for input. SELECT ansMsg FROM 'Y => NULL; -- ansArg is really aaa.bbb where aaa is the iNode and bbb is the mtime 'N => { PutMsg[msgStream, "%g\n", ansArg]; RETURN [ansArg] }; -- ansArg = error like not found ENDCASE => { PutMsg[msgStream, "Protocol error\n"]; RETURN ["Protocol error"] }; [ansMsg, ansArg] ¬ BridgeComm.PutMsgWithReply[nsp, 'R]; -- Read current file SELECT ansMsg FROM 'D => NULL; -- ansArg is the number of bytes in the file as reported by stat 'N => { PutMsg[msgStream, "%g\n", ansArg]; RETURN [ansArg] }; -- stat error ENDCASE => { PutMsg[msgStream, "Protocol error\n"]; RETURN ["Protocol error"] }; <> ansArgNumeric ¬ Convert.CardFromRope[ansArg -- really bytes in the file ! Convert.Error => ansArgNumeric ¬ CARD.LAST]; IF ansArgNumeric = 0 THEN { Process.PauseMsec[500] -- Kludge -- ; actionProcQuit ¬ FALSE; } ELSE { actionProcQuit ¬ action[nsp, ansArgNumeric, NIL]; -- send the bits. Should only get ansArgNumeric (byte count) IF actionProcQuit THEN IO.Reset[nsp.in]; }; WHILE NetworkStream.GetStreamState[nsp.in, TRUE].streamState # open DO NULL ENDLOOP; [] ¬ BridgeComm.PutMsgWithReply[nsp, 'i]; -- close the file PutMsg[msgStream, IF actionProcQuit THEN "aborted\n" ELSE "ok\n"]; }; MkTempName: PROC [name: ROPE] RETURNS [tempName: ROPE] ~ { tempName ¬ IO.PutFR["%g.%g", [rope[name]], [cardinal[BasicTime.ToNSTime[BasicTime.Now[]]]] ]; }; StoreStream: PUBLIC PROC [nsp: NetworkStreamPair, remoteName: ROPE, overwrite: BOOL, action: ActionProc, clientData: REF ¬ NIL, msgStream: STREAM ¬ NIL] RETURNS [excuse: ROPE ¬ NIL] ~ { ENABLE { ABORTED => { excuse ¬ "aborted"; CONTINUE }; BridgeComm.Error => { PutMsg[msgStream, "Communication error: %g\n", msg]; excuse ¬ "Bridge communication error"; CONTINUE }; IO.Error, NetworkStream.Error => { PutMsg[msgStream, "I/O error\n"]; excuse ¬ "I/O error"; CONTINUE }; }; ansMsg: CHAR; ansArg: ROPE; tempName: ROPE; actionProcQuit: BOOL; IF overwrite THEN { PutMsg[msgStream, "Writing %g ... ", remoteName]; [ansMsg, ansArg] ¬ BridgeComm.PutMsgWithReply[nsp, 'O, remoteName]; SELECT ansMsg FROM 'Y => NULL; 'N => { PutMsg[msgStream, "%g\n", ansArg]; RETURN [ansArg] }; ENDCASE => { PutMsg[msgStream, "Protocol error\n"]; RETURN ["Protocol error"] }; BridgeComm.PutMsg[nsp, 'W]; actionProcQuit ¬ action[nsp, -1, NIL]; NetworkStream.SendEndOfMessage[nsp.out]; [ansMsg, ansArg] ¬ BridgeComm.GetMsg[nsp]; SELECT ansMsg FROM 'Y => NULL; 'N => { PutMsg[msgStream, "%g\n", ansArg]; RETURN [ansArg] }; ENDCASE => { PutMsg[msgStream, "Protocol error\n"]; RETURN ["Protocol error"] }; [] ¬ BridgeComm.PutMsgWithReply[nsp, 'o]; <> PutMsg[msgStream, IF actionProcQuit THEN "aborted\n" ELSE "ok\n"]; } ELSE { PutMsg[msgStream, "Storing to temporary ... "]; tempName ¬ MkTempName[remoteName]; [ansMsg, ansArg] ¬ BridgeComm.PutMsgWithReply[nsp, 'N, tempName]; SELECT ansMsg FROM 'Y => NULL; 'N => { PutMsg[msgStream, "%g\n", ansArg]; RETURN [ansArg] }; ENDCASE => { PutMsg[msgStream, "Protocol error\n"]; RETURN ["Protocol error"] }; BridgeComm.PutMsg[nsp, 'W]; actionProcQuit ¬ action[nsp, -1, NIL]; NetworkStream.SendEndOfMessage[nsp.out]; [ansMsg, ansArg] ¬ BridgeComm.GetMsg[nsp]; SELECT ansMsg FROM 'Y => NULL; 'N => { PutMsg[msgStream, "%g\n", ansArg]; RETURN [ansArg] }; ENDCASE => { PutMsg[msgStream, "Protocol error\n"]; RETURN ["Protocol error"] }; [ansMsg, ansArg] ¬ BridgeComm.PutMsgWithReply[nsp, 'o]; SELECT ansMsg FROM 'Y => NULL; 'N => { PutMsg[msgStream, "%g\n", ansArg]; RETURN [ansArg] }; ENDCASE => { PutMsg[msgStream, "Protocol error\n"]; RETURN ["Protocol error"] }; IF actionProcQuit THEN { PutMsg[msgStream, "aborted\n"]; } ELSE { PutMsg[msgStream, "renaming temporary to %g ... ", remoteName]; [ansMsg, ansArg] ¬ BridgeComm.PutMsgWithReply[nsp, 'M, Rope.Cat[tempName, " ", remoteName]]; SELECT ansMsg FROM 'Y => NULL; 'N => { PutMsg[msgStream, "%g\n", ansArg]; RETURN [ansArg] }; ENDCASE => { PutMsg[msgStream, "Protocol error\n"]; RETURN ["Protocol error"] }; PutMsg[msgStream, "ok\n"]; }; }; }; PutMsg: PROC [s: STREAM, fmt: ROPE, msg: ROPE ¬ NIL] ~ { ENABLE IO.Error => CONTINUE; IF (s # NIL) THEN IO.PutF1[s, fmt, IF msg # NIL THEN [rope[msg]] ELSE [null[]]]; }; }...