~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/ftp.py

  • Committer: Aaron Bentley
  • Date: 2007-04-16 15:38:10 UTC
  • mto: (1551.19.24 Aaron's mergeable stuff)
  • mto: This revision was merged to the branch mainline in revision 2423.
  • Revision ID: abentley@panoramicfeedback.com-20070416153810-llz9qggakjio05ku
FTP does not require atomic rename. Fixes #89436

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
import errno
30
30
import ftplib
31
31
import os
 
32
import os.path
32
33
import urllib
33
34
import urlparse
34
35
import stat
39
40
 
40
41
from bzrlib import (
41
42
    errors,
 
43
    osutils,
42
44
    urlutils,
43
45
    )
44
46
from bzrlib.trace import mutter, warning
301
303
        :param retries: Number of retries after temporary failures so far
302
304
                        for this operation.
303
305
 
304
 
        TODO: jam 20051215 ftp as a protocol seems to support chmod, but ftplib does not
 
306
        TODO: jam 20051215 ftp as a protocol seems to support chmod, but
 
307
        ftplib does not
305
308
        """
306
309
        abspath = self._abspath(relpath)
307
310
        tmp_abspath = '%s.tmp.%.9f.%d.%d' % (abspath, time.time(),
313
316
            f = self._get_FTP()
314
317
            try:
315
318
                f.storbinary('STOR '+tmp_abspath, fp)
316
 
                f.rename(tmp_abspath, abspath)
 
319
                self._rename_and_overwrite(tmp_abspath, abspath, f)
317
320
            except (ftplib.error_temp,EOFError), e:
318
321
                warning("Failure during ftp PUT. Deleting temporary file.")
319
322
                try:
357
360
    def rmdir(self, rel_path):
358
361
        """Delete the directory at rel_path"""
359
362
        abspath = self._abspath(rel_path)
 
363
        f = self._get_FTP()
 
364
        self._rmdir(abspath, f)
 
365
 
 
366
    def _rmdir(self, abspath, f):
360
367
        try:
361
368
            mutter("FTP rmd: %s", abspath)
362
 
            f = self._get_FTP()
363
369
            f.rmd(abspath)
364
370
        except ftplib.error_perm, e:
365
371
            self._translate_perm_error(e, abspath, unknown_exc=errors.PathError)
439
445
        try:
440
446
            mutter("FTP mv: %s => %s", abs_from, abs_to)
441
447
            f = self._get_FTP()
442
 
            f.rename(abs_from, abs_to)
 
448
            self._rename_and_overwrite(abs_from, abs_to, f)
443
449
        except ftplib.error_perm, e:
444
450
            self._translate_perm_error(e, abs_from,
445
451
                extra='unable to rename to %r' % (rel_to,), 
447
453
 
448
454
    rename = move
449
455
 
 
456
    def _rename_and_overwrite(self, abs_from, abs_to, f):
 
457
        """Do a fancy rename on the remote server.
 
458
 
 
459
        Using the implementation provided by osutils.
 
460
        """
 
461
        def rename(abs_from, abs_to):
 
462
            try:
 
463
                f.rename(abs_from, abs_to)
 
464
            except ftplib.error_perm, e:
 
465
                self._translate_perm_error(e, abs_from,
 
466
                    ': unable to rename to %r' % (abs_to))
 
467
 
 
468
        def delete_or_rmdir(abspath):
 
469
            try:
 
470
                self._delete(abspath, f)
 
471
            except errors.NoSuchFile, e:
 
472
                self._rmdir(abspath, f)
 
473
            except Exception, e:
 
474
                pass
 
475
        osutils.fancy_rename(abs_from, abs_to, rename_func=rename,
 
476
                             unlink_func=delete_or_rmdir)
 
477
 
450
478
    def delete(self, relpath):
451
479
        """Delete the item at relpath"""
452
480
        abspath = self._abspath(relpath)
 
481
        f = self._get_FTP()
 
482
        self._delete(abspath, f)
 
483
 
 
484
    def _delete(self, abspath, f):
453
485
        try:
454
486
            mutter("FTP rm: %s", abspath)
455
 
            f = self._get_FTP()
456
487
            f.delete(abspath)
457
488
        except ftplib.error_perm, e:
458
489
            self._translate_perm_error(e, abspath, 'error deleting',
648
679
            pfrom = self.filesystem.translate(self._renaming)
649
680
            self._renaming = None
650
681
            pto = self.filesystem.translate(line[1])
 
682
            if os.path.exists(pto):
 
683
                self.respond('550 RNTO failed: file exists')
 
684
                return
651
685
            try:
652
686
                os.rename(pfrom, pto)
653
687
            except (IOError, OSError), e: