Commit d59fee07 authored by Jim Fulton's avatar Jim Fulton

Read-only files can't be removed on Windows. :(

Added APIs for removing committed blob data that makes files writable
before removing them and updated code that removes committed blobs or
blob directories to use them.
parent 2aafe8ad
......@@ -30,6 +30,7 @@ import shutil
# ZODB test support
import ZODB
import ZODB.blob
import ZODB.tests.util
from ZODB.tests.MinPO import MinPO
from ZODB.tests.StorageTestBase import zodb_unpickle
......@@ -164,7 +165,7 @@ class GenericTests(
def tearDown(self):
self._storage.close()
os.remove(self._conf_path)
shutil.rmtree(self.blob_cache_dir)
ZODB.blob.remove_committed_dir(self.blob_cache_dir)
for server in self._servers:
forker.shutdown_zeo_server(server)
if hasattr(os, 'waitpid'):
......@@ -616,7 +617,7 @@ class BlobAdaptedFileStorageTests(GenericTests, CommonBlobTests):
calls.append((oid, serial))
sendBlob_org(self, oid, serial)
os.remove(filename)
ZODB.blob.remove_committed(filename)
returns = []
threads = [
threading.Thread(
......
......@@ -1245,7 +1245,7 @@ class TmpStore:
os.makedirs(targetpath, 0700)
targetname = self._getCleanFilename(oid, serial)
rename_or_copy_blob(blobfilename, targetname)
rename_or_copy_blob(blobfilename, targetname, chmod=False)
def loadBlob(self, oid, serial):
"""Return the filename where the blob file can be found.
......
......@@ -189,7 +189,7 @@ class Blob(persistent.Persistent):
target = self._create_uncommitted_file()
# We need to unlink the freshly created target again
# to allow link() to do its job
os.unlink(target)
os.remove(target)
try:
rename_or_copy_blob(filename, target, chmod=False)
......@@ -198,7 +198,7 @@ class Blob(persistent.Persistent):
# might exist and mark the pointer to the uncommitted file.
self._p_blob_uncommitted = None
if os.path.exists(target):
os.unlink(target)
os.remove(target)
# If there was a file moved aside, bring it back including the
# pointer to the uncommitted file.
......@@ -212,7 +212,7 @@ class Blob(persistent.Persistent):
if previous_uncommitted:
# The relinking worked so we can remove the data that we had
# set aside.
os.unlink(target_aside)
os.remove(target_aside)
# We changed the blob state and have to make sure we join the
# transaction.
......@@ -448,7 +448,7 @@ class BlobStorage(SpecificationDecoratorBase):
oid, serial = self.dirty_oids.pop()
clean = self.fshelper.getBlobFilename(oid, serial)
if os.exists(clean):
os.unlink(clean)
remove_committed(clean)
@non_overridable
def loadBlob(self, oid, serial):
......@@ -487,7 +487,7 @@ class BlobStorage(SpecificationDecoratorBase):
fn = self.fshelper.getBlobFilename(oid, serial)
self.loadSerial(oid, serial)
except POSKeyError:
os.unlink(filepath)
remove_committed(filepath)
if not os.listdir(oid_path):
shutil.rmtree(oid_path)
......@@ -511,9 +511,9 @@ class BlobStorage(SpecificationDecoratorBase):
latest = files[-1] # depends on ever-increasing tids
files.remove(latest)
for file in files:
os.unlink(os.path.join(oid_path, file))
remove_committed(os.path.join(oid_path, file))
else:
shutil.rmtree(oid_path)
remove_committed_dir(oid_path)
continue
if not os.listdir(oid_path):
......@@ -630,6 +630,24 @@ def rename_or_copy_blob(f1, f2, chmod=True):
finally:
file1.close()
file2.close()
os.unlink(f1)
remove_committed(f1)
if chmod:
os.chmod(f2, stat.S_IREAD)
if sys.platform == 'win32':
# On Windows, you can't remove read-only files, so make the
# file writable first.
def remove_committed(filename):
os.chmod(filename, stat.S_IWRITE)
os.remove(filename)
def remove_committed_dir(path):
for (dirpath, dirnames, filenames) in os.walk(path):
for filename in filenames:
filename = os.path.join(dirpath, filename)
remove_committed(filename)
shutil.rmtree(path)
else:
remove_committed = os.remove
remove_committed_dir = shutil.rmtree
......@@ -76,8 +76,6 @@ You can't put blobs into a database that has uses a Non-Blob-Storage, though:
While we are testing this, we don't need the storage directory and
databases anymore:
>>> import shutil
>>> shutil.rmtree(blob_dir)
>>> transaction.abort()
>>> database.close()
>>> database2.close()
......@@ -90,8 +90,9 @@ Clean up our blob directory:
>>> base_storage1.close()
>>> base_storage2.close()
>>> shutil.rmtree(blob_dir1)
>>> shutil.rmtree(blob_dir2)
>>> import ZODB.blob
>>> ZODB.blob.remove_committed_dir(blob_dir1)
>>> ZODB.blob.remove_committed_dir(blob_dir2)
>>> os.unlink(exportfile)
>>> os.unlink(storagefile1)
>>> os.unlink(storagefile1+".index")
......
......@@ -316,8 +316,6 @@ Teardown
We don't need the storage directory and databases anymore::
>>> import shutil
>>> shutil.rmtree(blob_dir)
>>> tm1.abort()
>>> tm2.abort()
>>> database.close()
......@@ -19,6 +19,7 @@ import ZODB.tests.util
from ZODB import utils
from ZODB.FileStorage import FileStorage
from ZODB.blob import Blob, BlobStorage
import ZODB.blob
from ZODB.DB import DB
import transaction
......@@ -92,7 +93,7 @@ class BlobUndoTests(unittest.TestCase):
def tearDown(self):
os.chdir(self.here)
shutil.rmtree(self.test_dir)
ZODB.blob.remove_committed_dir(self.test_dir)
def testUndoWithoutPreviousVersion(self):
base_storage = FileStorage(self.storagefile)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment