/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/sftp.py

  • Committer: Martin Pool
  • Date: 2009-03-13 07:54:48 UTC
  • mfrom: (4144 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4189.
  • Revision ID: mbp@sourcefrog.net-20090313075448-jlz1t7baz7gzipqn
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
 
40
40
from bzrlib import (
41
41
    config,
 
42
    debug,
42
43
    errors,
43
44
    urlutils,
44
45
    )
95
96
 
96
97
class SFTPLock(object):
97
98
    """This fakes a lock in a remote location.
98
 
    
 
99
 
99
100
    A present lock is indicated just by the existence of a file.  This
100
 
    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
101
102
    deprecated storage formats.
102
103
    """
103
 
    
 
104
 
104
105
    __slots__ = ['path', 'lock_path', 'lock_file', 'transport']
105
106
 
106
107
    def __init__(self, path, transport):
182
183
                requests.append((start, next_size))
183
184
                size -= next_size
184
185
                start += next_size
185
 
        mutter('SFTP.readv(%s) %s offsets => %s coalesced => %s requests',
186
 
               self.relpath, len(sorted_offsets), len(coalesced),
187
 
               len(requests))
 
186
        if 'sftp' in debug.debug_flags:
 
187
            mutter('SFTP.readv(%s) %s offsets => %s coalesced => %s requests',
 
188
                self.relpath, len(sorted_offsets), len(coalesced),
 
189
                len(requests))
188
190
        return requests
189
191
 
190
192
    def request_and_yield_offsets(self, fp):
286
288
            del buffered_data[:]
287
289
            data_chunks.append((input_start, buffered))
288
290
        if data_chunks:
289
 
            mutter('SFTP readv left with %d out-of-order bytes',
290
 
                   sum(map(lambda x: len(x[1]), data_chunks)))
 
291
            if 'sftp' in debug.debug_flags:
 
292
                mutter('SFTP readv left with %d out-of-order bytes',
 
293
                    sum(map(lambda x: len(x[1]), data_chunks)))
291
294
            # We've processed all the readv data, at this point, anything we
292
295
            # couldn't process is in data_chunks. This doesn't happen often, so
293
296
            # this code path isn't optimized
346
349
 
347
350
    def _remote_path(self, relpath):
348
351
        """Return the path to be passed along the sftp protocol for relpath.
349
 
        
 
352
 
350
353
        :param relpath: is a urlencoded string.
351
354
        """
352
355
        relative = urlutils.unescape(relpath).encode('utf-8')
403
406
        """
404
407
        try:
405
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')
406
411
            return True
407
412
        except IOError:
408
413
            return False
413
418
        :param relpath: The relative path to the file
414
419
        """
415
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
416
426
            path = self._remote_path(relpath)
417
427
            f = self._get_sftp().file(path, mode='rb')
418
428
            if self._do_prefetch and (getattr(f, 'prefetch', None) is not None):
446
456
            readv = getattr(fp, 'readv', None)
447
457
            if readv:
448
458
                return self._sftp_readv(fp, offsets, relpath)
449
 
            mutter('seek and read %s offsets', len(offsets))
 
459
            if 'sftp' in debug.debug_flags:
 
460
                mutter('seek and read %s offsets', len(offsets))
450
461
            return self._seek_and_read(fp, offsets, relpath)
451
462
        except (IOError, paramiko.SSHException), e:
452
463
            self._translate_io_exception(e, path, ': error retrieving')
498
509
            #      sticky bit. So it is probably best to stop chmodding, and
499
510
            #      just tell users that they need to set the umask correctly.
500
511
            #      The attr.st_mode = mode, in _sftp_open_exclusive
501
 
            #      will handle when the user wants the final mode to be more 
502
 
            #      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
503
514
            #      paramiko decides to expose an async chmod()
504
515
 
505
516
            # This is designed to chmod() right before we close.
506
 
            # Because we set_pipelined() earlier, theoretically we might 
 
517
            # Because we set_pipelined() earlier, theoretically we might
507
518
            # avoid the round trip for fout.close()
508
519
            if mode is not None:
509
520
                self._get_sftp().chmod(tmp_abspath, mode)
551
562
                                                 ': unable to open')
552
563
 
553
564
                # This is designed to chmod() right before we close.
554
 
                # Because we set_pipelined() earlier, theoretically we might 
 
565
                # Because we set_pipelined() earlier, theoretically we might
555
566
                # avoid the round trip for fout.close()
556
567
                if mode is not None:
557
568
                    self._get_sftp().chmod(abspath, mode)
608
619
 
609
620
    def iter_files_recursive(self):
610
621
        """Walk the relative paths of all files in this transport."""
 
622
        # progress is handled by list_dir
611
623
        queue = list(self.list_dir('.'))
612
624
        while queue:
613
625
            relpath = queue.pop(0)
624
636
        else:
625
637
            local_mode = mode
626
638
        try:
 
639
            self._report_activity(len(abspath), 'write')
627
640
            self._get_sftp().mkdir(abspath, local_mode)
 
641
            self._report_activity(1, 'read')
628
642
            if mode is not None:
629
643
                # chmod a dir through sftp will erase any sgid bit set
630
644
                # on the server side.  So, if the bit mode are already
652
666
    def open_write_stream(self, relpath, mode=None):
653
667
        """See Transport.open_write_stream."""
654
668
        # initialise the file to zero-length
655
 
        # this is three round trips, but we don't use this 
656
 
        # 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
657
671
        # it is a tolerable overhead. Better would be to truncate
658
672
        # the file after opening. RBC 20070805
659
673
        self.put_bytes_non_atomic(relpath, "", mode)
682
696
        :param failure_exc: Paramiko has the super fun ability to raise completely
683
697
                           opaque errors that just set "e.args = ('Failure',)" with
684
698
                           no more information.
685
 
                           If this parameter is set, it defines the exception 
 
699
                           If this parameter is set, it defines the exception
686
700
                           to raise in these cases.
687
701
        """
688
702
        # paramiko seems to generate detailless errors.
729
743
 
730
744
    def _rename_and_overwrite(self, abs_from, abs_to):
731
745
        """Do a fancy rename on the remote server.
732
 
        
 
746
 
733
747
        Using the implementation provided by osutils.
734
748
        """
735
749
        try:
754
768
            self._get_sftp().remove(path)
755
769
        except (IOError, paramiko.SSHException), e:
756
770
            self._translate_io_exception(e, path, ': unable to delete')
757
 
            
 
771
 
758
772
    def external_url(self):
759
773
        """See bzrlib.transport.Transport.external_url."""
760
774
        # the external path for SFTP is the base
775
789
        path = self._remote_path(relpath)
776
790
        try:
777
791
            entries = self._get_sftp().listdir(path)
 
792
            self._report_activity(sum(map(len, entries)), 'read')
778
793
        except (IOError, paramiko.SSHException), e:
779
794
            self._translate_io_exception(e, path, ': failed to list_dir')
780
795
        return [urlutils.escape(entry) for entry in entries]
837
852
        """
838
853
        # TODO: jam 20060816 Paramiko >= 1.6.2 (probably earlier) supports
839
854
        #       using the 'x' flag to indicate SFTP_FLAG_EXCL.
840
 
        #       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
841
856
        #       time using the sftp_client.file() functionality.
842
857
        path = self._get_sftp()._adjust_cwd(abspath)
843
858
        # mutter('sftp abspath %s => %s', abspath, path)
844
859
        attr = SFTPAttributes()
845
860
        if mode is not None:
846
861
            attr.st_mode = mode
847
 
        omode = (SFTP_FLAG_WRITE | SFTP_FLAG_CREATE 
 
862
        omode = (SFTP_FLAG_WRITE | SFTP_FLAG_CREATE
848
863
                | SFTP_FLAG_TRUNC | SFTP_FLAG_EXCL)
849
864
        try:
850
865
            t, msg = self._get_sftp()._request(CMD_OPEN, path, omode, attr)
928
943
                # probably a failed test; unit test thread will log the
929
944
                # failure/error
930
945
                sys.excepthook(*sys.exc_info())
931
 
                warning('Exception from within unit test server thread: %r' % 
 
946
                warning('Exception from within unit test server thread: %r' %
932
947
                        x)
933
948
 
934
949
 
945
960
 
946
961
    Not all methods are implemented, this is deliberate as this class is not a
947
962
    replacement for the builtin sockets layer. fileno is not implemented to
948
 
    prevent the proxy being bypassed. 
 
963
    prevent the proxy being bypassed.
949
964
    """
950
965
 
951
966
    simulated_time = 0
953
968
        "close", "getpeername", "getsockname", "getsockopt", "gettimeout",
954
969
        "setblocking", "setsockopt", "settimeout", "shutdown"])
955
970
 
956
 
    def __init__(self, sock, latency, bandwidth=1.0, 
 
971
    def __init__(self, sock, latency, bandwidth=1.0,
957
972
                 really_sleep=True):
958
 
        """ 
 
973
        """
959
974
        :param bandwith: simulated bandwith (MegaBit)
960
975
        :param really_sleep: If set to false, the SocketDelay will just
961
976
        increase a counter, instead of calling time.sleep. This is useful for
964
979
        self.sock = sock
965
980
        self.latency = latency
966
981
        self.really_sleep = really_sleep
967
 
        self.time_per_byte = 1 / (bandwidth / 8.0 * 1024 * 1024) 
 
982
        self.time_per_byte = 1 / (bandwidth / 8.0 * 1024 * 1024)
968
983
        self.new_roundtrip = False
969
984
 
970
985
    def sleep(self, s):
1032
1047
 
1033
1048
    def _run_server_entry(self, sock):
1034
1049
        """Entry point for all implementations of _run_server.
1035
 
        
 
1050
 
1036
1051
        If self.add_latency is > 0.000001 then sock is given a latency adding
1037
1052
        decorator.
1038
1053
        """
1055
1070
        event = threading.Event()
1056
1071
        ssh_server.start_server(event, server)
1057
1072
        event.wait(5.0)
1058
 
    
 
1073
 
1059
1074
    def setUp(self, backing_server=None):
1060
1075
        # XXX: TODO: make sftpserver back onto backing_server rather than local
1061
1076
        # disk.