~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/sftp.py

  • Committer: John Arbash Meinel
  • Date: 2005-11-05 07:06:27 UTC
  • mto: (1185.50.1 jam-integration)
  • mto: This revision was merged to the branch mainline in revision 1518.
  • Revision ID: john@arbash-meinel.com-20051105070627-193d996deee82a31
Updating SftpTransport.put() so that it is atomic

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
import stat
24
24
import sys
25
25
import urllib
 
26
import time
 
27
import random
26
28
 
27
29
from bzrlib.errors import (FileExists, 
28
30
                           TransportNotPossible, NoSuchFile, NonRelativePath,
205
207
        :param relpath: Location to put the contents, relative to base.
206
208
        :param f:       File-like or string object.
207
209
        """
208
 
        # FIXME: should do something atomic or locking here, this is unsafe
209
210
        try:
210
 
            path = self._abspath(relpath)
211
 
            fout = self._sftp.file(path, 'wb')
 
211
            finalpath = self._abspath(relpath)
 
212
            tmp_path = '%s.tmp.%.9f.%d.%d' % (finalpath, time.time(),
 
213
                       os.getpid(), random.randint(0,0x7FFFFFFF))
 
214
            # I would *really* like to pass in the SFTP_FLAG_EXCL,
 
215
            # but there doesn't seem to be a way to do it in the
 
216
            # self._sftp.file() interface.
 
217
            fout = self._sftp.file(tmp_path, 'wb')
212
218
        except IOError, e:
 
219
            # Maybe this should actually be using the relative form of tmp_path
213
220
            self._translate_io_exception(e, relpath)
214
221
        except (IOError, paramiko.SSHException), x:
215
 
            raise SFTPTransportError('Unable to write file %r' % (path,), x)
 
222
            raise SFTPTransportError('Unable to open file %r' % (tmp_path,), x)
 
223
 
216
224
        try:
217
 
            self._pump(f, fout)
218
 
        finally:
 
225
            try:
 
226
                self._pump(f, fout)
 
227
            except IOError, e:
 
228
                self._translate_io_exception(e, relpath)
 
229
            except paramiko.SSHException, x:
 
230
                raise SFTPTransportError('Unable to write file %r' % (path,), x)
 
231
        except Exception, e:
 
232
            # If we fail, try to clean up the temporary file
 
233
            # before we throw the exception
 
234
            # but don't let another exception mess things up
 
235
            try:
 
236
                fout.close()
 
237
                self._sftp.remove(tmp_path)
 
238
            except:
 
239
                pass
 
240
            raise e
 
241
        else:
219
242
            fout.close()
 
243
            try:
 
244
                self._sftp.rename(tmp_path, finalpath)
 
245
            except IOError, e:
 
246
                self._translate_io_exception(e, relpath)
 
247
            except paramiko.SSHException, x:
 
248
                raise SFTPTransportError('Unable to rename into file %r' 
 
249
                                          % (path,), x)
220
250
 
221
251
    def iter_files_recursive(self):
222
252
        """Walk the relative paths of all files in this transport."""