-- FileIOPrivate.mesa -- Last edited by -- MBrown on February 8, 1983 4:46 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, FileSystem, RawOption, StreamBufferParms], 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]; JuniperDataHandle: TYPE = REF Data[juniper]; 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 Juniper streams. bufferSwapUnitLength: CARDINAL ← TRASH, -- The length of the buffer swap units, in bytes. Always <= 2*bufferLength. --Ignored by Juniper 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: FileIO.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], juniper => [ ], 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]. 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 February 8, 1983 4:46 pm -- Flushed Juniper support.