/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/transport/ftp.py

Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
29
29
import errno
30
30
import ftplib
31
31
import os
 
32
import os.path
32
33
import urllib
33
34
import urlparse
 
35
import select
34
36
import stat
35
37
import threading
36
38
import time
39
41
 
40
42
from bzrlib import (
41
43
    errors,
 
44
    osutils,
42
45
    urlutils,
43
46
    )
44
47
from bzrlib.trace import mutter, warning
47
50
    split_url,
48
51
    Transport,
49
52
    )
 
53
from bzrlib.transport.local import LocalURLServer
50
54
import bzrlib.ui
51
55
 
52
56
_have_medusa = False
161
165
        if ('no such file' in s
162
166
            or 'could not open' in s
163
167
            or 'no such dir' in s
 
168
            or 'could not create file' in s # vsftpd
164
169
            ):
165
170
            raise errors.NoSuchFile(path, extra=extra)
166
171
        if ('file exists' in s):
300
305
        :param retries: Number of retries after temporary failures so far
301
306
                        for this operation.
302
307
 
303
 
        TODO: jam 20051215 ftp as a protocol seems to support chmod, but ftplib does not
 
308
        TODO: jam 20051215 ftp as a protocol seems to support chmod, but
 
309
        ftplib does not
304
310
        """
305
311
        abspath = self._abspath(relpath)
306
312
        tmp_abspath = '%s.tmp.%.9f.%d.%d' % (abspath, time.time(),
312
318
            f = self._get_FTP()
313
319
            try:
314
320
                f.storbinary('STOR '+tmp_abspath, fp)
315
 
                f.rename(tmp_abspath, abspath)
 
321
                self._rename_and_overwrite(tmp_abspath, abspath, f)
316
322
            except (ftplib.error_temp,EOFError), e:
317
323
                warning("Failure during ftp PUT. Deleting temporary file.")
318
324
                try:
431
437
    #       to give it its own address as the 'to' location.
432
438
    #       So implement a fancier 'copy()'
433
439
 
 
440
    def rename(self, rel_from, rel_to):
 
441
        abs_from = self._abspath(rel_from)
 
442
        abs_to = self._abspath(rel_to)
 
443
        mutter("FTP rename: %s => %s", abs_from, abs_to)
 
444
        f = self._get_FTP()
 
445
        return self._rename(abs_from, abs_to, f)
 
446
 
 
447
    def _rename(self, abs_from, abs_to, f):
 
448
        try:
 
449
            f.rename(abs_from, abs_to)
 
450
        except ftplib.error_perm, e:
 
451
            self._translate_perm_error(e, abs_from,
 
452
                ': unable to rename to %r' % (abs_to))
 
453
 
434
454
    def move(self, rel_from, rel_to):
435
455
        """Move the item at rel_from to the location at rel_to"""
436
456
        abs_from = self._abspath(rel_from)
438
458
        try:
439
459
            mutter("FTP mv: %s => %s", abs_from, abs_to)
440
460
            f = self._get_FTP()
441
 
            f.rename(abs_from, abs_to)
 
461
            self._rename_and_overwrite(abs_from, abs_to, f)
442
462
        except ftplib.error_perm, e:
443
463
            self._translate_perm_error(e, abs_from,
444
464
                extra='unable to rename to %r' % (rel_to,), 
445
465
                unknown_exc=errors.PathError)
446
466
 
447
 
    rename = move
 
467
    def _rename_and_overwrite(self, abs_from, abs_to, f):
 
468
        """Do a fancy rename on the remote server.
 
469
 
 
470
        Using the implementation provided by osutils.
 
471
        """
 
472
        osutils.fancy_rename(abs_from, abs_to,
 
473
            rename_func=lambda p1, p2: self._rename(p1, p2, f),
 
474
            unlink_func=lambda p: self._delete(p, f))
448
475
 
449
476
    def delete(self, relpath):
450
477
        """Delete the item at relpath"""
451
478
        abspath = self._abspath(relpath)
 
479
        f = self._get_FTP()
 
480
        self._delete(abspath, f)
 
481
 
 
482
    def _delete(self, abspath, f):
452
483
        try:
453
484
            mutter("FTP rm: %s", abspath)
454
 
            f = self._get_FTP()
455
485
            f.delete(abspath)
456
486
        except ftplib.error_perm, e:
457
487
            self._translate_perm_error(e, abspath, 'error deleting',
549
579
        """This is used by medusa.ftp_server to log connections, etc."""
550
580
        self.logs.append(message)
551
581
 
552
 
    def setUp(self):
553
 
 
 
582
    def setUp(self, vfs_server=None):
554
583
        if not _have_medusa:
555
584
            raise RuntimeError('Must have medusa to run the FtpServer')
556
585
 
 
586
        assert vfs_server is None or isinstance(vfs_server, LocalURLServer), \
 
587
            "FtpServer currently assumes local transport, got %s" % vfs_server
 
588
 
557
589
        self._root = os.getcwdu()
558
590
        self._ftp_server = _ftp_server(
559
591
            authorizer=_test_authorizer(root=self._root),
565
597
        self._port = self._ftp_server.getsockname()[1]
566
598
        # Don't let it loop forever, or handle an infinite number of requests.
567
599
        # In this case it will run for 100s, or 1000 requests
568
 
        self._async_thread = threading.Thread(target=asyncore.loop,
 
600
        self._async_thread = threading.Thread(
 
601
                target=FtpServer._asyncore_loop_ignore_EBADF,
569
602
                kwargs={'timeout':0.1, 'count':1000})
570
603
        self._async_thread.setDaemon(True)
571
604
        self._async_thread.start()
577
610
        asyncore.close_all()
578
611
        self._async_thread.join()
579
612
 
 
613
    @staticmethod
 
614
    def _asyncore_loop_ignore_EBADF(*args, **kwargs):
 
615
        """Ignore EBADF during server shutdown.
 
616
 
 
617
        We close the socket to get the server to shutdown, but this causes
 
618
        select.select() to raise EBADF.
 
619
        """
 
620
        try:
 
621
            asyncore.loop(*args, **kwargs)
 
622
        except select.error, e:
 
623
            if e.args[0] != errno.EBADF:
 
624
                raise
 
625
 
580
626
 
581
627
_ftp_channel = None
582
628
_ftp_server = None
647
693
            pfrom = self.filesystem.translate(self._renaming)
648
694
            self._renaming = None
649
695
            pto = self.filesystem.translate(line[1])
 
696
            if os.path.exists(pto):
 
697
                self.respond('550 RNTO failed: file exists')
 
698
                return
650
699
            try:
651
700
                os.rename(pfrom, pto)
652
701
            except (IOError, OSError), e:
653
702
                # TODO: jam 20060516 return custom responses based on
654
703
                #       why the command failed
655
 
                self.respond('550 RNTO failed: %s' % (e,))
 
704
                # (bialix 20070418) str(e) on Python 2.5 @ Windows
 
705
                # sometimes don't provide expected error message;
 
706
                # so we obtain such message via os.strerror()
 
707
                self.respond('550 RNTO failed: %s' % os.strerror(e.errno))
656
708
            except:
657
709
                self.respond('550 RNTO failed')
658
710
                # For a test server, we will go ahead and just die
690
742
                    self.filesystem.mkdir (path)
691
743
                    self.respond ('257 MKD command successful.')
692
744
                except (IOError, OSError), e:
693
 
                    self.respond ('550 error creating directory: %s' % (e,))
 
745
                    # (bialix 20070418) str(e) on Python 2.5 @ Windows
 
746
                    # sometimes don't provide expected error message;
 
747
                    # so we obtain such message via os.strerror()
 
748
                    self.respond ('550 error creating directory: %s' %
 
749
                                  os.strerror(e.errno))
694
750
                except:
695
751
                    self.respond ('550 error creating directory.')
696
752