<<>> <> <> <> <> DIRECTORY BasicTime, FS, IO, MimSysOps, MimSysOpsPrivate, Rope, VM; MimSysOpsImpl: CEDAR MONITOR IMPORTS FS, IO, Rope, VM EXPORTS MimSysOps = BEGIN OPEN MimSysOps, MimSysOpsPrivate; GMT: TYPE = BasicTime.GMT; nullGMT: GMT = BasicTime.nullGMT; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; currentInterceptor: Interceptor ¬ NIL; openList: OpenStreamList ¬ NIL; OpenStreamList: TYPE = LIST OF OpenStreamEntry; OpenStreamEntry: TYPE = RECORD [stream: STREAM, kind: OpenKind]; Intercept: PUBLIC ENTRY PROC [interceptor: Interceptor] RETURNS [old: Interceptor] = { old ¬ currentInterceptor; currentInterceptor ¬ interceptor; }; <<>> Open: PUBLIC PROC [name: ROPE, kind: OpenKind] RETURNS [stream: STREAM ¬ NIL, err: ROPE ¬ NIL, time: GMT ¬ nullGMT] = { interceptor: 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: Interceptor ¬ currentInterceptor; kind: 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: 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: LIST OF MappedFileInner ¬ mappedFiles; IF sample = NIL THEN EXIT; [] ¬ RemMappedFileInner[sample.first, FALSE]; ENDLOOP; 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: 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: OpenKind] = { openList ¬ CONS[ [stream, kind], openList]; }; <> mappedFiles: LIST OF MappedFileInner ¬ NIL; MappedFile: TYPE = REF MappedFileRecord; MappedFileRecord: PUBLIC TYPE = MimSysOpsPrivate.MappedFileRecord; FindMappedFile: ENTRY PROC [name: ROPE] RETURNS [mf: MappedFile] = { ENABLE UNWIND => NULL; FOR each: LIST OF MappedFileInner ¬ mappedFiles, each.rest WHILE each # NIL DO mfi: MappedFileInner ¬ each.first; IF Rope.Equal[name, mfi.name] THEN { mfi.count ¬ mfi.count + 1; RETURN [NEW[MappedFileRecord ¬ [mfi]]]; }; ENDLOOP; RETURN [NIL]; }; AddMappedFileInner: ENTRY PROC [mfi: MappedFileInner] = { mappedFiles ¬ CONS[mfi, mappedFiles]; }; DestroyHandle: ENTRY PROC [mf: MappedFile] RETURNS [mfi: MappedFileInner] = { IF mf # NIL THEN { mfi ¬ mf.mfi; mf.mfi ¬ NIL; }; }; RemMappedFileInner: ENTRY PROC [mfi: MappedFileInner, decr: BOOL] RETURNS [st: STREAM] = { ENABLE UNWIND => NULL; lag: LIST OF MappedFileInner ¬ mappedFiles; IF decr THEN { IF mfi.count > 0 THEN mfi.count ¬ mfi.count - 1; RETURN; }; IF lag # NIL THEN { interval: VM.Interval ¬ mfi.interval; st ¬ mfi.stream; mfi.stream ¬ NIL; mfi.interval ¬ VM.nullInterval; mfi.base ¬ NIL; IF interval # VM.nullInterval THEN TRUSTED {VM.Free[interval]}; IF lag.first = mfi THEN {mappedFiles ¬ lag.rest; RETURN}; FOR each: LIST OF MappedFileInner ¬ lag.rest, each.rest WHILE each # NIL DO IF each.first = mfi THEN {lag.rest ¬ each.rest; RETURN}; lag ¬ each; ENDLOOP; }; }; Map: PUBLIC PROC [name: ROPE] RETURNS [mf: MappedFile, err: ROPE] = { mf ¬ FindMappedFile[name]; IF mf = NIL THEN { stream: STREAM; time: BasicTime.GMT; [stream, err, time] ¬ Open[name, read]; IF stream # NIL THEN { bytes: INT ¬ IO.GetLength[stream]; interval: VM.Interval ¬ VM.SimpleAllocate[VM.PagesForBytes[bytes]]; mfi: MappedFileInner ¬ NEW[MappedFileInnerRecord ¬ [ name: name, interval: interval, count: 1, stream: stream, base: VM.AddressForPageNumber[interval.page], bytes: bytes]]; TRUSTED { wp: LONG POINTER TO CARD ¬ LOOPHOLE[mfi.base]; wn: CARD ¬ VM.BytesForPages[interval.count] / BYTES[CARD]; WHILE wn # 0 DO wp­ ¬ CARD.LAST; wn ¬ wn - 1; ENDLOOP; IO.SetIndex[stream, 0]; [] ¬ IO.UnsafeGetBlock[ self: stream, block: [base: mfi.base, startIndex: 0, count: bytes]]; }; [] ¬ Close[stream, TRUE]; -- new mfi.stream ¬ NIL; -- new AddMappedFileInner[mfi]; mf ¬ NEW[MappedFileRecord ¬ [mfi]]; }; }; }; UnMap: PUBLIC PROC [mf: MappedFile] = { mfi: MappedFileInner ¬ DestroyHandle[mf]; IF mfi # NIL THEN { st: STREAM ¬ RemMappedFileInner[mfi, TRUE]; IF st # NIL THEN { [] ¬ Close[st, TRUE]; }; }; }; MapBase: PUBLIC PROC [mf: MappedFile] RETURNS [LONG POINTER] = { RETURN [mf.base]; }; MapLength: PUBLIC PROC [mf: MappedFile] RETURNS [CARD] = { RETURN [mf.bytes]; }; END.