summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2010-07-11 11:12:55 +1200
committerLars Wirzenius <liw@liw.fi>2010-07-11 11:12:55 +1200
commit5d4da199344780051b7e0070c6e11f0501a922e8 (patch)
tree98d14a97c6977736b5cf595b9dea004ef74f2c5e
parente11eaecf92bf123697f04ee375e3a258e4ffd7f1 (diff)
downloadobnam-5d4da199344780051b7e0070c6e11f0501a922e8.tar.gz
Change overwrite_file to use a temporary name while writing.
This is not quite as safe and secure as with local filesystems but as good as I can make it.
-rw-r--r--obnamlib/plugins/sftp_plugin.py36
1 files changed, 35 insertions, 1 deletions
diff --git a/obnamlib/plugins/sftp_plugin.py b/obnamlib/plugins/sftp_plugin.py
index 658b5046..ee1b8453 100644
--- a/obnamlib/plugins/sftp_plugin.py
+++ b/obnamlib/plugins/sftp_plugin.py
@@ -19,6 +19,7 @@ import errno
import logging
import os
import pwd
+import random
import stat
import urlparse
@@ -244,9 +245,42 @@ class SftpFS(obnamlib.VirtualFileSystem):
raise OSError(errno.EEXIST, 'File exists', pathname)
self._write_helper(pathname, 'wx', contents)
+ def _tempfile(self, dirname):
+ '''Generate a filename that does not exist.
+
+ This is _not_ as safe as tempfile.mkstemp. Plenty of race
+ conditions. But seems to be as good as SFTP will allow.
+
+ '''
+
+ while True:
+ i = random.randint(0, 2**64-1)
+ basename = 'tmp.%x' % i
+ pathname = os.path.join(dirname, basename)
+ if not self.exists(pathname):
+ return pathname
+
def overwrite_file(self, pathname, contents, make_backup=True):
- self._write_helper(pathname, 'w', contents)
+ dirname = os.path.dirname(pathname)
+ tempname = self._tempfile(dirname)
+ self._write_helper(pathname, 'wx', contents)
+ # Rename existing to have a .bak suffix. If _that_ file already
+ # exists, remove that.
+ bak = pathname + ".bak"
+ try:
+ self.remove(bak)
+ except OSError:
+ pass
+ if self.exists(pathname):
+ self.rename(pathname, bak)
+ self.rename(tempname, pathname)
+ if not make_backup:
+ try:
+ self.remove(bak)
+ except OSError:
+ pass
+
def _write_helper(self, pathname, mode, contents):
dirname = os.path.dirname(pathname)
if dirname: