Skip to content

Commit

Permalink
Use safer write to avoid corruption of data.
Browse files Browse the repository at this point in the history
  • Loading branch information
untitaker committed Apr 9, 2014
1 parent d3e4a52 commit 9b78360
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 2 deletions.
9 changes: 9 additions & 0 deletions tests/storage/test_filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,12 @@ def test_is_not_directory(self, tmpdir):
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()
27 changes: 25 additions & 2 deletions vdirsyncer/storage/filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -93,7 +116,7 @@ def upload(self, item):
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)

Expand All @@ -108,7 +131,7 @@ def update(self, href, item, etag):
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)

Expand Down

0 comments on commit 9b78360

Please sign in to comment.