def carveDeleteFiles_slow(self, catalogLBAs=None, filter_=None):
        self.fastMode = False
        self.files = {}
        if not self.ftlhax:
            self.ftlhax = self.nand.ftl.YAFTL_hax2()
        if not self.fileIds:
            self.getExistingFileIDs()
        if self.encrypted and len(self.keys) == 0:
            print "Carving attribute file for file keys"
            self.carveKeys()
        print "Carving catalog file"
        self.carveCatalog(catalogLBAs, filter_)

        self.okfiles = 0
        total = 0
        print "%d files" % len(self.files)
        for name, vv, usn in self.files.values():
            keys = set(self.keys.get(vv.data.fileID, [self.emfkey]))
            print "%s num keys = %d" % (name, len(keys))
            good_usn = 0
            for filekey in keys:
                if good_usn:
                    break
                first_block = vv.data.dataFork.HFSPlusExtentDescriptor[
                    0].startBlock
                for usn, pn in self.pagesForLBN(first_block).items():
                    d = self.decryptFileBlock(pn[-1], filekey,
                                              self.first_lba + first_block, 0)
                    if isDecryptedCorrectly(d):
                        #print "USN for first block : ", usn
                        good_usn = usn
                        break
            if good_usn == 0:
                continue
            self.getFileAtUSN(name, vv.data, filekey, good_usn)
    def carveDeleteFiles_slow(self, catalogLBAs=None, filter_=None):
        self.fastMode = False
        self.files = {}
        if not self.ftlhax:
            self.ftlhax = self.nand.ftl.YAFTL_hax2()
        if not self.fileIds:
            self.getExistingFileIDs()
        if self.encrypted and len(self.keys) == 0:
            print "Carving attribute file for file keys"
            self.carveKeys()
        print "Carving catalog file"
        self.carveCatalog(catalogLBAs, filter_)

        self.okfiles = 0
        total = 0
        print "%d files" % len(self.files)
        for name, vv, usn in self.files.values():
            keys = set(self.keys.get(vv.data.fileID, [self.emfkey]))
            print "%s num keys = %d" % (name, len(keys))
            good_usn = 0
            for filekey in keys:
                if good_usn:
                    break
                first_block = vv.data.dataFork.HFSPlusExtentDescriptor[0].startBlock
                for usn, pn in self.pagesForLBN(first_block).items():
                    d = self.decryptFileBlock(pn[-1], filekey, self.first_lba+first_block, 0)
                    if isDecryptedCorrectly(d):
                        #print "USN for first block : ", usn
                        good_usn = usn
                        break
            if good_usn == 0:
                continue
            self.getFileAtUSN(name, vv.data, filekey, good_usn)
    def readFileHax(self, filename, filerecord, filekeys):
        lba0 = self.first_lba + filerecord.dataFork.HFSPlusExtentDescriptor[
            0].startBlock
        filekey = None
        good_usn = None
        first_vpn = 0
        first_usn = 0
        hax = self.ftlhax
        print "%d versions for first lba" % len(hax.get(lba0, []))
        for k in filekeys:
            for vpn in hax.get(lba0, []):
                s, ciphertext = self.nand.ftl.YAFTL_readPage(vpn,
                                                             key=None,
                                                             lpn=None)
                if not ciphertext:
                    continue
                d = self.decryptFileBlock2(ciphertext, k, lba0, 0)
                #hexdump(d[:16])
                if isDecryptedCorrectly(d):
                    filekey = k
                    first_vpn = vpn
                    first_usn = good_usn = s.usn
                    block = vpn / self.nand.ftl.vfl.pages_per_sublk
                    break
        if not filekey:
            return False
        logicalSize = filerecord.dataFork.logicalSize
        missing_pages = 0
        file_pages = []
        lbns = []
        for extent in self.volume.getAllExtents(filerecord.dataFork,
                                                filerecord.fileID):
            for bn in xrange(extent.startBlock,
                             extent.startBlock + extent.blockCount):
                lbns.append(self.first_lba + bn)
        datas = {}
        usnblocksToLookAT = sorted(
            filter(lambda x: x >= good_usn, self.userblocks.keys()))[:5]
        print usnblocksToLookAT
        usnblocksToLookAT.insert(0, 0)
        first_block = True
        done = False
        for usn in usnblocksToLookAT:
            if first_block:
                bbtoc = self.getBBTOC(block)
                first_block = False
            else:
                bbtoc = self.getBBTOC(self.userblocks[usn])
            for lbn in bbtoc.keys():
                if not lbn in lbns:
                    continue
                idx = lbns.index(lbn)
                s, ciphertext = self.nand.ftl.YAFTL_readPage(bbtoc[lbn],
                                                             key=None,
                                                             lpn=None)
                if not ciphertext:
                    continue
                ciphertext = self.decryptFileBlock2(ciphertext, filekey, lbn,
                                                    idx * self.pageSize)
                if idx == 0:
                    if not isDecryptedCorrectly(ciphertext):
                        continue
                datas[idx * self.pageSize] = (ciphertext, lbn - self.first_lba)
                #if idx == len(lbns):
                if len(datas) == len(lbns):
                    done = True
                    break

            if done:
                break
        cleartext = ""
        decrypt_offset = 0
        for i in xrange(0, logicalSize, self.pageSize):
            if datas.has_key(i):
                ciphertext, lbn = datas[i]
                cleartext += ciphertext
            else:
                cleartext += self.blankPage
                missing_pages += 1
            decrypt_offset += self.pageSize

        print "Recovered %d:%s %d missing pages, size %s, created %s, contentModDate %s" % \
            (filerecord.fileID, filename.encode("utf-8"), missing_pages, sizeof_fmt(logicalSize), hfs_date(filerecord.createDate), hfs_date(filerecord.contentModDate))
        filename = "%d_%d_%s" % (filerecord.fileID, first_usn, filename)
        if missing_pages == 0:
            filename = "OK_" + filename
            self.okfiles += 1
        if True:  #exactSize:
            cleartext = cleartext[:logicalSize]
        self.writeUndeletedFile(filename, cleartext)
        return True
    def readFileHax(self, filename, filerecord, filekeys):
        lba0 = self.first_lba + filerecord.dataFork.HFSPlusExtentDescriptor[0].startBlock
        filekey = None
        good_usn = None
        first_vpn = 0
        first_usn = 0
        hax = self.ftlhax
        print "%d versions for first lba" % len(hax.get(lba0, []))
        for k in filekeys:
            for vpn in hax.get(lba0, []):
                s, ciphertext = self.nand.ftl.YAFTL_readPage(vpn, key=None, lpn=None)
                if not ciphertext:
                    continue
                d = self.decryptFileBlock2(ciphertext, k, lba0, 0)
                #hexdump(d[:16])
                if isDecryptedCorrectly(d):
                    filekey = k
                    first_vpn = vpn
                    first_usn = good_usn = s.usn
                    block = vpn / self.nand.ftl.vfl.pages_per_sublk
                    break
        if not filekey:
            return False
        logicalSize = filerecord.dataFork.logicalSize
        missing_pages = 0
        file_pages = []
        lbns = []
        for extent in self.volume.getAllExtents(filerecord.dataFork, filerecord.fileID):
            for bn in xrange(extent.startBlock, extent.startBlock + extent.blockCount):
                lbns.append(self.first_lba + bn)
        datas = {}
        usnblocksToLookAT = sorted(filter(lambda x: x >= good_usn, self.userblocks.keys()))[:5]
        print usnblocksToLookAT
        usnblocksToLookAT.insert(0, 0)
        first_block = True
        done = False
        for usn in usnblocksToLookAT:
            if first_block:
                bbtoc = self.getBBTOC(block)
                first_block = False
            else:
                bbtoc = self.getBBTOC(self.userblocks[usn])
            for lbn in bbtoc.keys():
                if not lbn in lbns:
                    continue
                idx = lbns.index(lbn)
                s, ciphertext = self.nand.ftl.YAFTL_readPage(bbtoc[lbn], key=None, lpn=None)
                if not ciphertext:
                    continue
                ciphertext = self.decryptFileBlock2(ciphertext, filekey, lbn, idx*self.pageSize)
                if idx == 0:
                    if not isDecryptedCorrectly(ciphertext):
                        continue
                datas[idx*self.pageSize] = (ciphertext, lbn - self.first_lba)
                #if idx == len(lbns):
                if len(datas) == len(lbns):
                    done=True
                    break
                    
            if done:
                break
        cleartext = ""
        decrypt_offset = 0
        for i in xrange(0,logicalSize, self.pageSize):
            if datas.has_key(i):
                ciphertext, lbn = datas[i]
                cleartext += ciphertext
            else:
                cleartext += self.blankPage
                missing_pages += 1
            decrypt_offset += self.pageSize

        print "Recovered %d:%s %d missing pages, size %s, created %s, contentModDate %s" % \
            (filerecord.fileID, filename.encode("utf-8"), missing_pages, sizeof_fmt(logicalSize), hfs_date(filerecord.createDate), hfs_date(filerecord.contentModDate))
        filename =  "%d_%d_%s" % (filerecord.fileID, first_usn, filename)
        if missing_pages == 0:
            filename = "OK_" + filename
            self.okfiles += 1
        if True:#exactSize:
            cleartext = cleartext[:logicalSize]
        self.writeUndeletedFile(filename, cleartext)
        return True
    def readFileHax(self, filename, filerecord, filekeys):
        lba0 = self.first_lba + filerecord.dataFork.HFSPlusExtentDescriptor[0].startBlock
        filekey = None
        good_usn = None
        first_usn = 0
        lba0_versions = self.nand.ftl.findAllVersions(lba0)
        print "%d versions for first lba" % len(lba0_versions)
        for k in filekeys:
            for addr in lba0_versions:
                ciphertext = self.nand.ftl.readPage1(addr, key=None, lpn=lba0)
                if not ciphertext:
                    continue
                d = self.decryptFileBlock2(ciphertext, k, lba0, 0)
                if isDecryptedCorrectly(d):
                    hexdump(d[:16])
                    filekey = k
                    weaveSeq = addr[0]
                    break
        if not filekey:
            return False
        logicalSize = filerecord.dataFork.logicalSize
        missing_pages = 0
        file_pages = []
        lbns = []
        for extent in self.volume.getAllExtents(filerecord.dataFork, filerecord.fileID):
            for bn in xrange(extent.startBlock, extent.startBlock + extent.blockCount):
                lbns.append(self.first_lba + bn)
        datas = {}
        
        first_block = True
        done = False
        for weaveSeq,lbn,ce,block,page in self.nand.ftl.findPagesInRange(weaveSeq, weaveSeq+50000):
            if not lbn in lbns:
                continue
            idx = lbns.index(lbn)
            ciphertext = self.nand.ftl.readPage1((weaveSeq,ce,block,page), key=None, lpn=lbn)
            if not ciphertext:
                continue
            ciphertext = self.decryptFileBlock2(ciphertext, filekey, lbn, idx*self.pageSize)
            if idx == 0:
                if not isDecryptedCorrectly(ciphertext):
                    continue
            datas[idx*self.pageSize] = (ciphertext, lbn - self.first_lba)
            #if idx == len(lbns):
            if len(datas) == len(lbns):
                done=True
                break
            if done:
                break
        cleartext = ""
        decrypt_offset = 0
        for i in xrange(0,logicalSize, self.pageSize):
            if datas.has_key(i):
                ciphertext, lbn = datas[i]
                cleartext += ciphertext
            else:
                cleartext += self.blankPage
                missing_pages += 1
            decrypt_offset += self.pageSize

        print "Recovered %d:%s %d missing pages, size %s, created %s, contentModDate %s" % \
            (filerecord.fileID, filename.encode("utf-8"), missing_pages, sizeof_fmt(logicalSize), hfs_date(filerecord.createDate), hfs_date(filerecord.contentModDate))
        filename =  "%d_%d_%s" % (filerecord.fileID, first_usn, filename)
        if missing_pages == 0:
            filename = "OK_" + filename
            self.okfiles += 1
        if True:#exactSize:
            cleartext = cleartext[:logicalSize]
        self.writeUndeletedFile(filename, cleartext)
        return True