RemoteFilesImpl.mesa
A package for producing IO streams on Alpine and FTP remote files, suited for ChipNDale I/O.
written by E. McCreight, November 9, 1983 12:42 pm
Last Edited by: Mccreight, November 9, 1983 2:47 pm
DIRECTORY
AlpineEnvironment,
AlpineInterimDirectory,
AlpInstance,
AlpFile,
AlpTransaction,
FileIO,
FileIOAlpine,
NewSTP,
IO,
RemoteFiles,
Rope,
Stream,
UnsafeSTP,
UserCredentials;
RemoteFilesImpl: CEDAR PROGRAM
IMPORTS AlpineInterimDirectory, AlpFile, AlpTransaction, FileIOAlpine, IO, NewSTP, Stream, UnsafeSTP, UserCredentials
EXPORTS RemoteFiles =
BEGIN
STPStreamDataRef: TYPE = REF STPStreamData;
STPStreamData: TYPE = RECORD [
handle: NewSTP.Handle,
stream: Stream.Handle];
OpenSTP: PUBLIC PROC [ fileName: Rope.ROPE, accessOptions: FileIO.AccessOptions ← read, host, connect, directory: Rope.ROPENIL ] RETURNS [ self: IO.STREAM, greetings: Rope.ROPE ] =
BEGIN -- simplified for output to Oliver servers like [vice]
stpHandle: NewSTP.Handle;
streamHandle: Stream.Handle;
SELECT accessOptions FROM
write -- , read -- => NULL;
ENDCASE => ERROR IO.Error[NotImplementedForThisStream, NIL];
stpHandle ← NewSTP.Create[];
IF host=NIL THEN host ← "indigo";
greetings ← stpHandle.Open[host];
stpHandle.Login[name: UserCredentials.GetUserCredentials[].name,
password: UserCredentials.GetUserCredentials[].password];
IF connect#NIL THEN stpHandle.Connect[name: connect, password: NIL];
IF directory#NIL THEN stpHandle.SetDirectory[directory: directory];
streamHandle ← stpHandle.CreateRemoteStream[
file: fileName,
access: (SELECT accessOptions FROM
read => read,
ENDCASE => write),
fileType: binary];
self ← IO.CreateProcsStream[
streamProcs: IO.CreateRefStreamProcs[
putChar: SendSTPChar,
unsafePutBlock: SendSTPBlock,
close: CloseSTP],
streamData: NEW[STPStreamData ← [
handle: stpHandle,
stream: streamHandle]]];
END;
SendSTPChar: PROC [ self: IO.STREAM, char: CHAR ] =
BEGIN
sd: STPStreamDataRef = NARROW[self.streamData];
TRUSTED {sd.stream.PutChar[char: char]};
END;
SendSTPBlock: PROC [ self: IO.STREAM, block: IO.UnsafeBlock ] =
BEGIN
sd: STPStreamDataRef = NARROW[self.streamData];
TRUSTED {sd.stream.PutBlock[block: [blockPointer: block.base, startIndex: block.startIndex, stopIndexPlusOne: block.stopIndexPlusOne]]};
END;
CloseSTP: PROC [ self: IO.STREAM, abort: BOOLFALSE ] =
BEGIN
BEGIN ENABLE UnsafeSTP.Error =>
IF abort THEN CONTINUE ELSE REJECT;
sd: STPStreamDataRef = NARROW[self.streamData];
TRUSTED {sd.stream.Delete[]};
sd.stream ← NIL;
sd.handle.Close[];
sd.handle ← NIL;
END;
END;
OpenAlpineForWrite: PUBLIC PROC [ fileName: Rope.ROPE, expectedLength: INT ← 6D6 ] RETURNS [ self: IO.STREAM ] =
BEGIN
server: AlpInstance.Handle;
trans: AlpTransaction.Handle;
file: AlpFile.Handle;
refUniversalFile: REF AlpineEnvironment.UniversalFile;
retryCount: INT ← 0;
DO { ENABLE AlpineInterimDirectory.Error => IF retryCount < 2 THEN LOOP;
retryCount ← retryCount + 1;
[instHandle: server, refUniversalFile: refUniversalFile] ←
AlpineInterimDirectory.Open[fileName: fileName, initialByteAllocation: expectedLength];
trans ← AlpTransaction.Create[server];
file ← AlpFile.Open[
transHandle: trans, universalFile: refUniversalFile^, access: $readWrite,
referencePattern: $sequential].handle;
file.SetSize[expectedLength/512];
file.WriteProperties[LIST[
[highWaterMark[highWaterMark: 0]]]];
IF trans.Finish[$commit].outcome # $commit THEN LOOP;
trans ← AlpTransaction.Create[server];
file ← AlpFile.Open[
transHandle: trans, universalFile: refUniversalFile^, access: $readWrite,
referencePattern: $sequential, lock: [mode: write, ifConflict: wait]].handle;
self ← FileIOAlpine.StreamFromAlpineOpenFile[
fileHandle: file, fileName: fileName, accessOptions: $write];
EXIT;
} ENDLOOP;
END;
Module START code...
END. -- of RemoteFilesImpl