~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:]
71
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
72
    def _realpath(self, path):
73
        return self.root + self.canonicalize(path)
74
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
75
    def canonicalize(self, path):
76
        if os.path.isabs(path):
77
            return os.path.normpath(path)
78
        else:
79
            return os.path.normpath('/' + os.path.join(self.home, path))
80
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
81
    def chattr(self, path, attr):
82
        try:
83
            SFTPServer.set_file_attr(path, attr)
84
        except OSError, e:
85
            return SFTPServer.convert_errno(e.errno)
86
        return SFTP_OK
87
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
88
    def list_folder(self, path):
89
        path = self._realpath(path)
90
        try:
91
            out = [ ]
92
            flist = os.listdir(path)
93
            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 \
94
                attr = SFTPAttributes.from_stat(os.stat(pathjoin(path, fname)))
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
95
                attr.filename = fname
96
                out.append(attr)
97
            return out
98
        except OSError, e:
99
            return SFTPServer.convert_errno(e.errno)
100
101
    def stat(self, path):
102
        path = self._realpath(path)
103
        try:
104
            return SFTPAttributes.from_stat(os.stat(path))
105
        except OSError, e:
106
            return SFTPServer.convert_errno(e.errno)
107
108
    def lstat(self, path):
109
        path = self._realpath(path)
110
        try:
111
            return SFTPAttributes.from_stat(os.lstat(path))
112
        except OSError, e:
113
            return SFTPServer.convert_errno(e.errno)
114
115
    def open(self, path, flags, attr):
116
        path = self._realpath(path)
117
        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.
118
            if hasattr(os, 'O_BINARY'):
119
                flags |= os.O_BINARY
1540.1.9 by John Arbash Meinel
Cleanup getattr() code, since getattr(None, '', None) still works
120
            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)
121
                fd = os.open(path, flags, attr.st_mode)
122
            else:
123
                fd = os.open(path, flags)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
124
        except OSError, e:
125
            return SFTPServer.convert_errno(e.errno)
126
        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)
127
            attr._flags &= ~attr.FLAG_PERMISSIONS
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
128
            SFTPServer.set_file_attr(path, attr)
129
        if flags & os.O_WRONLY:
1185.31.51 by John Arbash Meinel
Setting binary flags for sftp.
130
            fstr = 'wb'
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
131
        elif flags & os.O_RDWR:
1185.31.51 by John Arbash Meinel
Setting binary flags for sftp.
132
            fstr = 'rb+'
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
133
        else:
134
            # O_RDONLY (== 0)
1185.31.51 by John Arbash Meinel
Setting binary flags for sftp.
135
            fstr = 'rb'
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
136
        try:
137
            f = os.fdopen(fd, fstr)
138
        except OSError, e:
139
            return SFTPServer.convert_errno(e.errno)
140
        fobj = StubSFTPHandle()
141
        fobj.filename = path
142
        fobj.readfile = f
143
        fobj.writefile = f
144
        return fobj
145
146
    def remove(self, path):
147
        path = self._realpath(path)
148
        try:
149
            os.remove(path)
150
        except OSError, e:
151
            return SFTPServer.convert_errno(e.errno)
152
        return SFTP_OK
153
154
    def rename(self, oldpath, newpath):
155
        oldpath = self._realpath(oldpath)
156
        newpath = self._realpath(newpath)
157
        try:
158
            os.rename(oldpath, newpath)
159
        except OSError, e:
160
            return SFTPServer.convert_errno(e.errno)
161
        return SFTP_OK
162
163
    def mkdir(self, path, attr):
164
        path = self._realpath(path)
165
        try:
1540.1.5 by John Arbash Meinel
Bugfix to allow using paramiko > 1.5.2
166
            # Using getattr() in case st_mode is None or 0
167
            # both evaluate to False
1540.1.9 by John Arbash Meinel
Cleanup getattr() code, since getattr(None, '', None) still works
168
            if getattr(attr, 'st_mode', None):
1185.58.11 by John Arbash Meinel
Made the StubSFTPServer use umask even for mkdir()
169
                os.mkdir(path, attr.st_mode)
170
            else:
171
                os.mkdir(path)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
172
            if attr is not None:
1185.58.11 by John Arbash Meinel
Made the StubSFTPServer use umask even for mkdir()
173
                attr._flags &= ~attr.FLAG_PERMISSIONS
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
174
                SFTPServer.set_file_attr(path, attr)
175
        except OSError, e:
176
            return SFTPServer.convert_errno(e.errno)
177
        return SFTP_OK
178
179
    def rmdir(self, path):
180
        path = self._realpath(path)
181
        try:
182
            os.rmdir(path)
183
        except OSError, e:
184
            return SFTPServer.convert_errno(e.errno)
185
        return SFTP_OK
186
187
    # removed: chattr, symlink, readlink
188
    # (nothing in bzr's sftp transport uses those)