-- FileIOCommonImpl.mesa -- Last Edited by -- MBrown on February 8, 1983 4:45 pm -- Teitelman on June 9, 1982 9:14 pm DIRECTORY Rope USING [Fetch, Find, Length, ROPE], FileIO USING [AccessOptions, CreateOptions, CloseOptions, OpenFailed, OpenFailure, RawOption, StreamBufferParms, Trans], FileIOPrivate USING [CIFSOpen, ComSoftOpen, Data], IO USING [CreateRefStreamProcs, Error, GetChar, GetIndex, GetLength, SetIndex, STREAM, StreamProcs, UnsafeBlock], Transaction USING [Handle, nullHandle]; FileIOCommonImpl: CEDAR PROGRAM IMPORTS FileIO, FileIOPrivate, IO, Rope, Transaction EXPORTS FileIO, FileIOPrivate = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; DataHandle: TYPE = REF Data; Data: TYPE = FileIOPrivate.Data; OpenFailed: PUBLIC SIGNAL [why: FileIO.OpenFailure, fileName: ROPE] RETURNS [retryFileName: ROPE] = CODE; Open: PUBLIC PROC [ fileName: ROPE, accessOptions: FileIO.AccessOptions, createOptions: FileIO.CreateOptions, closeOptions: FileIO.CloseOptions, transaction: FileIO.Trans, raw: FileIO.RawOption, createLength: INT, streamBufferParms: FileIO.StreamBufferParms] RETURNS [STREAM] = TRUSTED { -- FileIO.Open -- This proc just decides which more specific Open proc to call, and handles a few errors. openFailure: FileIO.OpenFailure; { -- block for failure exit DirSystem: TYPE = { CIFS, ComSoft, Juniper }; SelectDirSystem: SAFE PROC [fileName: ROPE] RETURNS [dir: DirSystem] = CHECKED { RETURN [ SELECT fileName.Fetch[0] FROM '/ => CIFS, '[ => IF Rope.Find[s1: fileName, pos1: 0, s2: "[Juniper]", case: FALSE] = 0 THEN Juniper ELSE CIFS, ENDCASE => ComSoft ]; }; dirSystem: DirSystem; IF fileName.Length[] = 0 THEN { openFailure ← fileNotFound; GOTO failure }; IF accessOptions = read THEN createOptions ← oldOnly; dirSystem ← SelectDirSystem[fileName]; SELECT dirSystem FROM CIFS, ComSoft => { trans: Transaction.Handle ← Transaction.nullHandle; WITH t: transaction SELECT FROM pilot => trans ← t.trans; juniper => IF t.trans # NIL THEN { openFailure ← wrongTransactionType; GOTO failure }; ENDCASE => ERROR; IF dirSystem = CIFS THEN RETURN [FileIOPrivate.CIFSOpen[ fileName, accessOptions, createOptions, closeOptions, trans, raw, createLength, streamBufferParms]] ELSE RETURN [FileIOPrivate.ComSoftOpen[ fileName, accessOptions, createOptions, closeOptions, trans, raw, createLength, streamBufferParms]]; }; -- CIFS, ComSoft ENDCASE => ERROR; EXITS failure => { retryFileName: ROPE = SIGNAL FileIO.OpenFailed[why: openFailure, fileName: fileName]; RETURN [Open[retryFileName, accessOptions, createOptions, closeOptions, transaction, raw, createLength, streamBufferParms]] } }};--Open -- Procs exported to FileIOPrivate IsThisThingATiogaFile: PUBLIC PROC [h: STREAM] RETURNS [BOOLEAN, INT] = { -- FileIOPrivate.IsThisThingATiogaFile pos, len, length: INT; { -- block so EXITS code can use pos, len, and length. controlHeaderId: ARRAY [0..fileIdSize) OF CHAR = [235C,312C]; controlTrailerId: ARRAY [0..fileIdSize) OF CHAR = [205C,227C]; commentHeaderId: ARRAY [0..fileIdSize) OF CHAR = [0C,0C]; fileIdSize: NAT = 2; numTrailerLengths: NAT = 3; -- <file-props-length> <data-length> <file-length> endSize: NAT = fileIdSize+numTrailerLengths*4; -- trailer plus three lengths ReadLen: PROC [h: STREAM] RETURNS [INT] = { start: PACKED ARRAY [0..3] OF CHARACTER; start[0] ← h.GetChar[]; start[1] ← h.GetChar[]; start[2] ← h.GetChar[]; start[3] ← h.GetChar[]; RETURN [LOOPHOLE[start]] }; commentStart, commentLen, propsLen, controlLen, controlEnd: INT; pos ← h.GetIndex[]; -- save position to restore later length ← h.GetLength[]; -- length including any trailer stuff controlEnd ← length-endSize; -- where the trailer info starts IF controlEnd <= 0 THEN GOTO fail; -- too small h.SetIndex[controlEnd]; -- set up to read the trailer FOR i:NAT IN [0..fileIdSize) DO -- read the controlTrailerId IF h.GetChar[] # controlTrailerId[i] THEN GOTO fail; ENDLOOP; IF (propsLen ← ReadLen[h]) NOT IN [0..controlEnd) THEN GOTO fail; IF (commentStart ← ReadLen[h]) NOT IN [0..controlEnd) THEN GOTO fail; IF ReadLen[h] # length THEN GOTO fail; IF commentStart > 0 THEN { -- may have padded text with a null h.SetIndex[commentStart-1]; len ← IF h.GetChar[]=0C THEN commentStart-1 ELSE commentStart } ELSE h.SetIndex[len ← commentStart]; FOR i:NAT IN [0..fileIdSize) DO -- read the commentHeaderId IF h.GetChar[] # commentHeaderId[i] THEN GOTO fail; ENDLOOP; commentLen ← ReadLen[h]; -- the length of the comment section IF commentStart+commentLen NOT IN [0..controlEnd) THEN GOTO fail; h.SetIndex[commentStart+commentLen]; -- go to start of control info FOR i:NAT IN [0..fileIdSize) DO -- check the controlHeaderId IF h.GetChar[] # controlHeaderId[i] THEN GOTO fail; ENDLOOP; controlLen ← ReadLen[h]; -- the length of the control section IF commentStart+commentLen+controlLen # length THEN GOTO fail; GOTO succeed; EXITS fail => { h.SetIndex[pos]; RETURN [FALSE, length] }; succeed => { h.SetIndex[pos]; RETURN [TRUE, len] }; }}; GetCharDisallowed: PUBLIC PROC [self: STREAM] RETURNS [CHAR] = { RaiseStreamError[self]; ERROR }; PutCharDisallowed: PUBLIC PROC [self: STREAM, char: CHAR] = { RaiseStreamError[self] }; GetBlockDisallowed: PUBLIC PROC [self: STREAM, block: REF TEXT, startIndex: NAT, stopIndexPlusOne: NAT] RETURNS [nBytesRead: NAT] = { RaiseStreamError[self]; ERROR }; PutBlockDisallowed: PUBLIC PROC [self: STREAM, block: REF READONLY TEXT, startIndex: NAT, stopIndexPlusOne: NAT] = { RaiseStreamError[self] }; UnsafeGetBlockDisallowed: PUBLIC PROC [self: STREAM, block: IO.UnsafeBlock] RETURNS [nBytesRead: INT] = { RaiseStreamError[self]; ERROR }; UnsafePutBlockDisallowed: PUBLIC PROC [self: STREAM, block: IO.UnsafeBlock] = { RaiseStreamError[self] }; SetIndexDisallowed: PUBLIC PROC [self: STREAM, index: INT] = { RaiseStreamError[self] }; RaiseStreamError: PROC [self: STREAM] = { selfData: DataHandle = NARROW[self.streamData]; ERROR IO.Error[ IF selfData.streamIsClosed THEN StreamClosed ELSE NotImplementedForThisStream, self] }; Invalidate: PUBLIC PROC [self: STREAM] = { -- FileIOPrivate.Invalidate self.streamProcs ← commonFileIOInvalidProcs; -- Procs on self.propList must fend for themselves }; -- Procs called via commonFileIOInvalidProcs. GetIndexDisallowed: PROC [self: STREAM] RETURNS [i: INT] = { RaiseStreamError[self] }; DisallowedOpReturnsBoolean: PROC [self: STREAM] RETURNS[BOOL] = { RaiseStreamError[self]; ERROR }; StreamOpIsNoop: PROC [self: STREAM] = { }; CloseIsNoop: PROC [self: STREAM, abort: BOOL] = { }; commonFileIOInvalidProcs: REF IO.StreamProcs = IO.CreateRefStreamProcs[ getChar: GetCharDisallowed, endOf: DisallowedOpReturnsBoolean, charsAvail: DisallowedOpReturnsBoolean, getBlock: GetBlockDisallowed, unsafeGetBlock: UnsafeGetBlockDisallowed, putChar: PutCharDisallowed, putBlock: PutBlockDisallowed, unsafePutBlock: UnsafePutBlockDisallowed, flush: StreamOpIsNoop, reset: StreamOpIsNoop, close: CloseIsNoop, getIndex: GetIndexDisallowed, setIndex: SetIndexDisallowed, name: "Closed File" ]; END. CHANGE LOG Created by MBrown on December 12, 1980 12:56 PM Changed by MBrown on January 6, 1981 8:22 PM -- HandleFromFileName moved to FileByteStreamPilotImpl, since it now admits to being --Pilot-specific. Added Invalidate, and private disallowed procs (GetLength, etc). Changed by MBrown on 21-Jan-81 23:54:12 -- Added IndexTooLarge. Changed by MBrown on January 22, 1981 3:59 PM -- Make various procs raise streamClosed or operationDisallowed depending on value of --streamIsClosed. Changed by MBrown on 27-Jan-81 15:25:20 -- Moved Open here (juniper stuff being added). Changed by MBrown on 29-Jan-81 8:58:37 -- Bug in Open: passed fileName (including server) to JOpen. Juniper gave a "protection violation". Changed by MBrown on 29-Jan-81 20:38:29 -- Moved POpen and JOpen out. Changed by MBrown on 1-Mar-81 13:05:50 -- Minor changes due to change in CedarString interface (Rest procedure gone, SubString -> Substr). Changed by MBrown on 31-Mar-81 17:06:56 -- In Open, IF accessOptions = read THEN createOptions ← oldOnly. Change by Russ Atkinson, 26-May-81 14:00:13 -- CedarString -> Rope, LONG CARDINAL -> LONG INTEGER Changed by MBrown on 7-Dec-81 10:33:20 -- Changed name to FileIO, made compatible with IO, use INT, ROPE, etc. Changed by MBrown on March 25, 1982 9:07 am -- In Open, check for fileName.Length[] = 0 before doing fileName.Fetch[0]. Change --Rope.Size -> Rope.Length, Rope.Index -> Rope.Find. Changed by MBrown on March 26, 1982 5:14 pm -- Added IsThisThingATiogaFile, raw parm to Open. Changed by MBrown on September 1, 1982 9:37 pm -- FileIO.OpenFailed, CIFS access, initial file size in Open, buffer parms. Changed by MBrown on February 8, 1983 4:45 pm -- Flushed Juniper support.