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)