-- file CoreIO.Mesa -- edited by Kierr, May 3, 1978 5:24 PM. -- edited by Levin, January 16, 1981 1:37 PM. -- edited by Brotz, September 2, 1980 8:42 PM. DIRECTORY AltoFileDefs: FROM "AltoFileDefs", BFSDefs: FROM "BFSDefs", crD: FROM "CoreDefs", crID: FROM "CoreImpDefs", DiskDefs: FROM "DiskDefs", DiskKDDefs: FROM "DiskKDDefs", exD: FROM "ExceptionDefs", gsD: FROM "GlobalStorageDefs", MiscDefs: FROM "MiscDefs", ovD: FROM "OverviewDefs", SystemDefs: FROM "SystemDefs"; CoreIO: PROGRAM IMPORTS BFSDefs, crID, DiskDefs, DiskKDDefs, exD, gsD, MiscDefs, SystemDefs EXPORTS crD, crID --Alto[Read/Write]Pages-- SHARES crD = PUBLIC BEGIN OPEN crD, crID; -- Purpose: provides a Laurel style interface to files and raw storage/structures. ReadPages: PROCEDURE [buffer: gsD.MemoryPagePtr, byteCount: CARDINAL, pageNumber: PageNumber, uFH: UFileHandle] RETURNS [erc: ovD.ErrorCode, bytesRead: CARDINAL]= -- Reads up to "byteCount" bytes of data from the file asscoiated with uFH beginning with -- page "pageNumber" into the memory page(s) beginning at "buffer". The byteCount -- must be a multiple of 512 (an even page). The bytesRead returned is the count of bytes -- actually read and will be equal to the requested byteCount except at EOF, when it may -- be less. (Note that if pageNumber is beyound the end-of-file then bytesRead=0 is -- returned.) -- Error Codes: (##DO: Update)diskError. BEGIN [erc, bytesRead] _ uFH.read[buffer, byteCount, pageNumber, uFH]; END; -- of ReadPages. WritePages: PROCEDURE [buffer: gsD.MemoryPagePtr, byteCount: CARDINAL, pageNumber: PageNumber, uFH: UFileHandle] RETURNS [ovD.ErrorCode]= -- Writes byteCount of data from memory, beginning at buffer, to pageNumber of the file -- uFH. The operation is legal only if the file was opened in update OpenMode. This can -- be used to extend the file's size by writing beyond the current end. (Note, however, -- that the file is never shortened.) The byteCount must always be a multiple of 512, an -- even page, except on the last page of the file. -- Regarding byteCount, let "remainder" be (byteCount MOD 512). If non-zero, remainder -- denotes the number of bytes supplied by the client to be written on the last page of the -- current transaction. The number of byte actually written will be the -- MAX[current-bytes-on-that-file-page, remainder]; the value of all bytes beyond -- remainder are indeterminate. -- Side effects: Updates the file size in the uFH as needed. -- Error Codes: (##DO: Update), diskError. BEGIN RETURN [uFH.write[buffer, byteCount, pageNumber, uFH]]; END; -- of WritePages -- -- AltoCore: INTERNAL MODULE = -- Purpose: provides support for Alto file system in Laurel. -- ErrorCodes from ovD: ok: ovD.ErrorCode = ovD.ok; diskError: ovD.ErrorCode = ovD.diskError; diskCorrupted: ovD.ErrorCode = ovD.diskCorrupted; diskFull: ovD.ErrorCode = ovD.diskFull; fileInUse: ovD.ErrorCode = ovD.fileInUse; illegalFilename: ovD.ErrorCode = ovD.illegalFilename; fileNotFound: ovD.ErrorCode = ovD.fileNotFound; -- Note: all of the following operations require a UFileHandle for a file which is in open -- state. They have no way of checking the validity of the UFileHandle. Terrible things -- will happen if they are given an invalid UFileHandle. AltoReadPages: PROCEDURE [buffer: gsD.MemoryPagePtr, byteCount: CARDINAL, pageNumber: UPageNumber, uFH: UFileHandle] RETURNS [erc: ovD.ErrorCode, bytesRead: CARDINAL] = -- Reads up to "byteCount" bytes of data from the file asscoiated with uFH beginning with -- page "pageNumber" into the memory page(s) beginning at "buffer". The byteCount -- must be a multiple of 512 (an even page). The bytesRead returned is the count of bytes -- actually read and will be equal to the requested byteCount except at EOF, when it may -- be less. (Note that if pageNumber is beyound the end-of-file then bytesRead=0 is -- returned.) -- Error Codes: diskError. BEGIN firstPage: AltoPageNumber = MapUToAltoPage[pageNumber]; lastPage: AltoPageNumber = firstPage + (byteCount / 512) - 1; endPage: AltoPageNumber; numBytes: CARDINAL[0 .. 512]; aFH: AltoFileHandle; WITH fh: uFH SELECT FROM alto => aFH _ @fh; ENDCASE => exD.SysBug[]; IF LOOPHOLE[buffer, CARDINAL] MOD 256 ~= 0 THEN exD.SysBug[]; -- catch smash? IF pageNumber > aFH.lastFilePage -- Past EOF. OR firstPage > lastPage -- Reading less than a page. THEN RETURN[ovD.ok, 0]; [erc, endPage, numBytes] _ AltoTransferExistingPages [bufferAddress: buffer, firstPage: firstPage, lastPage: lastPage, aFH: aFH, action: ReadD]; bytesRead _ (endPage - firstPage) * 512 + numBytes; END; -- of AltoReadPages -- AltoWritePages: PROCEDURE [buffer: gsD.MemoryPagePtr, byteCount: CARDINAL, pageNumber: UPageNumber, uFH: UFileHandle] RETURNS [erc: ovD.ErrorCode] = -- Writes byteCount of data from memory, beginning at buffer, to pageNumber of the file -- aFH. The operation is legal only if the file was opened in update OpenMode. This can -- be used to extend the file's size by writing beyond the current end. (Note, however, -- that the file is never shortened.) The byteCount must always be a multiple of 512, an -- even page, except on the last page of the file. And it cannot be 0. -- Regarding byteCount, let "remainder" be (byteCount MOD 512). If non-zero, remainder -- denotes the number of bytes supplied by the client to be written on the last page of the -- current transaction. The number of byte actually written will be the -- MAX[current-bytes-on-that-file-page, remainder]; the value of all bytes beyond -- remainder are indeterminate. -- Side effects: Updates the file size in the uFH as needed. -- Error Codes: diskFull, diskError, fileTooBig. BEGIN smallCAs: ARRAY [0 .. 2) OF gsD.MemoryPagePtr; cAs: CAsPtr; scratchBufferPtr, zeroedBufferPtr, bigCAsPtr: POINTER _ NIL; lastFilePage: AltoPageNumber = MapUToAltoPage[uFH.lastFilePage]; firstPage: AltoPageNumber = MapUToAltoPage[pageNumber]; lastPage: AltoPageNumber _ firstPage + (byteCount + 511) / 512 - 1; bytesRequestedForLastPage: CARDINAL; -- [1 .. 512] bytesForLastPage: CARDINAL[0 .. 512]; pageCount: CARDINAL; i: AltoPageNumber; j: PageByte; aFH: AltoFileHandle; WITH fh: uFH SELECT FROM alto => aFH _ @fh; ENDCASE => exD.SysBug[]; BEGIN -- this is a "Block for EXITS" [i, ] _ MakeFileIndexCanonical[firstPage, byteCount]; -- Calculate new last page. IF i > maxVDAIndex THEN RETURN [ovD.fileTooBig]; -- Making file too long. IF byteCount = 0 -- Bad arg. OR aFH.access # update -- Read-only. THEN exD.SysBug[]; -- Part 1: Re-write previously existing full pages, i.e. the -- possibly empty interval [firstPage .. lastFilePage). IF firstPage < lastFilePage THEN BEGIN [erc, , ] _ AltoTransferExistingPages [bufferAddress: buffer, firstPage: firstPage, lastPage: MIN[lastPage, lastFilePage - 1], aFH: aFH, action: WriteD]; IF erc # ok -- Error. OR lastPage < lastFilePage -- All done. THEN RETURN; END; -- Part 2: Write the last file page and any new file pages, -- i.e. the possibly empty interval [lastFilePage .. lastPage]. -- Construct an array of buffers for the transaction. Then -- use WriteAtFileEnd to effect the transfers. bytesRequestedForLastPage _ ((byteCount + 511) MOD 512) + 1; bytesForLastPage _ IF lastPage = lastFilePage THEN MAX[bytesRequestedForLastPage, uFH.byteFF] ELSE bytesRequestedForLastPage; IF bytesForLastPage = 512 THEN -- Set-up to write an extra empty page at the end. {lastPage _ lastPage + 1; bytesForLastPage _ 0}; pageCount _ (lastPage + 1) - lastFilePage; cAs _ IF pageCount <= LENGTH[smallCAs] THEN LOOPHOLE[@smallCAs - lastFilePage] ELSE LOOPHOLE[(bigCAsPtr _ SystemDefs.AllocateHeapNode[pageCount]) - lastFilePage]; IF firstPage > lastFilePage THEN BEGIN -- Client is skipping over a hole. We should write zeros there. -- Prepare pointer (i.e. cAs[lastFilePage]) with which to -- overwrite current last file page. Depending on the byte -- count (aFH.byteFF) we will either read & re-write the last -- file page or just write a page of zeros. IF aFH.byteFF > 0 THEN BEGIN -- We have no good data for the current last file page, -- but there is good data there now, so preserve the -- current data for the write. cAs[lastFilePage] _ scratchBufferPtr _ GetPageBuffer[zeroOutData: FALSE]; [erc, , ] _ AltoTransferExistingPages [bufferAddress: scratchBufferPtr, firstPage: lastFilePage, lastPage: lastFilePage, aFH: aFH, action: ReadD]; IF erc # ok THEN GOTO leaving; -- Disk problems. END -- of aFH.byteFF > 0. ELSE -- i.e. aFH.byteFF = 0. Use zeroed data. cAs[lastFilePage] _ zeroedBufferPtr _ GetPageBuffer[zeroOutData: TRUE]; -- Prepare pointers for writing all pages beyound current last -- file page. -- Set up pointers to zeroed data. FOR i IN (lastFilePage .. firstPage) DO IF zeroedBufferPtr = NIL THEN zeroedBufferPtr _ GetPageBuffer[zeroOutData: TRUE]; -- Use zeroed data. cAs[i] _ zeroedBufferPtr; ENDLOOP; -- Set up pointers to clients data. FOR i IN [firstPage .. lastPage] DO cAs[i] _ buffer + 256 * (i - firstPage); ENDLOOP; END -- of firstPage > lastFilePage. ELSE -- i.e. firstPage <= lastFilePage (i.e., no filler needed) -- Set up pointers to clients data. FOR i IN [lastFilePage .. lastPage] DO cAs[i] _ buffer + 256 * (i - firstPage); ENDLOOP; [erc, i, j] _ WriteAtFileEnd[cAs, pageCount, bytesForLastPage, aFH]; IF erc = ovD.ok AND (i > lastFilePage OR (i = lastFilePage AND j # aFH.byteFF)) -- File length change -- THEN {aFH.lastFilePage _ MapAltoToUPage[i]; aFH.byteFF _ j}; GOTO leaving; EXITS leaving => BEGIN -- of cleanup for return. IF bigCAsPtr # NIL THEN SystemDefs.FreeHeapNode[bigCAsPtr]; IF scratchBufferPtr # NIL THEN gsD.ReturnMemoryPages[1, scratchBufferPtr]; IF zeroedBufferPtr # NIL THEN gsD.ReturnMemoryPages[1, zeroedBufferPtr]; END; -- of cleanup; END; -- of "Block for EXITS". END; -- of AltoWritePages -- GetPageBuffer: PROCEDURE [zeroOutData: BOOLEAN] RETURNS [p: gsD.MemoryPagePtr] = BEGIN p _ gsD.GetMemoryPages[1]; IF zeroOutData THEN MiscDefs.Zero[p, 256]; END; -- of GetPageBuffer -- AltoTransferExistingPages: PROCEDURE [bufferAddress: gsD.MemoryPagePtr, firstPage, lastPage: AltoPageNumber, aFH: AltoFileHandle, action: AltoFileDefs.vDC] RETURNS [errorCode: ovD.ErrorCode, endPage: AltoPageNumber, numBytes: [0 .. 512]] = -- Read/write a set of existing page to/from bufferAddress in memory, starting with -- firstPage. firstPage MUST be part of the file. If lastPage is off the end of the file, then -- page transfers will stop on end of file. -- If errorCode = ok, then returns the endPage actually transfered and numBytes on the end -- page. -- ErrorCodes: DiskError. BEGIN -- Method: Find firstPageVDA. Then use SwapPages to effect the transfer. Then record the -- VDA of the last page transfered and those on either side. Note that SwapPages does not -- use the vDATable, so the chunk mechanism (used elsewhere in this module) is -- bypassed. sDR: swap DiskDefs.DiskRequest; firstPageVDA: VDA; diskPageDesc: DiskDefs.DiskPageDesc; [errorCode, firstPageVDA] _ GetVDA[firstPage, aFH]; IF errorCode # ok THEN RETURN; sDR _ [ca: bufferAddress, da: @firstPageVDA, firstPage: firstPage, lastPage: lastPage, fp: @aFH.handle.fp, fixedCA: FALSE, action: action, lastAction: action, signalCheckError: FALSE, option: swap [desc: @diskPageDesc]]; errorCode _ ok; [endPage, numBytes] _ DiskDefs.SwapPages[@sDR ! DiskDefs.UnrecoverableDiskError => {errorCode _ diskError; CONTINUE}]; IF errorCode = ok THEN BEGIN TablePutVDA[aFH.vDATable, sDR.desc.page - 1, sDR.desc.prev]; TablePutVDA[aFH.vDATable, sDR.desc.page, sDR.desc.this]; TablePutVDA[aFH.vDATable, sDR.desc.page + 1, sDR.desc.next]; END; END; -- of AltoTransferExistingPages -- WriteAtFileEnd: PROCEDURE [cAs: CAsPtr, itemCount: CARDINAL, bytesInLastPage: PageByte, aFH: AltoFileHandle] RETURNS [erc: ovD.ErrorCode, lastPageWritten: AltoPageNumber, lastBytes: PageByte] = -- Write from memory buffers to file, starting with the last file page. cAs is the address of -- an array of pointers to memory buffers. itemCount is the number of buffers to be -- written. -- ErrorCodes: diskFull, diskError ## check for more & implications. BEGIN upDR: update DiskDefs.DiskRequest; extDR: extend DiskDefs.DiskRequest _ [ca: cAs, da: , firstPage: , lastPage: , fp: @aFH.handle.fp, fixedCA: FALSE, action: WriteD, lastAction: WriteD, signalCheckError: FALSE, option: extend[lastBytes: ]]; oldLastPage: AltoPageNumber = MapUToAltoPage[aFH.lastFilePage]; newLastPage: AltoPageNumber = oldLastPage + itemCount - 1; -- Limit of write. AssignPagesInChunk: PROCEDURE [firstP, lastP: AltoPageNumber, aFH: AltoFileHandle, vDAPtr: VDAsPtr] RETURNS [erc: ovD.ErrorCode] = -- Called to get new pages assigned at file's end. Uses the following variables from -- WriteAtFileEnd: upDR, oldLastPage. BEGIN p: AltoPageNumber; vDA: VDA; erc _ ok; -- Assume the best. upDR.da _ LOOPHOLE[vDAPtr, POINTER TO VDA]; upDR.firstPage _ firstP; upDR.lastPage _ lastP; BFSDefs.AssignPages[@upDR ! DiskKDDefs.DiskFull => BEGIN -- Oops, undo (any) assigned. erc _ diskFull; FOR p IN (oldLastPage .. lastP] DO vDA _ TableGetVDA[aFH.vDATable, p]; --Can't use vDAPtr. IF vDA = AltoFileDefs.fillinDA OR vDA = AltoFileDefs.eofDA THEN EXIT; DiskKDDefs.ReleaseDiskPage[vDA]; ENDLOOP; CONTINUE; END; DiskDefs.UnrecoverableDiskError => {erc _ diskError; CONTINUE}]; END; -- of AssignPagesInChunk -- RewritePagesInChunk: PROCEDURE [firstP, lastP: AltoPageNumber, aFH: AltoFileHandle, vDAPtr: VDAsPtr] RETURNS [erc: ovD.ErrorCode] = -- Called to write existing but not yet written pages for a chunk of the VDAs. Uses the -- following variables from WriteAtFileEnd: extDR, newLastPage, bytesInLastPage, -- lastPageWritten, lastBytes. BEGIN erc _ ok; extDR.da _ LOOPHOLE[vDAPtr, POINTER TO VDA]; extDR.firstPage _ firstP; extDR.lastPage _ lastP; extDR.lastBytes _ IF lastP = newLastPage THEN bytesInLastPage ELSE 512; [lastPageWritten, lastBytes] _ BFSDefs.RewritePages[@extDR ! DiskDefs.UnrecoverableDiskError => {erc _ diskError; CONTINUE}]; END; -- of RewritePagesInChunk -- -- Note: AssignPages requires that the VDA be present for the old last page and its -- predecessor. [erc, ] _ GetVDA[oldLastPage-1, aFH]; -- Make sure VDA is in the table. IF erc # ok THEN RETURN; [erc, ] _ GetVDA[oldLastPage, aFH]; -- Make sure VDA is in the table. IF erc # ok THEN RETURN; erc _ CallProcedureForChunks[oldLastPage + 1, newLastPage, aFH, AssignPagesInChunk]; IF erc # ok THEN RETURN; erc _ CallProcedureForChunks[oldLastPage, newLastPage, aFH, RewritePagesInChunk]; DecrementFreePageCount[itemCount - 1]; END; -- of WriteAtFileEnd -- -- END of AltoCore: INTERNAL MODULE; END. -- of CoreIO --z20461(529)\f1