~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
2
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.
7
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.
12
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
1666.1.6 by Robert Collins
Make knit the default format.
25
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 \
26
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.
27
from bzrlib.trace import mutter
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
28
29
30
class StubServer (ServerInterface):
1666.1.6 by Robert Collins
Make knit the default format.
31
1185.49.10 by John Arbash Meinel
Use a weakref dictionary to enable re-use of a connection (for sftp).
32
    def __init__(self, test_case):
33
        ServerInterface.__init__(self)
34
        self._test_case = test_case
35
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
36
    def check_auth_password(self, username, password):
37
        # all are allowed
1185.49.10 by John Arbash Meinel
Use a weakref dictionary to enable re-use of a connection (for sftp).
38
        self._test_case.log('sftpserver - authorizing: %s' % (username,))
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
39
        return AUTH_SUCCESSFUL
40
41
    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).
42
        self._test_case.log('sftpserver - channel request: %s, %s' % (kind, chanid))
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
43
        return OPEN_SUCCEEDED
44
45
46
class StubSFTPHandle (SFTPHandle):
47
    def stat(self):
48
        try:
49
            return SFTPAttributes.from_stat(os.fstat(self.readfile.fileno()))
50
        except OSError, e:
51
            return SFTPServer.convert_errno(e.errno)
52
53
    def chattr(self, attr):
54
        # python doesn't have equivalents to fchown or fchmod, so we have to
55
        # 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.
56
        mutter('Changing permissions on %s to %s', self.filename, attr)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
57
        try:
58
            SFTPServer.set_file_attr(self.filename, attr)
59
        except OSError, e:
60
            return SFTPServer.convert_errno(e.errno)
61
62
63
class StubSFTPServer (SFTPServerInterface):
1666.1.6 by Robert Collins
Make knit the default format.
64
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
65
    def __init__(self, server, root, home=None):
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
66
        SFTPServerInterface.__init__(self, server)
67
        self.root = root
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
68
        if home is None:
69
            self.home = self.root
70
        else:
71
            self.home = home[len(self.root):]
72
        if (len(self.home) > 0) and (self.home[0] == '/'):
73
            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
74
        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
75
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
76
    def _realpath(self, path):
77
        return self.root + self.canonicalize(path)
78
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
79
    def canonicalize(self, path):
80
        if os.path.isabs(path):
81
            return os.path.normpath(path)
82
        else:
83
            return os.path.normpath('/' + os.path.join(self.home, path))
84
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
85
    def chattr(self, path, attr):
86
        try:
87
            SFTPServer.set_file_attr(path, attr)
88
        except OSError, e:
89
            return SFTPServer.convert_errno(e.errno)
90
        return SFTP_OK
91
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
92
    def list_folder(self, path):
93
        path = self._realpath(path)
94
        try:
95
            out = [ ]
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
96
            # TODO: win32 incorrectly lists paths with non-ascii if path is not
97
            # unicode. However on Linux the server should only deal with
98
            # bytestreams and posix.listdir does the right thing 
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
99
            flist = os.listdir(path)
100
            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 \
101
                attr = SFTPAttributes.from_stat(os.stat(pathjoin(path, fname)))
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
102
                attr.filename = fname
103
                out.append(attr)
104
            return out
105
        except OSError, e:
106
            return SFTPServer.convert_errno(e.errno)
107
108
    def stat(self, path):
109
        path = self._realpath(path)
110
        try:
111
            return SFTPAttributes.from_stat(os.stat(path))
112
        except OSError, e:
113
            return SFTPServer.convert_errno(e.errno)
114
115
    def lstat(self, path):
116
        path = self._realpath(path)
117
        try:
118
            return SFTPAttributes.from_stat(os.lstat(path))
119
        except OSError, e:
120
            return SFTPServer.convert_errno(e.errno)
121
122
    def open(self, path, flags, attr):
123
        path = self._realpath(path)
124
        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.
125
            if hasattr(os, 'O_BINARY'):
126
                flags |= os.O_BINARY
1540.1.9 by John Arbash Meinel
Cleanup getattr() code, since getattr(None, '', None) still works
127
            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)
128
                fd = os.open(path, flags, attr.st_mode)
129
            else:
130
                fd = os.open(path, flags)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
131
        except OSError, e:
132
            return SFTPServer.convert_errno(e.errno)
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
133
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
134
        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)
135
            attr._flags &= ~attr.FLAG_PERMISSIONS
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
136
            SFTPServer.set_file_attr(path, attr)
137
        if flags & os.O_WRONLY:
1185.31.51 by John Arbash Meinel
Setting binary flags for sftp.
138
            fstr = 'wb'
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
139
        elif flags & os.O_RDWR:
1185.31.51 by John Arbash Meinel
Setting binary flags for sftp.
140
            fstr = 'rb+'
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
141
        else:
142
            # O_RDONLY (== 0)
1185.31.51 by John Arbash Meinel
Setting binary flags for sftp.
143
            fstr = 'rb'
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
144
        try:
145
            f = os.fdopen(fd, fstr)
146
        except OSError, e:
147
            return SFTPServer.convert_errno(e.errno)
148
        fobj = StubSFTPHandle()
149
        fobj.filename = path
150
        fobj.readfile = f
151
        fobj.writefile = f
152
        return fobj
153
154
    def remove(self, path):
155
        path = self._realpath(path)
156
        try:
157
            os.remove(path)
158
        except OSError, e:
159
            return SFTPServer.convert_errno(e.errno)
160
        return SFTP_OK
161
162
    def rename(self, oldpath, newpath):
163
        oldpath = self._realpath(oldpath)
164
        newpath = self._realpath(newpath)
165
        try:
166
            os.rename(oldpath, newpath)
167
        except OSError, e:
168
            return SFTPServer.convert_errno(e.errno)
169
        return SFTP_OK
170
171
    def mkdir(self, path, attr):
172
        path = self._realpath(path)
173
        try:
1540.1.5 by John Arbash Meinel
Bugfix to allow using paramiko > 1.5.2
174
            # Using getattr() in case st_mode is None or 0
175
            # both evaluate to False
1540.1.9 by John Arbash Meinel
Cleanup getattr() code, since getattr(None, '', None) still works
176
            if getattr(attr, 'st_mode', None):
1185.58.11 by John Arbash Meinel
Made the StubSFTPServer use umask even for mkdir()
177
                os.mkdir(path, attr.st_mode)
178
            else:
179
                os.mkdir(path)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
180
            if attr is not None:
1185.58.11 by John Arbash Meinel
Made the StubSFTPServer use umask even for mkdir()
181
                attr._flags &= ~attr.FLAG_PERMISSIONS
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
182
                SFTPServer.set_file_attr(path, attr)
183
        except OSError, e:
184
            return SFTPServer.convert_errno(e.errno)
185
        return SFTP_OK
186
187
    def rmdir(self, path):
188
        path = self._realpath(path)
189
        try:
190
            os.rmdir(path)
191
        except OSError, e:
192
            return SFTPServer.convert_errno(e.errno)
193
        return SFTP_OK
194
195
    # removed: chattr, symlink, readlink
196
    # (nothing in bzr's sftp transport uses those)