Commit | Line | Data |
---|---|---|
920dae64 AT |
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 == 0x13579ace: | |
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 |