Use safer write to avoid corruption of data.

This commit is contained in:
Markus Unterwaditzer 2014-04-09 18:36:46 +02:00
parent d3e4a52376
commit 9b78360515
2 changed files with 34 additions and 2 deletions

View file

@ -41,3 +41,12 @@ class TestFilesystemStorage(StorageTests):
def test_create_is_true(self, tmpdir):
self.storage_class(str(tmpdir), '.txt', collection='asd')
assert tmpdir.listdir() == [tmpdir.join('asd')]
def test_broken_data(self, tmpdir):
s = self.storage_class(str(tmpdir), '.txt')
class BrokenItem(object):
raw = b'Ц, Ш, Л, ж, Д, З, Ю'
uid = 'jeezus'
with pytest.raises(UnicodeError):
s.upload(BrokenItem)
assert not tmpdir.listdir()

View file

@ -19,6 +19,29 @@ def _get_etag(fpath):
return '{:.9f}'.format(os.path.getmtime(fpath))
class safe_write(object):
f = None
tmppath = None
fpath = None
mode = None
def __init__(self, fpath, mode):
self.tmppath = fpath + '.tmp'
self.fpath = fpath
self.mode = mode
def __enter__(self):
self.f = f = open(self.tmppath, self.mode)
self.write = f.write
return self
def __exit__(self, type, value, tb):
if type is None:
os.rename(self.tmppath, self.fpath)
else:
os.remove(self.tmppath)
class FilesystemStorage(Storage):
'''Saves data in vdir collection
@ -93,7 +116,7 @@ class FilesystemStorage(Storage):
fpath = self._get_filepath(href)
if os.path.exists(fpath):
raise exceptions.AlreadyExistingError(item.uid)
with open(fpath, 'wb+') as f:
with safe_write(fpath, 'wb+') as f:
f.write(item.raw.encode(self.encoding))
return href, _get_etag(fpath)
@ -108,7 +131,7 @@ class FilesystemStorage(Storage):
if etag != actual_etag:
raise exceptions.WrongEtagError(etag, actual_etag)
with open(fpath, 'wb') as f:
with safe_write(fpath, 'wb') as f:
f.write(item.raw.encode(self.encoding))
return _get_etag(fpath)