Coverage for /pythoncovmergedfiles/medio/medio/src/paramiko/paramiko/sftp.py: 35%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

94 statements  

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# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 

18 

19import select 

20import socket 

21import struct 

22 

23from paramiko import util 

24from paramiko.common import DEBUG, byte_chr, byte_ord 

25from paramiko.message import Message 

26 

27 

28( 

29 CMD_INIT, 

30 CMD_VERSION, 

31 CMD_OPEN, 

32 CMD_CLOSE, 

33 CMD_READ, 

34 CMD_WRITE, 

35 CMD_LSTAT, 

36 CMD_FSTAT, 

37 CMD_SETSTAT, 

38 CMD_FSETSTAT, 

39 CMD_OPENDIR, 

40 CMD_READDIR, 

41 CMD_REMOVE, 

42 CMD_MKDIR, 

43 CMD_RMDIR, 

44 CMD_REALPATH, 

45 CMD_STAT, 

46 CMD_RENAME, 

47 CMD_READLINK, 

48 CMD_SYMLINK, 

49) = range(1, 21) 

50(CMD_STATUS, CMD_HANDLE, CMD_DATA, CMD_NAME, CMD_ATTRS) = range(101, 106) 

51(CMD_EXTENDED, CMD_EXTENDED_REPLY) = range(200, 202) 

52 

53SFTP_OK = 0 

54( 

55 SFTP_EOF, 

56 SFTP_NO_SUCH_FILE, 

57 SFTP_PERMISSION_DENIED, 

58 SFTP_FAILURE, 

59 SFTP_BAD_MESSAGE, 

60 SFTP_NO_CONNECTION, 

61 SFTP_CONNECTION_LOST, 

62 SFTP_OP_UNSUPPORTED, 

63) = range(1, 9) 

64 

65SFTP_DESC = [ 

66 "Success", 

67 "End of file", 

68 "No such file", 

69 "Permission denied", 

70 "Failure", 

71 "Bad message", 

72 "No connection", 

73 "Connection lost", 

74 "Operation unsupported", 

75] 

76 

77SFTP_FLAG_READ = 0x1 

78SFTP_FLAG_WRITE = 0x2 

79SFTP_FLAG_APPEND = 0x4 

80SFTP_FLAG_CREATE = 0x8 

81SFTP_FLAG_TRUNC = 0x10 

82SFTP_FLAG_EXCL = 0x20 

83 

84_VERSION = 3 

85 

86 

87# for debugging 

88CMD_NAMES = { 

89 CMD_INIT: "init", 

90 CMD_VERSION: "version", 

91 CMD_OPEN: "open", 

92 CMD_CLOSE: "close", 

93 CMD_READ: "read", 

94 CMD_WRITE: "write", 

95 CMD_LSTAT: "lstat", 

96 CMD_FSTAT: "fstat", 

97 CMD_SETSTAT: "setstat", 

98 CMD_FSETSTAT: "fsetstat", 

99 CMD_OPENDIR: "opendir", 

100 CMD_READDIR: "readdir", 

101 CMD_REMOVE: "remove", 

102 CMD_MKDIR: "mkdir", 

103 CMD_RMDIR: "rmdir", 

104 CMD_REALPATH: "realpath", 

105 CMD_STAT: "stat", 

106 CMD_RENAME: "rename", 

107 CMD_READLINK: "readlink", 

108 CMD_SYMLINK: "symlink", 

109 CMD_STATUS: "status", 

110 CMD_HANDLE: "handle", 

111 CMD_DATA: "data", 

112 CMD_NAME: "name", 

113 CMD_ATTRS: "attrs", 

114 CMD_EXTENDED: "extended", 

115 CMD_EXTENDED_REPLY: "extended_reply", 

116} 

117 

118 

119# TODO: rewrite SFTP file/server modules' overly-flexible "make a request with 

120# xyz components" so we don't need this very silly method of signaling whether 

121# a given Python integer should be 32- or 64-bit. 

122# NOTE: this only became an issue when dropping Python 2 support; prior to 

123# doing so, we had to support actual-longs, which served as that signal. This 

124# is simply recreating that structure in a more tightly scoped fashion. 

125class int64(int): 

126 pass 

127 

128 

129class SFTPError(Exception): 

130 pass 

131 

132 

133class BaseSFTP: 

134 def __init__(self): 

135 self.logger = util.get_logger("paramiko.sftp") 

136 self.sock = None 

137 self.ultra_debug = False 

138 

139 # ...internals... 

140 

141 def _send_version(self): 

142 m = Message() 

143 m.add_int(_VERSION) 

144 self._send_packet(CMD_INIT, m) 

145 t, data = self._read_packet() 

146 if t != CMD_VERSION: 

147 raise SFTPError("Incompatible sftp protocol") 

148 version = struct.unpack(">I", data[:4])[0] 

149 # if version != _VERSION: 

150 # raise SFTPError('Incompatible sftp protocol') 

151 return version 

152 

153 def _send_server_version(self): 

154 # winscp will freak out if the server sends version info before the 

155 # client finishes sending INIT. 

156 t, data = self._read_packet() 

157 if t != CMD_INIT: 

158 raise SFTPError("Incompatible sftp protocol") 

159 version = struct.unpack(">I", data[:4])[0] 

160 # advertise that we support "check-file" 

161 extension_pairs = ["check-file", "md5,sha1"] 

162 msg = Message() 

163 msg.add_int(_VERSION) 

164 msg.add(*extension_pairs) 

165 self._send_packet(CMD_VERSION, msg) 

166 return version 

167 

168 def _log(self, level, msg, *args): 

169 self.logger.log(level, msg, *args) 

170 

171 def _write_all(self, out): 

172 while len(out) > 0: 

173 n = self.sock.send(out) 

174 if n <= 0: 

175 raise EOFError() 

176 if n == len(out): 

177 return 

178 out = out[n:] 

179 return 

180 

181 def _read_all(self, n): 

182 out = bytes() 

183 while n > 0: 

184 if isinstance(self.sock, socket.socket): 

185 # sometimes sftp is used directly over a socket instead of 

186 # through a paramiko channel. in this case, check periodically 

187 # if the socket is closed. (for some reason, recv() won't ever 

188 # return or raise an exception, but calling select on a closed 

189 # socket will.) 

190 while True: 

191 read, write, err = select.select([self.sock], [], [], 0.1) 

192 if len(read) > 0: 

193 x = self.sock.recv(n) 

194 break 

195 else: 

196 x = self.sock.recv(n) 

197 

198 if len(x) == 0: 

199 raise EOFError() 

200 out += x 

201 n -= len(x) 

202 return out 

203 

204 def _send_packet(self, t, packet): 

205 packet = packet.asbytes() 

206 out = struct.pack(">I", len(packet) + 1) + byte_chr(t) + packet 

207 if self.ultra_debug: 

208 self._log(DEBUG, util.format_binary(out, "OUT: ")) 

209 self._write_all(out) 

210 

211 def _read_packet(self): 

212 x = self._read_all(4) 

213 # most sftp servers won't accept packets larger than about 32k, so 

214 # anything with the high byte set (> 16MB) is just garbage. 

215 if byte_ord(x[0]): 

216 raise SFTPError("Garbage packet received") 

217 size = struct.unpack(">I", x)[0] 

218 data = self._read_all(size) 

219 if self.ultra_debug: 

220 self._log(DEBUG, util.format_binary(data, "IN: ")) 

221 if size > 0: 

222 t = byte_ord(data[0]) 

223 return t, data[1:] 

224 return 0, bytes()