2004-10-20 15:17:16 +08:00
|
|
|
# !/usr/bin/env python
|
1996-07-31 00:30:15 +08:00
|
|
|
"""Guess which db package to use to open a db file."""
|
|
|
|
|
2007-05-24 04:51:02 +08:00
|
|
|
import io
|
2001-03-02 14:43:49 +08:00
|
|
|
import os
|
2002-08-03 01:12:15 +08:00
|
|
|
import struct
|
2003-07-11 20:16:48 +08:00
|
|
|
import sys
|
2002-08-03 01:12:15 +08:00
|
|
|
|
|
|
|
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
|
2001-03-02 14:43:49 +08:00
|
|
|
|
1996-07-31 00:30:15 +08:00
|
|
|
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:
|
2007-08-16 22:35:24 +08:00
|
|
|
f = io.open(filename + ".pag", "rb")
|
1998-03-27 05:13:24 +08:00
|
|
|
f.close()
|
2003-07-11 20:16:48 +08:00
|
|
|
# dbm linked with gdbm on OS/2 doesn't have .dir file
|
|
|
|
if not (dbm.library == "GNU gdbm" and sys.platform == "os2emx"):
|
2007-08-16 22:35:24 +08:00
|
|
|
f = io.open(filename + ".dir", "rb")
|
2003-07-11 20:16:48 +08:00
|
|
|
f.close()
|
1998-03-27 05:13:24 +08:00
|
|
|
return "dbm"
|
1996-07-31 00:30:15 +08:00
|
|
|
except IOError:
|
2002-08-03 01:12:15 +08:00
|
|
|
# some dbm emulations based on Berkeley DB generate a .db file
|
|
|
|
# some do not, but they should be caught by the dbhash checks
|
|
|
|
try:
|
2007-08-16 22:35:24 +08:00
|
|
|
f = io.open(filename + ".db", "rb")
|
2002-08-03 01:12:15 +08:00
|
|
|
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
|
1996-07-31 00:30:15 +08:00
|
|
|
|
2003-10-20 22:01:56 +08:00
|
|
|
# Check for dumbdbm next -- this has a .dir and a .dat file
|
2000-08-04 16:46:59 +08:00
|
|
|
try:
|
2003-06-14 16:16:34 +08:00
|
|
|
# First check for presence of files
|
2007-08-16 22:35:24 +08:00
|
|
|
os.stat(filename + ".dat")
|
|
|
|
size = os.stat(filename + ".dir").st_size
|
2003-06-14 16:16:34 +08:00
|
|
|
# dumbdbm files with no keys are empty
|
2003-06-21 21:54:55 +08:00
|
|
|
if size == 0:
|
2003-06-14 16:16:34 +08:00
|
|
|
return "dumbdbm"
|
2007-08-16 22:35:24 +08:00
|
|
|
f = io.open(filename + ".dir", "rb")
|
2000-07-29 13:31:40 +08:00
|
|
|
try:
|
2007-05-24 04:51:02 +08:00
|
|
|
if f.read(1) in (b"'", b'"'):
|
2000-07-29 13:31:40 +08:00
|
|
|
return "dumbdbm"
|
|
|
|
finally:
|
|
|
|
f.close()
|
2003-06-14 16:16:34 +08:00
|
|
|
except (OSError, IOError):
|
2000-07-29 13:31:40 +08:00
|
|
|
pass
|
|
|
|
|
1996-07-31 00:30:15 +08:00
|
|
|
# See if the file exists, return None if not
|
|
|
|
try:
|
2007-05-24 04:51:02 +08:00
|
|
|
f = io.open(filename, "rb")
|
1996-07-31 00:30:15 +08:00
|
|
|
except IOError:
|
1998-03-27 05:13:24 +08:00
|
|
|
return None
|
1996-07-31 00:30:15 +08:00
|
|
|
|
1999-06-08 21:13:16 +08:00
|
|
|
# Read the start of the file -- the magic number
|
|
|
|
s16 = f.read(16)
|
1996-07-31 00:30:15 +08:00
|
|
|
f.close()
|
1999-06-08 21:13:16 +08:00
|
|
|
s = s16[0:4]
|
1996-07-31 00:30:15 +08:00
|
|
|
|
|
|
|
# Return "" if not at least 4 bytes
|
|
|
|
if len(s) != 4:
|
1998-03-27 05:13:24 +08:00
|
|
|
return ""
|
1996-07-31 00:30:15 +08:00
|
|
|
|
|
|
|
# Convert to 4-byte int in native byte order -- return "" if impossible
|
|
|
|
try:
|
1998-03-27 05:13:24 +08:00
|
|
|
(magic,) = struct.unpack("=l", s)
|
1996-07-31 00:30:15 +08:00
|
|
|
except struct.error:
|
1998-03-27 05:13:24 +08:00
|
|
|
return ""
|
1996-07-31 00:30:15 +08:00
|
|
|
|
|
|
|
# Check for GNU dbm
|
|
|
|
if magic == 0x13579ace:
|
1998-03-27 05:13:24 +08:00
|
|
|
return "gdbm"
|
1996-07-31 00:30:15 +08:00
|
|
|
|
2003-05-07 04:42:10 +08:00
|
|
|
# Check for old Berkeley db hash file format v2
|
1998-04-28 23:41:03 +08:00
|
|
|
if magic in (0x00061561, 0x61150600):
|
2003-05-07 04:42:10 +08:00
|
|
|
return "bsddb185"
|
1996-07-31 00:30:15 +08:00
|
|
|
|
2003-05-07 04:42:10 +08:00
|
|
|
# Later versions of Berkeley db hash file have a 12-byte pad in
|
|
|
|
# front of the file type
|
1999-06-08 21:13:16 +08:00
|
|
|
try:
|
2000-02-11 01:17:14 +08:00
|
|
|
(magic,) = struct.unpack("=l", s16[-4:])
|
1999-06-08 21:13:16 +08:00
|
|
|
except struct.error:
|
|
|
|
return ""
|
|
|
|
|
|
|
|
# Check for BSD hash
|
|
|
|
if magic in (0x00061561, 0x61150600):
|
|
|
|
return "dbhash"
|
|
|
|
|
1996-07-31 00:30:15 +08:00
|
|
|
# Unknown
|
|
|
|
return ""
|
2004-10-20 15:17:16 +08:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
for filename in sys.argv[1:]:
|
2007-02-09 13:37:30 +08:00
|
|
|
print(whichdb(filename) or "UNKNOWN", filename)
|