-- 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.