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