Ejemplo n.º 1
0
def main():

    cmdline = get_cmdline()

    dbfilename = cmdline.dbfilename
    if not os.path.exists(dbfilename) or os.path.isdir(dbfilename):
        errexit(1,"file '%s' not found!" % (dbfilename))

    #open database
    print("opening '%s' recovery info database..." % (dbfilename))
    db = RecDB(dbfilename)

    #get data on all uids present
    uidDataList = db.GetUIDDataList()

    #get blocksizes for every supported SBx version
    blocksizes = {}
    for v in seqbox.supported_vers:
        blocksizes[v] = seqbox.SbxBlock(ver=v).blocksize
    
    #info/report
    if cmdline.info:
        report(db, uidDataList, blocksizes)
        errexit(0)

    #build a list of uids to recover:
    uidRecoList = []
    if cmdline.all:
        uidRecoList = list(uidDataList)
    else:
        if cmdline.uid:
            for hexuid in cmdline.uid:
                if len(hexuid) % 2 != 0:
                    errexit(1, "invalid UID!")
                uid = int.from_bytes(binascii.unhexlify(hexuid),
                                     byteorder="big")
                if db.GetBlocksCountFromUID(uid):
                    uidRecoList.append(uid)
                else:
                    errexit(1,"no recoverable UID '%s'" % (hexuid))
        if cmdline.sbx:
            for sbxname in cmdline.sbx:
                uid = db.GetUIDFromSbxName(sbxname)
                if uid:
                    uidRecoList.append(uid)
                else:
                    errexit(1,"no recoverable sbx file '%s'" % (sbxname))
        if cmdline.file:
            for filename in cmdline.file:
                uid = db.GetUIDFromFileName(filename)
                if uid:
                    uidRecoList.append(uid)
                else:
                    errexit(1,"no recoverable file '%s'" % (filename))

    if len(uidRecoList) == 0:
        errexit(1, "nothing to recover!")

    print("recovering SBX files...")
    uid_list = sorted(set(uidRecoList))

    #open all the sources
    finlist = {}
    for key, value in db.GetSourcesList():
        finlist[key] = open(value, "rb")

    uidcount = 0
    totblocks = 0
    totblockserr = 0
    uiderrlist = []
    for uid in uidRecoList:
        uidcount += 1
        sbxver = uidDataList[uid]
        sbx = seqbox.SbxBlock(ver=sbxver, pswd=cmdline.password)
        hexuid = binascii.hexlify(uid.to_bytes(6, byteorder="big")).decode()
        print("UID %s (%i/%i)" % (hexuid, uidcount, len(uid_list)))

        blocksnum = db.GetBlocksCountFromUID(uid)
        print("  blocks: %i - size: %i bytes" %
              (blocksnum, blocksnum * sbx.blocksize))
        meta = db.GetMetaFromUID(uid)
        if "sbxname" in meta:
            sbxname = meta["sbxname"]
        else:
            #use hex uid as name if no metadata present
            sbxname = (binascii.hexlify(uid.to_bytes(6, byteorder="big")).decode() +
                       ".sbx")
        if cmdline.destpath:
            sbxname = os.path.join(cmdline.destpath, sbxname)
        print("  to: '%s'" % sbxname)

        if not cmdline.overwrite:
            sbxname = uniquifyFileName(sbxname)
        fout = open(sbxname, "wb", buffering = 1024*1024)

        blockdatalist = db.GetBlocksListFromUID(uid)
        #read 1 block to initialize the correct block parameters
        #(needed for filling in missing blocks)
        blockdata = blockdatalist[0]
        fin = finlist[blockdata[1]]
        bpos = blockdata[2]
        fin.seek(bpos, 0)
        try:
            sbx.decode(fin.read(sbx.blocksize))
        except seqbox.SbxDecodeError as err:
            print(err)
            errexit(1, "invalid block at offset %s file '%s'" %
                    (hex(bpos), fin.name))
        
        lastblock = -1
        ticks = 0
        missingblocks = 0
        updatetime = time() -1
        maxbnum =  blockdatalist[-1][0]
        #loop trough the block list and recreate SBx file
        for blockdata in blockdatalist:
            bnum = blockdata[0]
            #check for missing blocks and fill in
            if bnum != lastblock +1 and bnum != 1:
                for b in range(lastblock+1, bnum):
                    #no point in an empty block 0 with no metadata
                    if b > 0 and cmdline.fill:
                        sbx.blocknum = b
                        sbx.data = bytes(sbx.datasize)
                        buffer = sbx.encode()
                        fout.write(buffer)
                    missingblocks += 1

            fin = finlist[blockdata[1]]
            bpos = blockdata[2]
            fin.seek(bpos, 0)
            buffer = fin.read(sbx.blocksize)
            fout.write(buffer)
            lastblock = bnum

            #some progress report
            if time() > updatetime or bnum == maxbnum:
                print("  %.1f%%" % (bnum*100.0/maxbnum), " ",
                      "(missing blocks: %i)" % missingblocks,
                      end="\r", flush=True)
                updatetime = time() + .5

        fout.close()
        print()
        if missingblocks > 0:
            uiderrlist.append((uid, missingblocks))
            totblockserr += missingblocks

    print("\ndone.")
    if len(uiderrlist) == 0:
        print("all SBx files recovered with no errors!")
    else:
        print("errors detected in %i SBx file(s)!" % len(uiderrlist))
        report_err(db, uiderrlist, uidDataList, blocksizes)
Ejemplo n.º 2
0
def main():

    cmdline = get_cmdline()

    filenames = []
    for filename in cmdline.filename:
        if os.path.exists(filename):
            filenames.append(filename)
        else:
            errexit(1, "file '%s' not found!" % (filename))
    filenames = sorted(set(filenames), key=os.path.getsize)

    dbfilename = cmdline.dbfilename
    if os.path.isdir(dbfilename):
        dbfilename = os.path.join(dbfilename, "sbxscan.db3")

    #create database tables
    print("creating '%s' database..." % (dbfilename))
    if os.path.exists(dbfilename):
        os.remove(dbfilename)
    conn = sqlite3.connect(dbfilename)
    c = conn.cursor()
    c.execute("CREATE TABLE sbx_source (id INTEGER, name TEXT)")
    c.execute(
        "CREATE TABLE sbx_meta (uid INTEGER, size INTEGER, name TEXT, sbxname TEXT, datetime INTEGER, sbxdatetime INTEGER, fileid INTEGER)"
    )
    c.execute("CREATE TABLE sbx_uids (uid INTEGER, ver INTEGER)")
    c.execute(
        "CREATE TABLE sbx_blocks (uid INTEGER, num INTEGER, fileid INTEGER, pos INTEGER )"
    )
    c.execute("CREATE INDEX blocks ON sbx_blocks (uid, num, pos)")

    #scan all the files/devices
    sbx = seqbox.SbxBlock(ver=cmdline.sbxver, pswd=cmdline.password)
    offset = cmdline.offset
    filenum = 0
    uids = {}
    magic = b'SBx' + bytes([cmdline.sbxver])
    if cmdline.password:
        magic = seqbox.EncDec(cmdline.password, len(magic)).xor(magic)
    scanstep = cmdline.step
    if scanstep == 0:
        scanstep = sbx.blocksize

    for filename in filenames:
        filenum += 1
        print("scanning file/device '%s' (%i/%i)..." %
              (filename, filenum, len(filenames)))
        filesize = getFileSize(filename)

        c.execute("INSERT INTO sbx_source (id, name) VALUES (?, ?)",
                  (filenum, filename))
        conn.commit()

        fin = open(filename, "rb", buffering=cmdline.buffer * 1024)
        blocksfound = 0
        blocksmetafound = 0
        updatetime = time() - 1
        starttime = time()
        docommit = False
        for pos in range(offset, filesize, scanstep):
            fin.seek(pos, 0)
            buffer = fin.read(sbx.blocksize)
            #check for magic
            if buffer[:4] == magic:
                #check for valid block
                try:
                    sbx.decode(buffer)
                    #update uids table & list
                    if not sbx.uid in uids:
                        uids[sbx.uid] = True
                        c.execute(
                            "INSERT INTO sbx_uids (uid, ver) VALUES (?, ?)",
                            (int.from_bytes(sbx.uid,
                                            byteorder='big'), sbx.ver))
                        docommit = True

                    #update blocks table
                    blocksfound += 1
                    c.execute(
                        "INSERT INTO sbx_blocks (uid, num, fileid, pos) VALUES (?, ?, ?, ?)",
                        (int.from_bytes(sbx.uid, byteorder='big'),
                         sbx.blocknum, filenum, pos))
                    docommit = True

                    #update meta table
                    if sbx.blocknum == 0:
                        blocksmetafound += 1
                        if not "filedatetime" in sbx.metadata:
                            sbx.metadata["filedatetime"] = -1
                            sbx.metadata["sbxdatetime"] = -1

                        c.execute(
                            "INSERT INTO sbx_meta (uid , size, name, sbxname, datetime, sbxdatetime, fileid) VALUES (?, ?, ?, ?, ?, ?, ?)",
                            (int.from_bytes(sbx.uid, byteorder='big'),
                             sbx.metadata["filesize"],
                             sbx.metadata["filename"], sbx.metadata["sbxname"],
                             sbx.metadata["filedatetime"],
                             sbx.metadata["sbxdatetime"], filenum))
                        docommit = True

                except seqbox.SbxDecodeError:
                    pass

            #status update
            if (time() > updatetime) or (pos >= filesize - scanstep):
                etime = (time() - starttime)
                if etime == 0:
                    etime = 1
                print("%5.1f%% blocks: %i - meta: %i - files: %i - %.2fMB/s" %
                      (pos * 100.0 /
                       (filesize - scanstep), blocksfound, blocksmetafound,
                       len(uids), pos / (1024 * 1024) / etime),
                      end="\r",
                      flush=True)
                if docommit:
                    conn.commit()
                    docommit = False
                updatetime = time() + .5

        fin.close()
        print()

    c.close()
    conn.close()

    print("scan completed!")
Ejemplo n.º 3
0
def main():

    cmdline = get_cmdline()

    filename = cmdline.filename
    sbxfilename = cmdline.sbxfilename
    if not sbxfilename:
        sbxfilename = filename + ".sbx"
    elif os.path.isdir(sbxfilename):
        sbxfilename = os.path.join(sbxfilename,
                                   os.path.split(filename)[1] + ".sbx")
    if os.path.exists(sbxfilename) and not cmdline.overwrite:
        errexit(1, "SBX file '%s' already exists!" % (sbxfilename))
        
    #parse eventual custom uid
    uid = cmdline.uid
    if uid !="r":
        uid = uid[-12:]
        try:
            uid = int(uid, 16).to_bytes(6, byteorder='big')
        except:
            errexit(1, "invalid UID")

    if not os.path.exists(filename):
        errexit(1, "file '%s' not found" % (filename))
    filesize = os.path.getsize(filename)

    fout = open(sbxfilename, "wb", buffering=1024*1024)

    #calc hash - before all processing, and not while reading the file,
    #just to be cautious
    if not cmdline.nometa:
        print("hashing file '%s'..." % (filename))
        sha256 = getsha256(filename)
        print("SHA256",binascii.hexlify(sha256).decode())

    fin = open(filename, "rb", buffering=1024*1024)
    print("creating file '%s'..." % sbxfilename)

    sbx = seqbox.SbxBlock(uid=uid, ver=cmdline.sbxver, pswd=cmdline.password)
    
    #write metadata block 0
    if not cmdline.nometa:
        sbx.metadata = {"filesize":filesize,
                        "filename":os.path.split(filename)[1],
                        "sbxname":os.path.split(sbxfilename)[1],
                        "filedatetime":int(os.path.getmtime(filename)),
                        "sbxdatetime":int(time()),
                        "hash":b'\x12\x20'+sha256} #multihash
        fout.write(sbx.encode())
    
    #write all other blocks
    ticks = 0
    updatetime = time() 
    while True:
        buffer = fin.read(sbx.datasize)
        if len(buffer) < sbx.datasize:
            if len(buffer) == 0:
                break
        sbx.blocknum += 1
        sbx.data = buffer
        fout.write(sbx.encode())

        #some progress update
        if time() > updatetime:
            print("%.1f%%" % (fin.tell()*100.0/filesize), " ",
                  end="\r", flush=True)
            updatetime = time() + .1
        
    print("100%  ")
    fin.close()
    fout.close()

    totblocks = sbx.blocknum if cmdline.nometa else sbx.blocknum + 1
    sbxfilesize = totblocks * sbx.blocksize
    overhead = 100.0 * sbxfilesize / filesize - 100 if filesize > 0 else 0
    print("SBX file size: %i - blocks: %i - overhead: %.1f%%" %
          (sbxfilesize, totblocks, overhead))
Ejemplo n.º 4
0
def main():

    cmdline = get_cmdline()

    sbxfilename = cmdline.sbxfilename
    filename = cmdline.filename

    if not os.path.exists(sbxfilename):
        errexit(1, "sbx file '%s' not found" % (sbxfilename))
    sbxfilesize = os.path.getsize(sbxfilename)

    print("decoding '%s'..." % (sbxfilename))
    fin = open(sbxfilename, "rb", buffering=1024 * 1024)

    #check magic and get version
    header = fin.read(4)
    fin.seek(0, 0)
    if cmdline.password:
        e = seqbox.EncDec(cmdline.password, len(header))
        header = e.xor(header)
    if header[:3] != b"SBx":
        errexit(1, "not a SeqBox file!")
    sbxver = header[3]

    sbx = seqbox.SbxBlock(ver=sbxver, pswd=cmdline.password)
    metadata = {}
    trimfilesize = False

    hashtype = 0
    hashlen = 0
    hashdigest = b""
    hashcheck = False

    buffer = fin.read(sbx.blocksize)

    try:
        sbx.decode(buffer)
    except seqbox.SbxDecodeError as err:
        if cmdline.cont == False:
            print(err)
            errexit(errlev=1, mess="invalid block at offset 0x0")

    if sbx.blocknum > 1:
        errexit(errlev=1, mess="blocks missing or out of order at offset 0x0")
    elif sbx.blocknum == 0:
        print("metadata block found!")
        metadata = sbx.metadata
        if "filesize" in metadata:
            trimfilesize = True
        if "hash" in metadata:
            hashtype = metadata["hash"][0]
            if hashtype == 0x12:
                hashlen = metadata["hash"][1]
                hashdigest = metadata["hash"][2:2 + hashlen]
                hashcheck = True

    else:
        #first block is data, so reset from the start
        print("no metadata available")
        fin.seek(0, 0)

    #display some info and stop
    if cmdline.info:
        print("\nSeqBox container info:")
        print("  file size: %i bytes" % (sbxfilesize))
        print("  blocks: %i" % (sbxfilesize / sbx.blocksize))
        print("  version: %i" % (sbx.ver))
        print("  UID: %s" % (binascii.hexlify(sbx.uid).decode()))
        if metadata:
            print("metadata:")
            if "sbxname" in metadata:
                print("  SBX name : '%s'" % (metadata["sbxname"]))
            if "filename" in metadata:
                print("  file name: '%s'" % (metadata["filename"]))
            if "filesize" in metadata:
                print("  file size: %i bytes" % (metadata["filesize"]))
            if "sbxdatetime" in metadata:
                print("  SBX date&time : %s" %
                      (time.strftime("%Y-%m-%d %H:%M:%S",
                                     time.localtime(metadata["sbxdatetime"]))))
            if "filedatetime" in metadata:
                print(
                    "  file date&time: %s" %
                    (time.strftime("%Y-%m-%d %H:%M:%S",
                                   time.localtime(metadata["filedatetime"]))))
            if "hash" in metadata:
                if hashtype == 0x12:
                    print("  SHA256: %s" %
                          (binascii.hexlify(hashdigest).decode()))
                else:
                    print("  hash type not recognized!")
        sys.exit(0)

    #evaluate target filename
    if not cmdline.test:
        if not filename:
            if "filename" in metadata:
                filename = metadata["filename"]
            else:
                filename = sbxfilename + ".out"
        elif os.path.isdir(filename):
            if "filename" in metadata:
                filename = os.path.join(filename, metadata["filename"])
            else:
                filename = os.path.join(filename,
                                        os.path.split(sbxfilename)[1] + ".out")

        if os.path.exists(filename) and not cmdline.overwrite:
            errexit(1, "target file '%s' already exists!" % (filename))
        print("creating file '%s'..." % (filename))
        fout = open(filename, "wb", buffering=1024 * 1024)

    if hashtype == 0x12:
        d = hashlib.sha256()
    lastblocknum = 0

    filesize = 0
    blockmiss = 0
    updatetime = time.time()
    while True:
        buffer = fin.read(sbx.blocksize)
        if len(buffer) < sbx.blocksize:
            break

        try:
            sbx.decode(buffer)
            if sbx.blocknum > lastblocknum + 1:
                if cmdline.cont:
                    blockmiss += 1
                    lastblocknum += 1
                else:
                    errexit(errlev=1,
                            mess="block %i out of order or missing" %
                            (lastblocknum + 1))
            lastblocknum += 1
            if trimfilesize:
                filesize += sbx.datasize
                if filesize > metadata["filesize"]:
                    sbx.data = sbx.data[:-(filesize - metadata["filesize"])]
            if hashcheck:
                d.update(sbx.data)
            if not cmdline.test:
                fout.write(sbx.data)

        except seqbox.SbxDecodeError as err:
            if cmdline.cont:
                blockmiss += 1
                lastblocknum += 1
            else:
                print(err)
                errexit(errlev=1,
                        mess="invalid block at offset %s" %
                        (hex(fin.tell() - sbx.blocksize)))

        #some progress report
        if time.time() > updatetime:
            print("  %.1f%%" % (fin.tell() * 100.0 / sbxfilesize),
                  end="\r",
                  flush=True)
            updatetime = time.time() + .1

    fin.close()
    if not cmdline.test:
        fout.close()
        if metadata:
            if "filedatetime" in metadata:
                os.utime(filename,
                         (int(time.time()), metadata["filedatetime"]))

    print("SBX decoding complete")
    if blockmiss:
        errexit(1, "missing blocks: %i" % blockmiss)

    if hashcheck:
        if hashtype == 0x12:
            print("SHA256", d.hexdigest())

        if d.digest() == hashdigest:
            print("hash match!")
        else:
            errexit(1, "hash mismatch! decoded file corrupted!")
    else:
        print("can't check integrity via hash!")
        #if filesize unknown, estimate based on 0x1a padding at block's end
        if not trimfilesize:
            c = lastEofCount(sbx.data[-4:])
            print("EOF markers at the end of last block: %i/4" % c)