You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

186 lines
5.9 KiB

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

Powered by TurnKey Linux.