mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-03-25 08:55:50 +00:00
Use safer write to avoid corruption of data.
This commit is contained in:
parent
d3e4a52376
commit
9b78360515
2 changed files with 34 additions and 2 deletions
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue