_os = _os # for _commit()
_open = _open # for _commit()
- def __init__(self, filebasename, mode):
+ def __init__(self, filebasename, mode, flag='c'):
self._mode = mode
+ self._readonly = (flag == 'r')
# The directory file is a text file. Each line looks like
# "%r, (%d, %d)\n" % (key, pos, siz)
try:
f = _open(self._dirfile)
except IOError:
- pass
+ self._modified = not self._readonly
else:
+ self._modified = False
with f:
for line in f:
line = line.rstrip()
# CAUTION: It's vital that _commit() succeed, and _commit() can
# be called from __del__(). Therefore we must never reference a
# global in this routine.
- if self._index is None:
+ if self._index is None or not self._modified:
return # nothing to do
try:
def __setitem__(self, key, val):
if not type(key) == type('') == type(val):
raise TypeError, "keys and values must be strings"
+ self._modified = True
if key not in self._index:
self._addkey(key, self._addval(val))
else:
# (so that _commit() never gets called).
def __delitem__(self, key):
+ self._modified = True
# The blocks used by the associated value are lost.
del self._index[key]
# XXX It's unclear why we do a _commit() here (the code always
# Turn off any bits that are set in the umask
mode = mode & (~um)
- return _Database(file, mode)
+ return _Database(file, mode, flag)
"""
import os
+import stat
import unittest
import dumbdbm
from test import test_support
dumbdbm.open(_fname).close()
self.assertEqual(stdout.getvalue(), '')
+ @unittest.skipUnless(hasattr(os, 'chmod'), 'test needs os.chmod()')
+ def test_readonly_files(self):
+ dir = _fname
+ os.mkdir(dir)
+ try:
+ fname = os.path.join(dir, 'db')
+ f = dumbdbm.open(fname, 'n')
+ self.assertEqual(list(f.keys()), [])
+ for key in self._dict:
+ f[key] = self._dict[key]
+ f.close()
+ os.chmod(fname + ".dir", stat.S_IRUSR)
+ os.chmod(fname + ".dat", stat.S_IRUSR)
+ os.chmod(dir, stat.S_IRUSR|stat.S_IXUSR)
+ f = dumbdbm.open(fname, 'r')
+ self.assertEqual(sorted(f.keys()), sorted(self._dict))
+ f.close() # don't write
+ finally:
+ test_support.rmtree(dir)
+
def tearDown(self):
_delete_files()