~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/sftp.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-12-02 14:58:47 UTC
  • mfrom: (5554.1.3 trunk)
  • Revision ID: pqm@pqm.ubuntu.com-20101202145847-fw822sd3nyhvrwmi
(vila) Merge 2.2 into trunk including fix for bug #583667 and bug
        #681885 (Vincent Ladeuil)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011, 2016 Canonical Ltd
 
1
# Copyright (C) 2005-2010 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
 
 
21
19
# TODO: Remove the transport-based lock_read and lock_write methods.  They'll
22
20
# then raise TransportNotPossible, which will break remote access to any
23
21
# formats which rely on OS-level locks.  That should be fine as those formats
33
31
import stat
34
32
import sys
35
33
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,
 
45
                           NoSuchFile, PathNotChild,
46
46
                           TransportError,
47
47
                           LockError,
48
48
                           PathError,
49
49
                           ParamikoNotPresent,
50
50
                           )
51
 
from bzrlib.osutils import fancy_rename
 
51
from bzrlib.osutils import pathjoin, fancy_rename, getcwd
 
52
from bzrlib.symbol_versioning import (
 
53
        deprecated_function,
 
54
        )
52
55
from bzrlib.trace import mutter, warning
53
56
from bzrlib.transport import (
54
57
    FileFileStream,
55
58
    _file_streams,
 
59
    local,
 
60
    Server,
56
61
    ssh,
57
62
    ConnectedTransport,
58
63
    )
109
114
        except FileExists:
110
115
            raise LockError('File %r already locked' % (self.path,))
111
116
 
 
117
    def __del__(self):
 
118
        """Should this warn, or actually try to cleanup?"""
 
119
        if self.lock_file:
 
120
            warning("SFTPLock %r not explicitly unlocked" % (self.path,))
 
121
            self.unlock()
 
122
 
112
123
    def unlock(self):
113
124
        if not self.lock_file:
114
125
            return
270
281
                    buffered = buffered[buffered_offset:]
271
282
                    buffered_data = [buffered]
272
283
                    buffered_len = len(buffered)
273
 
        # now that the data stream is done, close the handle
274
 
        fp.close()
275
284
        if buffered_len:
276
285
            buffered = ''.join(buffered_data)
277
286
            del buffered_data[:]
332
341
    # up the request itself, rather than us having to worry about it
333
342
    _max_request_size = 32768
334
343
 
 
344
    def __init__(self, base, _from_transport=None):
 
345
        super(SFTPTransport, self).__init__(base,
 
346
                                            _from_transport=_from_transport)
 
347
 
335
348
    def _remote_path(self, relpath):
336
349
        """Return the path to be passed along the sftp protocol for relpath.
337
350
 
338
351
        :param relpath: is a urlencoded string.
339
352
        """
340
 
        remote_path = self._parsed_url.clone(relpath).path
 
353
        relative = urlutils.unescape(relpath).encode('utf-8')
 
354
        remote_path = self._combine_paths(self._path, relative)
341
355
        # the initial slash should be removed from the path, and treated as a
342
356
        # homedir relative path (the path begins with a double slash if it is
343
357
        # absolute).  see draft-ietf-secsh-scp-sftp-ssh-uri-03.txt
362
376
        in base url at transport creation time.
363
377
        """
364
378
        if credentials is None:
365
 
            password = self._parsed_url.password
 
379
            password = self._password
366
380
        else:
367
381
            password = credentials
368
382
 
369
383
        vendor = ssh._get_ssh_vendor()
370
 
        user = self._parsed_url.user
 
384
        user = self._user
371
385
        if user is None:
372
386
            auth = config.AuthenticationConfig()
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)
 
387
            user = auth.get_user('ssh', self._host, self._port)
 
388
        connection = vendor.connect_sftp(self._user, password,
 
389
                                         self._host, self._port)
377
390
        return connection, (user, password)
378
391
 
379
392
    def disconnect(self):
408
421
        :param relpath: The relative path to the file
409
422
        """
410
423
        try:
 
424
            # FIXME: by returning the file directly, we don't pass this
 
425
            # through to report_activity.  We could try wrapping the object
 
426
            # before it's returned.  For readv and get_bytes it's handled in
 
427
            # the higher-level function.
 
428
            # -- mbp 20090126
411
429
            path = self._remote_path(relpath)
412
430
            f = self._get_sftp().file(path, mode='rb')
413
431
            if self._do_prefetch and (getattr(f, 'prefetch', None) is not None):
593
611
                                    create_parent_dir=create_parent_dir,
594
612
                                    dir_mode=dir_mode)
595
613
 
596
 
    def put_bytes_non_atomic(self, relpath, raw_bytes, mode=None,
 
614
    def put_bytes_non_atomic(self, relpath, bytes, mode=None,
597
615
                             create_parent_dir=False,
598
616
                             dir_mode=None):
599
 
        if not isinstance(raw_bytes, str):
600
 
            raise TypeError(
601
 
                'raw_bytes must be a plain string, not %s' % type(raw_bytes))
602
 
 
603
617
        def writer(fout):
604
 
            fout.write(raw_bytes)
 
618
            fout.write(bytes)
605
619
        self._put_non_atomic_helper(relpath, writer, mode=mode,
606
620
                                    create_parent_dir=create_parent_dir,
607
621
                                    dir_mode=dir_mode)