-- file: FTPUserStore.mesa, Edit: HGM July 31, 1980 7:25 PM
-- Copyright Xerox Corporation 1979, 1980
DIRECTORY
FTPDefs,
FTPPrivateDefs,
MDSStorage USING [Node, Free];
FTPUserStore: PROGRAM
IMPORTS Storage: MDSStorage, FTPDefs, FTPPrivateDefs
EXPORTS FTPDefs
SHARES FTPDefs =
BEGIN OPEN FTPDefs, FTPPrivateDefs;
FTPStoreFile: PUBLIC PROCEDURE [
ftpuser: FTPUser, localFile, remoteFile: STRING, fileType: FileType]
RETURNS [byteCount: LONG INTEGER] =
BEGIN OPEN ftpuser;
-- local constants
bufferSize: CARDINAL = maximumDumpBlockSize + minimumDumpBlockSize;
-- local variables
creationDate: STRING = [maxDateLength];
writeDate: STRING = [maxDateLength];
readDate: STRING = [maxDateLength];
storeState: {inactive, initiated, waiting, transferring} ← inactive;
fileHandle: FileHandle ← NIL;
fileInfoObject: FileInfoObject ← [
fileType: fileType, byteSize: 0, byteCount: 0, creationDate: creationDate,
writeDate: writeDate, readDate: readDate, author: NIL];
dumpStateObject: DumpStateObject ← [
bufferAddress: NIL, bufferLength: 0, ftper: ftper, blockType:];
-- verify purpose and state
VerifyPurposeAndState[
ftpuser, files, IF state = connected THEN connected ELSE dumpFileBeingSent];
-- intercept errors
BEGIN
ENABLE
UNWIND =>
BEGIN
ENABLE FTPError => IF ftpError IN CommunicationError THEN CONTINUE;
IF dumpStateObject.bufferAddress # NIL THEN
Storage.Free[dumpStateObject.bufferAddress];
IF fileHandle # NIL THEN
filePrimitives.CloseFile[ftpuser.fileSystem, fileHandle, TRUE];
IF storeState = initiated THEN
SELECT GetCommand[ftper].mark FROM
markHereIsPropertyList =>
BEGIN
GetPropertyList[ftper, propertyList];
GetEOC[ftper];
storeState ← transferring;
END;
markNo => GetEOC[ftper];
ENDCASE; --illegalProtocolSequence
IF storeState = transferring THEN
BEGIN
PutCommandAndEOC[ftper, markNo, codeFileDataError];
GetSpecificCommand[ftper, markNo];
GetEOC[ftper];
END;
END;
-- determine file type if necessary
[fileHandle, fileInfoObject.fileType] ← filePrimitives.OpenFile[
ftpuser.fileSystem, localFile, read, fileType = unknown, @fileInfoObject];
-- initiate remote store
IF state = connected THEN
BEGIN
-- send store command
PutCommand[ftper, markNewStore, 0];
-- construct property list containing absolute and virtual filenames, credentials, and file information
ResetPropertyList[propertyList];
WriteFilename[remoteFile, propertyList, NIL, NIL, primaryPropertyList];
IF fileType # unknown THEN fileInfoObject.fileType ← fileType;
fileInfoObject.byteSize ← IF fileInfoObject.fileType = binary THEN 8 ELSE 0;
WriteFileInfo[propertyList, @fileInfoObject];
-- send property list and EOC
PutPropertyList[ftper, propertyList];
PutEOC[ftper];
-- note store initiated
storeState ← initiated;
END;
-- sustain remote store
IF state = connected THEN
BEGIN
-- note waiting to transfer
storeState ← waiting;
-- sustain remote store
GetSpecificCommand[ftper, markHereIsPropertyList];
GetPropertyList[ftper, propertyList];
GetEOC[ftper];
-- signal transmission of file
PutCommand[ftper, markHereIsFile, 0];
-- note transfer in progress
storeState ← transferring;
END;
-- send the file
byteCount ← ftper.totalByteCount;
IF state = connected THEN
filePrimitives.ReadFile[ftpuser.fileSystem, fileHandle, SendBlock, ftper]
ELSE
BEGIN
SendHeaderBlock[@dumpStateObject, remoteFile, creationDate];
-- allocate a buffer
dumpStateObject.bufferAddress ← Storage.Node[bufferSize];
-- send the file
filePrimitives.ReadFile[
ftpuser.fileSystem, fileHandle, DumpBlock, @dumpStateObject];
-- release the buffer
Storage.Free[dumpStateObject.bufferAddress];
dumpStateObject.bufferAddress ← NIL;
END;
byteCount ← ftper.totalByteCount - byteCount;
-- terminate remote store
IF state = connected THEN
BEGIN
-- send Yes and EOC
PutCommandAndEOC[ftper, markYes, 0];
storeState ← waiting;
-- close local file
-- Note: Closing of the local file is deferred
-- until end-of-file has been sent to the remote server
-- so that closing of the local and remote files can be overlapped.
filePrimitives.CloseFile[ftpuser.fileSystem, fileHandle, FALSE];
fileHandle ← NIL;
-- receive acknowledgment
GetYesAndEOC[ftper];
END
-- close local file
ELSE filePrimitives.CloseFile[ftpuser.fileSystem, fileHandle, FALSE];
END; -- enable
END;
END. -- of FTPUserStore