#!/usr/bin/python2 # program to show information that's in the database # DB LAYOUT v1.6 !!! # testvalues #CNID = 39112 #DEVICE = 2304 #INODE = 2999236 #import bsddb from bsddb3 import db import struct import string import getopt import sys, os def usage(): print "Browsing tool for netatalk 2.0.x CNID-Database (Berkeley DB)" print "USAGE: %s [-i|--inode ]|[-c|--cnid ] " % (sys.argv[0]) print "\t is optional, default is './.AppleDB', specify path w/o .AppleDB suffix!" print "\t--show-cnid-db shows human readable content of\n\t .AppleDB/cnid2.db->cnid2.db" print "\t--show-devino-db shows human readable content of\n\t .AppleDB/cnid2.db->devino.db" print "\t--show-didname-db shows human readable content of\n\t .AppleDB/cnid2.db->didname.db" print "\tWARNING: the --show-* options may output a vast amount of information!" print "\t-h|--help for help (this message)" sys.exit(1) try: opts, args = getopt.getopt(sys.argv[1:], "i:c:", ["inode", "cnid", "help", "show-cnid-db", "show-devino-db", "show-didname-db"]) except getopt.GetoptError: usage() if len(args) == 0: DB_PATH = './.AppleDB' elif len(args) == 1: DB_PATH = os.path.join (args[0] + '/.AppleDB') else: usage() if not os.path.isfile (DB_PATH + '/cnid2.db'): usage() #dbenv = db.DBEnv() #dbenv.open (DB_PATH) cnid2_db = db.DB() cnid2_db.set_get_returns_none(0) cnid2_db.open(DB_PATH + '/cnid2.db', 'cnid2.db', db.DB_BTREE, db.DB_RDONLY) cnid_db = cnid2_db.cursor() didname2_db = db.DB() didname2_db.set_get_returns_none(0) didname2_db.open(DB_PATH + '/cnid2.db', 'didname.db', db.DB_BTREE, db.DB_RDONLY) didname_db = didname2_db.cursor() devino2_db = db.DB() devino2_db.set_get_returns_none(0) devino2_db.open(DB_PATH + '/cnid2.db', 'devino.db', db.DB_BTREE, db.DB_RDONLY) print "entries in devino: %d" % len (devino2_db) devino_db = devino2_db.cursor() def prettyprint_didname_db(): print "%10s %10s NAME" % ('DID', 'CNID') i = 0 while i == 0: try: x = didname_db.next() if x is None: return key, value = x except db.DBError: i = 1 print "%10s %10s '%s'" % (struct.unpack (">I", key[:4])[0], struct.unpack(">I", value)[0], key[4:-1]) def prettyprint_cnid_db(): print "%10s %10s %10s %10s %10s NAME" % ('CNID', 'DEV', 'INODE', 'TYPE', 'DID') i = 0 while i == 0: try: x = cnid_db.next() if x is None: return key, value = x except db.DBError: i = 1 print "%10s %10s %10s %10s %10s '%s'" % (struct.unpack (">I", key)[0], struct.unpack (">Q", value[4:12])[0], struct.unpack (">Q", value[12:20])[0], struct.unpack (">L", value[20:24])[0], struct.unpack (">L", value[24:28])[0], value[28:-1]) def prettyprint_devino_db(): print "%10s %10s %10s" % ('DEV', 'INODE', 'CNID') print devino_db.first() i = 0 while i == 0: try: x = devino_db.next() if x is None: return key, value = x except db.DBError: i = 1 device, inode = struct.unpack (">QQ", key) print "%10s %10s %10s" % (device, inode, struct.unpack(">I", value)[0]) pInode = 0 pCNID = 0 ID = 0 for o, a in opts: if o in ("-i", "--inode"): if pCNID == 0: pInode = 1 DEVICE, INODE = string.split (a, ',') DEVICE = int (DEVICE) INODE = int (INODE) else: usage() if o in ("-c", "--cnid"): if pInode == 0: pCNID = 1 CNID = int(a) else: usage() if o == "--show-cnid-db": prettyprint_cnid_db() if o == "--show-devino-db": prettyprint_devino_db if o == "--show-didname-db": prettyprint_didname_db() if o in ("-h", "--help"): usage() # returns tuple [did, filename] def getFilenameFromCNID (cnid): global cnid_db, didname_db, devino_db try: data = cnid_db.set(struct.pack (">L", cnid), db.DB_SET) if data is None: return (-1, '.') except db.DBError: return (-1, '.') return (struct.unpack(">L", data[1][24:28])[0], data[1][28:-1]) # returns tuple [did, filename] def updateFilenameFromCNID (cnid, newname): global cnid_db, didname2_db, didname_db, devino_db # update cnid_db old_data = cnid_db.set(struct.pack (">L", cnid), db.DB_SET) new_data = old_data[1][:28] + newname + '\0' cnid_db.put (struct.pack (">L", cnid), new_data, db.DB_CURRENT) # update didname_db old_did_data = didname_db.set(old_data[1][24:], db.DB_SET) new_did_key = old_did_data[0][:4] + newname + '\0' didname2_db.delete (old_did_data[0]) didname2_db.put (new_did_key, old_did_data[1]) data = cnid_db.set(struct.pack (">L", cnid), db.DB_SET) print (struct.unpack(">L", data[1][24:28])[0], data[1][28:-1]) # returns path to filename def getFullPathFromCNID (cnid): did, filename = getFilenameFromCNID(cnid) fullname = filename while did != -1: did, filename = getFilenameFromCNID(did) fullname = filename + "/" + fullname return fullname if pInode: dev_inode = struct.pack (">QQ", DEVICE, INODE) try: devino_data = devino_db.set(dev_inode, db.DB_SET) #print devino_data print getFullPathFromCNID (struct.unpack(">L", devino_data[1])[0]) except db.DBError: sys.stderr.write ("DEVICE and INODE combination not found.\n") if pCNID: print getFullPathFromCNID (CNID)