summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/anydbm.py83
-rw-r--r--Lib/dbhash.py16
-rw-r--r--Lib/dbm/__init__.py198
-rw-r--r--Lib/dbm/bsd.py10
-rw-r--r--Lib/dbm/dumb.py (renamed from Lib/dumbdbm.py)6
-rw-r--r--Lib/dbm/gnu.py3
-rw-r--r--Lib/dbm/ndbm.py3
-rw-r--r--Lib/io.py2
-rw-r--r--Lib/shelve.py8
-rw-r--r--Lib/test/test___all__.py2
-rw-r--r--Lib/test/test_anydbm.py90
-rwxr-xr-xLib/test/test_bsddb.py2
-rw-r--r--Lib/test/test_dbm_dumb.py (renamed from Lib/test/test_dumbdbm.py)2
-rwxr-xr-xLib/test/test_dbm_gnu.py (renamed from Lib/test/test_gdbm.py)2
-rwxr-xr-xLib/test/test_dbm_ndbm.py (renamed from Lib/test/test_dbm.py)12
-rw-r--r--Lib/test/test_whichdb.py58
-rw-r--r--Lib/whichdb.py118
17 files changed, 287 insertions, 328 deletions
diff --git a/Lib/anydbm.py b/Lib/anydbm.py
deleted file mode 100644
index 41335a3..0000000
--- a/Lib/anydbm.py
+++ /dev/null
@@ -1,83 +0,0 @@
-"""Generic interface to all dbm clones.
-
-Instead of
-
- import dbm
- d = dbm.open(file, 'w', 0o666)
-
-use
-
- import anydbm
- d = anydbm.open(file, 'w')
-
-The returned object is a dbhash, gdbm, dbm or dumbdbm object,
-dependent on the type of database being opened (determined by whichdb
-module) in the case of an existing dbm. If the dbm does not exist and
-the create or new flag ('c' or 'n') was specified, the dbm type will
-be determined by the availability of the modules (tested in the above
-order).
-
-It has the following interface (key and data are strings):
-
- d[key] = data # store data at key (may override data at
- # existing key)
- data = d[key] # retrieve data at key (raise KeyError if no
- # such key)
- del d[key] # delete data stored at key (raises KeyError
- # if no such key)
- flag = key in d # true if the key exists
- list = d.keys() # return a list of all existing keys (slow!)
-
-Future versions may change the order in which implementations are
-tested for existence, add interfaces to other dbm-like
-implementations.
-
-The open function has an optional second argument. This can be 'r',
-for read-only access, 'w', for read-write access of an existing
-database, 'c' for read-write access to a new or existing database, and
-'n' for read-write access to a new database. The default is 'r'.
-
-Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it
-only if it doesn't exist; and 'n' always creates a new database.
-
-"""
-
-class error(Exception):
- pass
-
-_names = ['dbhash', 'gdbm', 'dbm', 'dumbdbm']
-_errors = [error]
-_defaultmod = None
-
-for _name in _names:
- try:
- _mod = __import__(_name)
- except ImportError:
- continue
- if not _defaultmod:
- _defaultmod = _mod
- _errors.append(_mod.error)
-
-if not _defaultmod:
- raise ImportError("no dbm clone found; tried %s" % _names)
-
-error = tuple(_errors)
-
-def open(file, flag = 'r', mode = 0o666):
- # guess the type of an existing database
- from whichdb import whichdb
- result=whichdb(file)
- if result is None:
- # db doesn't exist
- if 'c' in flag or 'n' in flag:
- # file doesn't exist and the new
- # flag was used so use default type
- mod = _defaultmod
- else:
- raise error("need 'c' or 'n' flag to open new db")
- elif result == "":
- # db type cannot be determined
- raise error("db type could not be determined")
- else:
- mod = __import__(result)
- return mod.open(file, flag, mode)
diff --git a/Lib/dbhash.py b/Lib/dbhash.py
deleted file mode 100644
index 3c60812..0000000
--- a/Lib/dbhash.py
+++ /dev/null
@@ -1,16 +0,0 @@
-"""Provide a (g)dbm-compatible interface to bsddb.hashopen."""
-
-import sys
-try:
- import bsddb
-except ImportError:
- # prevent a second import of this module from spuriously succeeding
- del sys.modules[__name__]
- raise
-
-__all__ = ["error","open"]
-
-error = bsddb.error # Exported for anydbm
-
-def open(file, flag = 'r', mode=0o666):
- return bsddb.hashopen(file, flag, mode)
diff --git a/Lib/dbm/__init__.py b/Lib/dbm/__init__.py
new file mode 100644
index 0000000..9fdd414
--- /dev/null
+++ b/Lib/dbm/__init__.py
@@ -0,0 +1,198 @@
+"""Generic interface to all dbm clones.
+
+Use
+
+ import dbm
+ d = dbm.open(file, 'w', 0o666)
+
+The returned object is a dbm.bsd, dbm.gnu, dbm.ndbm or dbm.dumb
+object, dependent on the type of database being opened (determined by
+the whichdb function) in the case of an existing dbm. If the dbm does
+not exist and the create or new flag ('c' or 'n') was specified, the
+dbm type will be determined by the availability of the modules (tested
+in the above order).
+
+It has the following interface (key and data are strings):
+
+ d[key] = data # store data at key (may override data at
+ # existing key)
+ data = d[key] # retrieve data at key (raise KeyError if no
+ # such key)
+ del d[key] # delete data stored at key (raises KeyError
+ # if no such key)
+ flag = key in d # true if the key exists
+ list = d.keys() # return a list of all existing keys (slow!)
+
+Future versions may change the order in which implementations are
+tested for existence, add interfaces to other dbm-like
+implementations.
+
+The open function has an optional second argument. This can be 'r',
+for read-only access, 'w', for read-write access of an existing
+database, 'c' for read-write access to a new or existing database, and
+'n' for read-write access to a new database. The default is 'r'.
+
+Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it
+only if it doesn't exist; and 'n' always creates a new database.
+"""
+
+__all__ = ['open', 'whichdb', 'error', 'errors']
+
+import io
+import os
+import struct
+import sys
+
+
+class error(Exception):
+ pass
+
+_names = ['dbm.bsd', 'dbm.gnu', 'dbm.ndbm', 'dbm.dumb']
+_errors = [error]
+_defaultmod = None
+_modules = {}
+
+for _name in _names:
+ try:
+ _mod = __import__(_name, fromlist=['open'])
+ except ImportError:
+ continue
+ if not _defaultmod:
+ _defaultmod = _mod
+ _modules[_name] = _mod
+ _errors.append(_mod.error)
+
+if not _defaultmod:
+ raise ImportError("no dbm clone found; tried %s" % _names)
+
+error = tuple(_errors)
+
+
+def open(file, flag = 'r', mode = 0o666):
+ # guess the type of an existing database
+ result = whichdb(file)
+ if result is None:
+ # db doesn't exist
+ if 'c' in flag or 'n' in flag:
+ # file doesn't exist and the new flag was used so use default type
+ mod = _defaultmod
+ else:
+ raise error("need 'c' or 'n' flag to open new db")
+ elif result == "":
+ # db type cannot be determined
+ raise error("db type could not be determined")
+ else:
+ mod = _modules[result]
+ return mod.open(file, flag, mode)
+
+
+try:
+ from dbm import ndbm
+ _dbmerror = ndbm.error
+except ImportError:
+ ndbm = None
+ # just some sort of valid exception which might be raised in the ndbm 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 name of the dbm submodule (e.g. "ndbm" or "gnu") if recognized.
+
+ Importing the given module may still fail, and opening the
+ database using that module may still fail.
+ """
+
+ # Check for ndbm first -- this has a .pag and a .dir file
+ try:
+ f = io.open(filename + ".pag", "rb")
+ f.close()
+ # dbm linked with gdbm on OS/2 doesn't have .dir file
+ if not (ndbm.library == "GNU gdbm" and sys.platform == "os2emx"):
+ f = io.open(filename + ".dir", "rb")
+ f.close()
+ return "dbm.ndbm"
+ except IOError:
+ # some dbm emulations based on Berkeley DB generate a .db file
+ # some do not, but they should be caught by the bsd checks
+ try:
+ f = io.open(filename + ".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 ndbm is not None:
+ d = ndbm.open(filename)
+ d.close()
+ return "dbm.ndbm"
+ 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 + ".dat")
+ size = os.stat(filename + ".dir").st_size
+ # dumbdbm files with no keys are empty
+ if size == 0:
+ return "dbm.dumb"
+ f = io.open(filename + ".dir", "rb")
+ try:
+ if f.read(1) in (b"'", b'"'):
+ return "dbm.dumb"
+ finally:
+ f.close()
+ except (OSError, IOError):
+ pass
+
+ # See if the file exists, return None if not
+ try:
+ f = io.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 "dbm.gnu"
+
+ ## Check for old Berkeley db hash file format v2
+ #if magic in (0x00061561, 0x61150600):
+ # return "bsddb185" # not supported anymore
+
+ # 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 "dbm.bsd"
+
+ # Unknown
+ return ""
+
+
+if __name__ == "__main__":
+ for filename in sys.argv[1:]:
+ print(whichdb(filename) or "UNKNOWN", filename)
diff --git a/Lib/dbm/bsd.py b/Lib/dbm/bsd.py
new file mode 100644
index 0000000..8353f50
--- /dev/null
+++ b/Lib/dbm/bsd.py
@@ -0,0 +1,10 @@
+"""Provide a (g)dbm-compatible interface to bsddb.hashopen."""
+
+import bsddb
+
+__all__ = ["error", "open"]
+
+error = bsddb.error
+
+def open(file, flag = 'r', mode=0o666):
+ return bsddb.hashopen(file, flag, mode)
diff --git a/Lib/dumbdbm.py b/Lib/dbm/dumb.py
index 8d58f87..76f4a63 100644
--- a/Lib/dumbdbm.py
+++ b/Lib/dbm/dumb.py
@@ -25,9 +25,11 @@ import io as _io
import os as _os
import collections
+__all__ = ["error", "open"]
+
_BLOCKSIZE = 512
-error = IOError # For anydbm
+error = IOError
class _Database(collections.MutableMapping):
@@ -231,7 +233,7 @@ def open(file, flag=None, mode=0o666):
"""Open the database file, filename, and return corresponding object.
The flag argument, used to control how the database is opened in the
- other DBM implementations, is ignored in the dumbdbm module; the
+ other DBM implementations, is ignored in the dbm.dumb module; the
database is always opened for update, and will be created if it does
not exist.
diff --git a/Lib/dbm/gnu.py b/Lib/dbm/gnu.py
new file mode 100644
index 0000000..b07a1de
--- /dev/null
+++ b/Lib/dbm/gnu.py
@@ -0,0 +1,3 @@
+"""Provide the _gdbm module as a dbm submodule."""
+
+from _gdbm import *
diff --git a/Lib/dbm/ndbm.py b/Lib/dbm/ndbm.py
new file mode 100644
index 0000000..23056a2
--- /dev/null
+++ b/Lib/dbm/ndbm.py
@@ -0,0 +1,3 @@
+"""Provide the _dbm module as a dbm submodule."""
+
+from _dbm import *
diff --git a/Lib/io.py b/Lib/io.py
index 207e428..0c993b1 100644
--- a/Lib/io.py
+++ b/Lib/io.py
@@ -270,7 +270,7 @@ class OpenWrapper:
"""Wrapper for builtins.open
Trick so that open won't become a bound method when stored
- as a class variable (as dumbdbm does).
+ as a class variable (as dbm.dumb does).
See initstdio() in Python/pythonrun.c.
"""
diff --git a/Lib/shelve.py b/Lib/shelve.py
index e6d6d40..d651b9e 100644
--- a/Lib/shelve.py
+++ b/Lib/shelve.py
@@ -190,15 +190,15 @@ class BsdDbShelf(Shelf):
class DbfilenameShelf(Shelf):
- """Shelf implementation using the "anydbm" generic dbm interface.
+ """Shelf implementation using the "dbm" generic dbm interface.
This is initialized with the filename for the dbm database.
See the module's __doc__ string for an overview of the interface.
"""
def __init__(self, filename, flag='c', protocol=None, writeback=False):
- import anydbm
- Shelf.__init__(self, anydbm.open(filename, flag), protocol, writeback)
+ import dbm
+ Shelf.__init__(self, dbm.open(filename, flag), protocol, writeback)
def open(filename, flag='c', protocol=None, writeback=False):
@@ -208,7 +208,7 @@ def open(filename, flag='c', protocol=None, writeback=False):
database. As a side-effect, an extension may be added to the
filename and more than one file may be created. The optional flag
parameter has the same interpretation as the flag parameter of
- anydbm.open(). The optional protocol parameter specifies the
+ dbm.open(). The optional protocol parameter specifies the
version of the pickle protocol (0, 1, or 2).
See the module's __doc__ string for an overview of the interface.
diff --git a/Lib/test/test___all__.py b/Lib/test/test___all__.py
index 615f6c5..ed8d8d9 100644
--- a/Lib/test/test___all__.py
+++ b/Lib/test/test___all__.py
@@ -57,7 +57,7 @@ class AllTest(unittest.TestCase):
self.check_all("copy")
self.check_all("copyreg")
self.check_all("csv")
- self.check_all("dbhash")
+ self.check_all("dbm.bsd")
self.check_all("decimal")
self.check_all("difflib")
self.check_all("dircache")
diff --git a/Lib/test/test_anydbm.py b/Lib/test/test_anydbm.py
index ace9dd2..aab1388 100644
--- a/Lib/test/test_anydbm.py
+++ b/Lib/test/test_anydbm.py
@@ -1,50 +1,34 @@
#! /usr/bin/env python
-"""Test script for the anydbm module
- based on testdumbdbm.py
-"""
+"""Test script for the dbm.open function based on testdumbdbm.py"""
import os
import unittest
-import anydbm
+import dbm
import glob
-from test import support
-
-_fname = support.TESTFN
-
-_all_modules = []
-
-for _name in anydbm._names:
- try:
- _module = __import__(_name)
- except ImportError:
- continue
- _all_modules.append(_module)
+import test.support
+_fname = test.support.TESTFN
#
-# Iterates over every database module supported by anydbm
-# currently available, setting anydbm to use each in turn,
-# and yielding that module
+# Iterates over every database module supported by dbm currently available,
+# setting dbm to use each in turn, and yielding that module
#
def dbm_iterator():
- old_default = anydbm._defaultmod
- for module in _all_modules:
- anydbm._defaultmod = module
+ old_default = dbm._defaultmod
+ for module in dbm._modules.values():
+ dbm._defaultmod = module
yield module
- anydbm._defaultmod = old_default
+ dbm._defaultmod = old_default
#
-# Clean up all scratch databases we might have created
-# during testing
+# Clean up all scratch databases we might have created during testing
#
def delete_files():
# we don't know the precise name the underlying database uses
# so we use glob to locate all names
for f in glob.glob(_fname + "*"):
- try:
- os.unlink(f)
- except OSError:
- pass
+ test.support.unlink(f)
+
class AnyDBMTestCase(unittest.TestCase):
_dict = {'0': b'',
@@ -60,7 +44,7 @@ class AnyDBMTestCase(unittest.TestCase):
unittest.TestCase.__init__(self, *args)
def test_anydbm_creation(self):
- f = anydbm.open(_fname, 'c')
+ f = dbm.open(_fname, 'c')
self.assertEqual(list(f.keys()), [])
for key in self._dict:
f[key.encode("ascii")] = self._dict[key]
@@ -69,26 +53,26 @@ class AnyDBMTestCase(unittest.TestCase):
def test_anydbm_modification(self):
self.init_db()
- f = anydbm.open(_fname, 'c')
+ f = dbm.open(_fname, 'c')
self._dict['g'] = f[b'g'] = b"indented"
self.read_helper(f)
f.close()
def test_anydbm_read(self):
self.init_db()
- f = anydbm.open(_fname, 'r')
+ f = dbm.open(_fname, 'r')
self.read_helper(f)
f.close()
def test_anydbm_keys(self):
self.init_db()
- f = anydbm.open(_fname, 'r')
+ f = dbm.open(_fname, 'r')
keys = self.keys_helper(f)
f.close()
def test_anydbm_access(self):
self.init_db()
- f = anydbm.open(_fname, 'r')
+ f = dbm.open(_fname, 'r')
key = "a".encode("ascii")
assert(key in f)
assert(f[key] == b"Python:")
@@ -100,7 +84,7 @@ class AnyDBMTestCase(unittest.TestCase):
self.assertEqual(self._dict[key], f[key.encode("ascii")])
def init_db(self):
- f = anydbm.open(_fname, 'n')
+ f = dbm.open(_fname, 'n')
for k in self._dict:
f[k.encode("ascii")] = self._dict[k]
f.close()
@@ -118,10 +102,44 @@ class AnyDBMTestCase(unittest.TestCase):
delete_files()
+class WhichDBTestCase(unittest.TestCase):
+ # Actual test methods are added to namespace after class definition.
+ def __init__(self, *args):
+ unittest.TestCase.__init__(self, *args)
+
+ def test_whichdb(self):
+ for module in dbm_iterator():
+ # Check whether whichdb correctly guesses module name
+ # for databases opened with "module" module.
+ # Try with empty files first
+ name = module.__name__
+ if name == 'dbm.dumb':
+ continue # whichdb can't support dbm.dumb
+ test.support.unlink(_fname)
+ f = module.open(_fname, 'c')
+ f.close()
+ self.assertEqual(name, dbm.whichdb(_fname))
+ # Now add a key
+ f = module.open(_fname, 'w')
+ f[b"1"] = b"1"
+ # and test that we can find it
+ self.assertTrue(b"1" in f)
+ # and read it
+ self.assertTrue(f[b"1"] == b"1")
+ f.close()
+ self.assertEqual(name, dbm.whichdb(_fname))
+
+ def tearDown(self):
+ delete_files()
+
+ def setUp(self):
+ delete_files()
+
+
def test_main():
try:
for module in dbm_iterator():
- support.run_unittest(AnyDBMTestCase)
+ test.support.run_unittest(AnyDBMTestCase, WhichDBTestCase)
finally:
delete_files()
diff --git a/Lib/test/test_bsddb.py b/Lib/test/test_bsddb.py
index 3eb291f..a722d8c 100755
--- a/Lib/test/test_bsddb.py
+++ b/Lib/test/test_bsddb.py
@@ -5,7 +5,7 @@
import os, sys
import copy
import bsddb
-import dbhash # Just so we know it's imported
+import dbm.bsd # Just so we know it's imported
import unittest
from test import support
diff --git a/Lib/test/test_dumbdbm.py b/Lib/test/test_dbm_dumb.py
index 24c178f..9bdc240 100644
--- a/Lib/test/test_dumbdbm.py
+++ b/Lib/test/test_dbm_dumb.py
@@ -6,7 +6,7 @@
import io
import os
import unittest
-import dumbdbm
+import dbm.dumb as dumbdbm
from test import support
_fname = support.TESTFN
diff --git a/Lib/test/test_gdbm.py b/Lib/test/test_dbm_gnu.py
index 42cb136..eddb970 100755
--- a/Lib/test/test_gdbm.py
+++ b/Lib/test/test_dbm_gnu.py
@@ -1,4 +1,4 @@
-import gdbm
+import dbm.gnu as gdbm
import unittest
import os
from test.support import verbose, TESTFN, run_unittest, unlink
diff --git a/Lib/test/test_dbm.py b/Lib/test/test_dbm_ndbm.py
index 2c6ce99..74d3238 100755
--- a/Lib/test/test_dbm.py
+++ b/Lib/test/test_dbm_ndbm.py
@@ -2,14 +2,14 @@ from test import support
import unittest
import os
import random
-import dbm
-from dbm import error
+import dbm.ndbm
+from dbm.ndbm import error
class DbmTestCase(unittest.TestCase):
def setUp(self):
self.filename = support.TESTFN
- self.d = dbm.open(self.filename, 'c')
+ self.d = dbm.ndbm.open(self.filename, 'c')
self.d.close()
def tearDown(self):
@@ -17,7 +17,7 @@ class DbmTestCase(unittest.TestCase):
support.unlink(self.filename + suffix)
def test_keys(self):
- self.d = dbm.open(self.filename, 'c')
+ self.d = dbm.ndbm.open(self.filename, 'c')
self.assert_(self.d.keys() == [])
self.d['a'] = 'b'
self.d['12345678910'] = '019237410982340912840198242'
@@ -28,9 +28,9 @@ class DbmTestCase(unittest.TestCase):
def test_modes(self):
for mode in ['r', 'rw', 'w', 'n']:
try:
- self.d = dbm.open(self.filename, mode)
+ self.d = dbm.ndbm.open(self.filename, mode)
self.d.close()
- except dbm.error:
+ except error:
self.fail()
def test_main():
diff --git a/Lib/test/test_whichdb.py b/Lib/test/test_whichdb.py
deleted file mode 100644
index d908ac5..0000000
--- a/Lib/test/test_whichdb.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#! /usr/bin/env python
-"""Test script for the whichdb module
- based on test_anydbm.py
-"""
-
-import os
-import test.support
-import unittest
-import whichdb
-import anydbm
-import glob
-from test.test_anydbm import delete_files, dbm_iterator
-
-_fname = test.support.TESTFN
-
-class WhichDBTestCase(unittest.TestCase):
- # Actual test methods are added to namespace
- # after class definition.
- def __init__(self, *args):
- unittest.TestCase.__init__(self, *args)
-
- def test_whichdb(self):
- for module in dbm_iterator():
- # Check whether whichdb correctly guesses module name
- # for databases opened with "module" module.
- # Try with empty files first
- name = module.__name__
- if name == 'dumbdbm':
- continue # whichdb can't support dumbdbm
- test.support.unlink(_fname)
- f = module.open(_fname, 'c')
- f.close()
- self.assertEqual(name, whichdb.whichdb(_fname))
- # Now add a key
- f = module.open(_fname, 'w')
- f[b"1"] = b"1"
- # and test that we can find it
- self.assertTrue(b"1" in f)
- # and read it
- self.assertTrue(f[b"1"] == b"1")
- f.close()
- self.assertEqual(name, whichdb.whichdb(_fname))
-
- def tearDown(self):
- delete_files()
-
- def setUp(self):
- delete_files()
-
-
-def test_main():
- try:
- test.support.run_unittest(WhichDBTestCase)
- finally:
- delete_files()
-
-if __name__ == "__main__":
- test_main()
diff --git a/Lib/whichdb.py b/Lib/whichdb.py
deleted file mode 100644
index ca9c736..0000000
--- a/Lib/whichdb.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# !/usr/bin/env python
-"""Guess which db package to use to open a db file."""
-
-import io
-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 = io.open(filename + ".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 = io.open(filename + ".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 = io.open(filename + ".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 + ".dat")
- size = os.stat(filename + ".dir").st_size
- # dumbdbm files with no keys are empty
- if size == 0:
- return "dumbdbm"
- f = io.open(filename + ".dir", "rb")
- try:
- if f.read(1) in (b"'", b'"'):
- return "dumbdbm"
- finally:
- f.close()
- except (OSError, IOError):
- pass
-
- # See if the file exists, return None if not
- try:
- f = io.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)