| # !/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 |