~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/sftp.py

  • Committer: Matt Nordhoff
  • Date: 2009-04-04 02:50:01 UTC
  • mfrom: (4253 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4256.
  • Revision ID: mnordhoff@mattnordhoff.com-20090404025001-z1403k0tatmc8l91
Merge bzr.dev, fixing conflicts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Implementation of Transport over SFTP, using paramiko."""
18
18
 
96
96
 
97
97
class SFTPLock(object):
98
98
    """This fakes a lock in a remote location.
99
 
    
 
99
 
100
100
    A present lock is indicated just by the existence of a file.  This
101
 
    doesn't work well on all transports and they are only used in 
 
101
    doesn't work well on all transports and they are only used in
102
102
    deprecated storage formats.
103
103
    """
104
 
    
 
104
 
105
105
    __slots__ = ['path', 'lock_path', 'lock_file', 'transport']
106
106
 
107
107
    def __init__(self, path, transport):
349
349
 
350
350
    def _remote_path(self, relpath):
351
351
        """Return the path to be passed along the sftp protocol for relpath.
352
 
        
 
352
 
353
353
        :param relpath: is a urlencoded string.
354
354
        """
355
355
        relative = urlutils.unescape(relpath).encode('utf-8')
406
406
        """
407
407
        try:
408
408
            self._get_sftp().stat(self._remote_path(relpath))
 
409
            # stat result is about 20 bytes, let's say
 
410
            self._report_activity(20, 'read')
409
411
            return True
410
412
        except IOError:
411
413
            return False
416
418
        :param relpath: The relative path to the file
417
419
        """
418
420
        try:
 
421
            # FIXME: by returning the file directly, we don't pass this
 
422
            # through to report_activity.  We could try wrapping the object
 
423
            # before it's returned.  For readv and get_bytes it's handled in
 
424
            # the higher-level function.
 
425
            # -- mbp 20090126
419
426
            path = self._remote_path(relpath)
420
427
            f = self._get_sftp().file(path, mode='rb')
421
428
            if self._do_prefetch and (getattr(f, 'prefetch', None) is not None):
502
509
            #      sticky bit. So it is probably best to stop chmodding, and
503
510
            #      just tell users that they need to set the umask correctly.
504
511
            #      The attr.st_mode = mode, in _sftp_open_exclusive
505
 
            #      will handle when the user wants the final mode to be more 
506
 
            #      restrictive. And then we avoid a round trip. Unless 
 
512
            #      will handle when the user wants the final mode to be more
 
513
            #      restrictive. And then we avoid a round trip. Unless
507
514
            #      paramiko decides to expose an async chmod()
508
515
 
509
516
            # This is designed to chmod() right before we close.
510
 
            # Because we set_pipelined() earlier, theoretically we might 
 
517
            # Because we set_pipelined() earlier, theoretically we might
511
518
            # avoid the round trip for fout.close()
512
519
            if mode is not None:
513
520
                self._get_sftp().chmod(tmp_abspath, mode)
555
562
                                                 ': unable to open')
556
563
 
557
564
                # This is designed to chmod() right before we close.
558
 
                # Because we set_pipelined() earlier, theoretically we might 
 
565
                # Because we set_pipelined() earlier, theoretically we might
559
566
                # avoid the round trip for fout.close()
560
567
                if mode is not None:
561
568
                    self._get_sftp().chmod(abspath, mode)
612
619
 
613
620
    def iter_files_recursive(self):
614
621
        """Walk the relative paths of all files in this transport."""
 
622
        # progress is handled by list_dir
615
623
        queue = list(self.list_dir('.'))
616
624
        while queue:
617
625
            relpath = queue.pop(0)
628
636
        else:
629
637
            local_mode = mode
630
638
        try:
 
639
            self._report_activity(len(abspath), 'write')
631
640
            self._get_sftp().mkdir(abspath, local_mode)
 
641
            self._report_activity(1, 'read')
632
642
            if mode is not None:
633
643
                # chmod a dir through sftp will erase any sgid bit set
634
644
                # on the server side.  So, if the bit mode are already
656
666
    def open_write_stream(self, relpath, mode=None):
657
667
        """See Transport.open_write_stream."""
658
668
        # initialise the file to zero-length
659
 
        # this is three round trips, but we don't use this 
660
 
        # api more than once per write_group at the moment so 
 
669
        # this is three round trips, but we don't use this
 
670
        # api more than once per write_group at the moment so
661
671
        # it is a tolerable overhead. Better would be to truncate
662
672
        # the file after opening. RBC 20070805
663
673
        self.put_bytes_non_atomic(relpath, "", mode)
686
696
        :param failure_exc: Paramiko has the super fun ability to raise completely
687
697
                           opaque errors that just set "e.args = ('Failure',)" with
688
698
                           no more information.
689
 
                           If this parameter is set, it defines the exception 
 
699
                           If this parameter is set, it defines the exception
690
700
                           to raise in these cases.
691
701
        """
692
702
        # paramiko seems to generate detailless errors.
733
743
 
734
744
    def _rename_and_overwrite(self, abs_from, abs_to):
735
745
        """Do a fancy rename on the remote server.
736
 
        
 
746
 
737
747
        Using the implementation provided by osutils.
738
748
        """
739
749
        try:
758
768
            self._get_sftp().remove(path)
759
769
        except (IOError, paramiko.SSHException), e:
760
770
            self._translate_io_exception(e, path, ': unable to delete')
761
 
            
 
771
 
762
772
    def external_url(self):
763
773
        """See bzrlib.transport.Transport.external_url."""
764
774
        # the external path for SFTP is the base
779
789
        path = self._remote_path(relpath)
780
790
        try:
781
791
            entries = self._get_sftp().listdir(path)
 
792
            self._report_activity(sum(map(len, entries)), 'read')
782
793
        except (IOError, paramiko.SSHException), e:
783
794
            self._translate_io_exception(e, path, ': failed to list_dir')
784
795
        return [urlutils.escape(entry) for entry in entries]
841
852
        """
842
853
        # TODO: jam 20060816 Paramiko >= 1.6.2 (probably earlier) supports
843
854
        #       using the 'x' flag to indicate SFTP_FLAG_EXCL.
844
 
        #       However, there is no way to set the permission mode at open 
 
855
        #       However, there is no way to set the permission mode at open
845
856
        #       time using the sftp_client.file() functionality.
846
857
        path = self._get_sftp()._adjust_cwd(abspath)
847
858
        # mutter('sftp abspath %s => %s', abspath, path)
848
859
        attr = SFTPAttributes()
849
860
        if mode is not None:
850
861
            attr.st_mode = mode
851
 
        omode = (SFTP_FLAG_WRITE | SFTP_FLAG_CREATE 
 
862
        omode = (SFTP_FLAG_WRITE | SFTP_FLAG_CREATE
852
863
                | SFTP_FLAG_TRUNC | SFTP_FLAG_EXCL)
853
864
        try:
854
865
            t, msg = self._get_sftp()._request(CMD_OPEN, path, omode, attr)
932
943
                # probably a failed test; unit test thread will log the
933
944
                # failure/error
934
945
                sys.excepthook(*sys.exc_info())
935
 
                warning('Exception from within unit test server thread: %r' % 
 
946
                warning('Exception from within unit test server thread: %r' %
936
947
                        x)
937
948
 
938
949
 
949
960
 
950
961
    Not all methods are implemented, this is deliberate as this class is not a
951
962
    replacement for the builtin sockets layer. fileno is not implemented to
952
 
    prevent the proxy being bypassed. 
 
963
    prevent the proxy being bypassed.
953
964
    """
954
965
 
955
966
    simulated_time = 0
957
968
        "close", "getpeername", "getsockname", "getsockopt", "gettimeout",
958
969
        "setblocking", "setsockopt", "settimeout", "shutdown"])
959
970
 
960
 
    def __init__(self, sock, latency, bandwidth=1.0, 
 
971
    def __init__(self, sock, latency, bandwidth=1.0,
961
972
                 really_sleep=True):
962
 
        """ 
 
973
        """
963
974
        :param bandwith: simulated bandwith (MegaBit)
964
975
        :param really_sleep: If set to false, the SocketDelay will just
965
976
        increase a counter, instead of calling time.sleep. This is useful for
968
979
        self.sock = sock
969
980
        self.latency = latency
970
981
        self.really_sleep = really_sleep
971
 
        self.time_per_byte = 1 / (bandwidth / 8.0 * 1024 * 1024) 
 
982
        self.time_per_byte = 1 / (bandwidth / 8.0 * 1024 * 1024)
972
983
        self.new_roundtrip = False
973
984
 
974
985
    def sleep(self, s):
1036
1047
 
1037
1048
    def _run_server_entry(self, sock):
1038
1049
        """Entry point for all implementations of _run_server.
1039
 
        
 
1050
 
1040
1051
        If self.add_latency is > 0.000001 then sock is given a latency adding
1041
1052
        decorator.
1042
1053
        """
1059
1070
        event = threading.Event()
1060
1071
        ssh_server.start_server(event, server)
1061
1072
        event.wait(5.0)
1062
 
    
 
1073
 
1063
1074
    def setUp(self, backing_server=None):
1064
1075
        # XXX: TODO: make sftpserver back onto backing_server rather than local
1065
1076
        # disk.