~email-tehk/zeitgeist-filesystem/commonly-used

« back to all changes in this revision

Viewing changes to src/fusepy.py

  • Committer: Markus Korn
  • Date: 2009-12-01 19:27:29 UTC
  • Revision ID: thekorn@gmx.de-20091201192729-mi26983cv7btjuvm
updated fusepy to latest upstream version (r36)

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
from ctypes import *
18
18
from ctypes.util import find_library
19
 
from errno import EFAULT
 
19
from errno import *
20
20
from functools import partial
21
21
from platform import machine, system
 
22
from stat import S_IFDIR
22
23
from traceback import print_exc
23
24
 
24
25
 
32
33
    pass    # Platform dependent
33
34
 
34
35
_system = system()
35
 
if _system == 'Darwin':
 
36
if _system in ('Darwin', 'FreeBSD'):
36
37
    _libiconv = CDLL(find_library("iconv"), RTLD_GLOBAL)     # libfuse dependency
37
38
    ENOTSUP = 45
38
39
    c_dev_t = c_int32
75
76
    getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t)
76
77
    
77
78
    _machine = machine()
78
 
    if _machine == 'i686':
79
 
        c_stat._fields_ = [
80
 
            ('st_dev', c_dev_t),
81
 
            ('__pad1', c_ushort),
82
 
            ('__st_ino', c_ulong),
83
 
            ('st_mode', c_mode_t),
84
 
            ('st_nlink', c_uint),
85
 
            ('st_uid', c_uid_t),
86
 
            ('st_gid', c_gid_t),
87
 
            ('st_rdev', c_dev_t),
88
 
            ('__pad2', c_ushort),
89
 
            ('st_size', c_off_t),
90
 
            ('st_blksize', c_long),
91
 
            ('st_blocks', c_longlong),
92
 
            ('st_atimespec', c_timespec),
93
 
            ('st_mtimespec', c_timespec),
94
 
            ('st_ctimespec', c_timespec),
95
 
            ('st_ino', c_ulonglong)]
96
 
    elif machine() == 'x86_64':
 
79
    if _machine == 'x86_64':
97
80
        c_stat._fields_ = [
98
81
            ('st_dev', c_dev_t),
99
82
            ('st_ino', c_ulong),
109
92
            ('st_atimespec', c_timespec),
110
93
            ('st_mtimespec', c_timespec),
111
94
            ('st_ctimespec', c_timespec)]
 
95
    elif _machine == 'ppc':
 
96
        c_stat._fields_ = [
 
97
            ('st_dev', c_dev_t),
 
98
            ('st_ino', c_ulonglong),
 
99
            ('st_mode', c_mode_t),
 
100
            ('st_nlink', c_uint),
 
101
            ('st_uid', c_uid_t),
 
102
            ('st_gid', c_gid_t),
 
103
            ('st_rdev', c_dev_t),
 
104
            ('__pad2', c_ushort),
 
105
            ('st_size', c_off_t),
 
106
            ('st_blksize', c_long),
 
107
            ('st_blocks', c_longlong),
 
108
            ('st_atimespec', c_timespec),
 
109
            ('st_mtimespec', c_timespec),
 
110
            ('st_ctimespec', c_timespec)]
112
111
    else:
113
 
        raise NotImplementedError('Linux %s is not supported.' % _machine)
 
112
        # i686, use as fallback for everything else
 
113
        c_stat._fields_ = [
 
114
            ('st_dev', c_dev_t),
 
115
            ('__pad1', c_ushort),
 
116
            ('__st_ino', c_ulong),
 
117
            ('st_mode', c_mode_t),
 
118
            ('st_nlink', c_uint),
 
119
            ('st_uid', c_uid_t),
 
120
            ('st_gid', c_gid_t),
 
121
            ('st_rdev', c_dev_t),
 
122
            ('__pad2', c_ushort),
 
123
            ('st_size', c_off_t),
 
124
            ('st_blksize', c_long),
 
125
            ('st_blocks', c_longlong),
 
126
            ('st_atimespec', c_timespec),
 
127
            ('st_mtimespec', c_timespec),
 
128
            ('st_ctimespec', c_timespec),
 
129
            ('st_ino', c_ulonglong)]
114
130
else:
115
131
    raise NotImplementedError('%s is not supported.' % _system)
116
132
 
126
142
        ('f_ffree', c_fsfilcnt_t),
127
143
        ('f_favail', c_fsfilcnt_t)]
128
144
 
 
145
if _system == 'FreeBSD':
 
146
    c_fsblkcnt_t = c_uint64
 
147
    c_fsfilcnt_t = c_uint64
 
148
    setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t, c_int)
 
149
    getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t)
 
150
    class c_statvfs(Structure):
 
151
        _fields_ = [
 
152
            ('f_bavail', c_fsblkcnt_t),
 
153
            ('f_bfree', c_fsblkcnt_t),
 
154
            ('f_blocks', c_fsblkcnt_t),
 
155
            ('f_favail', c_fsfilcnt_t),
 
156
            ('f_ffree', c_fsfilcnt_t),
 
157
            ('f_files', c_fsfilcnt_t),
 
158
            ('f_bsize', c_ulong),
 
159
            ('f_flag', c_ulong),
 
160
            ('f_frsize', c_ulong)]
 
161
 
129
162
class fuse_file_info(Structure):
130
163
    _fields_ = [
131
164
        ('flags', c_int),
180
213
            c_char_p, POINTER(c_stat), c_off_t), c_off_t, POINTER(fuse_file_info))),
181
214
        ('releasedir', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
182
215
        ('fsyncdir', CFUNCTYPE(c_int, c_char_p, c_int, POINTER(fuse_file_info))),
183
 
        ('init', c_voidp),      # Use __init__
184
 
        ('destroy', c_voidp),   # Use __del__
 
216
        ('init', CFUNCTYPE(c_voidp, c_voidp)),
 
217
        ('destroy', CFUNCTYPE(c_voidp, c_voidp)),
185
218
        ('access', CFUNCTYPE(c_int, c_char_p, c_int)),
186
219
        ('create', CFUNCTYPE(c_int, c_char_p, c_mode_t, POINTER(fuse_file_info))),
187
220
        ('ftruncate', CFUNCTYPE(c_int, c_char_p, c_off_t, POINTER(fuse_file_info))),
193
226
 
194
227
 
195
228
def time_of_timespec(ts):
196
 
    return ts.tv_sec + 1.0 * ts.tv_nsec / 10 ** 9
 
229
    return ts.tv_sec + ts.tv_nsec / 10 ** 9
197
230
 
198
231
def set_st_attrs(st, attrs):
199
232
    for key, val in attrs.items():
204
237
        elif hasattr(st, key):
205
238
            setattr(st, key, val)
206
239
 
207
 
_libfuse = CDLL(find_library("fuse"))
 
240
 
 
241
_libfuse_path = find_library('fuse')
 
242
if not _libfuse_path:
 
243
    raise EnvironmentError('Unable to find libfuse')
 
244
_libfuse = CDLL(_libfuse_path)
 
245
_libfuse.fuse_get_context.restype = POINTER(fuse_context)
208
246
 
209
247
 
210
248
def fuse_get_context():
211
249
    """Returns a (uid, gid, pid) tuple"""
212
 
    p = _libfuse.fuse_get_context()
213
 
    ctx = cast(p, POINTER(fuse_context)).contents
 
250
    ctxp = _libfuse.fuse_get_context()
 
251
    ctx = ctxp.contents
214
252
    return ctx.uid, ctx.gid, ctx.pid
215
253
 
216
254
 
264
302
    
265
303
    def readlink(self, path, buf, bufsize):
266
304
        ret = self.operations('readlink', path)
267
 
        strbuf = create_string_buffer(ret[:bufsize - 1])
268
 
        memmove(buf, strbuf, len(strbuf))
 
305
        data = create_string_buffer(ret[:bufsize - 1])
 
306
        memmove(buf, data, len(data))
269
307
        return 0
270
308
    
271
309
    def mknod(self, path, mode, dev):
309
347
    def read(self, path, buf, size, offset, fip):
310
348
        fh = fip.contents if self.raw_fi else fip.contents.fh
311
349
        ret = self.operations('read', path, size, offset, fh)
312
 
        if ret:
313
 
            memmove(buf, create_string_buffer(ret), size)
314
 
        return len(ret)
 
350
        if not ret:
 
351
            return 0
 
352
        data = create_string_buffer(ret[:size], size)
 
353
        memmove(buf, data, size)
 
354
        return size
315
355
    
316
356
    def write(self, path, buf, size, offset, fip):
317
357
        data = string_at(buf, size)
339
379
        return self.operations('fsync', path, datasync, fh)
340
380
    
341
381
    def setxattr(self, path, name, value, size, options, *args):
342
 
        s = string_at(value, size)
343
 
        return self.operations('setxattr', path, name, s, options, *args)
 
382
        data = string_at(value, size)
 
383
        return self.operations('setxattr', path, name, data, options, *args)
344
384
    
345
385
    def getxattr(self, path, name, value, size, *args):
346
386
        ret = self.operations('getxattr', path, name, *args)
347
 
        buf = create_string_buffer(ret)
 
387
        retsize = len(ret)
 
388
        buf = create_string_buffer(ret, retsize)    # Does not add trailing 0
348
389
        if bool(value):
349
 
            memmove(value, buf, size)
350
 
        return len(ret)
 
390
            if retsize > size:
 
391
                return -ERANGE
 
392
            memmove(value, buf, retsize)
 
393
        return retsize
351
394
    
352
395
    def listxattr(self, path, namebuf, size):
353
396
        ret = self.operations('listxattr', path)
354
 
        if not ret:
355
 
            return 0
356
 
        buf = create_string_buffer('\x00'.join(ret))
 
397
        buf = create_string_buffer('\x00'.join(ret)) if ret else ''
 
398
        bufsize = len(buf)
357
399
        if bool(namebuf):
358
 
            memmove(namebuf, buf, size)
359
 
        return len(buf)
 
400
            if bufsize > size:
 
401
                return -ERANGE
 
402
            memmove(namebuf, buf, bufsize)
 
403
        return bufsize
360
404
    
361
405
    def removexattr(self, path, name):
362
406
        return self.operations('removexattr', path, name)
389
433
    def fsyncdir(self, path, datasync, fip):
390
434
        # Ignore raw_fi
391
435
        return self.operations('fsyncdir', path, datasync, fip.contents.fh)
392
 
        
 
436
    
 
437
    def init(self, conn):
 
438
        return self.operations('init', '/')
 
439
    
 
440
    def destroy(self, private_data):
 
441
        return self.operations('destroy', '/')
 
442
    
393
443
    def access(self, path, amode):
394
444
        return self.operations('access', path, amode)
395
445
    
430
480
        return self.operations('bmap', path, blocksize, idx)
431
481
 
432
482
 
433
 
from errno import EACCES, ENOENT
434
 
from stat import S_IFDIR
435
 
 
436
 
class Operations:
 
483
class Operations(object):
437
484
    """This class should be subclassed and passed as an argument to FUSE on
438
485
       initialization. All operations should raise an OSError exception on
439
486
       error.
452
499
    bmap = None
453
500
    
454
501
    def chmod(self, path, mode):
455
 
        raise OSError(EACCES, '')
 
502
        raise OSError(EROFS, '')
456
503
    
457
504
    def chown(self, path, uid, gid):
458
 
        raise OSError(EACCES, '')
 
505
        raise OSError(EROFS, '')
459
506
    
460
507
    def create(self, path, mode, fi=None):
461
508
        """When raw_fi is False (default case), fi is None and create should
462
509
           return a numerical file handle.
463
510
           When raw_fi is True the file handle should be set directly by create
464
511
           and return 0."""
465
 
        raise OSError(EACCES, '')
466
 
        
 
512
        raise OSError(EROFS, '')
 
513
    
 
514
    def destroy(self, path):
 
515
        """Called on filesystem destruction. Path is always /"""
 
516
        pass
 
517
    
467
518
    def flush(self, path, fh):
468
519
        return 0
469
520
    
488
539
    def getxattr(self, path, name, position=0):
489
540
        raise OSError(ENOTSUP, '')
490
541
    
 
542
    def init(self, path):
 
543
        """Called on filesystem initialization. Path is always /
 
544
           Use it instead of __init__ if you start threads on initialization."""
 
545
        pass
 
546
    
491
547
    def link(self, target, source):
492
 
        raise OSError(EACCES, '')
 
548
        raise OSError(EROFS, '')
493
549
    
494
550
    def listxattr(self, path):
495
551
        return []
497
553
    lock = None
498
554
    
499
555
    def mkdir(self, path, mode):
500
 
        raise OSError(EACCES, '')
 
556
        raise OSError(EROFS, '')
501
557
    
502
558
    def mknod(self, path, mode, dev):
503
 
        raise OSError(EACCES, '')
 
559
        raise OSError(EROFS, '')
504
560
    
505
561
    def open(self, path, flags):
506
562
        """When raw_fi is False (default case), open should return a numerical
516
572
    
517
573
    def read(self, path, size, offset, fh):
518
574
        """Returns a string containing the data requested."""
519
 
        raise OSError(EACCES, '')
 
575
        raise OSError(ENOENT, '')
520
576
    
521
577
    def readdir(self, path, fh):
522
578
        """Can return either a list of names, or a list of (name, attrs, offset)
524
580
        return ['.', '..']
525
581
    
526
582
    def readlink(self, path):
527
 
        raise OSError(EACCES, '')
 
583
        raise OSError(ENOENT, '')
528
584
    
529
585
    def release(self, path, fh):
530
586
        return 0
536
592
        raise OSError(ENOTSUP, '')
537
593
    
538
594
    def rename(self, old, new):
539
 
        raise OSError(EACCES, '')
 
595
        raise OSError(EROFS, '')
540
596
    
541
597
    def rmdir(self, path):
542
 
        raise OSError(EACCES, '')
 
598
        raise OSError(EROFS, '')
543
599
    
544
600
    def setxattr(self, path, name, value, options, position=0):
545
601
        raise OSError(ENOTSUP, '')
546
602
    
547
603
    def statfs(self, path):
548
604
        """Returns a dictionary with keys identical to the statvfs C structure
549
 
           of statvfs(3). The f_frsize, f_favail, f_fsid and f_flag fields are
550
 
           ignored by FUSE though."""
 
605
           of statvfs(3).
 
606
           On Mac OS X f_bsize and f_frsize must be a power of 2 (minimum 512)."""
551
607
        return {}
552
608
    
553
609
    def symlink(self, target, source):
554
 
        raise OSError(EACCES, '')
 
610
        raise OSError(EROFS, '')
555
611
    
556
612
    def truncate(self, path, length, fh=None):
557
 
        raise OSError(EACCES, '')
 
613
        raise OSError(EROFS, '')
558
614
    
559
615
    def unlink(self, path):
560
 
        raise OSError(EACCES, '')
 
616
        raise OSError(EROFS, '')
561
617
    
562
618
    def utimens(self, path, times=None):
563
619
        """Times is a (atime, mtime) tuple. If None use current time."""
564
620
        return 0
565
621
    
566
622
    def write(self, path, data, offset, fh):
567
 
        raise OSError(EACCES, '')
 
623
        raise OSError(EROFS, '')
568
624
 
569
625
 
570
626
class LoggingMixIn: