Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-tools / pithos / tools / lib / fuse.py @ d50ed8d4

History | View | Annotate | Download (22.2 kB)

1
# Copyright (c) 2008 Giorgos Verigakis <verigak@gmail.com>
2
#
3
# Permission to use, copy, modify, and distribute this software for any
4
# purpose with or without fee is hereby granted, provided that the above
5
# copyright notice and this permission notice appear in all copies.
6
#
7
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14

    
15
from __future__ import division
16

    
17
from ctypes import *
18
from ctypes.util import find_library
19
from errno import *
20
from functools import partial
21
from os import strerror
22
from platform import machine, system
23
from stat import S_IFDIR
24
from traceback import print_exc
25

    
26

    
27
class c_timespec(Structure):
28
    _fields_ = [('tv_sec', c_long), ('tv_nsec', c_long)]
29

    
30

    
31
class c_utimbuf(Structure):
32
    _fields_ = [('actime', c_timespec), ('modtime', c_timespec)]
33

    
34

    
35
class c_stat(Structure):
36
    pass    # Platform dependent
37

    
38
_system = system()
39
if _system in ('Darwin', 'FreeBSD'):
40
    _libiconv = CDLL(
41
        find_library("iconv"), RTLD_GLOBAL)     # libfuse dependency
42
    ENOTSUP = 45
43
    c_dev_t = c_int32
44
    c_fsblkcnt_t = c_ulong
45
    c_fsfilcnt_t = c_ulong
46
    c_gid_t = c_uint32
47
    c_mode_t = c_uint16
48
    c_off_t = c_int64
49
    c_pid_t = c_int32
50
    c_uid_t = c_uint32
51
    setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
52
                           c_size_t, c_int, c_uint32)
53
    getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
54
                           c_size_t, c_uint32)
55
    c_stat._fields_ = [
56
        ('st_dev', c_dev_t),
57
        ('st_ino', c_uint32),
58
        ('st_mode', c_mode_t),
59
        ('st_nlink', c_uint16),
60
        ('st_uid', c_uid_t),
61
        ('st_gid', c_gid_t),
62
        ('st_rdev', c_dev_t),
63
        ('st_atimespec', c_timespec),
64
        ('st_mtimespec', c_timespec),
65
        ('st_ctimespec', c_timespec),
66
        ('st_size', c_off_t),
67
        ('st_blocks', c_int64),
68
        ('st_blksize', c_int32)]
69
elif _system == 'Linux':
70
    ENOTSUP = 95
71
    c_dev_t = c_ulonglong
72
    c_fsblkcnt_t = c_ulonglong
73
    c_fsfilcnt_t = c_ulonglong
74
    c_gid_t = c_uint
75
    c_mode_t = c_uint
76
    c_off_t = c_longlong
77
    c_pid_t = c_int
78
    c_uid_t = c_uint
79
    setxattr_t = CFUNCTYPE(
80
        c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t, c_int)
81
    getxattr_t = CFUNCTYPE(
82
        c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t)
83

    
84
    _machine = machine()
85
    if _machine == 'x86_64':
86
        c_stat._fields_ = [
87
            ('st_dev', c_dev_t),
88
            ('st_ino', c_ulong),
89
            ('st_nlink', c_ulong),
90
            ('st_mode', c_mode_t),
91
            ('st_uid', c_uid_t),
92
            ('st_gid', c_gid_t),
93
            ('__pad0', c_int),
94
            ('st_rdev', c_dev_t),
95
            ('st_size', c_off_t),
96
            ('st_blksize', c_long),
97
            ('st_blocks', c_long),
98
            ('st_atimespec', c_timespec),
99
            ('st_mtimespec', c_timespec),
100
            ('st_ctimespec', c_timespec)]
101
    elif _machine == 'ppc':
102
        c_stat._fields_ = [
103
            ('st_dev', c_dev_t),
104
            ('st_ino', c_ulonglong),
105
            ('st_mode', c_mode_t),
106
            ('st_nlink', c_uint),
107
            ('st_uid', c_uid_t),
108
            ('st_gid', c_gid_t),
109
            ('st_rdev', c_dev_t),
110
            ('__pad2', c_ushort),
111
            ('st_size', c_off_t),
112
            ('st_blksize', c_long),
113
            ('st_blocks', c_longlong),
114
            ('st_atimespec', c_timespec),
115
            ('st_mtimespec', c_timespec),
116
            ('st_ctimespec', c_timespec)]
117
    else:
118
        # i686, use as fallback for everything else
119
        c_stat._fields_ = [
120
            ('st_dev', c_dev_t),
121
            ('__pad1', c_ushort),
122
            ('__st_ino', c_ulong),
123
            ('st_mode', c_mode_t),
124
            ('st_nlink', c_uint),
125
            ('st_uid', c_uid_t),
126
            ('st_gid', c_gid_t),
127
            ('st_rdev', c_dev_t),
128
            ('__pad2', c_ushort),
129
            ('st_size', c_off_t),
130
            ('st_blksize', c_long),
131
            ('st_blocks', c_longlong),
132
            ('st_atimespec', c_timespec),
133
            ('st_mtimespec', c_timespec),
134
            ('st_ctimespec', c_timespec),
135
            ('st_ino', c_ulonglong)]
136
else:
137
    raise NotImplementedError('%s is not supported.' % _system)
138

    
139

    
140
class c_statvfs(Structure):
141
    _fields_ = [
142
        ('f_bsize', c_ulong),
143
        ('f_frsize', c_ulong),
144
        ('f_blocks', c_fsblkcnt_t),
145
        ('f_bfree', c_fsblkcnt_t),
146
        ('f_bavail', c_fsblkcnt_t),
147
        ('f_files', c_fsfilcnt_t),
148
        ('f_ffree', c_fsfilcnt_t),
149
        ('f_favail', c_fsfilcnt_t)]
150

    
151
if _system == 'FreeBSD':
152
    c_fsblkcnt_t = c_uint64
153
    c_fsfilcnt_t = c_uint64
154
    setxattr_t = CFUNCTYPE(
155
        c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t, c_int)
156
    getxattr_t = CFUNCTYPE(
157
        c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t)
158

    
159
    class c_statvfs(Structure):
160
        _fields_ = [
161
            ('f_bavail', c_fsblkcnt_t),
162
            ('f_bfree', c_fsblkcnt_t),
163
            ('f_blocks', c_fsblkcnt_t),
164
            ('f_favail', c_fsfilcnt_t),
165
            ('f_ffree', c_fsfilcnt_t),
166
            ('f_files', c_fsfilcnt_t),
167
            ('f_bsize', c_ulong),
168
            ('f_flag', c_ulong),
169
            ('f_frsize', c_ulong)]
170

    
171

    
172
class fuse_file_info(Structure):
173
    _fields_ = [
174
        ('flags', c_int),
175
        ('fh_old', c_ulong),
176
        ('writepage', c_int),
177
        ('direct_io', c_uint, 1),
178
        ('keep_cache', c_uint, 1),
179
        ('flush', c_uint, 1),
180
        ('padding', c_uint, 29),
181
        ('fh', c_uint64),
182
        ('lock_owner', c_uint64)]
183

    
184

    
185
class fuse_context(Structure):
186
    _fields_ = [
187
        ('fuse', c_voidp),
188
        ('uid', c_uid_t),
189
        ('gid', c_gid_t),
190
        ('pid', c_pid_t),
191
        ('private_data', c_voidp)]
192

    
193

    
194
class fuse_operations(Structure):
195
    _fields_ = [
196
        ('getattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_stat))),
197
        ('readlink', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t)),
198
        ('getdir', c_voidp),    # Deprecated, use readdir
199
        ('mknod', CFUNCTYPE(c_int, c_char_p, c_mode_t, c_dev_t)),
200
        ('mkdir', CFUNCTYPE(c_int, c_char_p, c_mode_t)),
201
        ('unlink', CFUNCTYPE(c_int, c_char_p)),
202
        ('rmdir', CFUNCTYPE(c_int, c_char_p)),
203
        ('symlink', CFUNCTYPE(c_int, c_char_p, c_char_p)),
204
        ('rename', CFUNCTYPE(c_int, c_char_p, c_char_p)),
205
        ('link', CFUNCTYPE(c_int, c_char_p, c_char_p)),
206
        ('chmod', CFUNCTYPE(c_int, c_char_p, c_mode_t)),
207
        ('chown', CFUNCTYPE(c_int, c_char_p, c_uid_t, c_gid_t)),
208
        ('truncate', CFUNCTYPE(c_int, c_char_p, c_off_t)),
209
        ('utime', c_voidp),     # Deprecated, use utimens
210
        ('open', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
211
        ('read', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t, c_off_t,
212
                           POINTER(fuse_file_info))),
213
        (
214
            'write', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t, c_off_t,
215
            POINTER(fuse_file_info))),
216
        ('statfs', CFUNCTYPE(c_int, c_char_p, POINTER(c_statvfs))),
217
        ('flush', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
218
        ('release', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
219
        ('fsync', CFUNCTYPE(c_int, c_char_p, c_int, POINTER(fuse_file_info))),
220
        ('setxattr', setxattr_t),
221
        ('getxattr', getxattr_t),
222
        ('listxattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t)),
223
        ('removexattr', CFUNCTYPE(c_int, c_char_p, c_char_p)),
224
        ('opendir', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
225
        (
226
            'readdir', CFUNCTYPE(c_int, c_char_p, c_voidp, CFUNCTYPE(c_int, c_voidp,
227
            c_char_p, POINTER(
228
                c_stat), c_off_t), c_off_t, POINTER(fuse_file_info))),
229
        ('releasedir', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
230
        ('fsyncdir', CFUNCTYPE(c_int, c_char_p, c_int, POINTER(
231
            fuse_file_info))),
232
        ('init', CFUNCTYPE(c_voidp, c_voidp)),
233
        ('destroy', CFUNCTYPE(c_voidp, c_voidp)),
234
        ('access', CFUNCTYPE(c_int, c_char_p, c_int)),
235
        ('create', CFUNCTYPE(c_int, c_char_p, c_mode_t, POINTER(
236
            fuse_file_info))),
237
        ('ftruncate', CFUNCTYPE(c_int, c_char_p, c_off_t, POINTER(
238
            fuse_file_info))),
239
        ('fgetattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_stat),
240
                               POINTER(fuse_file_info))),
241
        ('lock', CFUNCTYPE(
242
            c_int, c_char_p, POINTER(fuse_file_info), c_int, c_voidp)),
243
        ('utimens', CFUNCTYPE(c_int, c_char_p, POINTER(c_utimbuf))),
244
        ('bmap', CFUNCTYPE(c_int, c_char_p, c_size_t, POINTER(c_ulonglong)))]
245

    
246

    
247
def time_of_timespec(ts):
248
    return ts.tv_sec + ts.tv_nsec / 10 ** 9
249

    
250

    
251
def set_st_attrs(st, attrs):
252
    for key, val in attrs.items():
253
        if key in ('st_atime', 'st_mtime', 'st_ctime'):
254
            timespec = getattr(st, key + 'spec')
255
            timespec.tv_sec = int(val)
256
            timespec.tv_nsec = int((val - timespec.tv_sec) * 10 ** 9)
257
        elif hasattr(st, key):
258
            setattr(st, key, val)
259

    
260

    
261
_libfuse_path = find_library('fuse')
262
if not _libfuse_path:
263
    raise EnvironmentError('Unable to find libfuse')
264
_libfuse = CDLL(_libfuse_path)
265
_libfuse.fuse_get_context.restype = POINTER(fuse_context)
266

    
267

    
268
def fuse_get_context():
269
    """Returns a (uid, gid, pid) tuple"""
270
    ctxp = _libfuse.fuse_get_context()
271
    ctx = ctxp.contents
272
    return ctx.uid, ctx.gid, ctx.pid
273

    
274

    
275
class FuseOSError(OSError):
276
    def __init__(self, errno):
277
        super(FuseOSError, self).__init__(errno, strerror(errno))
278

    
279

    
280
class FUSE(object):
281
    """This class is the lower level interface and should not be subclassed
282
       under normal use. Its methods are called by fuse.
283
       Assumes API version 2.6 or later."""
284

    
285
    def __init__(self, operations, mountpoint, raw_fi=False, **kwargs):
286
        """Setting raw_fi to True will cause FUSE to pass the fuse_file_info
287
           class as is to Operations, instead of just the fh field.
288
           This gives you access to direct_io, keep_cache, etc."""
289

    
290
        self.operations = operations
291
        self.raw_fi = raw_fi
292
        args = ['fuse']
293
        if kwargs.pop('foreground', False):
294
            args.append('-f')
295
        if kwargs.pop('debug', False):
296
            args.append('-d')
297
        if kwargs.pop('nothreads', False):
298
            args.append('-s')
299
        kwargs.setdefault('fsname', operations.__class__.__name__)
300
        args.append('-o')
301
        args.append(','.join(key if val == True else '%s=%s' % (key, val)
302
                             for key, val in kwargs.items()))
303
        args.append(mountpoint)
304
        argv = (c_char_p * len(args))(*args)
305

    
306
        fuse_ops = fuse_operations()
307
        for name, prototype in fuse_operations._fields_:
308
            if prototype != c_voidp and getattr(operations, name, None):
309
                op = partial(self._wrapper_, getattr(self, name))
310
                setattr(fuse_ops, name, prototype(op))
311
        err = _libfuse.fuse_main_real(len(args), argv, pointer(fuse_ops),
312
                                      sizeof(fuse_ops), None)
313
        del self.operations     # Invoke the destructor
314
        if err:
315
            raise RuntimeError(err)
316

    
317
    def _wrapper_(self, func, *args, **kwargs):
318
        """Decorator for the methods that follow"""
319
        try:
320
            return func(*args, **kwargs) or 0
321
        except OSError, e:
322
            return -(e.errno or EFAULT)
323
        except:
324
            print_exc()
325
            return -EFAULT
326

    
327
    def getattr(self, path, buf):
328
        return self.fgetattr(path, buf, None)
329

    
330
    def readlink(self, path, buf, bufsize):
331
        ret = self.operations('readlink', path)
332
        data = create_string_buffer(ret[:bufsize - 1])
333
        memmove(buf, data, len(data))
334
        return 0
335

    
336
    def mknod(self, path, mode, dev):
337
        return self.operations('mknod', path, mode, dev)
338

    
339
    def mkdir(self, path, mode):
340
        return self.operations('mkdir', path, mode)
341

    
342
    def unlink(self, path):
343
        return self.operations('unlink', path)
344

    
345
    def rmdir(self, path):
346
        return self.operations('rmdir', path)
347

    
348
    def symlink(self, source, target):
349
        return self.operations('symlink', target, source)
350

    
351
    def rename(self, old, new):
352
        return self.operations('rename', old, new)
353

    
354
    def link(self, source, target):
355
        return self.operations('link', target, source)
356

    
357
    def chmod(self, path, mode):
358
        return self.operations('chmod', path, mode)
359

    
360
    def chown(self, path, uid, gid):
361
        # Check if any of the arguments is a -1 that has overflowed
362
        if c_uid_t(uid + 1).value == 0:
363
            uid = -1
364
        if c_gid_t(gid + 1).value == 0:
365
            gid = -1
366
        return self.operations('chown', path, uid, gid)
367

    
368
    def truncate(self, path, length):
369
        return self.operations('truncate', path, length)
370

    
371
    def open(self, path, fip):
372
        fi = fip.contents
373
        if self.raw_fi:
374
            return self.operations('open', path, fi)
375
        else:
376
            fi.fh = self.operations('open', path, fi.flags)
377
            return 0
378

    
379
    def read(self, path, buf, size, offset, fip):
380
        fh = fip.contents if self.raw_fi else fip.contents.fh
381
        ret = self.operations('read', path, size, offset, fh)
382
        if not ret:
383
            return 0
384
        data = create_string_buffer(ret[:size], size)
385
        memmove(buf, data, size)
386
        return size
387

    
388
    def write(self, path, buf, size, offset, fip):
389
        data = string_at(buf, size)
390
        fh = fip.contents if self.raw_fi else fip.contents.fh
391
        return self.operations('write', path, data, offset, fh)
392

    
393
    def statfs(self, path, buf):
394
        stv = buf.contents
395
        attrs = self.operations('statfs', path)
396
        for key, val in attrs.items():
397
            if hasattr(stv, key):
398
                setattr(stv, key, val)
399
        return 0
400

    
401
    def flush(self, path, fip):
402
        fh = fip.contents if self.raw_fi else fip.contents.fh
403
        return self.operations('flush', path, fh)
404

    
405
    def release(self, path, fip):
406
        fh = fip.contents if self.raw_fi else fip.contents.fh
407
        return self.operations('release', path, fh)
408

    
409
    def fsync(self, path, datasync, fip):
410
        fh = fip.contents if self.raw_fi else fip.contents.fh
411
        return self.operations('fsync', path, datasync, fh)
412

    
413
    def setxattr(self, path, name, value, size, options, *args):
414
        data = string_at(value, size)
415
        return self.operations('setxattr', path, name, data, options, *args)
416

    
417
    def getxattr(self, path, name, value, size, *args):
418
        ret = self.operations('getxattr', path, name, *args)
419
        retsize = len(ret)
420
        buf = create_string_buffer(ret, retsize)    # Does not add trailing 0
421
        if bool(value):
422
            if retsize > size:
423
                return -ERANGE
424
            memmove(value, buf, retsize)
425
        return retsize
426

    
427
    def listxattr(self, path, namebuf, size):
428
        ret = self.operations('listxattr', path)
429
        buf = create_string_buffer('\x00'.join(ret)) if ret else ''
430
        bufsize = len(buf)
431
        if bool(namebuf):
432
            if bufsize > size:
433
                return -ERANGE
434
            memmove(namebuf, buf, bufsize)
435
        return bufsize
436

    
437
    def removexattr(self, path, name):
438
        return self.operations('removexattr', path, name)
439

    
440
    def opendir(self, path, fip):
441
        # Ignore raw_fi
442
        fip.contents.fh = self.operations('opendir', path)
443
        return 0
444

    
445
    def readdir(self, path, buf, filler, offset, fip):
446
        # Ignore raw_fi
447
        for item in self.operations('readdir', path, fip.contents.fh):
448
            if isinstance(item, (str, unicode)):
449
                name, st, offset = item, None, 0
450
            else:
451
                name, attrs, offset = item
452
                if attrs:
453
                    st = c_stat()
454
                    set_st_attrs(st, attrs)
455
                else:
456
                    st = None
457
            if filler(buf, name, st, offset) != 0:
458
                break
459
        return 0
460

    
461
    def releasedir(self, path, fip):
462
        # Ignore raw_fi
463
        return self.operations('releasedir', path, fip.contents.fh)
464

    
465
    def fsyncdir(self, path, datasync, fip):
466
        # Ignore raw_fi
467
        return self.operations('fsyncdir', path, datasync, fip.contents.fh)
468

    
469
    def init(self, conn):
470
        return self.operations('init', '/')
471

    
472
    def destroy(self, private_data):
473
        return self.operations('destroy', '/')
474

    
475
    def access(self, path, amode):
476
        return self.operations('access', path, amode)
477

    
478
    def create(self, path, mode, fip):
479
        fi = fip.contents
480
        if self.raw_fi:
481
            return self.operations('create', path, mode, fi)
482
        else:
483
            fi.fh = self.operations('create', path, mode)
484
            return 0
485

    
486
    def ftruncate(self, path, length, fip):
487
        fh = fip.contents if self.raw_fi else fip.contents.fh
488
        return self.operations('truncate', path, length, fh)
489

    
490
    def fgetattr(self, path, buf, fip):
491
        memset(buf, 0, sizeof(c_stat))
492
        st = buf.contents
493
        fh = fip and (fip.contents if self.raw_fi else fip.contents.fh)
494
        attrs = self.operations('getattr', path, fh)
495
        set_st_attrs(st, attrs)
496
        return 0
497

    
498
    def lock(self, path, fip, cmd, lock):
499
        fh = fip.contents if self.raw_fi else fip.contents.fh
500
        return self.operations('lock', path, fh, cmd, lock)
501

    
502
    def utimens(self, path, buf):
503
        if buf:
504
            atime = time_of_timespec(buf.contents.actime)
505
            mtime = time_of_timespec(buf.contents.modtime)
506
            times = (atime, mtime)
507
        else:
508
            times = None
509
        return self.operations('utimens', path, times)
510

    
511
    def bmap(self, path, blocksize, idx):
512
        return self.operations('bmap', path, blocksize, idx)
513

    
514

    
515
class Operations(object):
516
    """This class should be subclassed and passed as an argument to FUSE on
517
       initialization. All operations should raise a FuseOSError exception
518
       on error.
519

520
       When in doubt of what an operation should do, check the FUSE header
521
       file or the corresponding system call man page."""
522

    
523
    def __call__(self, op, *args):
524
        if not hasattr(self, op):
525
            raise FuseOSError(EFAULT)
526
        return getattr(self, op)(*args)
527

    
528
    def access(self, path, amode):
529
        return 0
530

    
531
    bmap = None
532

    
533
    def chmod(self, path, mode):
534
        raise FuseOSError(EROFS)
535

    
536
    def chown(self, path, uid, gid):
537
        raise FuseOSError(EROFS)
538

    
539
    def create(self, path, mode, fi=None):
540
        """When raw_fi is False (default case), fi is None and create should
541
           return a numerical file handle.
542
           When raw_fi is True the file handle should be set directly by create
543
           and return 0."""
544
        raise FuseOSError(EROFS)
545

    
546
    def destroy(self, path):
547
        """Called on filesystem destruction. Path is always /"""
548
        pass
549

    
550
    def flush(self, path, fh):
551
        return 0
552

    
553
    def fsync(self, path, datasync, fh):
554
        return 0
555

    
556
    def fsyncdir(self, path, datasync, fh):
557
        return 0
558

    
559
    def getattr(self, path, fh=None):
560
        """Returns a dictionary with keys identical to the stat C structure
561
           of stat(2).
562
           st_atime, st_mtime and st_ctime should be floats.
563
           NOTE: There is an incombatibility between Linux and Mac OS X concerning
564
           st_nlink of directories. Mac OS X counts all files inside the directory,
565
           while Linux counts only the subdirectories."""
566

    
567
        if path != '/':
568
            raise FuseOSError(ENOENT)
569
        return dict(st_mode=(S_IFDIR | 0755), st_nlink=2)
570

    
571
    def getxattr(self, path, name, position=0):
572
        raise FuseOSError(ENOTSUP)
573

    
574
    def init(self, path):
575
        """Called on filesystem initialization. Path is always /
576
           Use it instead of __init__ if you start threads on initialization."""
577
        pass
578

    
579
    def link(self, target, source):
580
        raise FuseOSError(EROFS)
581

    
582
    def listxattr(self, path):
583
        return []
584

    
585
    lock = None
586

    
587
    def mkdir(self, path, mode):
588
        raise FuseOSError(EROFS)
589

    
590
    def mknod(self, path, mode, dev):
591
        raise FuseOSError(EROFS)
592

    
593
    def open(self, path, flags):
594
        """When raw_fi is False (default case), open should return a numerical
595
           file handle.
596
           When raw_fi is True the signature of open becomes:
597
               open(self, path, fi)
598
           and the file handle should be set directly."""
599
        return 0
600

    
601
    def opendir(self, path):
602
        """Returns a numerical file handle."""
603
        return 0
604

    
605
    def read(self, path, size, offset, fh):
606
        """Returns a string containing the data requested."""
607
        raise FuseOSError(EIO)
608

    
609
    def readdir(self, path, fh):
610
        """Can return either a list of names, or a list of (name, attrs, offset)
611
           tuples. attrs is a dict as in getattr."""
612
        return ['.', '..']
613

    
614
    def readlink(self, path):
615
        raise FuseOSError(ENOENT)
616

    
617
    def release(self, path, fh):
618
        return 0
619

    
620
    def releasedir(self, path, fh):
621
        return 0
622

    
623
    def removexattr(self, path, name):
624
        raise FuseOSError(ENOTSUP)
625

    
626
    def rename(self, old, new):
627
        raise FuseOSError(EROFS)
628

    
629
    def rmdir(self, path):
630
        raise FuseOSError(EROFS)
631

    
632
    def setxattr(self, path, name, value, options, position=0):
633
        raise FuseOSError(ENOTSUP)
634

    
635
    def statfs(self, path):
636
        """Returns a dictionary with keys identical to the statvfs C structure
637
           of statvfs(3).
638
           On Mac OS X f_bsize and f_frsize must be a power of 2 (minimum 512)."""
639
        return {}
640

    
641
    def symlink(self, target, source):
642
        raise FuseOSError(EROFS)
643

    
644
    def truncate(self, path, length, fh=None):
645
        raise FuseOSError(EROFS)
646

    
647
    def unlink(self, path):
648
        raise FuseOSError(EROFS)
649

    
650
    def utimens(self, path, times=None):
651
        """Times is a (atime, mtime) tuple. If None use current time."""
652
        return 0
653

    
654
    def write(self, path, data, offset, fh):
655
        raise FuseOSError(EROFS)
656

    
657

    
658
class LoggingMixIn:
659
    def __call__(self, op, path, *args):
660
        print '->', op, path, repr(args)
661
        ret = '[Unhandled Exception]'
662
        try:
663
            ret = getattr(self, op)(path, *args)
664
            return ret
665
        except OSError, e:
666
            ret = str(e)
667
            raise
668
        finally:
669
            print '<-', op, repr(ret)