-- File: SloshRecv.mesa, Last Edit: HGM February 4, 1981 12:49 PM DIRECTORY Put USING [Line], String USING [AppendChar, AppendString, AppendDecimal], Storage USING [Node, Free], Time USING [AppendCurrent], Window USING [Handle], File USING [Capability, nullCapability], George USING [ CountFreeDiskPages, CreateOutputStream, CreateNewFile, DeleteFileFromDisk, Destroy, DiskFull, Handle, NameToCapability, PutByte, PutWords], Lock USING [LockDiskAndWait, UnlockDisk], Slosh USING [ Arrived, Check, CopyFile, Failed, RecvStatus, RejectThisTrash, Release], EFTPDefs USING [ EFTPOpenForReceiving, EFTPAbortReceiving, EFTPGetBlock, EFTPFinishReceiving, EFTPEndReceiving, EFTPTimeOut, EFTPTroubleReceiving, EFTPSetRecvTimeout], PupTypes USING [PupAddress]; SloshRecv: MONITOR IMPORTS Put, String, Storage, Time, George, Lock, Slosh, EFTPDefs EXPORTS Slosh = BEGIN verbose: BOOLEAN = TRUE; -- Since disk space seems tight, this routine checks to see if the file already exists. If not, it writes it into the new file directly. If it does exist, the file is buffered into a buffer file to be sure we have it all before we clobber the old version. RecvFile: PUBLIC ENTRY PROCEDURE [ who: Window.Handle, fileName, scratch: STRING, file: File.Capability, me: PupTypes.PupAddress, ask: PROCEDURE] RETURNS [status: Slosh.RecvStatus] = BEGIN OPEN EFTPDefs; FixThingsUp: PROCEDURE [e: STRING, why: Slosh.RecvStatus] = BEGIN message ← e; EFTPAbortReceiving[message]; IF temp # NIL THEN George.Destroy[temp]; IF new THEN George.DeleteFileFromDisk[file]; -- delete the file that is half created status ← why; END; copy: File.Capability; new: BOOLEAN = file = File.nullCapability; pagesLeft: INTEGER; temp: George.Handle; buffer: POINTER TO PACKED ARRAY [0..512) OF [0..377B]; pages, bytes: CARDINAL ← 0; message: STRING ← NIL; trouble: STRING = [100]; Lock.LockDiskAndWait[fileName, write]; EFTPSetRecvTimeout[1000]; -- open the file before asking so booter won't get impatient IF new THEN BEGIN -- 500 looks big, but if we don't make it big enough to start with, the server times out while we are extending the file if we are on the same Ethernet. Large boot files (Othello) are almost 500 pages. This means that Pilot boot servers must have plenty of spare disk space. The parameter is ignored on Altos. file ← George.CreateNewFile[fileName, 500]; temp ← George.CreateOutputStream[file] END ELSE BEGIN copy ← George.NameToCapability[scratch, 100]; temp ← George.CreateOutputStream[copy]; END; buffer ← Storage.Node[1*256]; BEGIN ENABLE BEGIN EFTPTroubleReceiving => BEGIN String.AppendString[trouble, s]; GOTO EFTPTrouble; END; EFTPTimeOut => GOTO EFTPTimeout; END; n: CARDINAL ← 0; [] ← EFTPOpenForReceiving[ me ! EFTPTimeOut => BEGIN -- We expect to get here once since we haven't asked yet IF (n ← n + 1) > 3 THEN GOTO OpenFailed; ask[]; RESUME ; END]; EFTPSetRecvTimeout[60000]; -- This is a silly place to check, but it simplifies recovery IF George.CountFreeDiskPages[] < 100 THEN GOTO NotMuchRoom; DO n ← EFTPGetBlock[buffer, 2*256 ! EFTPEndReceiving => EXIT]; George.PutWords[temp, buffer, n/2 ! George.DiskFull[] => GOTO TempFull]; -- This will screwup if any but than the last block has an odd length. IF (n MOD 2) # 0 THEN George.PutByte[temp, buffer[n - 1]]; bytes ← bytes + n; IF bytes >= 512 THEN BEGIN bytes ← bytes - 512; pages ← pages + 1; END; ENDLOOP; EFTPFinishReceiving[]; George.Destroy[temp]; -- this sets the correct length temp ← NIL; Slosh.Check[ fileName, IF new THEN file ELSE copy ! Slosh.RejectThisTrash => BEGIN String.AppendString[trouble, text]; GOTO Rejected; END]; IF new THEN BEGIN status ← statusStoreOk; Slosh.Arrived[fileName, file]; END ELSE BEGIN Slosh.Release[fileName, file]; status ← Slosh.CopyFile[to: file, from: copy]; IF status = statusStoreOk THEN Slosh.Arrived[fileName, file] ELSE Slosh.Failed[fileName, file]; END; EXITS OpenFailed => FixThingsUp["EFTP Open Failed"L, statusEFTPFailed]; NotMuchRoom => FixThingsUp["Not much room on the disk"L, statusDiskFull]; EFTPTrouble => FixThingsUp["EFTP Trouble"L, LOOPHOLE[EFTPTroubleReceiving]]; EFTPTimeout => FixThingsUp["EFTP Timeout"L, LOOPHOLE[EFTPTroubleReceiving]]; TempFull => FixThingsUp[ "Disk Full while buffering into buffer file"L, statusDiskFull]; Rejected => FixThingsUp["Rejected locally"L, statusContentsRejected]; END; Storage.Free[buffer]; Lock.UnlockDisk[fileName]; IF ~new THEN BEGIN George.DeleteFileFromDisk[copy]; END; IF verbose THEN BEGIN text: STRING = [150]; Time.AppendCurrent[text]; IF message = NIL THEN BEGIN String.AppendString[text, " Got "L]; String.AppendString[text, fileName]; String.AppendString[text, " ok. Length="L]; String.AppendDecimal[text, pages]; String.AppendChar[text, '.]; String.AppendDecimal[text, bytes]; END ELSE BEGIN String.AppendString[text, " Recv aborted because: "L]; String.AppendString[text, message]; IF trouble.length # 0 THEN BEGIN String.AppendString[text, "("L]; String.AppendString[text, trouble]; String.AppendString[text, ") "L]; END; String.AppendString[text, " after page "L]; String.AppendDecimal[text, pages]; END; String.AppendString[text, ", pages left="L]; pagesLeft ← George.CountFreeDiskPages[]; String.AppendDecimal[text, pagesLeft]; String.AppendChar[text, '.]; LogString[who, text]; END; END; LogString: PROCEDURE [msg: Window.Handle, text: STRING] = BEGIN IF msg # NIL THEN Put.Line[msg, text]; Put.Line[NIL, text]; END; END.