~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/sftp.py

  • Committer: Tarmac
  • Author(s): Vincent Ladeuil
  • Date: 2017-01-30 14:42:05 UTC
  • mfrom: (6620.1.1 trunk)
  • Revision ID: tarmac-20170130144205-r8fh2xpmiuxyozpv
Merge  2.7 into trunk including fix for bug #1657238 [r=vila]

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2011, 2016, 2017 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
16
16
 
17
17
"""Implementation of Transport over SFTP, using paramiko."""
18
18
 
 
19
from __future__ import absolute_import
 
20
 
19
21
# TODO: Remove the transport-based lock_read and lock_write methods.  They'll
20
22
# then raise TransportNotPossible, which will break remote access to any
21
23
# formats which rely on OS-level locks.  That should be fine as those formats
31
33
import stat
32
34
import sys
33
35
import time
34
 
import urllib
35
 
import urlparse
36
36
import warnings
37
37
 
38
38
from bzrlib import (
42
42
    urlutils,
43
43
    )
44
44
from bzrlib.errors import (FileExists,
45
 
                           NoSuchFile, PathNotChild,
 
45
                           NoSuchFile,
46
46
                           TransportError,
47
47
                           LockError,
48
48
                           PathError,
49
49
                           ParamikoNotPresent,
50
50
                           )
51
 
from bzrlib.osutils import pathjoin, fancy_rename, getcwd
52
 
from bzrlib.symbol_versioning import (
53
 
        deprecated_function,
54
 
        )
 
51
from bzrlib.osutils import fancy_rename
55
52
from bzrlib.trace import mutter, warning
56
53
from bzrlib.transport import (
57
54
    FileFileStream,
58
55
    _file_streams,
59
 
    local,
60
 
    Server,
61
56
    ssh,
62
57
    ConnectedTransport,
63
58
    )
337
332
    # up the request itself, rather than us having to worry about it
338
333
    _max_request_size = 32768
339
334
 
340
 
    def __init__(self, base, _from_transport=None):
341
 
        super(SFTPTransport, self).__init__(base,
342
 
                                            _from_transport=_from_transport)
343
 
 
344
335
    def _remote_path(self, relpath):
345
336
        """Return the path to be passed along the sftp protocol for relpath.
346
337
 
347
338
        :param relpath: is a urlencoded string.
348
339
        """
349
 
        relative = urlutils.unescape(relpath).encode('utf-8')
350
 
        remote_path = self._combine_paths(self._path, relative)
 
340
        remote_path = self._parsed_url.clone(relpath).path
351
341
        # the initial slash should be removed from the path, and treated as a
352
342
        # homedir relative path (the path begins with a double slash if it is
353
343
        # absolute).  see draft-ietf-secsh-scp-sftp-ssh-uri-03.txt
372
362
        in base url at transport creation time.
373
363
        """
374
364
        if credentials is None:
375
 
            password = self._password
 
365
            password = self._parsed_url.password
376
366
        else:
377
367
            password = credentials
378
368
 
379
369
        vendor = ssh._get_ssh_vendor()
380
 
        user = self._user
 
370
        user = self._parsed_url.user
381
371
        if user is None:
382
372
            auth = config.AuthenticationConfig()
383
 
            user = auth.get_user('ssh', self._host, self._port)
384
 
        connection = vendor.connect_sftp(self._user, password,
385
 
                                         self._host, self._port)
 
373
            user = auth.get_user('ssh', self._parsed_url.host,
 
374
                self._parsed_url.port)
 
375
        connection = vendor.connect_sftp(self._parsed_url.user, password,
 
376
            self._parsed_url.host, self._parsed_url.port)
386
377
        return connection, (user, password)
387
378
 
388
379
    def disconnect(self):
419
410
        try:
420
411
            path = self._remote_path(relpath)
421
412
            f = self._get_sftp().file(path, mode='rb')
 
413
            size = f.stat().st_size
422
414
            if self._do_prefetch and (getattr(f, 'prefetch', None) is not None):
423
 
                f.prefetch()
 
415
                f.prefetch(size)
424
416
            return f
425
417
        except (IOError, paramiko.SSHException), e:
426
418
            self._translate_io_exception(e, path, ': error retrieving',
602
594
                                    create_parent_dir=create_parent_dir,
603
595
                                    dir_mode=dir_mode)
604
596
 
605
 
    def put_bytes_non_atomic(self, relpath, bytes, mode=None,
 
597
    def put_bytes_non_atomic(self, relpath, raw_bytes, mode=None,
606
598
                             create_parent_dir=False,
607
599
                             dir_mode=None):
 
600
        if not isinstance(raw_bytes, str):
 
601
            raise TypeError(
 
602
                'raw_bytes must be a plain string, not %s' % type(raw_bytes))
 
603
 
608
604
        def writer(fout):
609
 
            fout.write(bytes)
 
605
            fout.write(raw_bytes)
610
606
        self._put_non_atomic_helper(relpath, writer, mode=mode,
611
607
                                    create_parent_dir=create_parent_dir,
612
608
                                    dir_mode=dir_mode)