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