Revision d50ed8d4 snf-pithos-tools/pithos/tools/fs.py
b/snf-pithos-tools/pithos/tools/fs.py | ||
---|---|---|
1 | 1 |
#!/usr/bin/env python |
2 | 2 |
|
3 | 3 |
# Copyright 2011-2012 GRNET S.A. All rights reserved. |
4 |
#
|
|
4 |
# |
|
5 | 5 |
# Redistribution and use in source and binary forms, with or |
6 | 6 |
# without modification, are permitted provided that the following |
7 | 7 |
# conditions are met: |
8 |
#
|
|
8 |
# |
|
9 | 9 |
# 1. Redistributions of source code must retain the above |
10 | 10 |
# copyright notice, this list of conditions and the following |
11 | 11 |
# disclaimer. |
12 |
#
|
|
12 |
# |
|
13 | 13 |
# 2. Redistributions in binary form must reproduce the above |
14 | 14 |
# copyright notice, this list of conditions and the following |
15 | 15 |
# disclaimer in the documentation and/or other materials |
16 | 16 |
# provided with the distribution. |
17 |
#
|
|
17 |
# |
|
18 | 18 |
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
19 | 19 |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
20 | 20 |
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
... | ... | |
27 | 27 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
28 | 28 |
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | 29 |
# POSSIBILITY OF SUCH DAMAGE. |
30 |
#
|
|
30 |
# |
|
31 | 31 |
# The views and conclusions contained in the software and |
32 | 32 |
# documentation are those of the authors and should not be |
33 | 33 |
# interpreted as representing official policies, either expressed |
... | ... | |
35 | 35 |
|
36 | 36 |
from cStringIO import StringIO |
37 | 37 |
from errno import (EACCES, EBADF, EINVAL, EISDIR, EIO, ENOENT, ENOTDIR, |
38 |
ENOTEMPTY)
|
|
38 |
ENOTEMPTY) |
|
39 | 39 |
from getpass import getuser |
40 | 40 |
from stat import S_IFDIR, S_IFREG |
41 | 41 |
from sys import argv |
... | ... | |
55 | 55 |
def __init__(self, verbose=False): |
56 | 56 |
self.verbose = verbose |
57 | 57 |
self.client = OOS_Client(get_url(), get_auth(), get_user()) |
58 |
|
|
58 |
|
|
59 | 59 |
def __call__(self, op, path, *args): |
60 | 60 |
container, sep, object = path[1:].partition('/') |
61 | 61 |
if self.verbose: |
62 | 62 |
data = repr(args)[:100] |
63 | 63 |
print '-> %s %r %r %r' % (op, container, object, data) |
64 | 64 |
ret = '[Unhandled Exception]' |
65 |
|
|
65 |
|
|
66 | 66 |
try: |
67 | 67 |
if object: |
68 | 68 |
func = getattr(self, 'object_' + op, None) |
... | ... | |
78 | 78 |
# Fallback to defaults |
79 | 79 |
func = getattr(self, op) |
80 | 80 |
funcargs = (path,) + args |
81 |
|
|
81 |
|
|
82 | 82 |
ret = func(*funcargs) |
83 | 83 |
return ret |
84 | 84 |
except FuseOSError, e: |
... | ... | |
87 | 87 |
finally: |
88 | 88 |
if self.verbose: |
89 | 89 |
print '<-', op, repr(ret) |
90 |
|
|
91 |
|
|
90 |
|
|
92 | 91 |
def _get_container_meta(self, container, **kwargs): |
93 | 92 |
try: |
94 | 93 |
return self.client.retrieve_container_metadata(container, **kwargs) |
95 | 94 |
except Fault: |
96 | 95 |
raise FuseOSError(ENOENT) |
97 |
|
|
96 |
|
|
98 | 97 |
def _get_object_meta(self, container, object, **kwargs): |
99 | 98 |
try: |
100 | 99 |
return self.client.retrieve_object_metadata(container, object, |
101 | 100 |
**kwargs) |
102 | 101 |
except Fault: |
103 | 102 |
raise FuseOSError(ENOENT) |
104 |
|
|
105 |
|
|
103 |
|
|
106 | 104 |
# Global |
107 |
|
|
108 | 105 |
def statfs(self, path): |
109 |
return dict(f_bsize=1024, f_blocks=1024**2, f_bfree=1024**2, |
|
110 |
f_bavail=1024**2) |
|
111 |
|
|
112 |
|
|
106 |
return dict(f_bsize=1024, f_blocks=1024 ** 2, f_bfree=1024 ** 2, |
|
107 |
f_bavail=1024 ** 2) |
|
108 |
|
|
113 | 109 |
# Account Level |
114 |
|
|
115 | 110 |
def account_chmod(self, mode): |
116 | 111 |
self.client.update_account_metadata(mode=str(mode)) |
117 |
|
|
112 |
|
|
118 | 113 |
def account_chown(self, uid, gid): |
119 | 114 |
self.client.update_account_metadata(uid=uid, gid=gid) |
120 |
|
|
115 |
|
|
121 | 116 |
def account_getattr(self, fh=None): |
122 | 117 |
meta = self.client.retrieve_account_metadata() |
123 | 118 |
mode = int(meta.get('x-account-meta-mode', 0755)) |
... | ... | |
126 | 121 |
count = int(meta['x-account-container-count']) |
127 | 122 |
uid = int(meta.get('x-account-meta-uid', 0)) |
128 | 123 |
gid = int(meta.get('x-account-meta-gid', 0)) |
129 |
|
|
124 |
|
|
130 | 125 |
return { |
131 | 126 |
'st_mode': S_IFDIR | mode, |
132 | 127 |
'st_nlink': 2 + count, |
... | ... | |
135 | 130 |
'st_ctime': epoch, |
136 | 131 |
'st_mtime': modified, |
137 | 132 |
'st_atime': modified} |
138 |
|
|
133 |
|
|
139 | 134 |
def account_getxattr(self, name, position=0): |
140 | 135 |
meta = self.client.retrieve_account_metadata(restricted=True) |
141 | 136 |
return meta.get('xattr-' + name, '') |
142 |
|
|
137 |
|
|
143 | 138 |
def account_listxattr(self): |
144 | 139 |
meta = self.client.retrieve_account_metadata(restricted=True) |
145 | 140 |
prefix = 'xattr-' |
146 | 141 |
return [k[len(prefix):] for k in meta if k.startswith(prefix)] |
147 |
|
|
142 |
|
|
148 | 143 |
def account_readdir(self, fh): |
149 | 144 |
return ['.', '..'] + self.client.list_containers() or [] |
150 |
|
|
145 |
|
|
151 | 146 |
def account_removexattr(self, name): |
152 | 147 |
attr = 'xattr-' + name |
153 | 148 |
self.client.delete_account_metadata([attr]) |
154 |
|
|
149 |
|
|
155 | 150 |
def account_setxattr(self, name, value, options, position=0): |
156 | 151 |
attr = 'xattr-' + name |
157 | 152 |
meta = {attr: value} |
158 | 153 |
self.client.update_account_metadata(**meta) |
159 |
|
|
160 |
|
|
154 |
|
|
161 | 155 |
# Container Level |
162 |
|
|
163 | 156 |
def container_chmod(self, container, mode): |
164 | 157 |
self.client.update_container_metadata(container, mode=str(mode)) |
165 |
|
|
158 |
|
|
166 | 159 |
def container_chown(self, container, uid, gid): |
167 | 160 |
self.client.update_container_metadata(container, uid=uid, gid=gid) |
168 |
|
|
161 |
|
|
169 | 162 |
def container_getattr(self, container, fh=None): |
170 | 163 |
meta = self._get_container_meta(container) |
171 | 164 |
mode = int(meta.get('x-container-meta-mode', 0755)) |
... | ... | |
173 | 166 |
count = int(meta['x-container-object-count']) |
174 | 167 |
uid = int(meta.get('x-account-meta-uid', 0)) |
175 | 168 |
gid = int(meta.get('x-account-meta-gid', 0)) |
176 |
|
|
169 |
|
|
177 | 170 |
return { |
178 | 171 |
'st_mode': S_IFDIR | mode, |
179 | 172 |
'st_nlink': 2 + count, |
... | ... | |
182 | 175 |
'st_ctime': epoch, |
183 | 176 |
'st_mtime': modified, |
184 | 177 |
'st_atime': modified} |
185 |
|
|
178 |
|
|
186 | 179 |
def container_getxattr(self, container, name, position=0): |
187 | 180 |
meta = self._get_container_meta(container) |
188 | 181 |
return meta.get('xattr-' + name, '') |
189 |
|
|
182 |
|
|
190 | 183 |
def container_listxattr(self, container): |
191 | 184 |
meta = self._get_container_meta(container, restricted=True) |
192 | 185 |
prefix = 'xattr-' |
193 | 186 |
return [k[len(prefix):] for k in meta if k.startswith(prefix)] |
194 |
|
|
187 |
|
|
195 | 188 |
def container_mkdir(self, container, mode): |
196 | 189 |
mode = str(mode & 0777) |
197 | 190 |
self.client.create_container(container, mode=mode) |
198 |
|
|
191 |
|
|
199 | 192 |
def container_readdir(self, container, fh): |
200 | 193 |
objects = self.client.list_objects(container, delimiter='/', prefix='') |
201 | 194 |
files = [o for o in objects if not o.endswith('/')] |
202 | 195 |
return ['.', '..'] + files |
203 |
|
|
196 |
|
|
204 | 197 |
def container_removexattr(self, container, name): |
205 | 198 |
attr = 'xattr-' + name |
206 | 199 |
self.client.delete_container_metadata(container, [attr]) |
207 |
|
|
200 |
|
|
208 | 201 |
def container_rename(self, container, path): |
209 | 202 |
new_container, sep, new_object = path[1:].partition('/') |
210 | 203 |
if not new_container or new_object: |
211 | 204 |
raise FuseOSError(EINVAL) |
212 | 205 |
self.client.delete_container(container) |
213 | 206 |
self.client.create_container(new_container) |
214 |
|
|
207 |
|
|
215 | 208 |
def container_rmdir(self, container): |
216 | 209 |
try: |
217 | 210 |
self.client.delete_container(container) |
218 | 211 |
except Fault: |
219 | 212 |
raise FuseOSError(ENOENT) |
220 |
|
|
213 |
|
|
221 | 214 |
def container_setxattr(self, container, name, value, options, position=0): |
222 | 215 |
attr = 'xattr-' + name |
223 | 216 |
meta = {attr: value} |
224 | 217 |
self.client.update_container_metadata(container, **meta) |
225 |
|
|
226 |
|
|
218 |
|
|
227 | 219 |
# Object Level |
228 |
|
|
229 | 220 |
def object_chmod(self, container, object, mode): |
230 | 221 |
self.client.update_object_metadata(container, object, mode=str(mode)) |
231 |
|
|
222 |
|
|
232 | 223 |
def object_chown(self, container, uid, gid): |
233 | 224 |
self.client.update_object_metadata(container, object, |
234 |
uid=str(uid), gid=str(gid))
|
|
235 |
|
|
225 |
uid=str(uid), gid=str(gid)) |
|
226 |
|
|
236 | 227 |
def object_create(self, container, object, mode, fi=None): |
237 | 228 |
mode &= 0777 |
238 | 229 |
self.client.create_object(container, object, |
239 |
f=None,
|
|
240 |
content_type='application/octet-stream',
|
|
241 |
mode=str(mode))
|
|
230 |
f=None, |
|
231 |
content_type='application/octet-stream', |
|
232 |
mode=str(mode)) |
|
242 | 233 |
return 0 |
243 |
|
|
234 |
|
|
244 | 235 |
def object_getattr(self, container, object, fh=None): |
245 | 236 |
meta = self._get_object_meta(container, object) |
246 | 237 |
modified = parse_http_date(meta['last-modified']) |
247 | 238 |
uid = int(meta.get('x-account-meta-uid', 0)) |
248 | 239 |
gid = int(meta.get('x-account-meta-gid', 0)) |
249 | 240 |
size = int(meta.get('content-length', 0)) |
250 |
|
|
241 |
|
|
251 | 242 |
if meta['content-type'].split(';', 1)[0].strip() == 'application/directory': |
252 | 243 |
mode = int(meta.get('x-object-meta-mode', 0755)) |
253 | 244 |
flags = S_IFDIR |
... | ... | |
256 | 247 |
mode = int(meta.get('x-object-meta-mode', 0644)) |
257 | 248 |
flags = S_IFREG |
258 | 249 |
nlink = 1 |
259 |
|
|
250 |
|
|
260 | 251 |
return { |
261 | 252 |
'st_mode': flags | mode, |
262 | 253 |
'st_nlink': nlink, |
... | ... | |
266 | 257 |
'st_mtime': modified, |
267 | 258 |
'st_atime': modified, |
268 | 259 |
'st_size': size} |
269 |
|
|
260 |
|
|
270 | 261 |
def object_getxattr(self, container, object, name, position=0): |
271 | 262 |
meta = self._get_object_meta(container, object, restricted=True) |
272 | 263 |
return meta.get('xattr-' + name, '') |
273 |
|
|
264 |
|
|
274 | 265 |
def object_listxattr(self, container, object): |
275 | 266 |
meta = self._get_object_meta(container, object, restricted=True) |
276 | 267 |
prefix = 'xattr-' |
277 | 268 |
return [k[len(prefix):] for k in meta if k.startswith(prefix)] |
278 |
|
|
269 |
|
|
279 | 270 |
def object_mkdir(self, container, object, mode): |
280 | 271 |
mode = str(mode & 0777) |
281 | 272 |
self.client.create_directory_marker(container, object) |
282 | 273 |
self.client.update_object_metadata(container, object, mode=mode) |
283 |
|
|
274 |
|
|
284 | 275 |
def object_read(self, container, object, nbyte, offset, fh): |
285 | 276 |
data = self.client.retrieve_object(container, object) |
286 | 277 |
return data[offset:offset + nbyte] |
287 |
|
|
278 |
|
|
288 | 279 |
def object_readdir(self, container, object, fh): |
289 | 280 |
objects = self.client.list_objects(container, delimiter='/', |
290 |
prefix=object)
|
|
281 |
prefix=object) |
|
291 | 282 |
files = [o.rpartition('/')[2] for o in objects if not o.endswith('/')] |
292 | 283 |
return ['.', '..'] + files |
293 |
|
|
284 |
|
|
294 | 285 |
def object_removexattr(self, container, object, name): |
295 | 286 |
attr = 'xattr-' + name |
296 | 287 |
self.client.delete_object_metadata(container, object, [attr]) |
297 |
|
|
288 |
|
|
298 | 289 |
def object_rename(self, container, object, path): |
299 | 290 |
new_container, sep, new_object = path[1:].partition('/') |
300 | 291 |
if not new_container or not new_object: |
301 | 292 |
raise FuseOSError(EINVAL) |
302 | 293 |
self.client.move_object(container, object, new_container, new_object) |
303 |
|
|
294 |
|
|
304 | 295 |
def object_rmdir(self, container, object): |
305 | 296 |
self.client.delete_object(container, object) |
306 |
|
|
297 |
|
|
307 | 298 |
def object_setxattr(self, container, object, name, value, options, |
308 | 299 |
position=0): |
309 | 300 |
attr = 'xattr-' + name |
310 | 301 |
meta = {attr: value} |
311 | 302 |
self.client.update_object_metadata(container, object, **meta) |
312 |
|
|
303 |
|
|
313 | 304 |
def object_truncate(self, container, object, length, fh=None): |
314 | 305 |
data = self.client.retrieve_object(container, object) |
315 | 306 |
f = StringIO(data[:length]) |
316 | 307 |
self.client.update_object(container, object, f) |
317 |
|
|
308 |
|
|
318 | 309 |
def object_unlink(self, container, object): |
319 | 310 |
self.client.delete_object(container, object) |
320 |
|
|
311 |
|
|
321 | 312 |
def object_write(self, container, object, data, offset, fh): |
322 | 313 |
f = StringIO(data) |
323 | 314 |
self.client.update_object(container, object, f, offset=offset) |
... | ... | |
328 | 319 |
if len(argv) != 2: |
329 | 320 |
print 'usage: %s <mountpoint>' % argv[0] |
330 | 321 |
exit(1) |
331 |
|
|
322 |
|
|
332 | 323 |
user = getuser() |
333 | 324 |
fs = StoreFS(verbose=True) |
334 | 325 |
fuse = FUSE(fs, argv[1], foreground=True) |
... | ... | |
336 | 327 |
|
337 | 328 |
if __name__ == '__main__': |
338 | 329 |
main() |
339 |
|
Also available in: Unified diff