10c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""A dumb and slow but simple dbm clone. 20c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 30c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFor database spam, spam.dir contains the index (a text file), 40c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yispam.bak *may* contain a backup of the index (also a text file), 50c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiwhile spam.dat contains the data (a binary file). 60c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 70c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiXXX TO DO: 80c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 90c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi- seems to contain a bug when updating... 100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi- reclaim free space (currently, space once occupied by deleted or expanded 120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiitems is never reused) 130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi- support concurrent access (currently, if two processes take turns making 150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiupdates, they can mess up the index) 160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi- support efficient access to large databases (currently, the whole index 180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiis read when the database is opened, and some updates rewrite the whole index) 190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi- support opening for read-only (flag = 'm') 210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""" 230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport os as _os 250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport __builtin__ 260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport UserDict 270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi_open = __builtin__.open 290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi_BLOCKSIZE = 512 310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yierror = IOError # For anydbm 330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass _Database(UserDict.DictMixin): 350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # The on-disk directory and data files can remain in mutually 370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # inconsistent states for an arbitrarily long time (see comments 380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # at the end of __setitem__). This is only repaired when _commit() 390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # gets called. One place _commit() gets called is from __del__(), 400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # and if that occurs at program shutdown time, module globals may 410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # already have gotten rebound to None. Since it's crucial that 420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # _commit() finish successfully, we can't ignore shutdown races 430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # here, and _commit() must not reference any globals. 440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi _os = _os # for _commit() 450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi _open = _open # for _commit() 460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def __init__(self, filebasename, mode): 480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._mode = mode 490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # The directory file is a text file. Each line looks like 510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # "%r, (%d, %d)\n" % (key, pos, siz) 520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # where key is the string key, pos is the offset into the dat 530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # file of the associated value's first byte, and siz is the number 540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # of bytes in the associated value. 550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._dirfile = filebasename + _os.extsep + 'dir' 560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # The data file is a binary file pointed into by the directory 580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # file, and holds the values associated with keys. Each value 590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # begins at a _BLOCKSIZE-aligned byte offset, and is a raw 600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # binary 8-bit string value. 610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._datfile = filebasename + _os.extsep + 'dat' 620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._bakfile = filebasename + _os.extsep + 'bak' 630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # The index is an in-memory dict, mirroring the directory file. 650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._index = None # maps keys to (pos, siz) pairs 660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # Mod by Jack: create data file if needed 680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi try: 690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f = _open(self._datfile, 'r') 700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi except IOError: 710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f = _open(self._datfile, 'w') 720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._chmod(self._datfile) 730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f.close() 740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._update() 750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # Read directory file into the in-memory index dict. 770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def _update(self): 780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._index = {} 790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi try: 800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f = _open(self._dirfile) 810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi except IOError: 820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pass 830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi else: 840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi for line in f: 850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi line = line.rstrip() 860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi key, pos_and_siz_pair = eval(line) 870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._index[key] = pos_and_siz_pair 880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f.close() 890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # Write the index dict to the directory file. The original directory 910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # file (if any) is renamed with a .bak extension first. If a .bak 920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # file currently exists, it's deleted. 930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def _commit(self): 940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # CAUTION: It's vital that _commit() succeed, and _commit() can 950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # be called from __del__(). Therefore we must never reference a 960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # global in this routine. 970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if self._index is None: 980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return # nothing to do 990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi try: 1010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._os.unlink(self._bakfile) 1020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi except self._os.error: 1030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pass 1040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi try: 1060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._os.rename(self._dirfile, self._bakfile) 1070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi except self._os.error: 1080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pass 1090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f = self._open(self._dirfile, 'w') 1110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._chmod(self._dirfile) 1120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi for key, pos_and_siz_pair in self._index.iteritems(): 1130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f.write("%r, %r\n" % (key, pos_and_siz_pair)) 1140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f.close() 1150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi sync = _commit 1170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def __getitem__(self, key): 1190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pos, siz = self._index[key] # may raise KeyError 1200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f = _open(self._datfile, 'rb') 1210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f.seek(pos) 1220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi dat = f.read(siz) 1230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f.close() 1240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return dat 1250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # Append val to the data file, starting at a _BLOCKSIZE-aligned 1270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # offset. The data file is first padded with NUL bytes (if needed) 1280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # to get to an aligned offset. Return pair 1290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # (starting offset of val, len(val)) 1300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def _addval(self, val): 1310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f = _open(self._datfile, 'rb+') 1320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f.seek(0, 2) 1330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pos = int(f.tell()) 1340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi npos = ((pos + _BLOCKSIZE - 1) // _BLOCKSIZE) * _BLOCKSIZE 1350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f.write('\0'*(npos-pos)) 1360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pos = npos 1370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f.write(val) 1380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f.close() 1390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return (pos, len(val)) 1400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # Write val to the data file, starting at offset pos. The caller 1420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # is responsible for ensuring that there's enough room starting at 1430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # pos to hold val, without overwriting some other value. Return 1440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # pair (pos, len(val)). 1450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def _setval(self, pos, val): 1460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f = _open(self._datfile, 'rb+') 1470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f.seek(pos) 1480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f.write(val) 1490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f.close() 1500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return (pos, len(val)) 1510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # key is a new key whose associated value starts in the data file 1530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # at offset pos and with length siz. Add an index record to 1540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # the in-memory index dict, and append one to the directory file. 1550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def _addkey(self, key, pos_and_siz_pair): 1560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._index[key] = pos_and_siz_pair 1570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f = _open(self._dirfile, 'a') 1580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._chmod(self._dirfile) 1590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f.write("%r, %r\n" % (key, pos_and_siz_pair)) 1600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi f.close() 1610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def __setitem__(self, key, val): 1630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if not type(key) == type('') == type(val): 1640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi raise TypeError, "keys and values must be strings" 1650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if key not in self._index: 1660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._addkey(key, self._addval(val)) 1670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi else: 1680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # See whether the new value is small enough to fit in the 1690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # (padded) space currently occupied by the old value. 1700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pos, siz = self._index[key] 1710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi oldblocks = (siz + _BLOCKSIZE - 1) // _BLOCKSIZE 1720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi newblocks = (len(val) + _BLOCKSIZE - 1) // _BLOCKSIZE 1730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if newblocks <= oldblocks: 1740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._index[key] = self._setval(pos, val) 1750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi else: 1760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # The new value doesn't fit in the (padded) space used 1770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # by the old value. The blocks used by the old value are 1780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # forever lost. 1790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._index[key] = self._addval(val) 1800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # Note that _index may be out of synch with the directory 1820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # file now: _setval() and _addval() don't update the directory 1830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # file. This also means that the on-disk directory and data 1840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # files are in a mutually inconsistent state, and they'll 1850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # remain that way until _commit() is called. Note that this 1860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # is a disaster (for the database) if the program crashes 1870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # (so that _commit() never gets called). 1880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def __delitem__(self, key): 1900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # The blocks used by the associated value are lost. 1910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi del self._index[key] 1920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # XXX It's unclear why we do a _commit() here (the code always 1930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # XXX has, so I'm not changing it). _setitem__ doesn't try to 1940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # XXX keep the directory file in synch. Why should we? Or 1950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # XXX why shouldn't __setitem__? 1960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._commit() 1970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def keys(self): 1990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return self._index.keys() 2000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def has_key(self, key): 2020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return key in self._index 2030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def __contains__(self, key): 2050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return key in self._index 2060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def iterkeys(self): 2080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return self._index.iterkeys() 2090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi __iter__ = iterkeys 2100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def __len__(self): 2120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return len(self._index) 2130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def close(self): 2150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._commit() 2160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._index = self._datfile = self._dirfile = self._bakfile = None 2170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi __del__ = close 2190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def _chmod (self, file): 2210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if hasattr(self._os, 'chmod'): 2220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self._os.chmod(file, self._mode) 2230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef open(file, flag=None, mode=0666): 2260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi """Open the database file, filename, and return corresponding object. 2270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi The flag argument, used to control how the database is opened in the 2290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi other DBM implementations, is ignored in the dumbdbm module; the 2300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi database is always opened for update, and will be created if it does 2310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi not exist. 2320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi The optional mode argument is the UNIX mode of the file, used only when 2340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi the database has to be created. It defaults to octal code 0666 (and 2350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi will be modified by the prevailing umask). 2360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi """ 2380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # flag argument is currently ignored 2390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # Modify mode depending on the umask 2410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi try: 2420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi um = _os.umask(0) 2430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi _os.umask(um) 2440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi except AttributeError: 2450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pass 2460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi else: 2470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # Turn off any bits that are set in the umask 2480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi mode = mode & (~um) 2490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return _Database(file, mode) 251