[Bug #1633678] Improve pattern used for mbox 'From' lines; add a simple test
[pytest.git] / Lib / whichdb.py
blobf077f875310eeeacb0ff844c186db21baf36874c
1 # !/usr/bin/env python
2 """Guess which db package to use to open a db file."""
4 import os
5 import struct
6 import sys
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
17 def whichdb(filename):
18 """Guess which db package to use to open a db file.
20 Return values:
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.
26 Importing the given module may still fail, and opening the
27 database using that module may still fail.
28 """
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
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
72 # See if the file exists, return None if not
73 try:
74 f = open(filename, "rb")
75 except IOError:
76 return None
78 # Read the start of the file -- the magic number
79 s16 = f.read(16)
80 f.close()
81 s = s16[0:4]
83 # Return "" if not at least 4 bytes
84 if len(s) != 4:
85 return ""
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 ""
93 # Check for GNU dbm
94 if magic == 0x13579ace:
95 return "gdbm"
97 # Check for old Berkeley db hash file format v2
98 if magic in (0x00061561, 0x61150600):
99 return "bsddb185"
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 ""
108 # Check for BSD hash
109 if magic in (0x00061561, 0x61150600):
110 return "dbhash"
112 # Unknown
113 return ""
115 if __name__ == "__main__":
116 for filename in sys.argv[1:]:
117 print whichdb(filename) or "UNKNOWN", filename