| # !/usr/bin/env python | |
| """Guess which db package to use to open a db file.""" | |
| import os | |
| import struct | |
| import sys | |
| try: | |
| import dbm | |
| _dbmerror = dbm.error | |
| except ImportError: | |
| dbm = None | |
| # just some sort of valid exception which might be raised in the | |
| # dbm test | |
| _dbmerror = IOError | |
| def whichdb(filename): | |
| """Guess which db package to use to open a db file. | |
| Return values: | |
| - None if the database file can't be read; | |
| - empty string if the file can be read but can't be recognized | |
| - the module name (e.g. "dbm" or "gdbm") if recognized. | |
| Importing the given module may still fail, and opening the | |
| database using that module may still fail. | |
| """ | |
| # Check for dbm first -- this has a .pag and a .dir file | |
| try: | |
| f = open(filename + os.extsep + "pag", "rb") | |
| f.close() | |
| # dbm linked with gdbm on OS/2 doesn't have .dir file | |
| if not (dbm.library == "GNU gdbm" and sys.platform == "os2emx"): | |
| f = open(filename + os.extsep + "dir", "rb") | |
| f.close() | |
| return "dbm" | |
| except IOError: | |
| # some dbm emulations based on Berkeley DB generate a .db file | |
| # some do not, but they should be caught by the dbhash checks | |
| try: | |
| f = open(filename + os.extsep + "db", "rb") | |
| f.close() | |
| # guarantee we can actually open the file using dbm | |
| # kind of overkill, but since we are dealing with emulations | |
| # it seems like a prudent step | |
| if dbm is not None: | |
| d = dbm.open(filename) | |
| d.close() | |
| return "dbm" | |
| except (IOError, _dbmerror): | |
| pass | |
| # Check for dumbdbm next -- this has a .dir and a .dat file | |
| try: | |
| # First check for presence of files | |
| os.stat(filename + os.extsep + "dat") | |
| size = os.stat(filename + os.extsep + "dir").st_size | |
| # dumbdbm files with no keys are empty | |
| if size == 0: | |
| return "dumbdbm" | |
| f = open(filename + os.extsep + "dir", "rb") | |
| try: | |
| if f.read(1) in ("'", '"'): | |
| return "dumbdbm" | |
| finally: | |
| f.close() | |
| except (OSError, IOError): | |
| pass | |
| # See if the file exists, return None if not | |
| try: | |
| f = open(filename, "rb") | |
| except IOError: | |
| return None | |
| # Read the start of the file -- the magic number | |
| s16 = f.read(16) | |
| f.close() | |
| s = s16[0:4] | |
| # Return "" if not at least 4 bytes | |
| if len(s) != 4: | |
| return "" | |
| # Convert to 4-byte int in native byte order -- return "" if impossible | |
| try: | |
| (magic,) = struct.unpack("=l", s) | |
| except struct.error: | |
| return "" | |
| # Check for GNU dbm | |
| if magic == 0x13579ace: | |
| return "gdbm" | |
| # Check for old Berkeley db hash file format v2 | |
| if magic in (0x00061561, 0x61150600): | |
| return "bsddb185" | |
| # Later versions of Berkeley db hash file have a 12-byte pad in | |
| # front of the file type | |
| try: | |
| (magic,) = struct.unpack("=l", s16[-4:]) | |
| except struct.error: | |
| return "" | |
| # Check for BSD hash | |
| if magic in (0x00061561, 0x61150600): | |
| return "dbhash" | |
| # Unknown | |
| return "" | |
| if __name__ == "__main__": | |
| for filename in sys.argv[1:]: | |
| print whichdb(filename) or "UNKNOWN", filename |