19f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum"""A dumb and slow but simple dbm clone.
29f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum
39f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van RossumFor database spam, spam.dir contains the index (a text file),
49f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossumspam.bak *may* contain a backup of the index (also a text file),
59f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossumwhile spam.dat contains the data (a binary file).
69f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum
79f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van RossumXXX TO DO:
89f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum
99f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum- seems to contain a bug when updating...
109f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum
119f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum- reclaim free space (currently, space once occupied by deleted or expanded
129f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossumitems is never reused)
139f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum
149f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum- support concurrent access (currently, if two processes take turns making
159f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossumupdates, they can mess up the index)
169f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum
179f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum- support efficient access to large databases (currently, the whole index
189f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossumis read when the database is opened, and some updates rewrite the whole index)
199f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum
209f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum- support opening for read-only (flag = 'm')
219f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum
229f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum"""
239f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum
24c769040100c3957446acea6efed5c9ad4a552cf2Serhiy Storchakaimport ast as _ast
25d0cd95ce7febd97683d6e113e1b486b93bcf88ebMartin v. Löwisimport os as _os
269f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossumimport __builtin__
272dd1ed69b425d2f2ac8152548c7581aa1f01216dRaymond Hettingerimport UserDict
289f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum
299f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum_open = __builtin__.open
309f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum
319f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum_BLOCKSIZE = 512
329f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum
3388869f9787cd4ceb2298e4b13980beb057687824Tim Peterserror = IOError                         # For anydbm
3422a18904e43c47902ae1e58922abeb87b530b0aeGuido van Rossum
352dd1ed69b425d2f2ac8152548c7581aa1f01216dRaymond Hettingerclass _Database(UserDict.DictMixin):
369f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum
37d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters    # The on-disk directory and data files can remain in mutually
38d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters    # inconsistent states for an arbitrarily long time (see comments
39d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters    # at the end of __setitem__).  This is only repaired when _commit()
40d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters    # gets called.  One place _commit() gets called is from __del__(),
41d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters    # and if that occurs at program shutdown time, module globals may
42d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters    # already have gotten rebound to None.  Since it's crucial that
430320464583957258031ebee1b8897343211e4339Tim Peters    # _commit() finish successfully, we can't ignore shutdown races
44d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters    # here, and _commit() must not reference any globals.
45d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters    _os = _os       # for _commit()
46d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters    _open = _open   # for _commit()
47d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters
489bd44d6dab214ab17c5505aa445388ccf8695c87Serhiy Storchaka    def __init__(self, filebasename, mode, flag='c'):
492c8373bc234039fff699df9c28d2cb74efd6a37cFred Drake        self._mode = mode
509bd44d6dab214ab17c5505aa445388ccf8695c87Serhiy Storchaka        self._readonly = (flag == 'r')
517dfd5701b20c3566166e148f77591a2912164221Tim Peters
527dfd5701b20c3566166e148f77591a2912164221Tim Peters        # The directory file is a text file.  Each line looks like
537dfd5701b20c3566166e148f77591a2912164221Tim Peters        #    "%r, (%d, %d)\n" % (key, pos, siz)
547dfd5701b20c3566166e148f77591a2912164221Tim Peters        # where key is the string key, pos is the offset into the dat
557dfd5701b20c3566166e148f77591a2912164221Tim Peters        # file of the associated value's first byte, and siz is the number
567dfd5701b20c3566166e148f77591a2912164221Tim Peters        # of bytes in the associated value.
577dfd5701b20c3566166e148f77591a2912164221Tim Peters        self._dirfile = filebasename + _os.extsep + 'dir'
587dfd5701b20c3566166e148f77591a2912164221Tim Peters
597dfd5701b20c3566166e148f77591a2912164221Tim Peters        # The data file is a binary file pointed into by the directory
607dfd5701b20c3566166e148f77591a2912164221Tim Peters        # file, and holds the values associated with keys.  Each value
617dfd5701b20c3566166e148f77591a2912164221Tim Peters        # begins at a _BLOCKSIZE-aligned byte offset, and is a raw
627dfd5701b20c3566166e148f77591a2912164221Tim Peters        # binary 8-bit string value.
637dfd5701b20c3566166e148f77591a2912164221Tim Peters        self._datfile = filebasename + _os.extsep + 'dat'
647dfd5701b20c3566166e148f77591a2912164221Tim Peters        self._bakfile = filebasename + _os.extsep + 'bak'
657dfd5701b20c3566166e148f77591a2912164221Tim Peters
667dfd5701b20c3566166e148f77591a2912164221Tim Peters        # The index is an in-memory dict, mirroring the directory file.
677dfd5701b20c3566166e148f77591a2912164221Tim Peters        self._index = None  # maps keys to (pos, siz) pairs
687dfd5701b20c3566166e148f77591a2912164221Tim Peters
6988869f9787cd4ceb2298e4b13980beb057687824Tim Peters        # Mod by Jack: create data file if needed
7088869f9787cd4ceb2298e4b13980beb057687824Tim Peters        try:
7188869f9787cd4ceb2298e4b13980beb057687824Tim Peters            f = _open(self._datfile, 'r')
7288869f9787cd4ceb2298e4b13980beb057687824Tim Peters        except IOError:
7333ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            with _open(self._datfile, 'w') as f:
7433ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka                self._chmod(self._datfile)
7533ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka        else:
7633ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            f.close()
7788869f9787cd4ceb2298e4b13980beb057687824Tim Peters        self._update()
7888869f9787cd4ceb2298e4b13980beb057687824Tim Peters
797dfd5701b20c3566166e148f77591a2912164221Tim Peters    # Read directory file into the in-memory index dict.
8088869f9787cd4ceb2298e4b13980beb057687824Tim Peters    def _update(self):
8188869f9787cd4ceb2298e4b13980beb057687824Tim Peters        self._index = {}
8288869f9787cd4ceb2298e4b13980beb057687824Tim Peters        try:
8388869f9787cd4ceb2298e4b13980beb057687824Tim Peters            f = _open(self._dirfile)
8488869f9787cd4ceb2298e4b13980beb057687824Tim Peters        except IOError:
859bd44d6dab214ab17c5505aa445388ccf8695c87Serhiy Storchaka            self._modified = not self._readonly
8688869f9787cd4ceb2298e4b13980beb057687824Tim Peters        else:
879bd44d6dab214ab17c5505aa445388ccf8695c87Serhiy Storchaka            self._modified = False
8833ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            with f:
8933ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka                for line in f:
9033ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka                    line = line.rstrip()
91c769040100c3957446acea6efed5c9ad4a552cf2Serhiy Storchaka                    key, pos_and_siz_pair = _ast.literal_eval(line)
9233ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka                    self._index[key] = pos_and_siz_pair
9388869f9787cd4ceb2298e4b13980beb057687824Tim Peters
947dfd5701b20c3566166e148f77591a2912164221Tim Peters    # Write the index dict to the directory file.  The original directory
957dfd5701b20c3566166e148f77591a2912164221Tim Peters    # file (if any) is renamed with a .bak extension first.  If a .bak
967dfd5701b20c3566166e148f77591a2912164221Tim Peters    # file currently exists, it's deleted.
9788869f9787cd4ceb2298e4b13980beb057687824Tim Peters    def _commit(self):
98d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters        # CAUTION:  It's vital that _commit() succeed, and _commit() can
99d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters        # be called from __del__().  Therefore we must never reference a
100d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters        # global in this routine.
1019bd44d6dab214ab17c5505aa445388ccf8695c87Serhiy Storchaka        if self._index is None or not self._modified:
1027a6c733c3b8ee131d7860ecb0877837e412c2959Tim Peters            return  # nothing to do
1037a6c733c3b8ee131d7860ecb0877837e412c2959Tim Peters
1047dfd5701b20c3566166e148f77591a2912164221Tim Peters        try:
105d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters            self._os.unlink(self._bakfile)
106d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters        except self._os.error:
1077dfd5701b20c3566166e148f77591a2912164221Tim Peters            pass
1087dfd5701b20c3566166e148f77591a2912164221Tim Peters
1097dfd5701b20c3566166e148f77591a2912164221Tim Peters        try:
110d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters            self._os.rename(self._dirfile, self._bakfile)
111d7472ec13a65c6c5ff00365b1477677d1fecbb3cTim Peters        except self._os.error:
1127dfd5701b20c3566166e148f77591a2912164221Tim Peters            pass
1137dfd5701b20c3566166e148f77591a2912164221Tim Peters
11433ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka        with self._open(self._dirfile, 'w') as f:
11533ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            self._chmod(self._dirfile)
11633ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            for key, pos_and_siz_pair in self._index.iteritems():
11733ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka                f.write("%r, %r\n" % (key, pos_and_siz_pair))
11888869f9787cd4ceb2298e4b13980beb057687824Tim Peters
1196d06815b562e1540ee334d30953354210dfebd24Skip Montanaro    sync = _commit
1206d06815b562e1540ee334d30953354210dfebd24Skip Montanaro
12188869f9787cd4ceb2298e4b13980beb057687824Tim Peters    def __getitem__(self, key):
12288869f9787cd4ceb2298e4b13980beb057687824Tim Peters        pos, siz = self._index[key]     # may raise KeyError
12333ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka        with _open(self._datfile, 'rb') as f:
12433ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            f.seek(pos)
12533ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            dat = f.read(siz)
12688869f9787cd4ceb2298e4b13980beb057687824Tim Peters        return dat
12788869f9787cd4ceb2298e4b13980beb057687824Tim Peters
1287dfd5701b20c3566166e148f77591a2912164221Tim Peters    # Append val to the data file, starting at a _BLOCKSIZE-aligned
1297dfd5701b20c3566166e148f77591a2912164221Tim Peters    # offset.  The data file is first padded with NUL bytes (if needed)
1307dfd5701b20c3566166e148f77591a2912164221Tim Peters    # to get to an aligned offset.  Return pair
1317dfd5701b20c3566166e148f77591a2912164221Tim Peters    #     (starting offset of val, len(val))
13288869f9787cd4ceb2298e4b13980beb057687824Tim Peters    def _addval(self, val):
13333ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka        with _open(self._datfile, 'rb+') as f:
13433ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            f.seek(0, 2)
13533ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            pos = int(f.tell())
13633ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            npos = ((pos + _BLOCKSIZE - 1) // _BLOCKSIZE) * _BLOCKSIZE
13733ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            f.write('\0'*(npos-pos))
13833ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            pos = npos
13933ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            f.write(val)
14088869f9787cd4ceb2298e4b13980beb057687824Tim Peters        return (pos, len(val))
14188869f9787cd4ceb2298e4b13980beb057687824Tim Peters
1427dfd5701b20c3566166e148f77591a2912164221Tim Peters    # Write val to the data file, starting at offset pos.  The caller
1437dfd5701b20c3566166e148f77591a2912164221Tim Peters    # is responsible for ensuring that there's enough room starting at
1447dfd5701b20c3566166e148f77591a2912164221Tim Peters    # pos to hold val, without overwriting some other value.  Return
1457dfd5701b20c3566166e148f77591a2912164221Tim Peters    # pair (pos, len(val)).
14688869f9787cd4ceb2298e4b13980beb057687824Tim Peters    def _setval(self, pos, val):
14733ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka        with _open(self._datfile, 'rb+') as f:
14833ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            f.seek(pos)
14933ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            f.write(val)
15088869f9787cd4ceb2298e4b13980beb057687824Tim Peters        return (pos, len(val))
15188869f9787cd4ceb2298e4b13980beb057687824Tim Peters
1527dfd5701b20c3566166e148f77591a2912164221Tim Peters    # key is a new key whose associated value starts in the data file
1531d8d729af80c7d45161f20a40428d26698c11af8Tim Peters    # at offset pos and with length siz.  Add an index record to
1541d8d729af80c7d45161f20a40428d26698c11af8Tim Peters    # the in-memory index dict, and append one to the directory file.
1557dfd5701b20c3566166e148f77591a2912164221Tim Peters    def _addkey(self, key, pos_and_siz_pair):
1567dfd5701b20c3566166e148f77591a2912164221Tim Peters        self._index[key] = pos_and_siz_pair
15733ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka        with _open(self._dirfile, 'a') as f:
15833ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            self._chmod(self._dirfile)
15933ad0968eb624d22075d567123c52f62e7184d8dSerhiy Storchaka            f.write("%r, %r\n" % (key, pos_and_siz_pair))
16088869f9787cd4ceb2298e4b13980beb057687824Tim Peters
16188869f9787cd4ceb2298e4b13980beb057687824Tim Peters    def __setitem__(self, key, val):
16288869f9787cd4ceb2298e4b13980beb057687824Tim Peters        if not type(key) == type('') == type(val):
16388869f9787cd4ceb2298e4b13980beb057687824Tim Peters            raise TypeError, "keys and values must be strings"
1649bd44d6dab214ab17c5505aa445388ccf8695c87Serhiy Storchaka        self._modified = True
1657dfd5701b20c3566166e148f77591a2912164221Tim Peters        if key not in self._index:
1667dfd5701b20c3566166e148f77591a2912164221Tim Peters            self._addkey(key, self._addval(val))
16788869f9787cd4ceb2298e4b13980beb057687824Tim Peters        else:
1687dfd5701b20c3566166e148f77591a2912164221Tim Peters            # See whether the new value is small enough to fit in the
1697dfd5701b20c3566166e148f77591a2912164221Tim Peters            # (padded) space currently occupied by the old value.
17088869f9787cd4ceb2298e4b13980beb057687824Tim Peters            pos, siz = self._index[key]
171ef6573e52946c70778e29e3b33d61a8a0c6e4052Tim Peters            oldblocks = (siz + _BLOCKSIZE - 1) // _BLOCKSIZE
172ef6573e52946c70778e29e3b33d61a8a0c6e4052Tim Peters            newblocks = (len(val) + _BLOCKSIZE - 1) // _BLOCKSIZE
17388869f9787cd4ceb2298e4b13980beb057687824Tim Peters            if newblocks <= oldblocks:
1747dfd5701b20c3566166e148f77591a2912164221Tim Peters                self._index[key] = self._setval(pos, val)
17588869f9787cd4ceb2298e4b13980beb057687824Tim Peters            else:
1767dfd5701b20c3566166e148f77591a2912164221Tim Peters                # The new value doesn't fit in the (padded) space used
1777dfd5701b20c3566166e148f77591a2912164221Tim Peters                # by the old value.  The blocks used by the old value are
1787dfd5701b20c3566166e148f77591a2912164221Tim Peters                # forever lost.
1797dfd5701b20c3566166e148f77591a2912164221Tim Peters                self._index[key] = self._addval(val)
1807dfd5701b20c3566166e148f77591a2912164221Tim Peters
1817dfd5701b20c3566166e148f77591a2912164221Tim Peters            # Note that _index may be out of synch with the directory
1827dfd5701b20c3566166e148f77591a2912164221Tim Peters            # file now:  _setval() and _addval() don't update the directory
1831d8d729af80c7d45161f20a40428d26698c11af8Tim Peters            # file.  This also means that the on-disk directory and data
1841d8d729af80c7d45161f20a40428d26698c11af8Tim Peters            # files are in a mutually inconsistent state, and they'll
1851d8d729af80c7d45161f20a40428d26698c11af8Tim Peters            # remain that way until _commit() is called.  Note that this
1861d8d729af80c7d45161f20a40428d26698c11af8Tim Peters            # is a disaster (for the database) if the program crashes
1871d8d729af80c7d45161f20a40428d26698c11af8Tim Peters            # (so that _commit() never gets called).
18888869f9787cd4ceb2298e4b13980beb057687824Tim Peters
18988869f9787cd4ceb2298e4b13980beb057687824Tim Peters    def __delitem__(self, key):
1909bd44d6dab214ab17c5505aa445388ccf8695c87Serhiy Storchaka        self._modified = True
1917dfd5701b20c3566166e148f77591a2912164221Tim Peters        # The blocks used by the associated value are lost.
19288869f9787cd4ceb2298e4b13980beb057687824Tim Peters        del self._index[key]
1937dfd5701b20c3566166e148f77591a2912164221Tim Peters        # XXX It's unclear why we do a _commit() here (the code always
1947dfd5701b20c3566166e148f77591a2912164221Tim Peters        # XXX has, so I'm not changing it).  _setitem__ doesn't try to
1957dfd5701b20c3566166e148f77591a2912164221Tim Peters        # XXX keep the directory file in synch.  Why should we?  Or
1967dfd5701b20c3566166e148f77591a2912164221Tim Peters        # XXX why shouldn't __setitem__?
19788869f9787cd4ceb2298e4b13980beb057687824Tim Peters        self._commit()
19888869f9787cd4ceb2298e4b13980beb057687824Tim Peters
19988869f9787cd4ceb2298e4b13980beb057687824Tim Peters    def keys(self):
20088869f9787cd4ceb2298e4b13980beb057687824Tim Peters        return self._index.keys()
20188869f9787cd4ceb2298e4b13980beb057687824Tim Peters
20288869f9787cd4ceb2298e4b13980beb057687824Tim Peters    def has_key(self, key):
203793d4b49361a010e4baa485ec77e3adc430f0236Raymond Hettinger        return key in self._index
20488869f9787cd4ceb2298e4b13980beb057687824Tim Peters
205a7cc69e02ef9ec7014600911a66978898e545cf1Fred Drake    def __contains__(self, key):
206793d4b49361a010e4baa485ec77e3adc430f0236Raymond Hettinger        return key in self._index
207a7cc69e02ef9ec7014600911a66978898e545cf1Fred Drake
208a7cc69e02ef9ec7014600911a66978898e545cf1Fred Drake    def iterkeys(self):
209a7cc69e02ef9ec7014600911a66978898e545cf1Fred Drake        return self._index.iterkeys()
210a7cc69e02ef9ec7014600911a66978898e545cf1Fred Drake    __iter__ = iterkeys
211a7cc69e02ef9ec7014600911a66978898e545cf1Fred Drake
21288869f9787cd4ceb2298e4b13980beb057687824Tim Peters    def __len__(self):
21388869f9787cd4ceb2298e4b13980beb057687824Tim Peters        return len(self._index)
21488869f9787cd4ceb2298e4b13980beb057687824Tim Peters
21588869f9787cd4ceb2298e4b13980beb057687824Tim Peters    def close(self):
2161aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka        try:
2171aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka            self._commit()
2181aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka        finally:
2191aa2c0f073bdbed4fa824591d53e20bbf3d01addSerhiy Storchaka            self._index = self._datfile = self._dirfile = self._bakfile = None
2209f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum
2217a6c733c3b8ee131d7860ecb0877837e412c2959Tim Peters    __del__ = close
222e4418609f79b94b91bda2621b5e6f067fb6a31d5Tim Peters
223dc26758ffeb33f6d59cb30b0019da9252e0cea1cAndrew M. Kuchling    def _chmod (self, file):
224dc26758ffeb33f6d59cb30b0019da9252e0cea1cAndrew M. Kuchling        if hasattr(self._os, 'chmod'):
225dc26758ffeb33f6d59cb30b0019da9252e0cea1cAndrew M. Kuchling            self._os.chmod(file, self._mode)
226ed9057083bcdcce37ddb66bc01e9b7fddb5ea206Anthony Baxter
2279f824a7984fcd98d00dfc795e6a1d95317fd4b93Guido van Rossum
2282c8373bc234039fff699df9c28d2cb74efd6a37cFred Drakedef open(file, flag=None, mode=0666):
229aef22fb9cdf31fb7f0afc28ad049f08a89e23761Raymond Hettinger    """Open the database file, filename, and return corresponding object.
230aef22fb9cdf31fb7f0afc28ad049f08a89e23761Raymond Hettinger
231aef22fb9cdf31fb7f0afc28ad049f08a89e23761Raymond Hettinger    The flag argument, used to control how the database is opened in the
232aef22fb9cdf31fb7f0afc28ad049f08a89e23761Raymond Hettinger    other DBM implementations, is ignored in the dumbdbm module; the
233aef22fb9cdf31fb7f0afc28ad049f08a89e23761Raymond Hettinger    database is always opened for update, and will be created if it does
234aef22fb9cdf31fb7f0afc28ad049f08a89e23761Raymond Hettinger    not exist.
235aef22fb9cdf31fb7f0afc28ad049f08a89e23761Raymond Hettinger
236aef22fb9cdf31fb7f0afc28ad049f08a89e23761Raymond Hettinger    The optional mode argument is the UNIX mode of the file, used only when
237aef22fb9cdf31fb7f0afc28ad049f08a89e23761Raymond Hettinger    the database has to be created.  It defaults to octal code 0666 (and
238aef22fb9cdf31fb7f0afc28ad049f08a89e23761Raymond Hettinger    will be modified by the prevailing umask).
239aef22fb9cdf31fb7f0afc28ad049f08a89e23761Raymond Hettinger
240aef22fb9cdf31fb7f0afc28ad049f08a89e23761Raymond Hettinger    """
241f421e81e4112809380542af378575756247eba00Neal Norwitz    # flag argument is currently ignored
2429ef0ef5b729b88491be1d28ab46248b645645c44Andrew M. Kuchling
2439ef0ef5b729b88491be1d28ab46248b645645c44Andrew M. Kuchling    # Modify mode depending on the umask
2449ef0ef5b729b88491be1d28ab46248b645645c44Andrew M. Kuchling    try:
2459ef0ef5b729b88491be1d28ab46248b645645c44Andrew M. Kuchling        um = _os.umask(0)
2469ef0ef5b729b88491be1d28ab46248b645645c44Andrew M. Kuchling        _os.umask(um)
2479ef0ef5b729b88491be1d28ab46248b645645c44Andrew M. Kuchling    except AttributeError:
2489ef0ef5b729b88491be1d28ab46248b645645c44Andrew M. Kuchling        pass
2499ef0ef5b729b88491be1d28ab46248b645645c44Andrew M. Kuchling    else:
2509ef0ef5b729b88491be1d28ab46248b645645c44Andrew M. Kuchling        # Turn off any bits that are set in the umask
2519ef0ef5b729b88491be1d28ab46248b645645c44Andrew M. Kuchling        mode = mode & (~um)
252f733abb7831d6566cb0fccd0550d58ec3b7f05a4Tim Peters
2539bd44d6dab214ab17c5505aa445388ccf8695c87Serhiy Storchaka    return _Database(file, mode, flag)
254