<<>> <> <> <> <> <> DIRECTORY BasicTime USING [GMT, nullGMT], CinderSysOps USING [Interceptor, OpenKind], FS USING [Delete, Error, GetInfo, GetName, OpenFile, OpenFileFromStream, StreamOpen], IO USING [Close, Error, STREAM], Rope USING [ROPE]; CinderSysOpsImpl: CEDAR MONITOR IMPORTS FS, IO EXPORTS CinderSysOps = BEGIN GMT: TYPE = BasicTime.GMT; nullGMT: GMT = BasicTime.nullGMT; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; currentInterceptor: CinderSysOps.Interceptor ¬ NIL; openList: OpenStreamList ¬ NIL; OpenStreamList: TYPE = LIST OF OpenStreamEntry; OpenStreamEntry: TYPE = RECORD [stream: STREAM, kind: CinderSysOps.OpenKind]; Intercept: PUBLIC ENTRY PROC [interceptor: CinderSysOps.Interceptor] RETURNS [old: CinderSysOps.Interceptor] = { old ¬ currentInterceptor; currentInterceptor ¬ interceptor; }; <<>> Open: PUBLIC PROC [name: ROPE, kind: CinderSysOps.OpenKind] RETURNS [stream: STREAM ¬ NIL, err: ROPE ¬ NIL, time: GMT ¬ nullGMT] = { interceptor: CinderSysOps.Interceptor ¬ currentInterceptor; IF interceptor # NIL AND interceptor.open # NIL THEN [stream, err, time] ¬ interceptor.open[interceptor, name, kind] ELSE { <> ENABLE FS.Error => {err ¬ error.explanation; GO TO oops}; st: STREAM ¬ FS.StreamOpen[ fileName: name, accessOptions: IF kind = read THEN $read ELSE $create]; time ¬ FS.GetInfo[FS.OpenFileFromStream[st]].created; stream ¬ st; }; IF err = NIL THEN AddToList[stream, kind]; EXITS oops => {}; }; <<>> Close: PUBLIC PROC [stream: STREAM, abortAndDelete: BOOL] RETURNS [err: ROPE] = { interceptor: CinderSysOps.Interceptor ¬ currentInterceptor; kind: CinderSysOps.OpenKind; [stream, kind] ¬ RemFromList[stream]; IF stream = NIL THEN RETURN; IF interceptor # NIL AND interceptor.close # NIL THEN err ¬ interceptor.close[interceptor, stream, abortAndDelete] ELSE { <> ENABLE { FS.Error => {err ¬ error.explanation; GO TO exit}; IO.Error => GO TO exit; }; file: FS.OpenFile ¬ FS.OpenFileFromStream[stream]; name: ROPE ¬ FS.GetName[file].fullFName; time: BasicTime.GMT ¬ FS.GetInfo[file].created; SELECT kind FROM read, writeLog => IO.Close[stream]; ENDCASE => { IO.Close[stream, abortAndDelete]; IF abortAndDelete THEN FS.Delete[name, time]; }; }; EXITS exit => {}; }; Delete: PUBLIC PROC [name: ROPE] RETURNS [err: ROPE] = { interceptor: CinderSysOps.Interceptor ¬ currentInterceptor; IF interceptor # NIL AND interceptor.delete # NIL THEN err ¬ interceptor.delete[interceptor, name] ELSE FS.Delete[name ! FS.Error => {err ¬ error.explanation; CONTINUE}]; }; Cleanup: PUBLIC PROC [abortAndDelete: BOOL] = { DO sample: OpenStreamList ¬ openList; IF sample = NIL THEN EXIT; [] ¬ Close[sample.first.stream, abortAndDelete]; ENDLOOP; }; RemFromList: ENTRY PROC [stream: STREAM] RETURNS [st: STREAM ¬ NIL, kind: CinderSysOps.OpenKind ¬ read] = { lag: OpenStreamList ¬ openList; IF lag # NIL THEN { IF lag.first.stream = stream THEN { st ¬ stream; kind ¬ lag.first.kind; openList ¬ lag.rest; RETURN; }; DO next: OpenStreamList ¬ lag.rest; IF next = NIL THEN EXIT; IF next.first.stream = stream THEN { st ¬ stream; kind ¬ next.first.kind; lag.rest ¬ next.rest; RETURN; }; lag ¬ next; ENDLOOP; }; }; <<>> AddToList: ENTRY PROC [stream: STREAM, kind: CinderSysOps.OpenKind] = { openList ¬ CONS[ [stream, kind], openList]; }; <<>> END.