| Home | Trees | Indices | Help |
|---|
|
|
1 # Copyright (C) 2011 Jeff Forcier <jeff@bitprophet.org>
2 #
3 # This file is part of ssh.
4 #
5 # 'ssh' 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 # 'ssh' 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 'ssh'; 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 ssh.common import *
24 from ssh import util
25 from ssh.channel import Channel
26 from ssh.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
94
95
101
102
103 ### internals...
104
105
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
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
133
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
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 ssh 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
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
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
| Home | Trees | Indices | Help |
|---|
| Generated by Epydoc 3.0.1 on Fri Nov 18 08:56:23 2011 | http://epydoc.sourceforge.net |