StreamFromOpenFile:
PUBLIC
PROC [openFile:
FS.OpenFile, accessRights:
FS.Lock, initialPosition:
FS.InitialPosition, streamOptions:
FS.StreamOptions, streamBufferParms:
FS.StreamBufferParms, extendFileProc:
FS.ExtendFileProc]
RETURNS [stream:
STREAM] = {
no monitors are needed in this code since, until this proc returns,
no other code can refer to the streams
pageAllocation: PageCount;
byteLength: ByteCount;
fileName: ROPE = openFile.GetName[].fullFName;
fsData: FSDataHandle;
fsDataFile: FileDataHandle ;
node: BufferNodeHandle ;
Index must always be less than 64K, so we have to clip off a page from the max.
IF streamBufferParms.vmPagesPerBuffer = 128
THEN
streamBufferParms.vmPagesPerBuffer ← 127;
IF accessRights = $write
AND GetFileLock[openFile] # $write
THEN
FSBackdoor.ProduceError[wrongLock, fileName];
[pages: pageAllocation, bytes: byteLength] ← openFile.GetInfo[];
fsData ← NEW[Data ← []];
fsDataFile ←
NEW[FileData ← [
fileName: fileName,
accessRights: accessRights,
fileLength: byteLength,
fileHandle: openFile,
streamBufferParms: streamBufferParms,
extendFileProc: extendFileProc,
streamOptions: streamOptions,
byteLength: byteLength,
byteSize: pageAllocation*bytesPerFilePage,
validBytesOnDisk: byteLength]
];
IF fsDataFile.byteLength > fsDataFile.byteSize THEN ERROR;
fsData.fileData ← fsDataFile ;
fsDataFile.firstBufferNode ← node ←
CreateBufferSpace[streamBufferParms.vmPagesPerBuffer, accessRights];
FOR i:
INT
IN [2..streamBufferParms.nBuffers]
DO
node.nextBufferNode ←
CreateBufferSpace[streamBufferParms.vmPagesPerBuffer, accessRights];
node ← node.nextBufferNode ;
ENDLOOP;
stream ← IO.CreateStream[FileStreamPrivate.ProcHandleFromAccessRights[accessRights], fsData];
IOUtils.StoreData[self: stream, key: $Name, data: fsDataFile.fileName];
IF accessRights = $write
THEN {
fsDataFile.writeStreamData ← fsData ;
fsData.isWriteStream ← TRUE ;
IF fsDataFile.byteSize = 0
THEN {
fsDataFile.byteSize ← NewByteSize[fsDataFile.byteSize];
SetFileSize[fsDataFile.fileHandle, fsDataFile.byteSize];
};
}
ELSE {
fsDataFile.firstReadStream ← fsData;
};
IF initialPosition = start
THEN {
[] ← FileStreamPrivate.SetupBuffer[fileData: fsDataFile, fsData: fsData, fileByte: 0]
}
ELSE {
initialPosition = end
node ← FileStreamPrivate.SetupBuffer[fileData: fsDataFile,
fsData: fsData, fileByte: PageContainingLastByte[fsDataFile.fileLength]];
fsData.index ← node.dataBytesInBuffer;
};
IF streamOptions[tiogaRead]
AND byteLength > 0
THEN {
isTioga: BOOL; len: INT;
[yes: isTioga, len: len] ← IsThisThingATiogaFile[stream];
IF isTioga
THEN {
IF accessRights = $read
THEN {
make length look changed by sneaky call to SetLength (not in stream procs).
since stream is opened for read only, this call won't change the length in the file.
FileStream.SetLength[stream, len];
fsDataFile.tiogaReader ← TRUE
}
ELSE {
you can't incrementally update a Tioga file with IO!
stream.Close[];
FSBackdoor.ProduceError[cantUpdateTiogaFile, fileName];
}
}
};
IF FileStreamPrivate.DoFinalization
THEN {
FSLock.RecordREF[fsData];
SafeStorage.EnableFinalization[fsData];
};
fsData.ConvertFStoIOErrors ← TRUE;
fsData ← NIL ;
RETURN[stream];
};--StreamFromOpenFile
SetUpClonedStream:
ENTRY
PROC [fileData: FileDataHandle, fsData: FSDataHandle]
RETURNS [filePos:
INT]= {
ENABLE UNWIND => NULL;
node: BufferNodeHandle ← fileData.firstBufferNode;
Find last node
UNTIL node.nextBufferNode =
NIL
DO
node ← node.nextBufferNode;
ENDLOOP ;
Allocate some more nodes.
FOR i:
INT
IN [1..fileData.streamBufferParms.nBuffers]
DO
node.nextBufferNode ←
CreateBufferSpace[fileData.streamBufferParms.vmPagesPerBuffer, read];
node ← node.nextBufferNode;
ENDLOOP;
fileData.numberOfStreams ← fileData.numberOfStreams + 1 ;
filePos ← fsData.index + fsData.currentNode.firstFileByteInBuffer ;
fsData ← NIL ;
};