8687.15.17
by Karl Fogel
Add the copyright header block to the rest of the files under lib/lp/. |
1 |
# Copyright 2009 Canonical Ltd. This software is licensed under the
|
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
3 |
|
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
4 |
"""An SFTP server that backs on to a special kind of Bazaar Transport.
|
5 |
||
6 |
The Bazaar Transport is special in two ways:
|
|
7 |
||
8 |
1. It implements two methods `writeChunk` and `local_realPath` (see the
|
|
9 |
`FatLocalTransport` class for a description of these)
|
|
10 |
2. Every transport method returns Deferreds and does not block.
|
|
11 |
||
12 |
We call such a transport a "Twisted Transport".
|
|
13 |
"""
|
|
14 |
||
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
15 |
__metaclass__ = type |
7483.2.27
by Jonathan Lange
Log the close of an SFTP session. |
16 |
__all__ = [ |
10548.1.1
by Jonathan Lange
Move twistedsupport to lp.services |
17 |
'avatar_to_sftp_server', |
7483.2.27
by Jonathan Lange
Log the close of an SFTP session. |
18 |
'TransportSFTPServer', |
19 |
]
|
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
20 |
|
21 |
||
9949.3.1
by Aaron Bentley
Handle MemoryStat eccentricities in Launchpad itself. |
22 |
from copy import copy |
6125.4.8
by Jonathan Lange
Test error handling in sftp server |
23 |
import errno |
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
24 |
import os |
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
25 |
import stat |
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
26 |
|
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
27 |
from bzrlib import ( |
28 |
errors as bzr_errors, |
|
29 |
osutils, |
|
30 |
urlutils, |
|
31 |
)
|
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
32 |
from bzrlib.transport.local import LocalTransport |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
33 |
from twisted.conch.interfaces import ( |
34 |
ISFTPFile, |
|
35 |
ISFTPServer, |
|
36 |
)
|
|
37 |
from twisted.conch.ls import lsLine |
|
6125.4.4
by Jonathan Lange
Get PermissionDenied errors converted into failures correctly |
38 |
from twisted.conch.ssh import filetransfer |
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
39 |
from twisted.internet import defer |
40 |
from twisted.python import util |
|
6125.7.24
by Jonathan Lange
Merge from twisted-sync-transport. |
41 |
from zope.interface import implements |
42 |
||
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
43 |
from lp.codehosting.vfs import ( |
44 |
AsyncLaunchpadTransport, |
|
45 |
LaunchpadServer, |
|
46 |
)
|
|
14612.2.1
by William Grant
format-imports on lib/. So many imports. |
47 |
from lp.services.config import config |
11086.2.1
by James Westby
Move FileIsADirectory from codehosting.sftp to services.sshserver. |
48 |
from lp.services.sshserver.sftp import FileIsADirectory |
10548.1.1
by Jonathan Lange
Move twistedsupport to lp.services |
49 |
from lp.services.twistedsupport import gatherResults |
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
50 |
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
51 |
|
52 |
class FatLocalTransport(LocalTransport): |
|
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
53 |
"""A Bazaar transport that also implements writeChunk and local_realPath.
|
54 |
||
55 |
We need these so that we can implement SFTP over a Bazaar transport.
|
|
56 |
"""
|
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
57 |
|
7213.10.6
by Jonathan Lange
Fix up a lot of the SFTP tests by unbreaking the underlying transport's |
58 |
def clone(self, offset=None): |
59 |
if offset is None: |
|
60 |
abspath = self.base |
|
61 |
else: |
|
62 |
abspath = self.abspath(offset) |
|
63 |
return FatLocalTransport(abspath) |
|
64 |
||
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
65 |
def writeChunk(self, name, offset, data): |
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
66 |
"""Write a chunk of data to file `name` at `offset`."""
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
67 |
abspath = self._abspath(name) |
68 |
osutils.check_legal_path(abspath) |
|
6125.4.8
by Jonathan Lange
Test error handling in sftp server |
69 |
try: |
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
70 |
chunk_file = os.open(abspath, os.O_CREAT | os.O_WRONLY) |
71 |
except OSError, e: |
|
6125.4.8
by Jonathan Lange
Test error handling in sftp server |
72 |
if e.errno != errno.EISDIR: |
73 |
raise
|
|
74 |
raise FileIsADirectory(name) |
|
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
75 |
os.lseek(chunk_file, offset, 0) |
76 |
os.write(chunk_file, data) |
|
77 |
os.close(chunk_file) |
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
78 |
|
79 |
def local_realPath(self, path): |
|
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
80 |
"""Return the absolute path to `path`."""
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
81 |
abspath = self._abspath(path) |
6956.1.2
by Michael Hudson
fix realpath |
82 |
return urlutils.escape(os.path.realpath(abspath)) |
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
83 |
|
84 |
||
6125.4.8
by Jonathan Lange
Test error handling in sftp server |
85 |
def with_sftp_error(func): |
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
86 |
"""Decorator used to translate Bazaar errors into SFTP errors.
|
87 |
||
88 |
This assumes that the function being decorated returns a Deferred.
|
|
89 |
||
90 |
See `TransportSFTPServer.translateError` for the details of the
|
|
91 |
translation.
|
|
92 |
"""
|
|
6125.4.8
by Jonathan Lange
Test error handling in sftp server |
93 |
def decorator(*args, **kwargs): |
94 |
deferred = func(*args, **kwargs) |
|
6125.4.10
by Jonathan Lange
Customize error when mkdir fails |
95 |
return deferred.addErrback(TransportSFTPServer.translateError, |
96 |
func.__name__) |
|
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
97 |
return util.mergeFunctionMetadata(func, decorator) |
6125.4.8
by Jonathan Lange
Test error handling in sftp server |
98 |
|
99 |
||
7013.5.4
by Michael Hudson
move DirectoryListing out of the openDirectory method |
100 |
class DirectoryListing: |
101 |
"""Class to satisfy openDirectory return interface.
|
|
102 |
||
103 |
openDirectory returns an iterator -- with a `close` method. Hence
|
|
104 |
this class.
|
|
105 |
"""
|
|
106 |
||
107 |
def __init__(self, entries): |
|
108 |
self.iter = iter(entries) |
|
109 |
||
110 |
def __iter__(self): |
|
111 |
return self |
|
112 |
||
113 |
def next(self): |
|
114 |
return self.iter.next() |
|
115 |
||
116 |
def close(self): |
|
117 |
# I can't believe we had to implement a whole class just to
|
|
118 |
# have this do-nothing method (abentley).
|
|
119 |
pass
|
|
120 |
||
121 |
||
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
122 |
class TransportSFTPFile: |
123 |
"""An implementation of `ISFTPFile` that backs onto a Bazaar transport.
|
|
124 |
||
125 |
The transport must be a Twisted Transport.
|
|
126 |
"""
|
|
127 |
||
128 |
implements(ISFTPFile) |
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
129 |
|
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
130 |
def __init__(self, transport, name, flags, server): |
6382.6.14
by Jonathan Lange
Some fixes from review. |
131 |
self._unescaped_relpath = name |
132 |
self._escaped_path = urlutils.escape(self._unescaped_relpath) |
|
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
133 |
self._flags = flags |
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
134 |
self.transport = transport |
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
135 |
self._written = False |
136 |
self._server = server |
|
137 |
||
138 |
def _shouldAppend(self): |
|
139 |
"""Is this file opened append?"""
|
|
140 |
return bool(self._flags & filetransfer.FXF_APPEND) |
|
141 |
||
142 |
def _shouldCreate(self): |
|
143 |
"""Should we create a file?"""
|
|
144 |
# The Twisted VFS adapter creates a file when any of these flags are
|
|
145 |
# set. It's possible that we only need to check for FXF_CREAT.
|
|
146 |
create_mask = ( |
|
147 |
filetransfer.FXF_WRITE | filetransfer.FXF_APPEND | |
|
148 |
filetransfer.FXF_CREAT) |
|
149 |
return bool(self._flags & create_mask) |
|
150 |
||
151 |
def _shouldTruncate(self): |
|
152 |
"""Should we truncate the file?"""
|
|
153 |
return (bool(self._flags & filetransfer.FXF_TRUNC) |
|
154 |
and not self._written) |
|
155 |
||
156 |
def _shouldWrite(self): |
|
157 |
"""Is this file opened writable?"""
|
|
158 |
write_mask = (filetransfer.FXF_WRITE | filetransfer.FXF_APPEND) |
|
159 |
return bool(self._flags & write_mask) |
|
160 |
||
161 |
def _truncateFile(self): |
|
162 |
"""Truncate this file."""
|
|
163 |
self._written = True |
|
6382.6.11
by Jonathan Lange
Handle paths that need escaping in SFTPFile. |
164 |
return self.transport.put_bytes(self._escaped_path, '') |
6125.7.42
by Jonathan Lange
Give a name to creating an empty file. |
165 |
|
6125.4.8
by Jonathan Lange
Test error handling in sftp server |
166 |
@with_sftp_error
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
167 |
def writeChunk(self, offset, data): |
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
168 |
"""See `ISFTPFile`."""
|
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
169 |
if not self._shouldWrite(): |
170 |
raise filetransfer.SFTPError( |
|
171 |
filetransfer.FX_PERMISSION_DENIED, |
|
6382.6.14
by Jonathan Lange
Some fixes from review. |
172 |
"%r was opened read-only." % self._unescaped_relpath) |
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
173 |
if self._shouldTruncate(): |
174 |
deferred = self._truncateFile() |
|
175 |
else: |
|
176 |
deferred = defer.succeed(None) |
|
177 |
self._written = True |
|
178 |
if self._shouldAppend(): |
|
179 |
deferred.addCallback( |
|
180 |
lambda ignored: |
|
6382.6.11
by Jonathan Lange
Handle paths that need escaping in SFTPFile. |
181 |
self.transport.append_bytes(self._escaped_path, data)) |
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
182 |
else: |
183 |
deferred.addCallback( |
|
184 |
lambda ignored: |
|
6382.6.11
by Jonathan Lange
Handle paths that need escaping in SFTPFile. |
185 |
self.transport.writeChunk(self._escaped_path, offset, data)) |
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
186 |
return deferred |
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
187 |
|
6125.4.8
by Jonathan Lange
Test error handling in sftp server |
188 |
@with_sftp_error
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
189 |
def readChunk(self, offset, length): |
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
190 |
"""See `ISFTPFile`."""
|
6382.6.11
by Jonathan Lange
Handle paths that need escaping in SFTPFile. |
191 |
deferred = self.transport.readv( |
192 |
self._escaped_path, [(offset, length)]) |
|
6125.7.11
by Jonathan Lange
Create and register an adapter from LaunchpadAvatar to an SFTP server |
193 |
def get_first_chunk(read_things): |
194 |
return read_things.next()[1] |
|
6956.1.4
by Michael Hudson
rearrange, add docstring |
195 |
def handle_short_read(failure): |
196 |
"""Handle short reads by reading what was available.
|
|
197 |
||
198 |
Doing things this way around, by trying to read all the data
|
|
199 |
requested and then handling the short read error, might be a bit
|
|
200 |
inefficient, but the bzrlib sftp transport doesn't read past the
|
|
201 |
end of files, so we don't need to worry too much about performance
|
|
202 |
here.
|
|
203 |
"""
|
|
204 |
failure.trap(bzr_errors.ShortReadvError) |
|
205 |
return self.readChunk(failure.value.offset, failure.value.actual) |
|
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
206 |
deferred.addCallback(get_first_chunk) |
6956.1.4
by Michael Hudson
rearrange, add docstring |
207 |
return deferred.addErrback(handle_short_read) |
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
208 |
|
209 |
def setAttrs(self, attrs): |
|
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
210 |
"""See `ISFTPFile`.
|
211 |
||
212 |
The Transport interface does not allow setting any attributes.
|
|
213 |
"""
|
|
6125.5.2
by Michael Hudson
mumble |
214 |
# XXX 2008-05-09 JonathanLange: This should at least raise an error,
|
215 |
# not do nothing silently.
|
|
6382.6.14
by Jonathan Lange
Some fixes from review. |
216 |
return self._server.setAttrs(self._unescaped_relpath, attrs) |
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
217 |
|
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
218 |
@with_sftp_error
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
219 |
def getAttrs(self): |
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
220 |
"""See `ISFTPFile`."""
|
6382.6.14
by Jonathan Lange
Some fixes from review. |
221 |
return self._server.getAttrs(self._unescaped_relpath, False) |
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
222 |
|
223 |
def close(self): |
|
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
224 |
"""See `ISFTPFile`."""
|
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
225 |
if self._written or not self._shouldCreate(): |
226 |
return defer.succeed(None) |
|
227 |
||
228 |
if self._shouldTruncate(): |
|
229 |
return self._truncateFile() |
|
230 |
||
6382.6.11
by Jonathan Lange
Handle paths that need escaping in SFTPFile. |
231 |
deferred = self.transport.has(self._escaped_path) |
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
232 |
def maybe_create_file(already_exists): |
233 |
if not already_exists: |
|
234 |
return self._truncateFile() |
|
235 |
return deferred.addCallback(maybe_create_file) |
|
236 |
||
237 |
||
238 |
def _get_transport_for_dir(directory): |
|
239 |
url = urlutils.local_path_to_url(directory) |
|
240 |
return FatLocalTransport(url) |
|
241 |
||
242 |
||
243 |
def avatar_to_sftp_server(avatar): |
|
6406.3.7
by Jonathan Lange
Be clear about when we want the username and when we want the user id. |
244 |
user_id = avatar.user_id |
9590.1.15
by Michael Hudson
sftp fixes |
245 |
branch_transport = _get_transport_for_dir( |
7732.1.3
by Jonathan Lange
Get rid of the branchesdest config variable. |
246 |
config.codehosting.mirrored_branches_root) |
9590.1.48
by Michael Hudson
a start at combining the puller and filesystem endpoints |
247 |
server = LaunchpadServer( |
248 |
avatar.codehosting_proxy, user_id, branch_transport) |
|
10197.5.7
by Michael Hudson
fix some more stuff |
249 |
server.start_server() |
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
250 |
transport = AsyncLaunchpadTransport(server, server.get_url()) |
251 |
return TransportSFTPServer(transport) |
|
6125.7.24
by Jonathan Lange
Merge from twisted-sync-transport. |
252 |
|
253 |
||
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
254 |
class TransportSFTPServer: |
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
255 |
"""An implementation of `ISFTPServer` that backs onto a Bazaar transport.
|
256 |
||
257 |
The transport must be a Twisted Transport.
|
|
258 |
"""
|
|
259 |
||
6125.7.24
by Jonathan Lange
Merge from twisted-sync-transport. |
260 |
implements(ISFTPServer) |
261 |
||
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
262 |
def __init__(self, transport): |
263 |
self.transport = transport |
|
264 |
||
265 |
def extendedRequest(self, extendedName, extendedData): |
|
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
266 |
"""See `ISFTPServer`."""
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
267 |
raise NotImplementedError |
268 |
||
269 |
def makeLink(self, src, dest): |
|
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
270 |
"""See `ISFTPServer`."""
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
271 |
raise NotImplementedError() |
272 |
||
7013.5.7
by Michael Hudson
docstrings are nice |
273 |
def _stat_files_in_list(self, file_list, escaped_dir_path): |
7013.5.10
by Michael Hudson
expand docstring |
274 |
"""Stat the a list of files.
|
7013.5.7
by Michael Hudson
docstrings are nice |
275 |
|
7013.5.10
by Michael Hudson
expand docstring |
276 |
:param file_list: The list of escaped file names.
|
277 |
:param escaped_dir_path: The escaped path of the directory containing
|
|
278 |
the files.
|
|
7013.5.7
by Michael Hudson
docstrings are nice |
279 |
:return: A Deferred which will be called back with the list of all the
|
280 |
stat results.
|
|
281 |
"""
|
|
7013.5.5
by Michael Hudson
move things around a bit |
282 |
deferreds = [] |
283 |
for filename in file_list: |
|
7013.5.7
by Michael Hudson
docstrings are nice |
284 |
escaped_file_path = os.path.join(escaped_dir_path, filename) |
7013.5.5
by Michael Hudson
move things around a bit |
285 |
deferreds.append( |
286 |
self.transport.stat(escaped_file_path)) |
|
287 |
return gatherResults(deferreds) |
|
288 |
||
7013.5.7
by Michael Hudson
docstrings are nice |
289 |
def _format_directory_entries(self, stat_results, filenames): |
290 |
"""Produce entries suitable for returning from `openDirectory`.
|
|
291 |
||
292 |
:param stat_results: A list of the results of calling `stat` on each
|
|
293 |
file in filenames.
|
|
294 |
:param filenames: The list of filenames to produce entries for.
|
|
295 |
:return: An iterator of ``(shortname, longname, attributes)``.
|
|
296 |
"""
|
|
7013.5.5
by Michael Hudson
move things around a bit |
297 |
for stat_result, filename in zip(stat_results, filenames): |
298 |
shortname = urlutils.unescape(filename).encode('utf-8') |
|
9949.3.1
by Aaron Bentley
Handle MemoryStat eccentricities in Launchpad itself. |
299 |
stat_result = copy(stat_result) |
300 |
for attribute in ['st_uid', 'st_gid', 'st_mtime', 'st_nlink']: |
|
301 |
if getattr(stat_result, attribute, None) is None: |
|
302 |
setattr(stat_result, attribute, 0) |
|
7013.5.5
by Michael Hudson
move things around a bit |
303 |
longname = lsLine(shortname, stat_result) |
304 |
attr_dict = self._translate_stat(stat_result) |
|
305 |
yield (shortname, longname, attr_dict) |
|
306 |
||
6125.4.8
by Jonathan Lange
Test error handling in sftp server |
307 |
@with_sftp_error
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
308 |
def openDirectory(self, path): |
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
309 |
"""See `ISFTPServer`."""
|
7013.5.2
by Michael Hudson
show a longline too |
310 |
escaped_path = urlutils.escape(path) |
311 |
deferred = self.transport.list_dir(escaped_path) |
|
7013.5.7
by Michael Hudson
docstrings are nice |
312 |
def produce_entries_from_file_list(file_list): |
7013.5.9
by Michael Hudson
lint! |
313 |
stats_deferred = self._stat_files_in_list(file_list, escaped_path) |
314 |
stats_deferred.addCallback( |
|
7013.5.7
by Michael Hudson
docstrings are nice |
315 |
self._format_directory_entries, file_list) |
7013.5.9
by Michael Hudson
lint! |
316 |
return stats_deferred |
7013.5.7
by Michael Hudson
docstrings are nice |
317 |
return deferred.addCallback( |
318 |
produce_entries_from_file_list).addCallback(DirectoryListing) |
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
319 |
|
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
320 |
@with_sftp_error
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
321 |
def openFile(self, path, flags, attrs): |
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
322 |
"""See `ISFTPServer`."""
|
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
323 |
directory = os.path.dirname(path) |
324 |
deferred = self.transport.stat(directory) |
|
325 |
def open_file(stat_result): |
|
326 |
if stat.S_ISDIR(stat_result.st_mode): |
|
327 |
return TransportSFTPFile(self.transport, path, flags, self) |
|
328 |
else: |
|
329 |
raise filetransfer.SFTPError( |
|
330 |
filetransfer.FX_NO_SUCH_FILE, directory) |
|
331 |
return deferred.addCallback(open_file) |
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
332 |
|
333 |
def readLink(self, path): |
|
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
334 |
"""See `ISFTPServer`."""
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
335 |
raise NotImplementedError() |
336 |
||
337 |
def realPath(self, relpath): |
|
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
338 |
"""See `ISFTPServer`."""
|
6956.1.2
by Michael Hudson
fix realpath |
339 |
deferred = self.transport.local_realPath(urlutils.escape(relpath)) |
6956.1.3
by Michael Hudson
utf-8 is the default file system encoding in higher sftp versions, at least |
340 |
def unescape_path(path): |
6956.1.2
by Michael Hudson
fix realpath |
341 |
unescaped_path = urlutils.unescape(path) |
6956.1.3
by Michael Hudson
utf-8 is the default file system encoding in higher sftp versions, at least |
342 |
return unescaped_path.encode('utf-8') |
343 |
return deferred.addCallback(unescape_path) |
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
344 |
|
345 |
def setAttrs(self, path, attrs): |
|
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
346 |
"""See `ISFTPServer`.
|
347 |
||
348 |
This just delegates to TransportSFTPFile's implementation.
|
|
349 |
"""
|
|
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
350 |
return defer.succeed(None) |
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
351 |
|
7013.5.2
by Michael Hudson
show a longline too |
352 |
def _translate_stat(self, stat_val): |
7013.5.7
by Michael Hudson
docstrings are nice |
353 |
"""Translate the stat result `stat_val` into an attributes dict.
|
354 |
||
355 |
This is very like conch.ssh.unix.SFTPServerForUnixConchUser._getAttrs,
|
|
356 |
but (a) that is private and (b) we use getattr() to access the
|
|
357 |
attributes as not all the Bazaar transports return full stat results.
|
|
358 |
"""
|
|
7013.5.2
by Michael Hudson
show a longline too |
359 |
return { |
360 |
'size': getattr(stat_val, 'st_size', 0), |
|
361 |
'uid': getattr(stat_val, 'st_uid', 0), |
|
362 |
'gid': getattr(stat_val, 'st_gid', 0), |
|
363 |
'permissions': getattr(stat_val, 'st_mode', 0), |
|
364 |
'atime': getattr(stat_val, 'st_atime', 0), |
|
365 |
'mtime': getattr(stat_val, 'st_mtime', 0), |
|
366 |
}
|
|
367 |
||
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
368 |
@with_sftp_error
|
6125.4.6
by Jonathan Lange
Fix getAttr tests |
369 |
def getAttrs(self, path, followLinks): |
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
370 |
"""See `ISFTPServer`.
|
371 |
||
372 |
This just delegates to TransportSFTPFile's implementation.
|
|
373 |
"""
|
|
6382.6.8
by Jonathan Lange
Ensure that server tests pass when we use path segments that require url |
374 |
deferred = self.transport.stat(urlutils.escape(path)) |
7013.5.2
by Michael Hudson
show a longline too |
375 |
return deferred.addCallback(self._translate_stat) |
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
376 |
|
377 |
def gotVersion(self, otherVersion, extensionData): |
|
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
378 |
"""See `ISFTPServer`."""
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
379 |
return {} |
380 |
||
6125.4.8
by Jonathan Lange
Test error handling in sftp server |
381 |
@with_sftp_error
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
382 |
def makeDirectory(self, path, attrs): |
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
383 |
"""See `ISFTPServer`."""
|
6382.6.8
by Jonathan Lange
Ensure that server tests pass when we use path segments that require url |
384 |
return self.transport.mkdir( |
385 |
urlutils.escape(path), attrs['permissions']) |
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
386 |
|
6125.4.8
by Jonathan Lange
Test error handling in sftp server |
387 |
@with_sftp_error
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
388 |
def removeDirectory(self, path): |
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
389 |
"""See `ISFTPServer`."""
|
6382.6.8
by Jonathan Lange
Ensure that server tests pass when we use path segments that require url |
390 |
return self.transport.rmdir(urlutils.escape(path)) |
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
391 |
|
6125.4.8
by Jonathan Lange
Test error handling in sftp server |
392 |
@with_sftp_error
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
393 |
def removeFile(self, path): |
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
394 |
"""See `ISFTPServer`."""
|
6382.6.8
by Jonathan Lange
Ensure that server tests pass when we use path segments that require url |
395 |
return self.transport.delete(urlutils.escape(path)) |
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
396 |
|
6125.4.8
by Jonathan Lange
Test error handling in sftp server |
397 |
@with_sftp_error
|
6125.4.2
by Aaron Bentley
Implement a bzrlib transport to SFTP server adapter (with tests). |
398 |
def renameFile(self, oldpath, newpath): |
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
399 |
"""See `ISFTPServer`."""
|
6382.6.8
by Jonathan Lange
Ensure that server tests pass when we use path segments that require url |
400 |
return self.transport.rename( |
401 |
urlutils.escape(oldpath), urlutils.escape(newpath)) |
|
6125.4.4
by Jonathan Lange
Get PermissionDenied errors converted into failures correctly |
402 |
|
6125.4.7
by Jonathan Lange
Get tests passing with AsyncTransport |
403 |
@staticmethod
|
6125.4.10
by Jonathan Lange
Customize error when mkdir fails |
404 |
def translateError(failure, func_name): |
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
405 |
"""Translate Bazaar errors to `filetransfer.SFTPError` instances."""
|
6125.4.5
by Jonathan Lange
Handle permission denied, file exists, no such file, misc |
406 |
types_to_codes = { |
407 |
bzr_errors.PermissionDenied: filetransfer.FX_PERMISSION_DENIED, |
|
6382.6.1
by Jonathan Lange
Merge revisions for reverting sftp fix, but don't actually revert it. |
408 |
bzr_errors.TransportNotPossible: |
409 |
filetransfer.FX_PERMISSION_DENIED, |
|
6125.4.5
by Jonathan Lange
Handle permission denied, file exists, no such file, misc |
410 |
bzr_errors.NoSuchFile: filetransfer.FX_NO_SUCH_FILE, |
411 |
bzr_errors.FileExists: filetransfer.FX_FILE_ALREADY_EXISTS, |
|
6125.4.9
by Jonathan Lange
Add translation of Directory Not Empty |
412 |
bzr_errors.DirectoryNotEmpty: filetransfer.FX_FAILURE, |
9790.2.1
by Michael Hudson
test and fix |
413 |
bzr_errors.TransportError: filetransfer.FX_FAILURE, |
6125.4.8
by Jonathan Lange
Test error handling in sftp server |
414 |
FileIsADirectory: filetransfer.FX_FILE_IS_A_DIRECTORY, |
6125.4.5
by Jonathan Lange
Handle permission denied, file exists, no such file, misc |
415 |
}
|
6125.5.1
by Michael Hudson
documentation and properly Twisted tests. |
416 |
# Bazaar expects makeDirectory to fail with exactly the string "mkdir
|
417 |
# failed".
|
|
6125.4.10
by Jonathan Lange
Customize error when mkdir fails |
418 |
names_to_messages = { |
419 |
'makeDirectory': 'mkdir failed', |
|
420 |
}
|
|
6125.4.5
by Jonathan Lange
Handle permission denied, file exists, no such file, misc |
421 |
try: |
422 |
sftp_code = types_to_codes[failure.type] |
|
423 |
except KeyError: |
|
424 |
failure.raiseException() |
|
6125.4.10
by Jonathan Lange
Customize error when mkdir fails |
425 |
message = names_to_messages.get(func_name, failure.getErrorMessage()) |
426 |
raise filetransfer.SFTPError(sftp_code, message) |