~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/sftp.py

  • Committer: John Arbash Meinel
  • Date: 2005-12-01 20:58:36 UTC
  • mto: (1185.50.19 bzr-jam-integration)
  • mto: This revision was merged to the branch mainline in revision 1532.
  • Revision ID: john@arbash-meinel.com-20051201205836-7ac6c2ef4b1cbcf3
Cleaned up Exceptions for all transports.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
import weakref
31
31
 
32
32
from bzrlib.errors import (FileExists, 
33
 
                           TransportNotPossible, NoSuchFile, NonRelativePath,
 
33
                           TransportNotPossible, NoSuchFile, PathNotChild,
34
34
                           TransportError,
35
35
                           LockError)
36
36
from bzrlib.config import config_dir, ensure_config_dir_exists
181
181
        mutter('failed to save bzr host keys: ' + str(e))
182
182
 
183
183
 
184
 
 
185
 
class SFTPTransportError (TransportError):
186
 
    pass
187
 
 
188
184
class SFTPLock(object):
189
185
    """This fakes a lock in a remote location."""
190
186
    __slots__ = ['path', 'lock_path', 'lock_file', 'transport']
298
294
        if (not path.startswith(self._path)):
299
295
            error.append('path mismatch')
300
296
        if error:
301
 
            raise NonRelativePath('path %r is not under base URL %r: %s'
302
 
                           % (abspath, self.base, ', '.join(error)))
 
297
            extra = ': ' + ', '.join(error)
 
298
            raise PathNotChild(abspath, self.base, extra=extra)
303
299
        pl = len(self._path)
304
300
        return path[pl:].lstrip('/')
305
301
 
363
359
        try:
364
360
            try:
365
361
                self._pump(f, fout)
366
 
            except IOError, e:
367
 
                self._translate_io_exception(e, relpath)
368
 
            except paramiko.SSHException, x:
369
 
                raise SFTPTransportError('Unable to write file %r' % (relpath,), x)
 
362
            except (paramiko.SSHException, IOError), e:
 
363
                self._translate_io_exception(e, relpath, ': unable to write')
370
364
        except Exception, e:
371
365
            # If we fail, try to clean up the temporary file
372
366
            # before we throw the exception
390
384
            try:
391
385
                try:
392
386
                    self._sftp.rename(tmp_abspath, final_path)
393
 
                except IOError, e:
394
 
                    self._translate_io_exception(e, relpath)
395
 
                except paramiko.SSHException, x:
396
 
                    raise SFTPTransportError('Unable to rename into file %r' % (path,), x) 
 
387
                except (paramiko.SSHException, IOError), e:
 
388
                    self._translate_io_exception(e, relpath, ': unable to rename')
397
389
                else:
398
390
                    success = True
399
391
            finally:
420
412
        try:
421
413
            path = self._abspath(relpath)
422
414
            self._sftp.mkdir(path)
423
 
        except IOError, e:
424
 
            self._translate_io_exception(e, relpath)
425
 
        except (IOError, paramiko.SSHException), x:
426
 
            raise SFTPTransportError('Unable to mkdir %r' % (path,), x)
 
415
        except (paramiko.SSHException, IOError), e:
 
416
            self._translate_io_exception(e, relpath, ': unable to mkdir')
427
417
 
428
 
    def _translate_io_exception(self, e, relpath):
 
418
    def _translate_io_exception(self, e, relpath, more_info=''):
429
419
        # paramiko seems to generate detailless errors.
430
 
        if (e.errno == errno.ENOENT or
431
 
            e.args == ('No such file or directory',) or
432
 
            e.args == ('No such file',)):
433
 
            raise NoSuchFile(relpath)
434
 
        if (e.args == ('mkdir failed',)):
435
 
            raise FileExists(relpath)
436
 
        # strange but true, for the paramiko server.
437
 
        if (e.args == ('Failure',)):
438
 
            raise FileExists(relpath)
439
 
        raise
 
420
        self._translate_error(e, relpath, raise_generic=False)
 
421
        if hasattr(e, 'args'):
 
422
            if (e.args == ('No such file or directory',) or
 
423
                e.args == ('No such file',)):
 
424
                raise NoSuchFile(relpath, str(e) + more_info)
 
425
            if (e.args == ('mkdir failed',)):
 
426
                raise FileExists(relpath, str(e) + more_info)
 
427
            # strange but true, for the paramiko server.
 
428
            if (e.args == ('Failure',)):
 
429
                raise FileExists(relpath, str(e) + more_info)
 
430
        raise e
440
431
 
441
432
    def append(self, relpath, f):
442
433
        """
448
439
            fout = self._sftp.file(path, 'ab')
449
440
            self._pump(f, fout)
450
441
        except (IOError, paramiko.SSHException), x:
451
 
            raise SFTPTransportError('Unable to append file %r' % (path,), x)
 
442
            raise TransportError('Unable to append file %r' % (path,), x)
452
443
 
453
444
    def copy(self, rel_from, rel_to):
454
445
        """Copy the item at rel_from to the location at rel_to"""
480
471
            finally:
481
472
                fin.close()
482
473
        except (IOError, paramiko.SSHException), x:
483
 
            raise SFTPTransportError('Unable to copy %r to %r' % (path_from, path_to), x)
 
474
            raise TransportError('Unable to copy %r to %r' % (path_from, path_to), x)
484
475
 
485
476
    def copy_to(self, relpaths, other, pb=None):
486
477
        """Copy a set of entries from self into another Transport.
516
507
        try:
517
508
            self._sftp.rename(path_from, path_to)
518
509
        except (IOError, paramiko.SSHException), x:
519
 
            raise SFTPTransportError('Unable to move %r to %r' % (path_from, path_to), x)
 
510
            raise TransportError('Unable to move %r to %r' % (path_from, path_to), x)
520
511
 
521
512
    def delete(self, relpath):
522
513
        """Delete the item at relpath"""
524
515
        try:
525
516
            self._sftp.remove(path)
526
517
        except (IOError, paramiko.SSHException), x:
527
 
            raise SFTPTransportError('Unable to delete %r' % (path,), x)
 
518
            raise TransportError('Unable to delete %r' % (path,), x)
528
519
            
529
520
    def listable(self):
530
521
        """Return True if this store supports listing."""
539
530
        try:
540
531
            return self._sftp.listdir(path)
541
532
        except (IOError, paramiko.SSHException), x:
542
 
            raise SFTPTransportError('Unable to list folder %r' % (path,), x)
 
533
            raise TransportError('Unable to list folder %r' % (path,), x)
543
534
 
544
535
    def stat(self, relpath):
545
536
        """Return the stat information for a file."""
547
538
        try:
548
539
            return self._sftp.stat(path)
549
540
        except (IOError, paramiko.SSHException), x:
550
 
            raise SFTPTransportError('Unable to stat %r' % (path,), x)
 
541
            raise TransportError('Unable to stat %r' % (path,), x)
551
542
 
552
543
    def lock_read(self, relpath):
553
544
        """
613
604
            try:
614
605
                port = int(port)
615
606
            except ValueError:
616
 
                raise SFTPTransportError('%s: invalid port number' % port)
 
607
                raise TransportError('%s: invalid port number' % port)
617
608
        host = urllib.unquote(host)
618
609
 
619
610
        path = urllib.unquote(path)
634
625
    def _sftp_connect(self):
635
626
        """Connect to the remote sftp server.
636
627
        After this, self._sftp should have a valid connection (or
637
 
        we raise an SFTPTransportError 'could not connect').
 
628
        we raise an TransportError 'could not connect').
638
629
 
639
630
        TODO: Raise a more reasonable ConnectionFailed exception
640
631
        """
665
656
            t = paramiko.Transport((self._host, self._port))
666
657
            t.start_client()
667
658
        except paramiko.SSHException:
668
 
            raise SFTPTransportError('Unable to reach SSH host %s:%d' % (self._host, self._port))
 
659
            raise TransportError('Unable to reach SSH host %s:%d' % (self._host, self._port))
669
660
            
670
661
        server_key = t.get_remote_server_key()
671
662
        server_key_hex = paramiko.util.hexify(server_key.get_fingerprint())
687
678
        if server_key != our_server_key:
688
679
            filename1 = os.path.expanduser('~/.ssh/known_hosts')
689
680
            filename2 = pathjoin(config_dir(), 'ssh_host_keys')
690
 
            raise SFTPTransportError('Host keys for %s do not match!  %s != %s' % \
 
681
            raise TransportError('Host keys for %s do not match!  %s != %s' % \
691
682
                (self._host, our_server_key_hex, server_key_hex),
692
683
                ['Try editing %s or %s' % (filename1, filename2)])
693
684
 
708
699
        # Also, it would mess up the self.relpath() functionality
709
700
        username = self._username or getpass.getuser()
710
701
 
711
 
        agent = paramiko.Agent()
712
 
        for key in agent.get_keys():
713
 
            mutter('Trying SSH agent key %s' % paramiko.util.hexify(key.get_fingerprint()))
714
 
            try:
715
 
                transport.auth_publickey(username, key)
716
 
                return
717
 
            except paramiko.SSHException, e:
718
 
                pass
 
702
        # Paramiko tries to open a socket.AF_UNIX in order to connect
 
703
        # to ssh-agent. That attribute doesn't exist on win32 (it does in cygwin)
 
704
        # so we get an AttributeError exception. For now, just don't try to
 
705
        # connect to an agent if we are on win32
 
706
        if sys.platform != 'win32':
 
707
            agent = paramiko.Agent()
 
708
            for key in agent.get_keys():
 
709
                mutter('Trying SSH agent key %s' % paramiko.util.hexify(key.get_fingerprint()))
 
710
                try:
 
711
                    transport.auth_publickey(username, key)
 
712
                    return
 
713
                except paramiko.SSHException, e:
 
714
                    pass
719
715
        
720
716
        # okay, try finding id_rsa or id_dss?  (posix only)
721
717
        if self._try_pkey_auth(transport, paramiko.RSAKey, username, 'id_rsa'):
740
736
        try:
741
737
            transport.auth_password(username, password)
742
738
        except paramiko.SSHException:
743
 
            raise SFTPTransportError('Unable to authenticate to SSH host as %s@%s' % \
 
739
            raise TransportError('Unable to authenticate to SSH host as %s@%s' % \
744
740
                (username, self._host))
745
741
 
746
742
    def _try_pkey_auth(self, transport, pkey_class, username, filename):
784
780
        try:
785
781
            t, msg = self._sftp._request(CMD_OPEN, path, mode, attr)
786
782
            if t != CMD_HANDLE:
787
 
                raise SFTPTransportError('Expected an SFTP handle')
 
783
                raise TransportError('Expected an SFTP handle')
788
784
            handle = msg.get_string()
789
785
            return SFTPFile(self._sftp, handle, 'w', -1)
790
 
        except IOError, e:
791
 
            self._translate_io_exception(e, relpath)
792
 
        except paramiko.SSHException, x:
793
 
            raise SFTPTransportError('Unable to open file %r' % (path,), x)
 
786
        except (paramiko.SSHException, IOError), e:
 
787
            self._translate_io_exception(e, relpath, ': unable to open')
794
788