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 distributed 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 import util 
 24  from paramiko.common import asbytes, DEBUG 
 25  from paramiko.message import Message 
 26  from paramiko.py3compat import byte_chr, byte_ord 
 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 = range(1, 21) 
 32  CMD_STATUS, CMD_HANDLE, CMD_DATA, CMD_NAME, CMD_ATTRS = range(101, 106) 
 33  CMD_EXTENDED, CMD_EXTENDED_REPLY = range(200, 202) 
 34   
 35  SFTP_OK = 0 
 36  SFTP_EOF, SFTP_NO_SUCH_FILE, SFTP_PERMISSION_DENIED, SFTP_FAILURE, SFTP_BAD_MESSAGE, \ 
 37      SFTP_NO_CONNECTION, SFTP_CONNECTION_LOST, SFTP_OP_UNSUPPORTED = range(1, 9) 
 38   
 39  SFTP_DESC = ['Success', 
 40               'End of file', 
 41               'No such file', 
 42               'Permission denied', 
 43               'Failure', 
 44               'Bad message', 
 45               'No connection', 
 46               'Connection lost', 
 47               'Operation unsupported'] 
 48   
 49  SFTP_FLAG_READ = 0x1 
 50  SFTP_FLAG_WRITE = 0x2 
 51  SFTP_FLAG_APPEND = 0x4 
 52  SFTP_FLAG_CREATE = 0x8 
 53  SFTP_FLAG_TRUNC = 0x10 
 54  SFTP_FLAG_EXCL = 0x20 
 55   
 56  _VERSION = 3 
 57   
 58   
 59  # for debugging 
 60  CMD_NAMES = { 
 61      CMD_INIT: 'init', 
 62      CMD_VERSION: 'version', 
 63      CMD_OPEN: 'open', 
 64      CMD_CLOSE: 'close', 
 65      CMD_READ: 'read', 
 66      CMD_WRITE: 'write', 
 67      CMD_LSTAT: 'lstat', 
 68      CMD_FSTAT: 'fstat', 
 69      CMD_SETSTAT: 'setstat', 
 70      CMD_FSETSTAT: 'fsetstat', 
 71      CMD_OPENDIR: 'opendir', 
 72      CMD_READDIR: 'readdir', 
 73      CMD_REMOVE: 'remove', 
 74      CMD_MKDIR: 'mkdir', 
 75      CMD_RMDIR: 'rmdir', 
 76      CMD_REALPATH: 'realpath', 
 77      CMD_STAT: 'stat', 
 78      CMD_RENAME: 'rename', 
 79      CMD_READLINK: 'readlink', 
 80      CMD_SYMLINK: 'symlink', 
 81      CMD_STATUS: 'status', 
 82      CMD_HANDLE: 'handle', 
 83      CMD_DATA: 'data', 
 84      CMD_NAME: 'name', 
 85      CMD_ATTRS: 'attrs', 
 86      CMD_EXTENDED: 'extended', 
 87      CMD_EXTENDED_REPLY: 'extended_reply' 
 88  } 
 89   
 90   
91 -class SFTPError (Exception):
92 pass
93 94
95 -class BaseSFTP (object):
96 - def __init__(self):
97 self.logger = util.get_logger('paramiko.sftp') 98 self.sock = None 99 self.ultra_debug = False
100 101 ### internals... 102
103 - def _send_version(self):
104 self._send_packet(CMD_INIT, struct.pack('>I', _VERSION)) 105 t, data = self._read_packet() 106 if t != CMD_VERSION: 107 raise SFTPError('Incompatible sftp protocol') 108 version = struct.unpack('>I', data[:4])[0] 109 # if version != _VERSION: 110 # raise SFTPError('Incompatible sftp protocol') 111 return version
112
113 - def _send_server_version(self):
114 # winscp will freak out if the server sends version info before the 115 # client finishes sending INIT. 116 t, data = self._read_packet() 117 if t != CMD_INIT: 118 raise SFTPError('Incompatible sftp protocol') 119 version = struct.unpack('>I', data[:4])[0] 120 # advertise that we support "check-file" 121 extension_pairs = ['check-file', 'md5,sha1'] 122 msg = Message() 123 msg.add_int(_VERSION) 124 msg.add(*extension_pairs) 125 self._send_packet(CMD_VERSION, msg) 126 return version
127
128 - def _log(self, level, msg, *args):
129 self.logger.log(level, msg, *args)
130
131 - def _write_all(self, out):
132 while len(out) > 0: 133 n = self.sock.send(out) 134 if n <= 0: 135 raise EOFError() 136 if n == len(out): 137 return 138 out = out[n:] 139 return
140
141 - def _read_all(self, n):
142 out = bytes() 143 while n > 0: 144 if isinstance(self.sock, socket.socket): 145 # sometimes sftp is used directly over a socket instead of 146 # through a paramiko channel. in this case, check periodically 147 # if the socket is closed. (for some reason, recv() won't ever 148 # return or raise an exception, but calling select on a closed 149 # socket will.) 150 while True: 151 read, write, err = select.select([self.sock], [], [], 0.1) 152 if len(read) > 0: 153 x = self.sock.recv(n) 154 break 155 else: 156 x = self.sock.recv(n) 157 158 if len(x) == 0: 159 raise EOFError() 160 out += x 161 n -= len(x) 162 return out
163
164 - def _send_packet(self, t, packet):
165 #self._log(DEBUG2, 'write: %s (len=%d)' % (CMD_NAMES.get(t, '0x%02x' % t), len(packet))) 166 packet = asbytes(packet) 167 out = struct.pack('>I', len(packet) + 1) + byte_chr(t) + packet 168 if self.ultra_debug: 169 self._log(DEBUG, util.format_binary(out, 'OUT: ')) 170 self._write_all(out)
171
172 - def _read_packet(self):
173 x = self._read_all(4) 174 # most sftp servers won't accept packets larger than about 32k, so 175 # anything with the high byte set (> 16MB) is just garbage. 176 if byte_ord(x[0]): 177 raise SFTPError('Garbage packet received') 178 size = struct.unpack('>I', x)[0] 179 data = self._read_all(size) 180 if self.ultra_debug: 181 self._log(DEBUG, util.format_binary(data, 'IN: ')) 182 if size > 0: 183 t = byte_ord(data[0]) 184 #self._log(DEBUG2, 'read: %s (len=%d)' % (CMD_NAMES.get(t), '0x%02x' % t, len(data)-1)) 185 return t, data[1:] 186 return 0, bytes()
187