17db96d56Sopenharmony_ci"""Generic interface to all dbm clones. 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciUse 47db96d56Sopenharmony_ci 57db96d56Sopenharmony_ci import dbm 67db96d56Sopenharmony_ci d = dbm.open(file, 'w', 0o666) 77db96d56Sopenharmony_ci 87db96d56Sopenharmony_ciThe returned object is a dbm.gnu, dbm.ndbm or dbm.dumb object, dependent on the 97db96d56Sopenharmony_citype of database being opened (determined by the whichdb function) in the case 107db96d56Sopenharmony_ciof an existing dbm. If the dbm does not exist and the create or new flag ('c' 117db96d56Sopenharmony_cior 'n') was specified, the dbm type will be determined by the availability of 127db96d56Sopenharmony_cithe modules (tested in the above order). 137db96d56Sopenharmony_ci 147db96d56Sopenharmony_ciIt has the following interface (key and data are strings): 157db96d56Sopenharmony_ci 167db96d56Sopenharmony_ci d[key] = data # store data at key (may override data at 177db96d56Sopenharmony_ci # existing key) 187db96d56Sopenharmony_ci data = d[key] # retrieve data at key (raise KeyError if no 197db96d56Sopenharmony_ci # such key) 207db96d56Sopenharmony_ci del d[key] # delete data stored at key (raises KeyError 217db96d56Sopenharmony_ci # if no such key) 227db96d56Sopenharmony_ci flag = key in d # true if the key exists 237db96d56Sopenharmony_ci list = d.keys() # return a list of all existing keys (slow!) 247db96d56Sopenharmony_ci 257db96d56Sopenharmony_ciFuture versions may change the order in which implementations are 267db96d56Sopenharmony_citested for existence, and add interfaces to other dbm-like 277db96d56Sopenharmony_ciimplementations. 287db96d56Sopenharmony_ci""" 297db96d56Sopenharmony_ci 307db96d56Sopenharmony_ci__all__ = ['open', 'whichdb', 'error'] 317db96d56Sopenharmony_ci 327db96d56Sopenharmony_ciimport io 337db96d56Sopenharmony_ciimport os 347db96d56Sopenharmony_ciimport struct 357db96d56Sopenharmony_ciimport sys 367db96d56Sopenharmony_ci 377db96d56Sopenharmony_ci 387db96d56Sopenharmony_ciclass error(Exception): 397db96d56Sopenharmony_ci pass 407db96d56Sopenharmony_ci 417db96d56Sopenharmony_ci_names = ['dbm.gnu', 'dbm.ndbm', 'dbm.dumb'] 427db96d56Sopenharmony_ci_defaultmod = None 437db96d56Sopenharmony_ci_modules = {} 447db96d56Sopenharmony_ci 457db96d56Sopenharmony_cierror = (error, OSError) 467db96d56Sopenharmony_ci 477db96d56Sopenharmony_citry: 487db96d56Sopenharmony_ci from dbm import ndbm 497db96d56Sopenharmony_ciexcept ImportError: 507db96d56Sopenharmony_ci ndbm = None 517db96d56Sopenharmony_ci 527db96d56Sopenharmony_ci 537db96d56Sopenharmony_cidef open(file, flag='r', mode=0o666): 547db96d56Sopenharmony_ci """Open or create database at path given by *file*. 557db96d56Sopenharmony_ci 567db96d56Sopenharmony_ci Optional argument *flag* can be 'r' (default) for read-only access, 'w' 577db96d56Sopenharmony_ci for read-write access of an existing database, 'c' for read-write access 587db96d56Sopenharmony_ci to a new or existing database, and 'n' for read-write access to a new 597db96d56Sopenharmony_ci database. 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_ci Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it 627db96d56Sopenharmony_ci only if it doesn't exist; and 'n' always creates a new database. 637db96d56Sopenharmony_ci """ 647db96d56Sopenharmony_ci global _defaultmod 657db96d56Sopenharmony_ci if _defaultmod is None: 667db96d56Sopenharmony_ci for name in _names: 677db96d56Sopenharmony_ci try: 687db96d56Sopenharmony_ci mod = __import__(name, fromlist=['open']) 697db96d56Sopenharmony_ci except ImportError: 707db96d56Sopenharmony_ci continue 717db96d56Sopenharmony_ci if not _defaultmod: 727db96d56Sopenharmony_ci _defaultmod = mod 737db96d56Sopenharmony_ci _modules[name] = mod 747db96d56Sopenharmony_ci if not _defaultmod: 757db96d56Sopenharmony_ci raise ImportError("no dbm clone found; tried %s" % _names) 767db96d56Sopenharmony_ci 777db96d56Sopenharmony_ci # guess the type of an existing database, if not creating a new one 787db96d56Sopenharmony_ci result = whichdb(file) if 'n' not in flag else None 797db96d56Sopenharmony_ci if result is None: 807db96d56Sopenharmony_ci # db doesn't exist or 'n' flag was specified to create a new db 817db96d56Sopenharmony_ci if 'c' in flag or 'n' in flag: 827db96d56Sopenharmony_ci # file doesn't exist and the new flag was used so use default type 837db96d56Sopenharmony_ci mod = _defaultmod 847db96d56Sopenharmony_ci else: 857db96d56Sopenharmony_ci raise error[0]("db file doesn't exist; " 867db96d56Sopenharmony_ci "use 'c' or 'n' flag to create a new db") 877db96d56Sopenharmony_ci elif result == "": 887db96d56Sopenharmony_ci # db type cannot be determined 897db96d56Sopenharmony_ci raise error[0]("db type could not be determined") 907db96d56Sopenharmony_ci elif result not in _modules: 917db96d56Sopenharmony_ci raise error[0]("db type is {0}, but the module is not " 927db96d56Sopenharmony_ci "available".format(result)) 937db96d56Sopenharmony_ci else: 947db96d56Sopenharmony_ci mod = _modules[result] 957db96d56Sopenharmony_ci return mod.open(file, flag, mode) 967db96d56Sopenharmony_ci 977db96d56Sopenharmony_ci 987db96d56Sopenharmony_cidef whichdb(filename): 997db96d56Sopenharmony_ci """Guess which db package to use to open a db file. 1007db96d56Sopenharmony_ci 1017db96d56Sopenharmony_ci Return values: 1027db96d56Sopenharmony_ci 1037db96d56Sopenharmony_ci - None if the database file can't be read; 1047db96d56Sopenharmony_ci - empty string if the file can be read but can't be recognized 1057db96d56Sopenharmony_ci - the name of the dbm submodule (e.g. "ndbm" or "gnu") if recognized. 1067db96d56Sopenharmony_ci 1077db96d56Sopenharmony_ci Importing the given module may still fail, and opening the 1087db96d56Sopenharmony_ci database using that module may still fail. 1097db96d56Sopenharmony_ci """ 1107db96d56Sopenharmony_ci 1117db96d56Sopenharmony_ci # Check for ndbm first -- this has a .pag and a .dir file 1127db96d56Sopenharmony_ci filename = os.fsencode(filename) 1137db96d56Sopenharmony_ci try: 1147db96d56Sopenharmony_ci f = io.open(filename + b".pag", "rb") 1157db96d56Sopenharmony_ci f.close() 1167db96d56Sopenharmony_ci f = io.open(filename + b".dir", "rb") 1177db96d56Sopenharmony_ci f.close() 1187db96d56Sopenharmony_ci return "dbm.ndbm" 1197db96d56Sopenharmony_ci except OSError: 1207db96d56Sopenharmony_ci # some dbm emulations based on Berkeley DB generate a .db file 1217db96d56Sopenharmony_ci # some do not, but they should be caught by the bsd checks 1227db96d56Sopenharmony_ci try: 1237db96d56Sopenharmony_ci f = io.open(filename + b".db", "rb") 1247db96d56Sopenharmony_ci f.close() 1257db96d56Sopenharmony_ci # guarantee we can actually open the file using dbm 1267db96d56Sopenharmony_ci # kind of overkill, but since we are dealing with emulations 1277db96d56Sopenharmony_ci # it seems like a prudent step 1287db96d56Sopenharmony_ci if ndbm is not None: 1297db96d56Sopenharmony_ci d = ndbm.open(filename) 1307db96d56Sopenharmony_ci d.close() 1317db96d56Sopenharmony_ci return "dbm.ndbm" 1327db96d56Sopenharmony_ci except OSError: 1337db96d56Sopenharmony_ci pass 1347db96d56Sopenharmony_ci 1357db96d56Sopenharmony_ci # Check for dumbdbm next -- this has a .dir and a .dat file 1367db96d56Sopenharmony_ci try: 1377db96d56Sopenharmony_ci # First check for presence of files 1387db96d56Sopenharmony_ci os.stat(filename + b".dat") 1397db96d56Sopenharmony_ci size = os.stat(filename + b".dir").st_size 1407db96d56Sopenharmony_ci # dumbdbm files with no keys are empty 1417db96d56Sopenharmony_ci if size == 0: 1427db96d56Sopenharmony_ci return "dbm.dumb" 1437db96d56Sopenharmony_ci f = io.open(filename + b".dir", "rb") 1447db96d56Sopenharmony_ci try: 1457db96d56Sopenharmony_ci if f.read(1) in (b"'", b'"'): 1467db96d56Sopenharmony_ci return "dbm.dumb" 1477db96d56Sopenharmony_ci finally: 1487db96d56Sopenharmony_ci f.close() 1497db96d56Sopenharmony_ci except OSError: 1507db96d56Sopenharmony_ci pass 1517db96d56Sopenharmony_ci 1527db96d56Sopenharmony_ci # See if the file exists, return None if not 1537db96d56Sopenharmony_ci try: 1547db96d56Sopenharmony_ci f = io.open(filename, "rb") 1557db96d56Sopenharmony_ci except OSError: 1567db96d56Sopenharmony_ci return None 1577db96d56Sopenharmony_ci 1587db96d56Sopenharmony_ci with f: 1597db96d56Sopenharmony_ci # Read the start of the file -- the magic number 1607db96d56Sopenharmony_ci s16 = f.read(16) 1617db96d56Sopenharmony_ci s = s16[0:4] 1627db96d56Sopenharmony_ci 1637db96d56Sopenharmony_ci # Return "" if not at least 4 bytes 1647db96d56Sopenharmony_ci if len(s) != 4: 1657db96d56Sopenharmony_ci return "" 1667db96d56Sopenharmony_ci 1677db96d56Sopenharmony_ci # Convert to 4-byte int in native byte order -- return "" if impossible 1687db96d56Sopenharmony_ci try: 1697db96d56Sopenharmony_ci (magic,) = struct.unpack("=l", s) 1707db96d56Sopenharmony_ci except struct.error: 1717db96d56Sopenharmony_ci return "" 1727db96d56Sopenharmony_ci 1737db96d56Sopenharmony_ci # Check for GNU dbm 1747db96d56Sopenharmony_ci if magic in (0x13579ace, 0x13579acd, 0x13579acf): 1757db96d56Sopenharmony_ci return "dbm.gnu" 1767db96d56Sopenharmony_ci 1777db96d56Sopenharmony_ci # Later versions of Berkeley db hash file have a 12-byte pad in 1787db96d56Sopenharmony_ci # front of the file type 1797db96d56Sopenharmony_ci try: 1807db96d56Sopenharmony_ci (magic,) = struct.unpack("=l", s16[-4:]) 1817db96d56Sopenharmony_ci except struct.error: 1827db96d56Sopenharmony_ci return "" 1837db96d56Sopenharmony_ci 1847db96d56Sopenharmony_ci # Unknown 1857db96d56Sopenharmony_ci return "" 1867db96d56Sopenharmony_ci 1877db96d56Sopenharmony_ci 1887db96d56Sopenharmony_ciif __name__ == "__main__": 1897db96d56Sopenharmony_ci for filename in sys.argv[1:]: 1907db96d56Sopenharmony_ci print(whichdb(filename) or "UNKNOWN", filename) 191