1
# Copyright (C) 2006, 2007 Canonical Ltd
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.
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.
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
17
"""VFS operations for the smart server.
19
This module defines the smart server methods that are low-level file operations
20
-- i.e. methods that operate directly on files and directories, rather than
21
higher-level concepts like branches and revisions.
23
These methods, plus 'hello' and 'get_bundle', are version 1 of the smart server
24
protocol, as implemented in bzr 0.11 and later.
29
from bzrlib import errors
30
from bzrlib.smart import request
33
def _deserialise_optional_mode(mode):
34
# XXX: FIXME this should be on the protocol object. Later protocol versions
35
# might serialise modes differently.
43
"""Is the VFS enabled ?
45
the VFS is disabled when the BZR_NO_SMART_VFS environment variable is set.
47
:return: True if it is enabled.
49
return not 'BZR_NO_SMART_VFS' in os.environ
52
class VfsRequest(request.SmartServerRequest):
53
"""Base class for VFS requests.
55
VFS requests are disabled if vfs_enabled() returns False.
58
def _check_enabled(self):
60
raise errors.DisabledMethod(self.__class__.__name__)
63
class HasRequest(VfsRequest):
65
def do(self, relpath):
66
relpath = self.translate_client_path(relpath)
67
r = self._backing_transport.has(relpath) and 'yes' or 'no'
68
return request.SuccessfulSmartServerResponse((r,))
71
class GetRequest(VfsRequest):
73
def do(self, relpath):
74
relpath = self.translate_client_path(relpath)
76
backing_bytes = self._backing_transport.get_bytes(relpath)
77
except errors.ReadError:
78
# cannot read the file
79
return request.FailedSmartServerResponse(('ReadError', ))
80
except errors.PermissionDenied:
81
return request.FailedSmartServerResponse(('PermissionDenied',))
82
return request.SuccessfulSmartServerResponse(('ok',), backing_bytes)
85
class AppendRequest(VfsRequest):
87
def do(self, relpath, mode):
88
relpath = self.translate_client_path(relpath)
89
self._relpath = relpath
90
self._mode = _deserialise_optional_mode(mode)
92
def do_body(self, body_bytes):
93
old_length = self._backing_transport.append_bytes(
94
self._relpath, body_bytes, self._mode)
95
return request.SuccessfulSmartServerResponse(('appended', '%d' % old_length))
98
class DeleteRequest(VfsRequest):
100
def do(self, relpath):
101
relpath = self.translate_client_path(relpath)
102
self._backing_transport.delete(relpath)
103
return request.SuccessfulSmartServerResponse(('ok', ))
106
class IterFilesRecursiveRequest(VfsRequest):
108
def do(self, relpath):
109
if not relpath.endswith('/'):
111
relpath = self.translate_client_path(relpath)
112
transport = self._backing_transport.clone(relpath)
113
filenames = transport.iter_files_recursive()
114
return request.SuccessfulSmartServerResponse(('names',) + tuple(filenames))
117
class ListDirRequest(VfsRequest):
119
def do(self, relpath):
120
if not relpath.endswith('/'):
122
relpath = self.translate_client_path(relpath)
123
filenames = self._backing_transport.list_dir(relpath)
124
return request.SuccessfulSmartServerResponse(('names',) + tuple(filenames))
127
class MkdirRequest(VfsRequest):
129
def do(self, relpath, mode):
130
relpath = self.translate_client_path(relpath)
131
self._backing_transport.mkdir(relpath,
132
_deserialise_optional_mode(mode))
133
return request.SuccessfulSmartServerResponse(('ok',))
136
class MoveRequest(VfsRequest):
138
def do(self, rel_from, rel_to):
139
rel_from = self.translate_client_path(rel_from)
140
rel_to = self.translate_client_path(rel_to)
141
self._backing_transport.move(rel_from, rel_to)
142
return request.SuccessfulSmartServerResponse(('ok',))
145
class PutRequest(VfsRequest):
147
def do(self, relpath, mode):
148
relpath = self.translate_client_path(relpath)
149
self._relpath = relpath
150
self._mode = _deserialise_optional_mode(mode)
152
def do_body(self, body_bytes):
153
self._backing_transport.put_bytes(self._relpath, body_bytes, self._mode)
154
return request.SuccessfulSmartServerResponse(('ok',))
157
class PutNonAtomicRequest(VfsRequest):
159
def do(self, relpath, mode, create_parent, dir_mode):
160
relpath = self.translate_client_path(relpath)
161
self._relpath = relpath
162
self._dir_mode = _deserialise_optional_mode(dir_mode)
163
self._mode = _deserialise_optional_mode(mode)
164
# a boolean would be nicer XXX
165
self._create_parent = (create_parent == 'T')
167
def do_body(self, body_bytes):
168
self._backing_transport.put_bytes_non_atomic(self._relpath,
171
create_parent_dir=self._create_parent,
172
dir_mode=self._dir_mode)
173
return request.SuccessfulSmartServerResponse(('ok',))
176
class ReadvRequest(VfsRequest):
178
def do(self, relpath):
179
relpath = self.translate_client_path(relpath)
180
self._relpath = relpath
182
def do_body(self, body_bytes):
183
"""accept offsets for a readv request."""
184
offsets = self._deserialise_offsets(body_bytes)
185
backing_bytes = ''.join(bytes for offset, bytes in
186
self._backing_transport.readv(self._relpath, offsets))
187
return request.SuccessfulSmartServerResponse(('readv',), backing_bytes)
189
def _deserialise_offsets(self, text):
190
# XXX: FIXME this should be on the protocol object.
192
for line in text.split('\n'):
195
start, length = line.split(',')
196
offsets.append((int(start), int(length)))
200
class RenameRequest(VfsRequest):
202
def do(self, rel_from, rel_to):
203
rel_from = self.translate_client_path(rel_from)
204
rel_to = self.translate_client_path(rel_to)
205
self._backing_transport.rename(rel_from, rel_to)
206
return request.SuccessfulSmartServerResponse(('ok', ))
209
class RmdirRequest(VfsRequest):
211
def do(self, relpath):
212
relpath = self.translate_client_path(relpath)
213
self._backing_transport.rmdir(relpath)
214
return request.SuccessfulSmartServerResponse(('ok', ))
217
class StatRequest(VfsRequest):
219
def do(self, relpath):
220
if not relpath.endswith('/'):
222
relpath = self.translate_client_path(relpath)
223
stat = self._backing_transport.stat(relpath)
224
return request.SuccessfulSmartServerResponse(
225
('stat', str(stat.st_size), oct(stat.st_mode)))