-- FileIOPrivate.mesa
-- Last edited by
-- MBrown on May 16, 1983 2:05 pm
-- Teitelman on May 26, 1982 4:52 pm
DIRECTORY
CIFS USING [OpenFile],
Environment USING [Byte],
File USING [Capability],
IO USING [STREAM, UnsafeBlock],
FileIO USING [AccessOptions, CreateOptions, CloseOptions, defaultCloseOptions,
--FileSystem,
RawOption, StreamBufferParms, minimumStreamBufferParms, bytesPerPage],
FileStream USING [Subtype],
Rope USING [ROPE],
Space USING [Handle],
System USING [GreenwichMeanTime],
Transaction USING [Handle];
FileIOPrivate: CEDAR DEFINITIONS =
BEGIN
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
-- We model the behavior of a File IOStream with variables "file", "fileLen", and
--"streamIndex", where
-- file is an ARRAY [0..fileLen) OF CHAR
-- streamIndex is an INT [0..fileLen]
-- The real stream contains a lot of redundant state to make the frequently-used
--operations GetChar and PutChar fast. We shall list some invariant properties of
--this state below. These invariants hold on entry to and exit from each stream
--operation. (Redundant properties, included for their intuitive value, are given in
--parentheses.)
-- We also define a piece of fictional state: trueDataBytesInBuffer.
-- trueDataBytesInBuffer ::= MIN[bufferBytes, fileLen - firstByteInBuffer].
-- trueDataBytesInBuffer is too expensive for PutByte to maintain at all times, but it
--is useful for other operations.
DataHandle: TYPE = REF Data;
PilotDataHandle: TYPE = REF Data.pilot;
AlpineDataHandle: TYPE = REF Data.alpine;
FileSystem: TYPE = {pilot, alpine};
Data: TYPE = RECORD [
-- common part, followed by variant depending on FileSystem.
-- order these components to optimize the code generated for GetChar and PutChar.
index: CARDINAL ← 0,
-- index is IN [0..bufferBytes].
-- didPut AND index >= dataBytesInBuffer => trueDataBytesInBuffer = index.
dataBytesInBuffer: CARDINAL ← 0,
-- dataBytesInBuffer is IN [0..trueDataBytesInBuffer] => IN [0..bufferBytes].
-- NOT didPut OR (didPut AND index <= dataBytesInBuffer) =>
-- trueDataBytesInBuffer = dataBytesInBuffer.
bufferBytes: CARDINAL ← 0,
-- (see buffer below).
eofInBuffer: BOOL ← FALSE,
-- eofInBuffer <=> fileLen <= firstFileByteInBuffer + bufferBytes.
-- (this means fileLen = 0, or file[fileLen-1] is contained in the buffer. This
--is a useful piece of redundant state; fortunately, none of the cheap operations
--need to update it).
didPut: BOOL ← FALSE,
-- (somebody has done a Put and not updated dataBytesInBuffer, FileLength, and
--bufferDirty).
bufferDirty: BOOL ← FALSE,
-- didPut OR bufferDirty => there exists some i IN [0..trueDataBytesInBuffer) such
--that buffer[i] # file[i] as last read from file system. (Not maintained for
--Pilot because of its mapped files.)
tiogaReader: BOOL ← FALSE,
-- TRUE iff file is being read as a Tioga file (reading the plain text only).
--This implies that the file length shown in the stream is not the true file length,
--but instead is the Tioga plain text length.
streamIsClosed: BOOL ← FALSE,
-- stream.Close[] was called.
-- (all operations should now raise StreamError[streamClosed]).
firstFileByteInBuffer: INT ← 0,
-- streamIndex = firstFileByteInBuffer + index.
-- firstFileByteInBuffer < fileLen OR firstFileByteInBuffer = fileLen = 0.
-- firstFileByteInBuffer MOD bytesPerPage = 0.
-- (buffer[0] is indentified with file[firstFileByteInBuffer]. There is always
--one file byte in the buffer unless file is empty.)
fileLength: INT ← 0,
-- NOT didPut => fileLen = fileLength.
-- didPut AND index > dataBytesInBuffer => fileLen = firstFileByteInBuffer +
--index.
buffer: LONG POINTER TO PACKED ARRAY [0..0) OF Environment.Byte ← NIL,
-- (the current stream buffer.)
-- buffer is PACKED ARRAY [0..bufferBytes) OF CHARACTER.
-- file[firstFileByteInBuffer..firstFileByteInBuffer+trueDataBytesInBuffer) =
-- buffer[0..trueDataBytesInBuffer)
-- (in case of Pilot, buffer[0..bufferBytes) are always backed by pages of file.)
bufferLength: CARDINAL ← TRASH,
-- The length of the buffer space, in bytes. It is possible that not all of the
-- buffer space is mapped; bufferBytes gives the length of the mapped prefix.
-- Ignored by Alpine streams.
bufferSwapUnitLength: CARDINAL ← TRASH,
-- The length of the buffer swap units, in bytes. Always <= 2*bufferLength.
--Ignored by Alpine streams.
bufferSpace: Space.Handle ← TRASH,
-- (a space of length maxBufferPages pages for the stream buffer above. If buffer
--= NIL, the space has not yet been created.)
accessOptions: FileIO.AccessOptions,
closeOptions: FileIO.CloseOptions,
fileName: ROPE,
body: SELECT type: FileSystem FROM
pilot => [
fileBytes: INT ← 0,
-- fileBytes MOD bytesPerPage = 0.
-- length of pilot file, in bytes on all allocated pages. This is the
--"logical" length, i.e. it excludes the leader page if any).
dataOffset: [0..1] ← 0,
-- pages to skip at start of file in finding data pages: 1 if file has a
--leader page, 0 if it doesn't.
leader: LONG POINTER TO LeaderPage ← NIL,
-- the leader page (may be absent). Its length field will generally be out of
--date.
leaderSpace: Space.Handle ← TRASH,
-- if leader = NIL, no leaderSpace has been created.
openFile: CIFS.OpenFile ← NIL,
-- if openFile = NIL then file was not opened through CIFS.
file: File.Capability,
trans: Transaction.Handle],
alpine => [
fileHandle: REF ANY, --AlpFile.Handle (includes transaction)
byteLength: INT, --current value of fileHandle.ReadProperties[[byteLength: TRUE]]
byteSize: INT --current value of fileHandle.GetSize[]*bytesPerPage
],
ENDCASE];
GetCharDisallowed: PROC [self: STREAM] RETURNS [CHAR];
PutCharDisallowed: PROC [self: STREAM, char: CHAR];
GetBlockDisallowed: PROC [self: STREAM, block: REF TEXT,
startIndex: NAT ← 0, stopIndexPlusOne: NAT] RETURNS [nBytesRead: NAT];
PutBlockDisallowed: PROC [self: STREAM, block: REF READONLY TEXT, startIndex: NAT,
stopIndexPlusOne: NAT];
UnsafeGetBlockDisallowed: PUBLIC PROC [self: STREAM, block: IO.UnsafeBlock]
RETURNS [nBytesRead: INT];
UnsafePutBlockDisallowed: PUBLIC PROC [self: STREAM, block: IO.UnsafeBlock];
SetIndexDisallowed: PROC [self: STREAM, index: INT];
-- These all raise IO.Error[IF streamIsClosed THEN StreamClosed ELSE
--NotImplementedForThisStream].
Invalidate: PROC [self: STREAM];
-- Substitutes a new ProcHandle into self such that all operations raise
--IO.Error[IF streamIsClosed THEN StreamClosed ELSE NotImplementedForThisStream].
AlpineOpen: PROC [
fileName: ROPE,
accessOptions: FileIO.AccessOptions ← read,
createOptions: FileIO.CreateOptions ← none,
closeOptions: FileIO.CloseOptions ← FileIO.defaultCloseOptions,
transaction: REF ANY ← NIL, -- AlpTransaction.Handle
raw: FileIO.RawOption ← FALSE,
createLength: INT ← 10 * FileIO.bytesPerPage,
streamBufferParms: FileIO.StreamBufferParms ← FileIO.minimumStreamBufferParms]
RETURNS [STREAM];
-- Alpine version of FileIO.Open.
CIFSOpen: PROC [
fileName: ROPE,
accessOptions: FileIO.AccessOptions,
createOptions: FileIO.CreateOptions,
closeOptions: FileIO.CloseOptions,
transaction: Transaction.Handle,
raw: FileIO.RawOption,
createLength: INT,
streamBufferParms: FileIO.StreamBufferParms]
RETURNS [STREAM];
-- CIFS version of FileIO.Open.
ComSoftOpen: PROC [
fileName: ROPE,
accessOptions: FileIO.AccessOptions,
createOptions: FileIO.CreateOptions,
closeOptions: FileIO.CloseOptions,
transaction: Transaction.Handle,
raw: FileIO.RawOption,
createLength: INT,
streamBufferParms: FileIO.StreamBufferParms]
RETURNS [STREAM];
-- Common Software Directory Package version of FileIO.Open.
IsThisThingATiogaFile: PROC [h: STREAM] RETURNS [yes: BOOLEAN, len: INT];
-- h must be a file stream. Checks to see if the file behind h is in tioga format,
--and if so returns the number of bytes of plain text in it.
-- Pilot leader page format (must agree with format used by directory implementation).
LeaderPage: TYPE = MACHINE DEPENDENT RECORD [
versionID: CARDINAL,
-- key to identify this leader page format
dataType: FileStream.Subtype,
-- ??
create, write, read: System.GreenwichMeanTime,
length: INT,
-- number of bytes in file
nameLength: CARDINAL,
-- number of bytes in name string
name: PACKED ARRAY [0..maxLeaderNameCharacters) OF CHARACTER];
leaderVersionID: CARDINAL = 01240;
maxLeaderNameCharacters: CARDINAL = 40;
END.
CHANGE LOG
Created by MBrown on December 12, 1980 12:04 PM
Changed by MBrown on January 6, 1981 8:53 PM
-- Added Invalidate, added trans field to pilot data.
Changed by MBrown on January 16, 1981 10:00 AM
-- DataObject is now defined without using a Stream.Handle (copied structure from
--FileStreamImpl).
Changed by MBrown on January 18, 1981 1:00 AM
-- LeaderPage now defined here (but it uses something called FileStream.Subtype for its
--"dataType" field).
Changed by MBrown on 18-Jan-81 16:49:31
-- Added bufferDirty (for juniper stream use). and streamIsClosed (for diagnosis from
--the debugger). Improved the description of invariants.
Changed by MBrown on January 21, 1981 3:45 PM
-- Complete re-think of Pilot FileStream state, to make Put faster and generally reduce
--the number of expensive conversions betweeen pages and bytes. Not yet implemented.
Changed by MBrown on January 22, 1981 3:12 PM
-- Improved comments on invariants.
Changed by MBrown on January 25, 1981 8:19 PM
-- Added Juniper variant of Data.
Changed by MBrown on 27-Jan-81 15:10:07
-- FileByteStreamJuniper -> Juniper.
Changed by MBrown on 29-Jan-81 20:43:05
-- Added JOpen, POpen.
Changed by Russ Atkinson on 26-May-81 14:07:10
-- CedarString -> Rope, LONG CARDINAL -> LONG INTEGER
Changed by MBrown on 7-Dec-81 10:30:56
-- Conversion to IO, INT, ROPE, etc.
Changed by MBrown on March 26, 1982 4:40 pm
-- Added tiogaReader field (this is redundant, but may be useful for debugging), and the
--IsThisThingATiogaFile proc.
Changed by Teitelman on May 26, 1982 4:52 pm
-- changed to safe language, name change IOStream -> IO.
Changed by MBrown on August 23, 1982 2:18 pm
-- Eliminated TEXTDataOffset, added bufferParms, renamed JOpen -> JuniperOpen,
--POpen -> ComSoftOpen, added CIFSOpen, added CIFS open file to pilot variant of Data.
Changed by MBrown on May 16, 1983 2:03 pm
-- Eliminated Juniper stuff, added Alpine stuff.