github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/lib/python/fusepy/fuse24.py (about) 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 platform import machine, system 21 from stat import S_IFDIR 22 from traceback import print_exc 23 24 25 class c_timespec(Structure): 26 _fields_ = [('tv_sec', c_long), ('tv_nsec', c_long)] 27 28 class c_utimbuf(Structure): 29 _fields_ = [('actime', c_timespec), ('modtime', c_timespec)] 30 31 class c_stat(Structure): 32 pass # Platform dependent 33 34 _system = system() 35 if _system in ('Darwin', 'FreeBSD'): 36 _libiconv = CDLL(find_library("iconv"), RTLD_GLOBAL) # libfuse dependency 37 ENOTSUP = 45 38 c_dev_t = c_int32 39 c_fsblkcnt_t = c_ulong 40 c_fsfilcnt_t = c_ulong 41 c_gid_t = c_uint32 42 c_mode_t = c_uint16 43 c_off_t = c_int64 44 c_pid_t = c_int32 45 c_uid_t = c_uint32 46 setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), 47 c_size_t, c_int, c_uint32) 48 getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), 49 c_size_t, c_uint32) 50 c_stat._fields_ = [ 51 ('st_dev', c_dev_t), 52 ('st_ino', c_uint32), 53 ('st_mode', c_mode_t), 54 ('st_nlink', c_uint16), 55 ('st_uid', c_uid_t), 56 ('st_gid', c_gid_t), 57 ('st_rdev', c_dev_t), 58 ('st_atimespec', c_timespec), 59 ('st_mtimespec', c_timespec), 60 ('st_ctimespec', c_timespec), 61 ('st_size', c_off_t), 62 ('st_blocks', c_int64), 63 ('st_blksize', c_int32)] 64 elif _system == 'Linux': 65 ENOTSUP = 95 66 c_dev_t = c_ulonglong 67 c_fsblkcnt_t = c_ulonglong 68 c_fsfilcnt_t = c_ulonglong 69 c_gid_t = c_uint 70 c_mode_t = c_uint 71 c_off_t = c_longlong 72 c_pid_t = c_int 73 c_uid_t = c_uint 74 setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t, c_int) 75 getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t) 76 77 _machine = machine() 78 if _machine == 'x86_64': 79 c_stat._fields_ = [ 80 ('st_dev', c_dev_t), 81 ('st_ino', c_ulong), 82 ('st_nlink', c_ulong), 83 ('st_mode', c_mode_t), 84 ('st_uid', c_uid_t), 85 ('st_gid', c_gid_t), 86 ('__pad0', c_int), 87 ('st_rdev', c_dev_t), 88 ('st_size', c_off_t), 89 ('st_blksize', c_long), 90 ('st_blocks', c_long), 91 ('st_atimespec', c_timespec), 92 ('st_mtimespec', c_timespec), 93 ('st_ctimespec', c_timespec)] 94 elif _machine == 'ppc': 95 c_stat._fields_ = [ 96 ('st_dev', c_dev_t), 97 ('st_ino', c_ulonglong), 98 ('st_mode', c_mode_t), 99 ('st_nlink', c_uint), 100 ('st_uid', c_uid_t), 101 ('st_gid', c_gid_t), 102 ('st_rdev', c_dev_t), 103 ('__pad2', c_ushort), 104 ('st_size', c_off_t), 105 ('st_blksize', c_long), 106 ('st_blocks', c_longlong), 107 ('st_atimespec', c_timespec), 108 ('st_mtimespec', c_timespec), 109 ('st_ctimespec', c_timespec)] 110 else: 111 # i686, use as fallback for everything else 112 c_stat._fields_ = [ 113 ('st_dev', c_dev_t), 114 ('__pad1', c_ushort), 115 ('__st_ino', c_ulong), 116 ('st_mode', c_mode_t), 117 ('st_nlink', c_uint), 118 ('st_uid', c_uid_t), 119 ('st_gid', c_gid_t), 120 ('st_rdev', c_dev_t), 121 ('__pad2', c_ushort), 122 ('st_size', c_off_t), 123 ('st_blksize', c_long), 124 ('st_blocks', c_longlong), 125 ('st_atimespec', c_timespec), 126 ('st_mtimespec', c_timespec), 127 ('st_ctimespec', c_timespec), 128 ('st_ino', c_ulonglong)] 129 else: 130 raise NotImplementedError('%s is not supported.' % _system) 131 132 133 class c_statvfs(Structure): 134 _fields_ = [ 135 ('f_bsize', c_ulong), 136 ('f_frsize', c_ulong), 137 ('f_blocks', c_fsblkcnt_t), 138 ('f_bfree', c_fsblkcnt_t), 139 ('f_bavail', c_fsblkcnt_t), 140 ('f_files', c_fsfilcnt_t), 141 ('f_ffree', c_fsfilcnt_t), 142 ('f_favail', c_fsfilcnt_t)] 143 144 if _system == 'FreeBSD': 145 c_fsblkcnt_t = c_uint64 146 c_fsfilcnt_t = c_uint64 147 setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t, c_int) 148 getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t) 149 class c_statvfs(Structure): 150 _fields_ = [ 151 ('f_bavail', c_fsblkcnt_t), 152 ('f_bfree', c_fsblkcnt_t), 153 ('f_blocks', c_fsblkcnt_t), 154 ('f_favail', c_fsfilcnt_t), 155 ('f_ffree', c_fsfilcnt_t), 156 ('f_files', c_fsfilcnt_t), 157 ('f_bsize', c_ulong), 158 ('f_flag', c_ulong), 159 ('f_frsize', c_ulong)] 160 161 class fuse_file_info(Structure): 162 _fields_ = [ 163 ('flags', c_int), 164 ('fh_old', c_ulong), 165 ('writepage', c_int), 166 ('direct_io', c_uint, 1), 167 ('keep_cache', c_uint, 1), 168 ('flush', c_uint, 1), 169 ('padding', c_uint, 29), 170 ('fh', c_uint64), 171 ('lock_owner', c_uint64)] 172 173 class fuse_context(Structure): 174 _fields_ = [ 175 ('fuse', c_voidp), 176 ('uid', c_uid_t), 177 ('gid', c_gid_t), 178 ('pid', c_pid_t), 179 ('private_data', c_voidp)] 180 181 class fuse_operations(Structure): 182 _fields_ = [ 183 ('getattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_stat))), 184 ('readlink', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t)), 185 ('getdir', c_voidp), # Deprecated, use readdir 186 ('mknod', CFUNCTYPE(c_int, c_char_p, c_mode_t, c_dev_t)), 187 ('mkdir', CFUNCTYPE(c_int, c_char_p, c_mode_t)), 188 ('unlink', CFUNCTYPE(c_int, c_char_p)), 189 ('rmdir', CFUNCTYPE(c_int, c_char_p)), 190 ('symlink', CFUNCTYPE(c_int, c_char_p, c_char_p)), 191 ('rename', CFUNCTYPE(c_int, c_char_p, c_char_p)), 192 ('link', CFUNCTYPE(c_int, c_char_p, c_char_p)), 193 ('chmod', CFUNCTYPE(c_int, c_char_p, c_mode_t)), 194 ('chown', CFUNCTYPE(c_int, c_char_p, c_uid_t, c_gid_t)), 195 ('truncate', CFUNCTYPE(c_int, c_char_p, c_off_t)), 196 ('utime', c_voidp), # Deprecated, use utimens 197 ('open', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))), 198 ('read', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t, c_off_t, 199 POINTER(fuse_file_info))), 200 ('write', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t, c_off_t, 201 POINTER(fuse_file_info))), 202 ('statfs', CFUNCTYPE(c_int, c_char_p, POINTER(c_statvfs))), 203 ('flush', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))), 204 ('release', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))), 205 ('fsync', CFUNCTYPE(c_int, c_char_p, c_int, POINTER(fuse_file_info))), 206 ('setxattr', setxattr_t), 207 ('getxattr', getxattr_t), 208 ('listxattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t)), 209 ('removexattr', CFUNCTYPE(c_int, c_char_p, c_char_p)), 210 ('opendir', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))), 211 ('readdir', CFUNCTYPE(c_int, c_char_p, c_voidp, CFUNCTYPE(c_int, c_voidp, 212 c_char_p, POINTER(c_stat), c_off_t), c_off_t, POINTER(fuse_file_info))), 213 ('releasedir', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))), 214 ('fsyncdir', CFUNCTYPE(c_int, c_char_p, c_int, POINTER(fuse_file_info))), 215 ('init', CFUNCTYPE(c_voidp, c_voidp)), 216 ('destroy', CFUNCTYPE(c_voidp, c_voidp)), 217 ('access', CFUNCTYPE(c_int, c_char_p, c_int)), 218 ('create', CFUNCTYPE(c_int, c_char_p, c_mode_t, POINTER(fuse_file_info))), 219 ('ftruncate', CFUNCTYPE(c_int, c_char_p, c_off_t, POINTER(fuse_file_info))), 220 ('fgetattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_stat), 221 POINTER(fuse_file_info))), 222 ('lock', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info), c_int, c_voidp)), 223 ('utimens', CFUNCTYPE(c_int, c_char_p, POINTER(c_utimbuf))), 224 ('bmap', CFUNCTYPE(c_int, c_char_p, c_size_t, POINTER(c_ulonglong)))] 225 226 227 def time_of_timespec(ts): 228 return ts.tv_sec + ts.tv_nsec / 10 ** 9 229 230 def set_st_attrs(st, attrs): 231 for key, val in attrs.items(): 232 if key in ('st_atime', 'st_mtime', 'st_ctime'): 233 timespec = getattr(st, key + 'spec') 234 timespec.tv_sec = int(val) 235 timespec.tv_nsec = int((val - timespec.tv_sec) * 10 ** 9) 236 elif hasattr(st, key): 237 setattr(st, key, val) 238 239 240 _libfuse_path = find_library('fuse') 241 if not _libfuse_path: 242 raise EnvironmentError('Unable to find libfuse') 243 _libfuse = CDLL(_libfuse_path) 244 _libfuse.fuse_get_context.restype = POINTER(fuse_context) 245 246 247 def fuse_get_context(): 248 """Returns a (uid, gid, pid) tuple""" 249 ctxp = _libfuse.fuse_get_context() 250 ctx = ctxp.contents 251 return ctx.uid, ctx.gid, ctx.pid 252 253 254 class FUSE(object): 255 """This class is the lower level interface and should not be subclassed 256 under normal use. Its methods are called by fuse. 257 Assumes API version 2.6 or later.""" 258 259 def __init__(self, operations, mountpoint, raw_fi=False, **kwargs): 260 """Setting raw_fi to True will cause FUSE to pass the fuse_file_info 261 class as is to Operations, instead of just the fh field. 262 This gives you access to direct_io, keep_cache, etc.""" 263 264 self.operations = operations 265 self.raw_fi = raw_fi 266 args = ['fuse'] 267 if kwargs.pop('foreground', False): 268 args.append('-f') 269 if kwargs.pop('debug', False): 270 args.append('-d') 271 if kwargs.pop('nothreads', False): 272 args.append('-s') 273 kwargs.setdefault('fsname', operations.__class__.__name__) 274 args.append('-o') 275 args.append(','.join(val is True and key or '%s=%s' % (key, val) 276 for key, val in kwargs.items())) 277 args.append(mountpoint) 278 argv = (c_char_p * len(args))(*args) 279 280 fuse_ops = fuse_operations() 281 for name, prototype in fuse_operations._fields_: 282 if prototype != c_voidp and getattr(operations, name, None): 283 op = self._create_wrapper_(getattr(self, name)) 284 setattr(fuse_ops, name, prototype(op)) 285 _libfuse.fuse_main_real(len(args), argv, pointer(fuse_ops), 286 sizeof(fuse_ops), None) 287 del self.operations # Invoke the destructor 288 289 @staticmethod 290 def _create_wrapper_(func): 291 def _wrapper_(*args, **kwargs): 292 """Decorator for the methods that follow""" 293 try: 294 return func(*args, **kwargs) or 0 295 except OSError, e: 296 return -(e.errno or EFAULT) 297 except: 298 print_exc() 299 return -EFAULT 300 return _wrapper_ 301 302 def getattr(self, path, buf): 303 return self.fgetattr(path, buf, None) 304 305 def readlink(self, path, buf, bufsize): 306 ret = self.operations('readlink', path) 307 data = create_string_buffer(ret[:bufsize - 1]) 308 memmove(buf, data, len(data)) 309 return 0 310 311 def mknod(self, path, mode, dev): 312 return self.operations('mknod', path, mode, dev) 313 314 def mkdir(self, path, mode): 315 return self.operations('mkdir', path, mode) 316 317 def unlink(self, path): 318 return self.operations('unlink', path) 319 320 def rmdir(self, path): 321 return self.operations('rmdir', path) 322 323 def symlink(self, source, target): 324 return self.operations('symlink', target, source) 325 326 def rename(self, old, new): 327 return self.operations('rename', old, new) 328 329 def link(self, source, target): 330 return self.operations('link', target, source) 331 332 def chmod(self, path, mode): 333 return self.operations('chmod', path, mode) 334 335 def chown(self, path, uid, gid): 336 return self.operations('chown', path, uid, gid) 337 338 def truncate(self, path, length): 339 return self.operations('truncate', path, length) 340 341 def open(self, path, fip): 342 fi = fip.contents 343 if self.raw_fi: 344 return self.operations('open', path, fi) 345 else: 346 fi.fh = self.operations('open', path, fi.flags) 347 return 0 348 349 def read(self, path, buf, size, offset, fip): 350 if self.raw_fi: 351 fh = fip.contents 352 else: 353 fh = fip.contents.fh 354 ret = self.operations('read', path, size, offset, fh) 355 if not ret: 356 return 0 357 data = create_string_buffer(ret[:size], size) 358 memmove(buf, data, size) 359 return size 360 361 def write(self, path, buf, size, offset, fip): 362 data = string_at(buf, size) 363 if self.raw_fi: 364 fh = fip.contents 365 else: 366 fh = fip.contents.fh 367 return self.operations('write', path, data, offset, fh) 368 369 def statfs(self, path, buf): 370 stv = buf.contents 371 attrs = self.operations('statfs', path) 372 for key, val in attrs.items(): 373 if hasattr(stv, key): 374 setattr(stv, key, val) 375 return 0 376 377 def flush(self, path, fip): 378 if self.raw_fi: 379 fh = fip.contents 380 else: 381 fh = fip.contents.fh 382 return self.operations('flush', path, fh) 383 384 def release(self, path, fip): 385 if self.raw_fi: 386 fh = fip.contents 387 else: 388 fh = fip.contents.fh 389 return self.operations('release', path, fh) 390 391 def fsync(self, path, datasync, fip): 392 if self.raw_fi: 393 fh = fip.contents 394 else: 395 fh = fip.contents.fh 396 return self.operations('fsync', path, datasync, fh) 397 398 def setxattr(self, path, name, value, size, options, *args): 399 data = string_at(value, size) 400 return self.operations('setxattr', path, name, data, options, *args) 401 402 def getxattr(self, path, name, value, size, *args): 403 ret = self.operations('getxattr', path, name, *args) 404 retsize = len(ret) 405 buf = create_string_buffer(ret, retsize) # Does not add trailing 0 406 if bool(value): 407 if retsize > size: 408 return -ERANGE 409 memmove(value, buf, retsize) 410 return retsize 411 412 def listxattr(self, path, namebuf, size): 413 ret = self.operations('listxattr', path) 414 if ret: 415 buf = create_string_buffer('\x00'.join(ret)) 416 else: 417 buf = '' 418 bufsize = len(buf) 419 if bool(namebuf): 420 if bufsize > size: 421 return -ERANGE 422 memmove(namebuf, buf, bufsize) 423 return bufsize 424 425 def removexattr(self, path, name): 426 return self.operations('removexattr', path, name) 427 428 def opendir(self, path, fip): 429 # Ignore raw_fi 430 fip.contents.fh = self.operations('opendir', path) 431 return 0 432 433 def readdir(self, path, buf, filler, offset, fip): 434 # Ignore raw_fi 435 for item in self.operations('readdir', path, fip.contents.fh): 436 if isinstance(item, str): 437 name, st, offset = item, None, 0 438 else: 439 name, attrs, offset = item 440 if attrs: 441 st = c_stat() 442 set_st_attrs(st, attrs) 443 else: 444 st = None 445 if filler(buf, name, st, offset) != 0: 446 break 447 return 0 448 449 def releasedir(self, path, fip): 450 # Ignore raw_fi 451 return self.operations('releasedir', path, fip.contents.fh) 452 453 def fsyncdir(self, path, datasync, fip): 454 # Ignore raw_fi 455 return self.operations('fsyncdir', path, datasync, fip.contents.fh) 456 457 def init(self, conn): 458 return self.operations('init', '/') 459 460 def destroy(self, private_data): 461 return self.operations('destroy', '/') 462 463 def access(self, path, amode): 464 return self.operations('access', path, amode) 465 466 def create(self, path, mode, fip): 467 fi = fip.contents 468 if self.raw_fi: 469 return self.operations('create', path, mode, fi) 470 else: 471 fi.fh = self.operations('create', path, mode) 472 return 0 473 474 def ftruncate(self, path, length, fip): 475 if self.raw_fi: 476 fh = fip.contents 477 else: 478 fh = fip.contents.fh 479 return self.operations('truncate', path, length, fh) 480 481 def fgetattr(self, path, buf, fip): 482 memset(buf, 0, sizeof(c_stat)) 483 st = buf.contents 484 if not fip: 485 fh = fip 486 elif self.raw_fi: 487 fh = fip.contents 488 else: 489 fh = fip.contents.fh 490 attrs = self.operations('getattr', path, fh) 491 set_st_attrs(st, attrs) 492 return 0 493 494 def lock(self, path, fip, cmd, lock): 495 if self.raw_fi: 496 fh = fip.contents 497 else: 498 fh = fip.contents.fh 499 return self.operations('lock', path, fh, cmd, lock) 500 501 def utimens(self, path, buf): 502 if buf: 503 atime = time_of_timespec(buf.contents.actime) 504 mtime = time_of_timespec(buf.contents.modtime) 505 times = (atime, mtime) 506 else: 507 times = None 508 return self.operations('utimens', path, times) 509 510 def bmap(self, path, blocksize, idx): 511 return self.operations('bmap', path, blocksize, idx) 512 513 514 class Operations(object): 515 """This class should be subclassed and passed as an argument to FUSE on 516 initialization. All operations should raise an OSError exception on 517 error. 518 519 When in doubt of what an operation should do, check the FUSE header 520 file or the corresponding system call man page.""" 521 522 def __call__(self, op, *args): 523 if not hasattr(self, op): 524 raise OSError(EFAULT, '') 525 return getattr(self, op)(*args) 526 527 def access(self, path, amode): 528 return 0 529 530 bmap = None 531 532 def chmod(self, path, mode): 533 raise OSError(EROFS, '') 534 535 def chown(self, path, uid, gid): 536 raise OSError(EROFS, '') 537 538 def create(self, path, mode, fi=None): 539 """When raw_fi is False (default case), fi is None and create should 540 return a numerical file handle. 541 When raw_fi is True the file handle should be set directly by create 542 and return 0.""" 543 raise OSError(EROFS, '') 544 545 def destroy(self, path): 546 """Called on filesystem destruction. Path is always /""" 547 pass 548 549 def flush(self, path, fh): 550 return 0 551 552 def fsync(self, path, datasync, fh): 553 return 0 554 555 def fsyncdir(self, path, datasync, fh): 556 return 0 557 558 def getattr(self, path, fh=None): 559 """Returns a dictionary with keys identical to the stat C structure 560 of stat(2). 561 st_atime, st_mtime and st_ctime should be floats. 562 NOTE: There is an incombatibility between Linux and Mac OS X concerning 563 st_nlink of directories. Mac OS X counts all files inside the directory, 564 while Linux counts only the subdirectories.""" 565 566 if path != '/': 567 raise OSError(ENOENT, '') 568 return dict(st_mode=(S_IFDIR | 0755), st_nlink=2) 569 570 def getxattr(self, path, name, position=0): 571 raise OSError(ENOTSUP, '') 572 573 def init(self, path): 574 """Called on filesystem initialization. Path is always / 575 Use it instead of __init__ if you start threads on initialization.""" 576 pass 577 578 def link(self, target, source): 579 raise OSError(EROFS, '') 580 581 def listxattr(self, path): 582 return [] 583 584 lock = None 585 586 def mkdir(self, path, mode): 587 raise OSError(EROFS, '') 588 589 def mknod(self, path, mode, dev): 590 raise OSError(EROFS, '') 591 592 def open(self, path, flags): 593 """When raw_fi is False (default case), open should return a numerical 594 file handle. 595 When raw_fi is True the signature of open becomes: 596 open(self, path, fi) 597 and the file handle should be set directly.""" 598 return 0 599 600 def opendir(self, path): 601 """Returns a numerical file handle.""" 602 return 0 603 604 def read(self, path, size, offset, fh): 605 """Returns a string containing the data requested.""" 606 raise OSError(ENOENT, '') 607 608 def readdir(self, path, fh): 609 """Can return either a list of names, or a list of (name, attrs, offset) 610 tuples. attrs is a dict as in getattr.""" 611 return ['.', '..'] 612 613 def readlink(self, path): 614 raise OSError(ENOENT, '') 615 616 def release(self, path, fh): 617 return 0 618 619 def releasedir(self, path, fh): 620 return 0 621 622 def removexattr(self, path, name): 623 raise OSError(ENOTSUP, '') 624 625 def rename(self, old, new): 626 raise OSError(EROFS, '') 627 628 def rmdir(self, path): 629 raise OSError(EROFS, '') 630 631 def setxattr(self, path, name, value, options, position=0): 632 raise OSError(ENOTSUP, '') 633 634 def statfs(self, path): 635 """Returns a dictionary with keys identical to the statvfs C structure 636 of statvfs(3). 637 On Mac OS X f_bsize and f_frsize must be a power of 2 (minimum 512).""" 638 return {} 639 640 def symlink(self, target, source): 641 raise OSError(EROFS, '') 642 643 def truncate(self, path, length, fh=None): 644 raise OSError(EROFS, '') 645 646 def unlink(self, path): 647 raise OSError(EROFS, '') 648 649 def utimens(self, path, times=None): 650 """Times is a (atime, mtime) tuple. If None use current time.""" 651 return 0 652 653 def write(self, path, data, offset, fh): 654 raise OSError(EROFS, '') 655 656 657 class LoggingMixIn: 658 def __call__(self, op, path, *args): 659 print '->', op, path, repr(args) 660 ret = '[Unknown Error]' 661 try: 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)