def _fsWriteDirSegs(self, f): """Write the directory segments.""" # How many of the dir segments will we use? Need to # hold files in file list plus end of segment marker per dir seg dsNeeded = math.ceil((len(self.fsFileList) + self.fsNumDirSegs) / self.fsDirEntPerSeg) # Sanity check: Will the entries fit? rt11util.assertError(dsNeeded <= self.fsNumDirSegs, "Not enough directory segments to hold file list.") # Start constructing dir segs in memory. Represent as lists of 16-bit # word values for now. dirSegs = [None] * self.fsNumDirSegs for dsNum in range(self.fsNumDirSegs): dirSegs[dsNum] = [0] * rt11util.rtBlockSize # Fill in header info that we already know for dsNum in range(len(dirSegs)): dirSegs[dsNum][:rtDirSegHdrSize] = [self.fsNumDirSegs, 0, 0, self.fsExtraWords * 2, 0] # Fill in file information dsNum = 1 deNum = 0 highDs = 0 blkNum = self.fsDataStart for de in self.fsFileList: # Fill in more directory entry header information if deNum == 0: dirSegs[dsNum - 1][1] = dsNum + 1 dirSegs[dsNum - 1][4] = blkNum # Fill in one directory entry deOffset = rtDirSegHdrSize + (deNum * self.fsDirEntSize) dirSegs[dsNum - 1][deOffset : deOffset + rtDirEntSize] = [ de.deStatus, de.deName[0], de.deName[1], de.deName[2], de.deLength, de.deJobChan, de.deDate, ] rt11util.assertError(blkNum == de.deStart, "Block number calculation error.") blkNum = blkNum + de.deLength if self.fsDirEntSize > rtDirEntSize: # Fill in extra bytes dirsegs[dsNum - 1][deOffset + rtDirEntSize : deOffset + self.fsDirEntSize] = de.deExtra deNum = deNum + 1 if deNum == (self.fsDirEntPerSeg - 1): # Add end of segment marker deOffset = rtDirSegHdrSize + (deNum * self.fsDirEntSize) dirSegs[dsNum - 1][deOffset] = deEEOS deNum = 0 dsNum = dsNum + 1 if deNum != 0: # If deNum == 0, we should have just written an end of segment # marker. If not, add one now. deOffset = rtDirSegHdrSize + (deNum * self.fsDirEntSize) dirSegs[dsNum - 1][deOffset] = deEEOS # Next dir seg pointer = 0 dirSegs[dsNum - 1][1] = 0 # Now plug in high dir seg number highDs = dsNum for dsNum in range(len(dirSegs)): dirSegs[dsNum][2] = highDs # Write the constructed dir segs to disk blks = bytearray(0) for ds in dirSegs: blks += rt11util.wordsToBytes(ds) rt11util.writeBlocks(f, blks, self.fsFirstDirSeg, self.fsNumDirSegs * 2)
def _fsReadDirSegs(self, f): """Parse the directory segments. Directory segments are 2 blocks long, start at block number fsFirstDirSeg, and are numbered 1 through 31. We ignore garbage in unused directory segments.""" if self.fsVerbose: print "_fsReadDirSegs():" dsNum = 1 while dsNum > 0: # Read directory segment, convert to 16-bit words bnum = self.fsFirstDirSeg + ((dsNum - 1) * 2) if self.fsVerbose: print " blocks {:d},{:d}".format(bnum, bnum + 1) blk = rt11util.readBlocks(f, bnum, 2) wblk = rt11util.bytesToWords(blk) # Extract fields from directory segment header numDs, nextDs, highDs, xBytes, dStart = wblk[:rtDirSegHdrSize] if self.fsVerbose: print " numDs =", numDs print " nextDs =", nextDs print " highDs =", highDs print " xBytes =", xBytes print " dStart =", dStart rt11util.assertError((xBytes % 2) == 0, "Extra bytes count must be even.") if dsNum == 1: # Initialize stuff from first dir segment header self.fsNumDirSegs = numDs self.fsExtraWords = xBytes / 2 self.fsDirEntSize = rtDirEntSize + self.fsExtraWords self.fsDirEntPerSeg = (rtDirSegSize - rtDirSegHdrSize) / self.fsDirEntSize self.fsDataStart = dStart else: # Sanity checks # Each segment should have matching number of dir segs count in header rt11util.assertWarn( numDs == self.fsNumDirSegs, "Number of directory segments changed in segment " + str(dsNum) ) # Each segment should have matching extra byte count in header rt11util.assertWarn( xBytes / 2 == self.fsExtraWords, "Number of extra entry bytes changed in segment " + str(dsNum) ) # Dir segments should point to contiguous sets of data blocks rt11util.assertWarn(dStart == dsDataBlock, "Non-contiguous data in directory segment " + str(dsNum)) # Unpack remainder of directory segment into list of # directory entry tuples. # This line is so ugly, it ought to be in Perl. # Don't ask me how it works; I barely understood it when I wrote it. dsEntries = zip(*[iter(wblk[rtDirSegHdrSize:])] * self.fsDirEntSize) dsDataBlock = dStart for dsEntry in dsEntries: statWord, fn1, fn2, ext, fileLen, jobChan, fileDate = dsEntry[:7] if statWord & deEEOS: # End of this directory segment break entry = dirEntry( name=[fn1, fn2, ext], length=fileLen, start=dsDataBlock, status=statWord, jobchan=jobChan, date=fileDate, extra=rt11util.wordsToBytes(dsEntry[7:]), ) self.fsFileList.append(entry) self.fsDataBlocks += fileLen dsDataBlock = dsDataBlock + fileLen if nextDs > 0: rt11util.assertWarn(nextDs == dsNum + 1, "Non-sequential directory segments.") dsNum = nextDs