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