YggFileStreamImpl.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Bob Hagmann January 20, 1989 3:40:53 pm PST
DIRECTORY
BasicTime USING [GMT],
Camelot USING [tidT],
File USING [wordsPerPage],
FileStream USING [StreamFromOpenFile],
FS USING [FileType, Lock, OpenFile, tUnspecified],
FSBackdoor USING [CreateProcsOpenFile, CreateFileProcs, FileProcs],
IO USING [STREAM],
PBasics USING [bytesPerWord, Move, Word],
Rope USING [ROPE],
YggBuffMan USING [ReadPages, WritePages, VMPageSet],
YggDID USING [],
YggFile USING [FileHandle, Info, SetByteSize, SetSize, WordsForPages],
YggFileStream USING [],
YggFileInternal USING [FileHandleRep],
YggInternal USING [FileHandle];
YggFileStreamImpl: CEDAR PROGRAM
IMPORTS FileStream, FSBackdoor, PBasics, YggBuffMan, YggFile
EXPORTS YggFile, YggFileStream, YggInternal
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
FileProcs: REF FSBackdoor.FileProcs;
FileHandle: TYPE = YggInternal.FileHandle;
FileHandleRep: PUBLIC TYPE = YggFileInternal.FileHandleRep;
FileDataRep: TYPE = RECORD [
openFile: YggFile.FileHandle,
tid: Camelot.tidT
];
wordsPerPage: INT ← 1024;
bytesPerPage: INT ← wordsPerPage * PBasics.bytesPerWord;
unitsPerPage: INT ← wordsPerPage * UNITS[PBasics.Word];
fileBytesPerPage: INT ← File.wordsPerPage * BYTES[WORD];
filePagesPerMyPage: INT ← bytesPerPage/fileBytesPerPage;
YggFile procs
FileFromComponentFiles: PUBLIC PROC [componentFiles: LIST OF FileHandle, fileUse: ATOM] RETURNS [file: FileHandle ← NIL] ~ {
Select a file
FOR cf: LIST OF FileHandle ← componentFiles, cf.rest UNTIL cf = NIL DO
IF cf.first.fileUse = fileUse THEN {
RETURN[cf.first];
};
ENDLOOP;
};
FileUseFromComponentFiles: PUBLIC PROC [componentFiles: LIST OF FileHandle] RETURNS [fileUses: LIST OF ATOM] ~ {
Find the uses of all the files
FOR cf: LIST OF FileHandle ← componentFiles, cf.rest UNTIL cf = NIL DO
fileUses ← CONS[cf.first.fileUse, fileUses];
ENDLOOP;
};
StreamFromComponentFilesAndTid: PUBLIC PROC [componentFiles: LIST OF YggInternal.FileHandle, fileUse: ATOM, tid: Camelot.tidT, readOnly: BOOL] RETURNS [stream: IO.STREAMNIL] = {
FOR cf: LIST OF FileHandle ← componentFiles, cf.rest UNTIL cf = NIL DO
IF cf.first.fileUse = fileUse THEN {
stream ← StreamFromOpenFileAndTid[cf.first, tid, readOnly];
};
ENDLOOP;
};
StreamFromOpenFileAndTid: PUBLIC PROC [file: YggFile.FileHandle, tid: Camelot.tidT, readOnly: BOOL] RETURNS [stream: IO.STREAMNIL] = {
fsOpenFile: FS.OpenFile;
fileDataRep: REF FileDataRep;
fileDataRep ← NEW[FileDataRep ← [openFile: file, tid: tid]];
fsOpenFile ← FSBackdoor.CreateProcsOpenFile[clientFile: fileDataRep, fileProcs: FileProcs];
stream ← FileStream.StreamFromOpenFile[fsOpenFile, IF readOnly THEN $read ELSE $write];
};
FS file procs
GetClass: PROC [clientFile: REF] RETURNS [ATOM] = {
RETURN [$Yggdrasil];
};
SameFile: PROC [clientFile1, clientFile2: REF] RETURNS [BOOL] = {
ERROR;
};
GetName: PROC [clientFile: REF] RETURNS [fullFName, attachedTo: Rope.ROPE] = {
WITH clientFile SELECT FROM
fileData: REF FileDataRep => {
RETURN [NIL, NIL];
};
ENDCASE => ERROR;
};
GetInfo: PROC [clientFile: REF] RETURNS [keep: CARDINAL ← 1, pages, bytes: INT,
created: BasicTime.GMT, lock: FS.Lock ← write, fileType: FS.FileType ← FS.tUnspecified] = {
WITH clientFile SELECT FROM
fileData: REF FileDataRep => {
[size: pages, byteSize: bytes] ← YggFile.Info[file: fileData.openFile, tid: fileData.tid];
pages ← pages*filePagesPerMyPage;
};
ENDCASE => ERROR;
};
SetPageCount: PROC [clientFile: REF, pages: INT] = {
WITH clientFile SELECT FROM
fileData: REF FileDataRep => {
YggFile.SetSize[file: fileData.openFile, size: (pages + filePagesPerMyPage - 1)/filePagesPerMyPage, tid: fileData.tid];
};
ENDCASE => ERROR;
};
SetByteCountAndCreatedTime: PROC [clientFile: REF, bytes: INT,
created: BasicTime.GMT] = {
WITH clientFile SELECT FROM
fileData: REF FileDataRep => {
YggFile.SetByteSize[file: fileData.openFile, byteSize: bytes, tid: fileData.tid];
};
ENDCASE => ERROR;
};
Read: UNSAFE PROC [clientFile: REF, from, nPages: INT, to: LONG POINTER] = {
WITH clientFile SELECT FROM
fileData: REF FileDataRep => {
toPtr: LONG POINTER ← to;
nPagesLeft: INT ← nPages;
vMPageSet: YggBuffMan.VMPageSet;
IF from MOD filePagesPerMyPage # 0 THEN ERROR;
vMPageSet ← YggBuffMan.ReadPages[fileHandle: fileData.openFile, tid: fileData.tid, pageRun: [from/filePagesPerMyPage, (nPages + filePagesPerMyPage - 1) /filePagesPerMyPage]];
FOR vmp: YggBuffMan.VMPageSet ← vMPageSet, vmp.rest UNTIL vmp = NIL DO
nowPages: INTMIN[vmp.first.pageRun.pages, nPagesLeft];
TRUSTED {PBasics.Move[dst: toPtr, src: vmp.first.buffer, nWords: YggFile.WordsForPages[nowPages]]; };
toPtr ← toPtr + YggFile.WordsForPages[nowPages]*UNITS[WORD];
nPagesLeft ← nPagesLeft ← nowPages;
ENDLOOP;
};
ENDCASE => ERROR;
};
Write: PROC [clientFile: REF, to: INT, nPages: INT, from: LONG POINTER] = {
WITH clientFile SELECT FROM
fileData: REF FileDataRep => {
IF to MOD filePagesPerMyPage # 0 THEN ERROR;
YggBuffMan.WritePages[fileHandle: fileData.openFile, tid: fileData.tid, to: to/filePagesPerMyPage, nPages: (nPages + filePagesPerMyPage - 1) /filePagesPerMyPage, from: from];
};
ENDCASE => ERROR;
};
Close: PROC [clientFile: REF] = {
};
Initialization
FileProcs ← FSBackdoor.CreateFileProcs[GetClass, SameFile, GetName, GetInfo, SetPageCount, SetByteCountAndCreatedTime, Read, Write, Close];
END.