// IfsLeafVMemOpen.bcpl - Leaf VMem Open - SWAPPABLE // Copyright Xerox Corporation 1979, 1980, 1981 // Last modified December 4, 1981 12:05 PM by Taft get ksTypeReadOnly, charItem from "Streams.d"; get ecAllocLeafVMem, ecBadPageSize, ecBadOldPageNumber from "IfsLeafErrors.decl"; get DSK, eofDA, fillInDA, lnPageSize from "Disks.d"; get FD, dr, modeRead, modeReadWrite, oldPageNumber from "IfsDirs.decl"; get "IfsLeaf.decl"; get "IfsLeafVMem.decl"; get "IfsIsf.d"; // This is gross, but it's absolutely impossible to get Tfs.d here... // get DCreadnD from "Tfs.d"; manifest DCreadnD = 153011B; external [ //outgoing procedures OpenLeafVMem; FindLVMD; FMapChecksum; //incoming procedures Allocate; CloseIFSFile; Closes; CreateDiskStream; DoubleUsc; Enqueue; FileLength; Free; GetDiskFromFD; GetBufferForFD; IFSError; InitFmap; InsertBefore; MultEq; MoveBlock; Noop; OpenIFSFile; ReadCalendar; TransferLeaderPage; Zero; ActOnDiskPages; //incoming statics leafVMI; sysZone; ] //---------------------------------------------------------------------------- let OpenLeafVMem(fd, mode, lvEc) = valof //---------------------------------------------------------------------------- [ let ild = GetBufferForFD(fd); @lvEc = OpenIFSFile(fd, mode, ild); if @lvEc ne 0 then [ Free(sysZone, ild); resultis 0; ] let fp = lv fd>>FD.dr>>DR.fp; let disk = GetDiskFromFD(fd); if disk>>DSK.lnPageSize - logVMPageLength ne logVPagesPerLeafPage then IFSError(ecBadPageSize); // Verify the hintLastPageFA here..... let page = ild>>ILD.hintLastPageFa.pageNumber; let DAs = vec 3; DAs!0 = fillInDA; DAs!1 = ild>>ILD.hintLastPageFa.da; DAs!2 = fillInDA; let numChars = nil; if page eq 0 % ActOnDiskPages(disk, nil, DAs-page+1, lv fd>>FD.dr>>DR.fp, page, page, DCreadnD, lv numChars, 0, nil, 0, 0, true) ne page % DAs!2 ne eofDA % numChars ne ild>>ILD.hintLastPageFa.charPos then [ // hintLastPageFa is wrong; use DiskStreams to fix it. // We don't use IFSStreams because we want the file to stay open. let s = CreateDiskStream(fp, ksTypeReadOnly, charItem, 0, 0, 0, nil, disk); if s eq 0 then [ CloseIFSFile(fd); Free(sysZone, ild); @lvEc = ecAllocLeafVMem; resultis 0; ] FileLength(s); Closes(s); TransferLeaderPage(fd, ild); ] if fd>>FD.oldPageNumber eq 0 then fd>>FD.oldPageNumber = ild>>ILD.hintLastPageFa.pageNumber; let lvmd = 0; let lastpage = ild>>ILD.hintLastPageFa.pageNumber-1; // Look for existing lvmd w/same da. unless mode eq modeReadWrite do lvmd = FindLVMD(fp); if lvmd eq 0 then [ lvmd = MakeLVMD(fp, ild, disk); // Assign a file index, and insert into ordered lvmd queue. let fileIndex = 0; let testLVMD = leafVMI>>LeafVMI.lvmdQueue.head; while testLVMD ne 0 & fileIndex eq testLVMD>>LVMD.fileIndex do [ let onebit = signBit; for i = 1 to bitsPerWord do // "add" one to fileIndex [ fileIndex = fileIndex xor onebit; if (fileIndex & onebit) ne 0 then break; onebit = onebit rshift 1; ] testLVMD = @testLVMD; ] test testLVMD eq 0 ifso Enqueue(lv leafVMI>>LeafVMI.lvmdQueue, lvmd); ifnot InsertBefore(lv leafVMI>>LeafVMI.lvmdQueue, testLVMD, lvmd); lvmd>>LVMD.fileIndex = fileIndex; lvmd>>LVMD.lastAddress.high = lastpage rshift logPagesPerWord; lvmd>>LVMD.lastAddress.low = lastpage lshift logBytesPerPage + ild>>ILD.hintLastPageFa.charPos; ] ReadCalendar(lv ild>>ILD.read) unless mode eq modeRead do [ ReadCalendar(lv ild>>ILD.created); ReadCalendar(lv ild>>ILD.written); ild>>ILD.checksum = 0; // changing data will invalidate software checksum ] TransferLeaderPage(fd, ild, true); Free(sysZone, ild); lvmd>>LVMD.refCount = lvmd>>LVMD.refCount + 1; resultis lvmd; ] //---------------------------------------------------------------------------- and FindLVMD(fp) = valof //---------------------------------------------------------------------------- [ manifest fpOffset = (offset LVMD.fmap + offset FM.fp)/16; let unit = fp>>IFP.unit; let page = fp>>IFP.page; let lvmd = leafVMI>>LeafVMI.lvmdQueue.head; while lvmd ne 0 do test unit eq (lvmd+fpOffset)>>IFP.unit & page eq (lvmd+fpOffset)>>IFP.page ifso break; ifnot lvmd = @lvmd; resultis lvmd; ] //---------------------------------------------------------------------------- and MakeLVMD(fp, ild, disk) = valof //---------------------------------------------------------------------------- [ // Try old page 0 filemap...remember, // "last" is relative to the start of the MAP itself. let oldMap = lv ild>>LeafILD.fmap; let last = ild>>LeafILD.fmapLast; // Compute the page number and DA of last file page referenced in the map. // Compare these with the hintLastPageFA. let lastRun = lv oldMap!(last-2); let lastPage = oldMap!last - 1; let oldMapOK = oldMap!(last+1) eq fillInDA % lastPage eq ild>>ILD.hintLastPageFa.pageNumber & (lastRun!1 + (lastPage - lastRun!0)) eq ild>>ILD.hintLastPageFa.da // Check the stored fp on the leader page, the fmap checksum, // the validity of "last", the seal, and make sure that the // fmap write date is later than the last write date of the file. oldMapOK = oldMapOK & ild>>LeafILD.fmapChecksum eq FMapChecksum(oldMap,last) & (last ge lenMapEntry) & (last le maxLenOldFMap-lenMapEntry) & MultEq(fp, lv ild>>LeafILD.fmapFP, lFP) & ild>>LeafILD.fmapSeal eq version & DoubleUsc(lv ild>>LeafILD.fmapWritten, lv ild>>ILD.written) ge 0 let mapLength = oldMapOK? last+mapoffset+lenMapEntry, lenLeafFMap; let lvmd = Allocate(sysZone, lenLVMD + mapLength); Zero(lvmd, lenLVMD); let fmap = lv lvmd>>LVMD.fmap; // This doesn't fail unless lenLeafFMap is wrong!! InitFmap(fmap, mapLength, fp, false, 0, sysZone, disk, leafFMapDelta) if oldMapOK then [ MoveBlock(lv fmap>>FM.map, oldMap, last+lenMapEntry); fmap>>FM.last = last+mapoffset; ] resultis lvmd; ] //---------------------------------------------------------------------------- and FMapChecksum(map, last) = valof //---------------------------------------------------------------------------- [ let sum = 0; for i = map to lv map!(last+1) do sum = sum + @i; resultis sum; ]