mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-04-27 14:57:41 +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):
|
def test_create_is_true(self, tmpdir):
|
||||||
self.storage_class(str(tmpdir), '.txt', collection='asd')
|
self.storage_class(str(tmpdir), '.txt', collection='asd')
|
||||||
assert tmpdir.listdir() == [tmpdir.join('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))
|
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):
|
class FilesystemStorage(Storage):
|
||||||
|
|
||||||
'''Saves data in vdir collection
|
'''Saves data in vdir collection
|
||||||
|
|
@ -93,7 +116,7 @@ class FilesystemStorage(Storage):
|
||||||
fpath = self._get_filepath(href)
|
fpath = self._get_filepath(href)
|
||||||
if os.path.exists(fpath):
|
if os.path.exists(fpath):
|
||||||
raise exceptions.AlreadyExistingError(item.uid)
|
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))
|
f.write(item.raw.encode(self.encoding))
|
||||||
return href, _get_etag(fpath)
|
return href, _get_etag(fpath)
|
||||||
|
|
||||||
|
|
@ -108,7 +131,7 @@ class FilesystemStorage(Storage):
|
||||||
if etag != actual_etag:
|
if etag != actual_etag:
|
||||||
raise exceptions.WrongEtagError(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))
|
f.write(item.raw.encode(self.encoding))
|
||||||
return _get_etag(fpath)
|
return _get_etag(fpath)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue