def fsValidate(self): """Sanity-check filesystem parameters.""" rt11util.assertError(self.fsSize > 9, "Filesystem is too small.") # ? rt11util.assertError(self.fsSize < 65536, "Filesystem is too large.") rt11util.assertError(self.fsNumDirSegs > 0, "No directory segments.") rt11util.assertError(self.fsNumDirSegs < 32, "Too many directory segments.") rt11util.assertError(self.fsExtraWords >= 0, "Negative extra dir entry byte count.") rt11util.assertWarn(self.fsFirstDirSeg == 6, "Unexpected first directory segment block number.") rt11util.assertWarn( self.fsDataStart == (self.fsFirstDirSeg + (self.fsNumDirSegs * 2)), "Data blocks do not start immediately after directory segments.", ) rt11util.assertError( self.fsDataStart + self.fsDataBlocks + self.fsResBlocks == self.fsSize, "Invalid block counts." ) rt11util.assertError(self.fsResBlocks >= 0, "Negative reserved block count.")
def fsSaveFile(self, rtFilename, hostFilename=""): """Save permanent file with specified name to host filesystem. If hostFilename is not specified, RT-11 filename will be used and file will be saved in current directory. If host filename is specified, it may include a relative or absolute path.""" r50Name = rad50.filenameToRad50(rtFilename) rtFilename = rad50.rad50ToFilename(r50Name) savedFile = False for de in self.fsFileList: if (de.deStatus & deEPERM) and (de.deName == r50Name): savedFile = True de.deSaveFile(hostFilename) break rt11util.assertWarn(savedFile, "Could not find file " + rtFilename)
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