| 1 | # !/usr/bin/env python
|
|---|
| 2 | """Guess which db package to use to open a db file."""
|
|---|
| 3 |
|
|---|
| 4 | import os
|
|---|
| 5 | import struct
|
|---|
| 6 | import sys
|
|---|
| 7 |
|
|---|
| 8 | try:
|
|---|
| 9 | import dbm
|
|---|
| 10 | _dbmerror = dbm.error
|
|---|
| 11 | except ImportError:
|
|---|
| 12 | dbm = None
|
|---|
| 13 | # just some sort of valid exception which might be raised in the
|
|---|
| 14 | # dbm test
|
|---|
| 15 | _dbmerror = IOError
|
|---|
| 16 |
|
|---|
| 17 | def whichdb(filename):
|
|---|
| 18 | """Guess which db package to use to open a db file.
|
|---|
| 19 |
|
|---|
| 20 | Return values:
|
|---|
| 21 |
|
|---|
| 22 | - None if the database file can't be read;
|
|---|
| 23 | - empty string if the file can be read but can't be recognized
|
|---|
| 24 | - the module name (e.g. "dbm" or "gdbm") if recognized.
|
|---|
| 25 |
|
|---|
| 26 | Importing the given module may still fail, and opening the
|
|---|
| 27 | database using that module may still fail.
|
|---|
| 28 | """
|
|---|
| 29 |
|
|---|
| 30 | # Check for dbm first -- this has a .pag and a .dir file
|
|---|
| 31 | try:
|
|---|
| 32 | f = open(filename + os.extsep + "pag", "rb")
|
|---|
| 33 | f.close()
|
|---|
| 34 | # dbm linked with gdbm on OS/2 doesn't have .dir file
|
|---|
| 35 | if not (dbm.library == "GNU gdbm" and sys.platform == "os2emx"):
|
|---|
| 36 | f = open(filename + os.extsep + "dir", "rb")
|
|---|
| 37 | f.close()
|
|---|
| 38 | return "dbm"
|
|---|
| 39 | except IOError:
|
|---|
| 40 | # some dbm emulations based on Berkeley DB generate a .db file
|
|---|
| 41 | # some do not, but they should be caught by the dbhash checks
|
|---|
| 42 | try:
|
|---|
| 43 | f = open(filename + os.extsep + "db", "rb")
|
|---|
| 44 | f.close()
|
|---|
| 45 | # guarantee we can actually open the file using dbm
|
|---|
| 46 | # kind of overkill, but since we are dealing with emulations
|
|---|
| 47 | # it seems like a prudent step
|
|---|
| 48 | if dbm is not None:
|
|---|
| 49 | d = dbm.open(filename)
|
|---|
| 50 | d.close()
|
|---|
| 51 | return "dbm"
|
|---|
| 52 | except (IOError, _dbmerror):
|
|---|
| 53 | pass
|
|---|
| 54 |
|
|---|
| 55 | # Check for dumbdbm next -- this has a .dir and a .dat file
|
|---|
| 56 | try:
|
|---|
| 57 | # First check for presence of files
|
|---|
| 58 | os.stat(filename + os.extsep + "dat")
|
|---|
| 59 | size = os.stat(filename + os.extsep + "dir").st_size
|
|---|
| 60 | # dumbdbm files with no keys are empty
|
|---|
| 61 | if size == 0:
|
|---|
| 62 | return "dumbdbm"
|
|---|
| 63 | f = open(filename + os.extsep + "dir", "rb")
|
|---|
| 64 | try:
|
|---|
| 65 | if f.read(1) in ("'", '"'):
|
|---|
| 66 | return "dumbdbm"
|
|---|
| 67 | finally:
|
|---|
| 68 | f.close()
|
|---|
| 69 | except (OSError, IOError):
|
|---|
| 70 | pass
|
|---|
| 71 |
|
|---|
| 72 | # See if the file exists, return None if not
|
|---|
| 73 | try:
|
|---|
| 74 | f = open(filename, "rb")
|
|---|
| 75 | except IOError:
|
|---|
| 76 | return None
|
|---|
| 77 |
|
|---|
| 78 | # Read the start of the file -- the magic number
|
|---|
| 79 | s16 = f.read(16)
|
|---|
| 80 | f.close()
|
|---|
| 81 | s = s16[0:4]
|
|---|
| 82 |
|
|---|
| 83 | # Return "" if not at least 4 bytes
|
|---|
| 84 | if len(s) != 4:
|
|---|
| 85 | return ""
|
|---|
| 86 |
|
|---|
| 87 | # Convert to 4-byte int in native byte order -- return "" if impossible
|
|---|
| 88 | try:
|
|---|
| 89 | (magic,) = struct.unpack("=l", s)
|
|---|
| 90 | except struct.error:
|
|---|
| 91 | return ""
|
|---|
| 92 |
|
|---|
| 93 | # Check for GNU dbm
|
|---|
| 94 | if magic in (0x13579ace, 0x13579acd, 0x13579acf):
|
|---|
| 95 | return "gdbm"
|
|---|
| 96 |
|
|---|
| 97 | # Check for old Berkeley db hash file format v2
|
|---|
| 98 | if magic in (0x00061561, 0x61150600):
|
|---|
| 99 | return "bsddb185"
|
|---|
| 100 |
|
|---|
| 101 | # Later versions of Berkeley db hash file have a 12-byte pad in
|
|---|
| 102 | # front of the file type
|
|---|
| 103 | try:
|
|---|
| 104 | (magic,) = struct.unpack("=l", s16[-4:])
|
|---|
| 105 | except struct.error:
|
|---|
| 106 | return ""
|
|---|
| 107 |
|
|---|
| 108 | # Check for BSD hash
|
|---|
| 109 | if magic in (0x00061561, 0x61150600):
|
|---|
| 110 | return "dbhash"
|
|---|
| 111 |
|
|---|
| 112 | # Unknown
|
|---|
| 113 | return ""
|
|---|
| 114 |
|
|---|
| 115 | if __name__ == "__main__":
|
|---|
| 116 | for filename in sys.argv[1:]:
|
|---|
| 117 | print whichdb(filename) or "UNKNOWN", filename
|
|---|