diff options
author | Georg Brandl <georg@python.org> | 2008-05-26 10:29:35 (GMT) |
---|---|---|
committer | Georg Brandl <georg@python.org> | 2008-05-26 10:29:35 (GMT) |
commit | 0a7ac7d70d370544c6a9d118bbbd6886ad4f5ce5 (patch) | |
tree | ec61fd6d53e6425b8639567860140c724ea7bc63 /Lib | |
parent | e6f00637be87c8f5f0e50bf317d684ea421a6d19 (diff) | |
download | cpython-0a7ac7d70d370544c6a9d118bbbd6886ad4f5ce5.zip cpython-0a7ac7d70d370544c6a9d118bbbd6886ad4f5ce5.tar.gz cpython-0a7ac7d70d370544c6a9d118bbbd6886ad4f5ce5.tar.bz2 |
Create the dbm package from PEP 3108. #2881.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/anydbm.py | 83 | ||||
-rw-r--r-- | Lib/dbhash.py | 16 | ||||
-rw-r--r-- | Lib/dbm/__init__.py | 198 | ||||
-rw-r--r-- | Lib/dbm/bsd.py | 10 | ||||
-rw-r--r-- | Lib/dbm/dumb.py (renamed from Lib/dumbdbm.py) | 6 | ||||
-rw-r--r-- | Lib/dbm/gnu.py | 3 | ||||
-rw-r--r-- | Lib/dbm/ndbm.py | 3 | ||||
-rw-r--r-- | Lib/io.py | 2 | ||||
-rw-r--r-- | Lib/shelve.py | 8 | ||||
-rw-r--r-- | Lib/test/test___all__.py | 2 | ||||
-rw-r--r-- | Lib/test/test_anydbm.py | 90 | ||||
-rwxr-xr-x | Lib/test/test_bsddb.py | 2 | ||||
-rw-r--r-- | Lib/test/test_dbm_dumb.py (renamed from Lib/test/test_dumbdbm.py) | 2 | ||||
-rwxr-xr-x | Lib/test/test_dbm_gnu.py (renamed from Lib/test/test_gdbm.py) | 2 | ||||
-rwxr-xr-x | Lib/test/test_dbm_ndbm.py (renamed from Lib/test/test_dbm.py) | 12 | ||||
-rw-r--r-- | Lib/test/test_whichdb.py | 58 | ||||
-rw-r--r-- | Lib/whichdb.py | 118 |
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 * @@ -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) |