paramiko.sftp

Package paramiko :: Module sftp |
[frames] | no frames]

# Source Code for Module paramiko.sftp

      1  # Copyright (C) 2003-2007  Robey Pointer <robeypointer@gmail.com>
      2  #
      3  # This file is part of paramiko.
      4  #
      5  # Paramiko is free software; you can redistribute it and/or modify it under the
      6  # terms of the GNU Lesser General Public License as published by the Free
      7  # Software Foundation; either version 2.1 of the License, or (at your option)
      8  # any later version.
      9  #
     10  # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY
     11  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     12  # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
     13  # details.
     14  #
     15  # You should have received a copy of the GNU Lesser General Public License
     16  # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
     17  # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
     18
     19  import select
     20  import socket
     21  import struct
     22
     23  from paramiko.common import *
     24  from paramiko import util
     25  from paramiko.channel import Channel
     26  from paramiko.message import Message
     27
     28
     29  CMD_INIT, CMD_VERSION, CMD_OPEN, CMD_CLOSE, CMD_READ, CMD_WRITE, CMD_LSTAT, CMD_FSTAT, \
     30             CMD_SETSTAT, CMD_FSETSTAT, CMD_OPENDIR, CMD_READDIR, CMD_REMOVE, CMD_MKDIR, \
     31             CMD_RMDIR, CMD_REALPATH, CMD_STAT, CMD_RENAME, CMD_READLINK, CMD_SYMLINK \
     32             = range(1, 21)
     33  CMD_STATUS, CMD_HANDLE, CMD_DATA, CMD_NAME, CMD_ATTRS = range(101, 106)
     34  CMD_EXTENDED, CMD_EXTENDED_REPLY = range(200, 202)
     35
     36  SFTP_OK = 0
     37  SFTP_EOF, SFTP_NO_SUCH_FILE, SFTP_PERMISSION_DENIED, SFTP_FAILURE, SFTP_BAD_MESSAGE, \
     38           SFTP_NO_CONNECTION, SFTP_CONNECTION_LOST, SFTP_OP_UNSUPPORTED = range(1, 9)
     39
     40  SFTP_DESC = [ 'Success',
     41                'End of file',
     42                'No such file',
     43                'Permission denied',
     44                'Failure',
     45                'Bad message',
     46                'No connection',
     47                'Connection lost',
     48                'Operation unsupported' ]
     49
     50  SFTP_FLAG_READ = 0x1
     51  SFTP_FLAG_WRITE = 0x2
     52  SFTP_FLAG_APPEND = 0x4
     53  SFTP_FLAG_CREATE = 0x8
     54  SFTP_FLAG_TRUNC = 0x10
     55  SFTP_FLAG_EXCL = 0x20
     56
     57  _VERSION = 3
     58
     59
     60  # for debugging
     61  CMD_NAMES = {
     62      CMD_INIT: 'init',
     63      CMD_VERSION: 'version',
     64      CMD_OPEN: 'open',
     65      CMD_CLOSE: 'close',
     66      CMD_READ: 'read',
     67      CMD_WRITE: 'write',
     68      CMD_LSTAT: 'lstat',
     69      CMD_FSTAT: 'fstat',
     70      CMD_SETSTAT: 'setstat',
     71      CMD_FSETSTAT: 'fsetstat',
     72      CMD_OPENDIR: 'opendir',
     73      CMD_READDIR: 'readdir',
     74      CMD_REMOVE: 'remove',
     75      CMD_MKDIR: 'mkdir',
     76      CMD_RMDIR: 'rmdir',
     77      CMD_REALPATH: 'realpath',
     78      CMD_STAT: 'stat',
     79      CMD_RENAME: 'rename',
     80      CMD_READLINK: 'readlink',
     81      CMD_SYMLINK: 'symlink',
     82      CMD_STATUS: 'status',
     83      CMD_HANDLE: 'handle',
     84      CMD_DATA: 'data',
     85      CMD_NAME: 'name',
     86      CMD_ATTRS: 'attrs',
     87      CMD_EXTENDED: 'extended',
     88      CMD_EXTENDED_REPLY: 'extended_reply'
     89      }
     90
     91
     92 -class SFTPError (Exception):
     93      pass
     94
     95
     96 -class BaseSFTP (object):
     97 -    def __init__(self):
     98          self.logger = util.get_logger('paramiko.sftp')
     99          self.sock = None
    100          self.ultra_debug = False
    101
    102
    103      ###  internals...
    104
    105
    106 -    def _send_version(self):
    107          self._send_packet(CMD_INIT, struct.pack('>I', _VERSION))
    108          t, data = self._read_packet()
    109          if t != CMD_VERSION:
    110              raise SFTPError('Incompatible sftp protocol')
    111          version = struct.unpack('>I', data[:4])[0]
    112          #        if version != _VERSION:
    113          #            raise SFTPError('Incompatible sftp protocol')
    114          return version
    115
    116 -    def _send_server_version(self):
    117          # winscp will freak out if the server sends version info before the
    118          # client finishes sending INIT.
    119          t, data = self._read_packet()
    120          if t != CMD_INIT:
    121              raise SFTPError('Incompatible sftp protocol')
    122          version = struct.unpack('>I', data[:4])[0]
    123          # advertise that we support "check-file"
    124          extension_pairs = [ 'check-file', 'md5,sha1' ]
    125          msg = Message()
    126          msg.add_int(_VERSION)
    127          msg.add(*extension_pairs)
    128          self._send_packet(CMD_VERSION, str(msg))
    129          return version
    130
    131 -    def _log(self, level, msg, *args):
    132          self.logger.log(level, msg, *args)
    133
    134 -    def _write_all(self, out):
    135          while len(out) > 0:
    136              n = self.sock.send(out)
    137              if n <= 0:
    138                  raise EOFError()
    139              if n == len(out):
    140                  return
    141              out = out[n:]
    142          return
    143
    144 -    def _read_all(self, n):
    145          out = ''
    146          while n > 0:
    147              if isinstance(self.sock, socket.socket):
    148                  # sometimes sftp is used directly over a socket instead of
    149                  # through a paramiko channel.  in this case, check periodically
    150                  # if the socket is closed.  (for some reason, recv() won't ever
    151                  # return or raise an exception, but calling select on a closed
    152                  # socket will.)
    153                  while True:
    154                      read, write, err = select.select([ self.sock ], [], [], 0.1)
    155                      if len(read) > 0:
    156                          x = self.sock.recv(n)
    157                          break
    158              else:
    159                  x = self.sock.recv(n)
    160
    161              if len(x) == 0:
    162                  raise EOFError()
    163              out += x
    164              n -= len(x)
    165          return out
    166
    167 -    def _send_packet(self, t, packet):
    168          #self._log(DEBUG2, 'write: %s (len=%d)' % (CMD_NAMES.get(t, '0x%02x' % t), len(packet)))
    169          out = struct.pack('>I', len(packet) + 1) + chr(t) + packet
    170          if self.ultra_debug:
    171              self._log(DEBUG, util.format_binary(out, 'OUT: '))
    172          self._write_all(out)
    173
    174 -    def _read_packet(self):
    175          x = self._read_all(4)
    176          # most sftp servers won't accept packets larger than about 32k, so
    177          # anything with the high byte set (> 16MB) is just garbage.
    178          if x[0] != '\x00':
    179              raise SFTPError('Garbage packet received')
    180          size = struct.unpack('>I', x)[0]
    181          data = self._read_all(size)
    182          if self.ultra_debug:
    183              self._log(DEBUG, util.format_binary(data, 'IN: '));
    184          if size > 0:
    185              t = ord(data[0])
    186              #self._log(DEBUG2, 'read: %s (len=%d)' % (CMD_NAMES.get(t), '0x%02x' % t, len(data)-1))
    187              return t, data[1:]
    188          return 0, ''
    189