~bzr-pqm/bzr/bzr.dev

1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
1
# Copyright (C) 2005 Robey Pointer <robey@lag.net>, Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""
18
A stub SFTP server for loopback SFTP testing.
19
Adapted from the one in paramiko's unit tests.
20
"""
21
22
import os
23
from paramiko import ServerInterface, SFTPServerInterface, SFTPServer, SFTPAttributes, \
24
    SFTPHandle, SFTP_OK, AUTH_SUCCESSFUL, OPEN_SUCCEEDED
1711.5.1 by John Arbash Meinel
Get most SFTP tests to pass. StubSFTPServer now talks the same path protocol that SFTPTransport talks. on win32
25
import sys
1666.1.6 by Robert Collins
Make knit the default format.
26
1185.31.32 by John Arbash Meinel
Updated the bzr sourcecode to use bzrlib.osutils.pathjoin rather than os.path.join to enforce internal use of / instead of \
27
from bzrlib.osutils import pathjoin
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
28
from bzrlib.trace import mutter
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
29
30
31
class StubServer (ServerInterface):
1666.1.6 by Robert Collins
Make knit the default format.
32
1185.49.10 by John Arbash Meinel
Use a weakref dictionary to enable re-use of a connection (for sftp).
33
    def __init__(self, test_case):
34
        ServerInterface.__init__(self)
35
        self._test_case = test_case
36
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
37
    def check_auth_password(self, username, password):
38
        # all are allowed
1185.49.10 by John Arbash Meinel
Use a weakref dictionary to enable re-use of a connection (for sftp).
39
        self._test_case.log('sftpserver - authorizing: %s' % (username,))
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
40
        return AUTH_SUCCESSFUL
41
42
    def check_channel_request(self, kind, chanid):
1185.49.10 by John Arbash Meinel
Use a weakref dictionary to enable re-use of a connection (for sftp).
43
        self._test_case.log('sftpserver - channel request: %s, %s' % (kind, chanid))
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
44
        return OPEN_SUCCEEDED
45
46
47
class StubSFTPHandle (SFTPHandle):
48
    def stat(self):
49
        try:
50
            return SFTPAttributes.from_stat(os.fstat(self.readfile.fileno()))
51
        except OSError, e:
52
            return SFTPServer.convert_errno(e.errno)
53
54
    def chattr(self, attr):
55
        # python doesn't have equivalents to fchown or fchmod, so we have to
56
        # use the stored filename
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
57
        mutter('Changing permissions on %s to %s', self.filename, attr)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
58
        try:
59
            SFTPServer.set_file_attr(self.filename, attr)
60
        except OSError, e:
61
            return SFTPServer.convert_errno(e.errno)
62
63
64
class StubSFTPServer (SFTPServerInterface):
1666.1.6 by Robert Collins
Make knit the default format.
65
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
66
    def __init__(self, server, root, home=None):
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
67
        SFTPServerInterface.__init__(self, server)
1711.5.1 by John Arbash Meinel
Get most SFTP tests to pass. StubSFTPServer now talks the same path protocol that SFTPTransport talks. on win32
68
        # All paths are actually relative to 'root'.
69
        # this is like implementing chroot().
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
70
        self.root = root
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
71
        if home is None:
1711.5.4 by John Arbash Meinel
Update stub_sftp based on Robey's comments.
72
            self.home = ''
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
73
        else:
1711.5.1 by John Arbash Meinel
Get most SFTP tests to pass. StubSFTPServer now talks the same path protocol that SFTPTransport talks. on win32
74
            assert home.startswith(self.root), \
75
                    "home must be a subdirectory of root (%s vs %s)" \
76
                    % (home, root)
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
77
            self.home = home[len(self.root):]
1711.5.1 by John Arbash Meinel
Get most SFTP tests to pass. StubSFTPServer now talks the same path protocol that SFTPTransport talks. on win32
78
        if self.home.startswith('/'):
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
79
            self.home = self.home[1:]
1547.1.1 by Robey Pointer
modify the sftp unit tests to perform sftp over a direct localhost socket instead of over an actual ssh2 transport
80
        server._test_case.log('sftpserver - new connection')
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
81
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
82
    def _realpath(self, path):
1711.5.4 by John Arbash Meinel
Update stub_sftp based on Robey's comments.
83
        # paths returned from self.canonicalize() always start with
84
        # a path separator. So if 'root' is just '/', this would cause
85
        # a double slash at the beginning '//home/dir'. 
86
        if self.root == '/':
87
            return self.canonicalize(path)
88
        return self.root + self.canonicalize(path)
89
90
    if sys.platform == 'win32':
91
        def canonicalize(self, path):
1711.5.1 by John Arbash Meinel
Get most SFTP tests to pass. StubSFTPServer now talks the same path protocol that SFTPTransport talks. on win32
92
            # Win32 sftp paths end up looking like
1711.5.4 by John Arbash Meinel
Update stub_sftp based on Robey's comments.
93
            #     sftp://host@foo/h:/foo/bar
94
            # which means absolute paths look like:
95
            #     /h:/foo/bar
96
            # and relative paths stay the same:
97
            #     foo/bar
98
            # win32 needs to use the Unicode APIs. so we require the 
99
            # paths to be utf8 (Linux just uses bytestreams)
1711.5.1 by John Arbash Meinel
Get most SFTP tests to pass. StubSFTPServer now talks the same path protocol that SFTPTransport talks. on win32
100
            thispath = path.decode('utf8')
101
            if path.startswith('/'):
1711.5.4 by John Arbash Meinel
Update stub_sftp based on Robey's comments.
102
                # Abspath H:/foo/bar
103
                return os.path.normpath(thispath[1:])
104
            else:
105
                return os.path.normpath(os.path.join(self.home, thispath))
106
    else:
107
        def canonicalize(self, path):
108
            if os.path.isabs(path):
109
                return os.path.normpath(path)
110
            else:
111
                return os.path.normpath('/' + os.path.join(self.home, path))
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
112
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
113
    def chattr(self, path, attr):
114
        try:
115
            SFTPServer.set_file_attr(path, attr)
116
        except OSError, e:
117
            return SFTPServer.convert_errno(e.errno)
118
        return SFTP_OK
119
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
120
    def list_folder(self, path):
121
        path = self._realpath(path)
122
        try:
123
            out = [ ]
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
124
            # TODO: win32 incorrectly lists paths with non-ascii if path is not
125
            # unicode. However on Linux the server should only deal with
126
            # bytestreams and posix.listdir does the right thing 
1711.5.1 by John Arbash Meinel
Get most SFTP tests to pass. StubSFTPServer now talks the same path protocol that SFTPTransport talks. on win32
127
            if sys.platform == 'win32':
128
                flist = [f.encode('utf8') for f in os.listdir(path)]
129
            else:
130
                flist = os.listdir(path)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
131
            for fname in flist:
1185.31.32 by John Arbash Meinel
Updated the bzr sourcecode to use bzrlib.osutils.pathjoin rather than os.path.join to enforce internal use of / instead of \
132
                attr = SFTPAttributes.from_stat(os.stat(pathjoin(path, fname)))
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
133
                attr.filename = fname
134
                out.append(attr)
135
            return out
136
        except OSError, e:
137
            return SFTPServer.convert_errno(e.errno)
138
139
    def stat(self, path):
140
        path = self._realpath(path)
141
        try:
142
            return SFTPAttributes.from_stat(os.stat(path))
143
        except OSError, e:
144
            return SFTPServer.convert_errno(e.errno)
145
146
    def lstat(self, path):
147
        path = self._realpath(path)
148
        try:
149
            return SFTPAttributes.from_stat(os.lstat(path))
150
        except OSError, e:
151
            return SFTPServer.convert_errno(e.errno)
152
153
    def open(self, path, flags, attr):
154
        path = self._realpath(path)
155
        try:
1185.31.52 by John Arbash Meinel
O_BINARY doesn't exist outside of win32, don't pass it if it isn't there.
156
            if hasattr(os, 'O_BINARY'):
157
                flags |= os.O_BINARY
1540.1.9 by John Arbash Meinel
Cleanup getattr() code, since getattr(None, '', None) still works
158
            if getattr(attr, 'st_mode', None):
1185.58.10 by John Arbash Meinel
[patch] Robey Pointer to fix sftp server using umask for files (failing tests for directories)
159
                fd = os.open(path, flags, attr.st_mode)
160
            else:
1988.1.1 by John Arbash Meinel
Restore mode bit tests for sftp, and track down bugs
161
                # os.open() defaults to 0777 which is
162
                # an odd default mode for files
163
                fd = os.open(path, flags, 0666)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
164
        except OSError, e:
165
            return SFTPServer.convert_errno(e.errno)
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
166
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
167
        if (flags & os.O_CREAT) and (attr is not None):
1185.58.10 by John Arbash Meinel
[patch] Robey Pointer to fix sftp server using umask for files (failing tests for directories)
168
            attr._flags &= ~attr.FLAG_PERMISSIONS
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
169
            SFTPServer.set_file_attr(path, attr)
170
        if flags & os.O_WRONLY:
1185.31.51 by John Arbash Meinel
Setting binary flags for sftp.
171
            fstr = 'wb'
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
172
        elif flags & os.O_RDWR:
1185.31.51 by John Arbash Meinel
Setting binary flags for sftp.
173
            fstr = 'rb+'
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
174
        else:
175
            # O_RDONLY (== 0)
1185.31.51 by John Arbash Meinel
Setting binary flags for sftp.
176
            fstr = 'rb'
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
177
        try:
178
            f = os.fdopen(fd, fstr)
1711.3.1 by John Arbash Meinel
opening a dir instead of a file raises an IOError, not OSError
179
        except (IOError, OSError), e:
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
180
            return SFTPServer.convert_errno(e.errno)
181
        fobj = StubSFTPHandle()
182
        fobj.filename = path
183
        fobj.readfile = f
184
        fobj.writefile = f
185
        return fobj
186
187
    def remove(self, path):
188
        path = self._realpath(path)
189
        try:
190
            os.remove(path)
191
        except OSError, e:
192
            return SFTPServer.convert_errno(e.errno)
193
        return SFTP_OK
194
195
    def rename(self, oldpath, newpath):
196
        oldpath = self._realpath(oldpath)
197
        newpath = self._realpath(newpath)
198
        try:
199
            os.rename(oldpath, newpath)
200
        except OSError, e:
201
            return SFTPServer.convert_errno(e.errno)
202
        return SFTP_OK
203
204
    def mkdir(self, path, attr):
205
        path = self._realpath(path)
206
        try:
1540.1.5 by John Arbash Meinel
Bugfix to allow using paramiko > 1.5.2
207
            # Using getattr() in case st_mode is None or 0
208
            # both evaluate to False
1540.1.9 by John Arbash Meinel
Cleanup getattr() code, since getattr(None, '', None) still works
209
            if getattr(attr, 'st_mode', None):
1185.58.11 by John Arbash Meinel
Made the StubSFTPServer use umask even for mkdir()
210
                os.mkdir(path, attr.st_mode)
211
            else:
212
                os.mkdir(path)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
213
            if attr is not None:
1185.58.11 by John Arbash Meinel
Made the StubSFTPServer use umask even for mkdir()
214
                attr._flags &= ~attr.FLAG_PERMISSIONS
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
215
                SFTPServer.set_file_attr(path, attr)
216
        except OSError, e:
217
            return SFTPServer.convert_errno(e.errno)
218
        return SFTP_OK
219
220
    def rmdir(self, path):
221
        path = self._realpath(path)
222
        try:
223
            os.rmdir(path)
224
        except OSError, e:
225
            return SFTPServer.convert_errno(e.errno)
226
        return SFTP_OK
227
228
    # removed: chattr, symlink, readlink
229
    # (nothing in bzr's sftp transport uses those)