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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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)
75
backing_bytes = self._backing_transport.get_bytes(relpath)
76
return request.SuccessfulSmartServerResponse(('ok',), backing_bytes)
79
class AppendRequest(VfsRequest):
81
def do(self, relpath, mode):
82
relpath = self.translate_client_path(relpath)
83
self._relpath = relpath
84
self._mode = _deserialise_optional_mode(mode)
86
def do_body(self, body_bytes):
87
old_length = self._backing_transport.append_bytes(
88
self._relpath, body_bytes, self._mode)
89
return request.SuccessfulSmartServerResponse(('appended', '%d' % old_length))
92
class DeleteRequest(VfsRequest):
94
def do(self, relpath):
95
relpath = self.translate_client_path(relpath)
96
self._backing_transport.delete(relpath)
97
return request.SuccessfulSmartServerResponse(('ok', ))
100
class IterFilesRecursiveRequest(VfsRequest):
102
def do(self, relpath):
103
if not relpath.endswith('/'):
105
relpath = self.translate_client_path(relpath)
106
transport = self._backing_transport.clone(relpath)
107
filenames = transport.iter_files_recursive()
108
return request.SuccessfulSmartServerResponse(('names',) + tuple(filenames))
111
class ListDirRequest(VfsRequest):
113
def do(self, relpath):
114
if not relpath.endswith('/'):
116
relpath = self.translate_client_path(relpath)
117
filenames = self._backing_transport.list_dir(relpath)
118
return request.SuccessfulSmartServerResponse(('names',) + tuple(filenames))
121
class MkdirRequest(VfsRequest):
123
def do(self, relpath, mode):
124
relpath = self.translate_client_path(relpath)
125
self._backing_transport.mkdir(relpath,
126
_deserialise_optional_mode(mode))
127
return request.SuccessfulSmartServerResponse(('ok',))
130
class MoveRequest(VfsRequest):
132
def do(self, rel_from, rel_to):
133
rel_from = self.translate_client_path(rel_from)
134
rel_to = self.translate_client_path(rel_to)
135
self._backing_transport.move(rel_from, rel_to)
136
return request.SuccessfulSmartServerResponse(('ok',))
139
class PutRequest(VfsRequest):
141
def do(self, relpath, mode):
142
relpath = self.translate_client_path(relpath)
143
self._relpath = relpath
144
self._mode = _deserialise_optional_mode(mode)
146
def do_body(self, body_bytes):
147
self._backing_transport.put_bytes(self._relpath, body_bytes, self._mode)
148
return request.SuccessfulSmartServerResponse(('ok',))
151
class PutNonAtomicRequest(VfsRequest):
153
def do(self, relpath, mode, create_parent, dir_mode):
154
relpath = self.translate_client_path(relpath)
155
self._relpath = relpath
156
self._dir_mode = _deserialise_optional_mode(dir_mode)
157
self._mode = _deserialise_optional_mode(mode)
158
# a boolean would be nicer XXX
159
self._create_parent = (create_parent == 'T')
161
def do_body(self, body_bytes):
162
self._backing_transport.put_bytes_non_atomic(self._relpath,
165
create_parent_dir=self._create_parent,
166
dir_mode=self._dir_mode)
167
return request.SuccessfulSmartServerResponse(('ok',))
170
class ReadvRequest(VfsRequest):
172
def do(self, relpath):
173
relpath = self.translate_client_path(relpath)
174
self._relpath = relpath
176
def do_body(self, body_bytes):
177
"""accept offsets for a readv request."""
178
offsets = self._deserialise_offsets(body_bytes)
179
backing_bytes = ''.join(bytes for offset, bytes in
180
self._backing_transport.readv(self._relpath, offsets))
181
return request.SuccessfulSmartServerResponse(('readv',), backing_bytes)
183
def _deserialise_offsets(self, text):
184
# XXX: FIXME this should be on the protocol object.
186
for line in text.split('\n'):
189
start, length = line.split(',')
190
offsets.append((int(start), int(length)))
194
class RenameRequest(VfsRequest):
196
def do(self, rel_from, rel_to):
197
rel_from = self.translate_client_path(rel_from)
198
rel_to = self.translate_client_path(rel_to)
199
self._backing_transport.rename(rel_from, rel_to)
200
return request.SuccessfulSmartServerResponse(('ok', ))
203
class RmdirRequest(VfsRequest):
205
def do(self, relpath):
206
relpath = self.translate_client_path(relpath)
207
self._backing_transport.rmdir(relpath)
208
return request.SuccessfulSmartServerResponse(('ok', ))
211
class StatRequest(VfsRequest):
213
def do(self, relpath):
214
if not relpath.endswith('/'):
216
relpath = self.translate_client_path(relpath)
217
stat = self._backing_transport.stat(relpath)
218
return request.SuccessfulSmartServerResponse(
219
('stat', str(stat.st_size), oct(stat.st_mode)))