Revision d50ed8d4 snf-pithos-tools/pithos/tools/lib/fuse.py

b/snf-pithos-tools/pithos/tools/lib/fuse.py
1 1
# Copyright (c) 2008 Giorgos Verigakis <verigak@gmail.com>
2
# 
2
#
3 3
# Permission to use, copy, modify, and distribute this software for any
4 4
# purpose with or without fee is hereby granted, provided that the above
5 5
# copyright notice and this permission notice appear in all copies.
6
# 
6
#
7 7
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 8
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 9
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
......
27 27
class c_timespec(Structure):
28 28
    _fields_ = [('tv_sec', c_long), ('tv_nsec', c_long)]
29 29

  
30

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

  
34

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

  
36 38
_system = system()
37 39
if _system in ('Darwin', 'FreeBSD'):
38
    _libiconv = CDLL(find_library("iconv"), RTLD_GLOBAL)     # libfuse dependency
40
    _libiconv = CDLL(
41
        find_library("iconv"), RTLD_GLOBAL)     # libfuse dependency
39 42
    ENOTSUP = 45
40 43
    c_dev_t = c_int32
41 44
    c_fsblkcnt_t = c_ulong
......
46 49
    c_pid_t = c_int32
47 50
    c_uid_t = c_uint32
48 51
    setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
49
        c_size_t, c_int, c_uint32)
52
                           c_size_t, c_int, c_uint32)
50 53
    getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
51
        c_size_t, c_uint32)
54
                           c_size_t, c_uint32)
52 55
    c_stat._fields_ = [
53 56
        ('st_dev', c_dev_t),
54 57
        ('st_ino', c_uint32),
......
73 76
    c_off_t = c_longlong
74 77
    c_pid_t = c_int
75 78
    c_uid_t = c_uint
76
    setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t, c_int)
77
    getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t)
78
    
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

  
79 84
    _machine = machine()
80 85
    if _machine == 'x86_64':
81 86
        c_stat._fields_ = [
......
146 151
if _system == 'FreeBSD':
147 152
    c_fsblkcnt_t = c_uint64
148 153
    c_fsfilcnt_t = c_uint64
149
    setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t, c_int)
150
    getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t)
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

  
151 159
    class c_statvfs(Structure):
152 160
        _fields_ = [
153 161
            ('f_bavail', c_fsblkcnt_t),
......
160 168
            ('f_flag', c_ulong),
161 169
            ('f_frsize', c_ulong)]
162 170

  
171

  
163 172
class fuse_file_info(Structure):
164 173
    _fields_ = [
165 174
        ('flags', c_int),
......
172 181
        ('fh', c_uint64),
173 182
        ('lock_owner', c_uint64)]
174 183

  
184

  
175 185
class fuse_context(Structure):
176 186
    _fields_ = [
177 187
        ('fuse', c_voidp),
......
180 190
        ('pid', c_pid_t),
181 191
        ('private_data', c_voidp)]
182 192

  
193

  
183 194
class fuse_operations(Structure):
184 195
    _fields_ = [
185 196
        ('getattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_stat))),
......
198 209
        ('utime', c_voidp),     # Deprecated, use utimens
199 210
        ('open', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
200 211
        ('read', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t, c_off_t,
201
            POINTER(fuse_file_info))),
202
        ('write', 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,
203 215
            POINTER(fuse_file_info))),
204 216
        ('statfs', CFUNCTYPE(c_int, c_char_p, POINTER(c_statvfs))),
205 217
        ('flush', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
......
210 222
        ('listxattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t)),
211 223
        ('removexattr', CFUNCTYPE(c_int, c_char_p, c_char_p)),
212 224
        ('opendir', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
213
        ('readdir', CFUNCTYPE(c_int, c_char_p, c_voidp, CFUNCTYPE(c_int, c_voidp,
214
            c_char_p, POINTER(c_stat), c_off_t), c_off_t, 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))),
215 229
        ('releasedir', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
216
        ('fsyncdir', CFUNCTYPE(c_int, c_char_p, c_int, POINTER(fuse_file_info))),
230
        ('fsyncdir', CFUNCTYPE(c_int, c_char_p, c_int, POINTER(
231
            fuse_file_info))),
217 232
        ('init', CFUNCTYPE(c_voidp, c_voidp)),
218 233
        ('destroy', CFUNCTYPE(c_voidp, c_voidp)),
219 234
        ('access', CFUNCTYPE(c_int, c_char_p, c_int)),
220
        ('create', CFUNCTYPE(c_int, c_char_p, c_mode_t, POINTER(fuse_file_info))),
221
        ('ftruncate', CFUNCTYPE(c_int, c_char_p, c_off_t, POINTER(fuse_file_info))),
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))),
222 239
        ('fgetattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_stat),
223
            POINTER(fuse_file_info))),
224
        ('lock', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info), c_int, c_voidp)),
240
                               POINTER(fuse_file_info))),
241
        ('lock', CFUNCTYPE(
242
            c_int, c_char_p, POINTER(fuse_file_info), c_int, c_voidp)),
225 243
        ('utimens', CFUNCTYPE(c_int, c_char_p, POINTER(c_utimbuf))),
226 244
        ('bmap', CFUNCTYPE(c_int, c_char_p, c_size_t, POINTER(c_ulonglong)))]
227 245

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

  
250

  
232 251
def set_st_attrs(st, attrs):
233 252
    for key, val in attrs.items():
234 253
        if key in ('st_atime', 'st_mtime', 'st_ctime'):
......
262 281
    """This class is the lower level interface and should not be subclassed
263 282
       under normal use. Its methods are called by fuse.
264 283
       Assumes API version 2.6 or later."""
265
    
284

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

  
271 290
        self.operations = operations
272 291
        self.raw_fi = raw_fi
273 292
        args = ['fuse']
......
280 299
        kwargs.setdefault('fsname', operations.__class__.__name__)
281 300
        args.append('-o')
282 301
        args.append(','.join(key if val == True else '%s=%s' % (key, val)
283
            for key, val in kwargs.items()))
302
                             for key, val in kwargs.items()))
284 303
        args.append(mountpoint)
285 304
        argv = (c_char_p * len(args))(*args)
286
        
305

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

  
298 317
    def _wrapper_(self, func, *args, **kwargs):
299 318
        """Decorator for the methods that follow"""
300 319
        try:
......
304 323
        except:
305 324
            print_exc()
306 325
            return -EFAULT
307
    
326

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

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

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

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

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

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

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

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

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

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

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

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

  
352 371
    def open(self, path, fip):
353 372
        fi = fip.contents
354 373
        if self.raw_fi:
......
356 375
        else:
357 376
            fi.fh = self.operations('open', path, fi.flags)
358 377
            return 0
359
    
378

  
360 379
    def read(self, path, buf, size, offset, fip):
361 380
        fh = fip.contents if self.raw_fi else fip.contents.fh
362 381
        ret = self.operations('read', path, size, offset, fh)
......
365 384
        data = create_string_buffer(ret[:size], size)
366 385
        memmove(buf, data, size)
367 386
        return size
368
    
387

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

  
374 393
    def statfs(self, path, buf):
375 394
        stv = buf.contents
376 395
        attrs = self.operations('statfs', path)
......
378 397
            if hasattr(stv, key):
379 398
                setattr(stv, key, val)
380 399
        return 0
381
    
400

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

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

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

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

  
398 417
    def getxattr(self, path, name, value, size, *args):
399 418
        ret = self.operations('getxattr', path, name, *args)
400 419
        retsize = len(ret)
......
404 423
                return -ERANGE
405 424
            memmove(value, buf, retsize)
406 425
        return retsize
407
    
426

  
408 427
    def listxattr(self, path, namebuf, size):
409 428
        ret = self.operations('listxattr', path)
410 429
        buf = create_string_buffer('\x00'.join(ret)) if ret else ''
......
414 433
                return -ERANGE
415 434
            memmove(namebuf, buf, bufsize)
416 435
        return bufsize
417
    
436

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

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

  
426 445
    def readdir(self, path, buf, filler, offset, fip):
427 446
        # Ignore raw_fi
428 447
        for item in self.operations('readdir', path, fip.contents.fh):
......
438 457
            if filler(buf, name, st, offset) != 0:
439 458
                break
440 459
        return 0
441
    
460

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

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

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

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

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

  
459 478
    def create(self, path, mode, fip):
460 479
        fi = fip.contents
461 480
        if self.raw_fi:
......
463 482
        else:
464 483
            fi.fh = self.operations('create', path, mode)
465 484
            return 0
466
    
485

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

  
471 490
    def fgetattr(self, path, buf, fip):
472 491
        memset(buf, 0, sizeof(c_stat))
473 492
        st = buf.contents
......
475 494
        attrs = self.operations('getattr', path, fh)
476 495
        set_st_attrs(st, attrs)
477 496
        return 0
478
    
497

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

  
483 502
    def utimens(self, path, buf):
484 503
        if buf:
485 504
            atime = time_of_timespec(buf.contents.actime)
......
488 507
        else:
489 508
            times = None
490 509
        return self.operations('utimens', path, times)
491
    
510

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

  
......
497 516
    """This class should be subclassed and passed as an argument to FUSE on
498 517
       initialization. All operations should raise a FuseOSError exception
499 518
       on error.
500
       
519

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

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

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

  
512 531
    bmap = None
513
    
532

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

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

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

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

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

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

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

  
540 559
    def getattr(self, path, fh=None):
541 560
        """Returns a dictionary with keys identical to the stat C structure
542 561
           of stat(2).
......
544 563
           NOTE: There is an incombatibility between Linux and Mac OS X concerning
545 564
           st_nlink of directories. Mac OS X counts all files inside the directory,
546 565
           while Linux counts only the subdirectories."""
547
        
566

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

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

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

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

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

  
566 585
    lock = None
567
    
586

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

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

  
574 593
    def open(self, path, flags):
575 594
        """When raw_fi is False (default case), open should return a numerical
576 595
           file handle.
......
578 597
               open(self, path, fi)
579 598
           and the file handle should be set directly."""
580 599
        return 0
581
    
600

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  

Also available in: Unified diff