~davide-cst00/uftp/0.2

« back to all changes in this revision

Viewing changes to paramiko/sftp.py

  • Committer: Davide Costa
  • Date: 2018-09-14 12:21:37 UTC
  • Revision ID: davide.cst00@gmail.com-20180914122137-j0ycqb4tk9z2r1k5
Xenial release 0.2.1

Show diffs side-by-side

added added

removed removed

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