summaryrefslogtreecommitdiff
path: root/fuse.py
diff options
context:
space:
mode:
Diffstat (limited to 'fuse.py')
-rw-r--r--fuse.py518
1 files changed, 329 insertions, 189 deletions
diff --git a/fuse.py b/fuse.py
index e4e4c0e..2cea0c6 100644
--- a/fuse.py
+++ b/fuse.py
@@ -17,45 +17,60 @@ from __future__ import division
from ctypes import *
from ctypes.util import find_library
from errno import *
-from functools import partial
from os import strerror
from platform import machine, system
from signal import signal, SIGINT, SIG_DFL
from stat import S_IFDIR
from traceback import print_exc
+import logging
-__version__ = '1.1'
+try:
+ from functools import partial
+except ImportError:
+ # http://docs.python.org/library/functools.html#functools.partial
+ def partial(func, *args, **keywords):
+ def newfunc(*fargs, **fkeywords):
+ newkeywords = keywords.copy()
+ newkeywords.update(fkeywords)
+ return func(*(args + fargs), **newkeywords)
+
+ newfunc.func = func
+ newfunc.args = args
+ newfunc.keywords = keywords
+ return newfunc
+
+if not hasattr(__builtins__, 'basestring'):
+ basestring = str
+
+class c_timespec(Structure):
+ _fields_ = [('tv_sec', c_long), ('tv_nsec', c_long)]
+
+class c_utimbuf(Structure):
+ _fields_ = [('actime', c_timespec), ('modtime', c_timespec)]
+
+class c_stat(Structure):
+ pass # Platform dependent
_system = system()
_machine = machine()
if _system == 'Darwin':
- _libfuse_path = find_library('fuse4x') or find_library('osxfuse') or \
- find_library('fuse')
+ _libiconv = CDLL(find_library('iconv'), RTLD_GLOBAL) # libfuse dependency
+ _libfuse_path = (find_library('fuse4x') or find_library('osxfuse') or
+ find_library('fuse'))
else:
_libfuse_path = find_library('fuse')
+
if not _libfuse_path:
raise EnvironmentError('Unable to find libfuse')
-
-if _system == 'Darwin':
- _libiconv = CDLL(find_library('iconv'), RTLD_GLOBAL) # libfuse dependency
-_libfuse = CDLL(_libfuse_path)
+else:
+ _libfuse = CDLL(_libfuse_path)
if _system == 'Darwin' and hasattr(_libfuse, 'macfuse_version'):
_system = 'Darwin-MacFuse'
-class c_timespec(Structure):
- _fields_ = [('tv_sec', c_long), ('tv_nsec', c_long)]
-
-class c_utimbuf(Structure):
- _fields_ = [('actime', c_timespec), ('modtime', c_timespec)]
-
-class c_stat(Structure):
- pass # Platform dependent
-
-
if _system in ('Darwin', 'Darwin-MacFuse', 'FreeBSD'):
ENOTSUP = 45
c_dev_t = c_int32
@@ -115,9 +130,12 @@ elif _system == 'Linux':
c_off_t = c_longlong
c_pid_t = c_int
c_uid_t = c_uint
- setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t, c_int)
- getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t)
-
+ setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
+ c_size_t, c_int)
+
+ getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
+ c_size_t)
+
if _machine == 'x86_64':
c_stat._fields_ = [
('st_dev', c_dev_t),
@@ -187,8 +205,12 @@ class c_statvfs(Structure):
if _system == 'FreeBSD':
c_fsblkcnt_t = c_uint64
c_fsfilcnt_t = c_uint64
- setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t, c_int)
- getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), c_size_t)
+ setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
+ c_size_t, c_int)
+
+ getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte),
+ c_size_t)
+
class c_statvfs(Structure):
_fields_ = [
('f_bavail', c_fsblkcnt_t),
@@ -223,6 +245,7 @@ class fuse_context(Structure):
_libfuse.fuse_get_context.restype = POINTER(fuse_context)
+
class fuse_operations(Structure):
_fields_ = [
('getattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_stat))),
@@ -240,10 +263,13 @@ class fuse_operations(Structure):
('truncate', CFUNCTYPE(c_int, c_char_p, c_off_t)),
('utime', c_voidp), # Deprecated, use utimens
('open', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
- ('read', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t, c_off_t,
- POINTER(fuse_file_info))),
- ('write', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t, c_off_t,
- POINTER(fuse_file_info))),
+
+ ('read', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t,
+ c_off_t, POINTER(fuse_file_info))),
+
+ ('write', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t,
+ c_off_t, POINTER(fuse_file_info))),
+
('statfs', CFUNCTYPE(c_int, c_char_p, POINTER(c_statvfs))),
('flush', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
('release', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
@@ -253,20 +279,36 @@ class fuse_operations(Structure):
('listxattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t)),
('removexattr', CFUNCTYPE(c_int, c_char_p, c_char_p)),
('opendir', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
- ('readdir', CFUNCTYPE(c_int, c_char_p, c_voidp, CFUNCTYPE(c_int, c_voidp,
- c_char_p, POINTER(c_stat), c_off_t), c_off_t, POINTER(fuse_file_info))),
+
+ ('readdir', CFUNCTYPE(c_int, c_char_p, c_voidp,
+ CFUNCTYPE(c_int, c_voidp, c_char_p,
+ POINTER(c_stat), c_off_t),
+ c_off_t, POINTER(fuse_file_info))),
+
('releasedir', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info))),
- ('fsyncdir', CFUNCTYPE(c_int, c_char_p, c_int, POINTER(fuse_file_info))),
+
+ ('fsyncdir', CFUNCTYPE(c_int, c_char_p, c_int,
+ POINTER(fuse_file_info))),
+
('init', CFUNCTYPE(c_voidp, c_voidp)),
('destroy', CFUNCTYPE(c_voidp, c_voidp)),
('access', CFUNCTYPE(c_int, c_char_p, c_int)),
- ('create', CFUNCTYPE(c_int, c_char_p, c_mode_t, POINTER(fuse_file_info))),
- ('ftruncate', CFUNCTYPE(c_int, c_char_p, c_off_t, POINTER(fuse_file_info))),
+
+ ('create', CFUNCTYPE(c_int, c_char_p, c_mode_t,
+ POINTER(fuse_file_info))),
+
+ ('ftruncate', CFUNCTYPE(c_int, c_char_p, c_off_t,
+ POINTER(fuse_file_info))),
+
('fgetattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_stat),
- POINTER(fuse_file_info))),
- ('lock', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info), c_int, c_voidp)),
+ POINTER(fuse_file_info))),
+
+ ('lock', CFUNCTYPE(c_int, c_char_p, POINTER(fuse_file_info),
+ c_int, c_voidp)),
+
('utimens', CFUNCTYPE(c_int, c_char_p, POINTER(c_utimbuf))),
- ('bmap', CFUNCTYPE(c_int, c_char_p, c_size_t, POINTER(c_ulonglong)))]
+ ('bmap', CFUNCTYPE(c_int, c_char_p, c_size_t, POINTER(c_ulonglong))),
+ ]
def time_of_timespec(ts):
@@ -298,14 +340,18 @@ class FUSE(object):
"""This class is the lower level interface and should not be subclassed
under normal use. Its methods are called by fuse.
Assumes API version 2.6 or later."""
-
- def __init__(self, operations, mountpoint, raw_fi=False, **kwargs):
+
+ def __init__(self, operations, mountpoint, raw_fi=False, encoding='utf-8',
+ **kwargs):
+
"""Setting raw_fi to True will cause FUSE to pass the fuse_file_info
class as is to Operations, instead of just the fh field.
This gives you access to direct_io, keep_cache, etc."""
-
+
self.operations = operations
self.raw_fi = raw_fi
+ self.encoding = encoding
+
args = ['fuse']
if kwargs.pop('foreground', False):
args.append('-f')
@@ -315,29 +361,39 @@ class FUSE(object):
args.append('-s')
kwargs.setdefault('fsname', operations.__class__.__name__)
args.append('-o')
- args.append(','.join(key if val == True else '%s=%s' % (key, val)
- for key, val in kwargs.items()))
+ args.append(','.join(self._normalize_fuse_options(**kwargs)))
args.append(mountpoint)
+
+ args = [arg.encode(encoding) for arg in args]
argv = (c_char_p * len(args))(*args)
-
+
fuse_ops = fuse_operations()
for name, prototype in fuse_operations._fields_:
if prototype != c_voidp and getattr(operations, name, None):
- op = partial(self._wrapper_, getattr(self, name))
+ op = partial(self._wrapper, getattr(self, name))
setattr(fuse_ops, name, prototype(op))
-
+
old_handler = signal(SIGINT, SIG_DFL)
-
+
err = _libfuse.fuse_main_real(len(args), argv, pointer(fuse_ops),
sizeof(fuse_ops), None)
-
+
signal(SIGINT, old_handler)
-
+
del self.operations # Invoke the destructor
if err:
raise RuntimeError(err)
-
- def _wrapper_(self, func, *args, **kwargs):
+
+ @staticmethod
+ def _normalize_fuse_options(**kargs):
+ for key, value in kargs.items():
+ if isinstance(value, bool):
+ if value is True: yield key
+ else:
+ yield '%s=%s' % (key, value)
+
+ @staticmethod
+ def _wrapper(func, *args, **kwargs):
"""Decorator for the methods that follow"""
try:
return func(*args, **kwargs) or 0
@@ -346,129 +402,176 @@ class FUSE(object):
except:
print_exc()
return -EFAULT
-
+
def getattr(self, path, buf):
return self.fgetattr(path, buf, None)
-
+
def readlink(self, path, buf, bufsize):
- ret = self.operations('readlink', path)
+ ret = self.operations('readlink', path).encode(self.encoding)
data = create_string_buffer(ret[:bufsize - 1])
memmove(buf, data, len(data))
return 0
-
+
def mknod(self, path, mode, dev):
- return self.operations('mknod', path, mode, dev)
-
+ return self.operations('mknod', path.decode(self.encoding), mode, dev)
+
def mkdir(self, path, mode):
- return self.operations('mkdir', path, mode)
-
+ return self.operations('mkdir', path.decode(self.encoding), mode)
+
def unlink(self, path):
- return self.operations('unlink', path)
-
+ return self.operations('unlink', path.decode(self.encoding))
+
def rmdir(self, path):
- return self.operations('rmdir', path)
-
+ return self.operations('rmdir', path.decode(self.encoding))
+
def symlink(self, source, target):
- return self.operations('symlink', target, source)
-
+ return self.operations('symlink', target.decode(self.encoding),
+ source.decode(self.encoding))
+
def rename(self, old, new):
- return self.operations('rename', old, new)
-
+ return self.operations('rename', old.decode(self.encoding),
+ new.decode(self.encoding))
+
def link(self, source, target):
- return self.operations('link', target, source)
-
+ return self.operations('link', target.decode(self.encoding),
+ source.decode(self.encoding))
+
def chmod(self, path, mode):
- return self.operations('chmod', path, mode)
-
+ return self.operations('chmod', path.decode(self.encoding), mode)
+
def chown(self, path, uid, gid):
# Check if any of the arguments is a -1 that has overflowed
if c_uid_t(uid + 1).value == 0:
uid = -1
if c_gid_t(gid + 1).value == 0:
gid = -1
- return self.operations('chown', path, uid, gid)
-
+
+ return self.operations('chown', path.decode(self.encoding), uid, gid)
+
def truncate(self, path, length):
- return self.operations('truncate', path, length)
-
+ return self.operations('truncate', path.decode(self.encoding), length)
+
def open(self, path, fip):
fi = fip.contents
if self.raw_fi:
- return self.operations('open', path, fi)
+ return self.operations('open', path.decode(self.encoding), fi)
else:
- fi.fh = self.operations('open', path, fi.flags)
+ fi.fh = self.operations('open', path.decode(self.encoding),
+ fi.flags)
+
return 0
-
+
def read(self, path, buf, size, offset, fip):
- fh = fip.contents if self.raw_fi else fip.contents.fh
- ret = self.operations('read', path, size, offset, fh)
- if not ret:
- return 0
+ if self.raw_fi:
+ fh = fip.contents
+ else:
+ fh = fip.contents.fh
+
+ ret = self.operations('read', path.decode(self.encoding), size,
+ offset, fh)
+
+ if not ret: return 0
+
data = create_string_buffer(ret[:size], size)
memmove(buf, data, size)
return size
-
+
def write(self, path, buf, size, offset, fip):
data = string_at(buf, size)
- fh = fip.contents if self.raw_fi else fip.contents.fh
- return self.operations('write', path, data, offset, fh)
-
+
+ if self.raw_fi:
+ fh = fip.contents
+ else:
+ fh = fip.contents.fh
+
+ return self.operations('write', path.decode(self.encoding), data,
+ offset, fh)
+
def statfs(self, path, buf):
stv = buf.contents
- attrs = self.operations('statfs', path)
+ attrs = self.operations('statfs', path.decode(self.encoding))
for key, val in attrs.items():
if hasattr(stv, key):
setattr(stv, key, val)
+
return 0
-
+
def flush(self, path, fip):
- fh = fip.contents if self.raw_fi else fip.contents.fh
- return self.operations('flush', path, fh)
-
+ if self.raw_fi:
+ fh = fip.contents
+ else:
+ fh = fip.contents.fh
+
+ return self.operations('flush', path.decode(self.encoding), fh)
+
def release(self, path, fip):
- fh = fip.contents if self.raw_fi else fip.contents.fh
- return self.operations('release', path, fh)
-
+ if self.raw_fi:
+ fh = fip.contents
+ else:
+ fh = fip.contents.fh
+
+ return self.operations('release', path.decode(self.encoding), fh)
+
def fsync(self, path, datasync, fip):
- fh = fip.contents if self.raw_fi else fip.contents.fh
- return self.operations('fsync', path, datasync, fh)
-
+ if self.raw_fi:
+ fh = fip.contents
+ else:
+ fh = fip.contents.fh
+
+ return self.operations('fsync', path.decode(self.encoding), datasync,
+ fh)
+
def setxattr(self, path, name, value, size, options, *args):
data = string_at(value, size)
- return self.operations('setxattr', path, name, data, options, *args)
-
+ return self.operations('setxattr', path.decode(self.encoding),
+ name.decode(self.encoding),
+ data.decode(self.encoding), options, *args)
+
def getxattr(self, path, name, value, size, *args):
- ret = self.operations('getxattr', path, name, *args)
+ ret = self.operations('getxattr', path.decode(self.encoding),
+ name.decode(self.encoding), *args) \
+ .encode(self.encoding)
+
retsize = len(ret)
buf = create_string_buffer(ret, retsize) # Does not add trailing 0
- if bool(value):
- if retsize > size:
- return -ERANGE
+
+ if value:
+ if retsize > size: return -ERANGE
+
memmove(value, buf, retsize)
+
return retsize
-
+
def listxattr(self, path, namebuf, size):
- ret = self.operations('listxattr', path)
- buf = create_string_buffer('\x00'.join(ret)) if ret else ''
+ ret = '\x00'.join(self.operations('listxattr', path) or '') \
+ .encode(self.encoding)
+
+ buf = create_string_buffer(ret)
bufsize = len(buf)
- if bool(namebuf):
- if bufsize > size:
- return -ERANGE
+ if namebuf:
+ if bufsize > size: return -ERANGE
+
memmove(namebuf, buf, bufsize)
+
return bufsize
-
+
def removexattr(self, path, name):
- return self.operations('removexattr', path, name)
-
+ return self.operations('removexattr', path.decode(self.encoding),
+ name.decode(self.encoding))
+
def opendir(self, path, fip):
# Ignore raw_fi
- fip.contents.fh = self.operations('opendir', path)
+ fip.contents.fh = self.operations('opendir',
+ path.decode(self.encoding))
+
return 0
-
+
def readdir(self, path, buf, filler, offset, fip):
# Ignore raw_fi
- for item in self.operations('readdir', path, fip.contents.fh):
- if isinstance(item, str):
+ for item in self.operations('readdir', path.decode(self.encoding),
+ fip.contents.fh):
+
+ if isinstance(item, basestring):
name, st, offset = item, None, 0
else:
name, attrs, offset = item
@@ -477,51 +580,74 @@ class FUSE(object):
set_st_attrs(st, attrs)
else:
st = None
- if filler(buf, name, st, offset) != 0:
+
+ if filler(buf, name.encode(self.encoding), st, offset) != 0:
break
+
return 0
-
+
def releasedir(self, path, fip):
# Ignore raw_fi
- return self.operations('releasedir', path, fip.contents.fh)
-
+ return self.operations('releasedir', path.decode(self.encoding),
+ fip.contents.fh)
+
def fsyncdir(self, path, datasync, fip):
# Ignore raw_fi
- return self.operations('fsyncdir', path, datasync, fip.contents.fh)
-
+ return self.operations('fsyncdir', path.decode(self.encoding),
+ datasync, fip.contents.fh)
+
def init(self, conn):
return self.operations('init', '/')
-
+
def destroy(self, private_data):
return self.operations('destroy', '/')
-
+
def access(self, path, amode):
- return self.operations('access', path, amode)
-
+ return self.operations('access', path.decode(self.encoding), amode)
+
def create(self, path, mode, fip):
fi = fip.contents
+ path = path.decode(self.encoding)
+
if self.raw_fi:
return self.operations('create', path, mode, fi)
else:
fi.fh = self.operations('create', path, mode)
return 0
-
+
def ftruncate(self, path, length, fip):
- fh = fip.contents if self.raw_fi else fip.contents.fh
- return self.operations('truncate', path, length, fh)
-
+ if self.raw_fi:
+ fh = fip.contents
+ else:
+ fh = fip.contents.fh
+
+ return self.operations('truncate', path.decode(self.encoding),
+ length, fh)
+
def fgetattr(self, path, buf, fip):
memset(buf, 0, sizeof(c_stat))
+
st = buf.contents
- fh = fip and (fip.contents if self.raw_fi else fip.contents.fh)
- attrs = self.operations('getattr', path, fh)
+ if not fip:
+ fh = fip
+ elif self.raw_fi:
+ fh = fip.contents
+ else:
+ fh = fip.contents.fh
+
+ attrs = self.operations('getattr', path.decode(self.encoding), fh)
set_st_attrs(st, attrs)
return 0
-
+
def lock(self, path, fip, cmd, lock):
- fh = fip.contents if self.raw_fi else fip.contents.fh
- return self.operations('lock', path, fh, cmd, lock)
-
+ if self.raw_fi:
+ fh = fip.contents
+ else:
+ fh = fip.contents.fh
+
+ return self.operations('lock', path.decode(self.encoding), fh, cmd,
+ lock)
+
def utimens(self, path, buf):
if buf:
atime = time_of_timespec(buf.contents.actime)
@@ -529,158 +655,172 @@ class FUSE(object):
times = (atime, mtime)
else:
times = None
- return self.operations('utimens', path, times)
-
+
+ return self.operations('utimens', path.decode(self.encoding), times)
+
def bmap(self, path, blocksize, idx):
- return self.operations('bmap', path, blocksize, idx)
+ return self.operations('bmap', path.decode(self.encoding), blocksize,
+ idx)
class Operations(object):
"""This class should be subclassed and passed as an argument to FUSE on
initialization. All operations should raise a FuseOSError exception
on error.
-
+
When in doubt of what an operation should do, check the FUSE header
file or the corresponding system call man page."""
-
+
def __call__(self, op, *args):
if not hasattr(self, op):
raise FuseOSError(EFAULT)
return getattr(self, op)(*args)
-
+
def access(self, path, amode):
return 0
-
+
bmap = None
-
+
def chmod(self, path, mode):
raise FuseOSError(EROFS)
-
+
def chown(self, path, uid, gid):
raise FuseOSError(EROFS)
-
+
def create(self, path, mode, fi=None):
"""When raw_fi is False (default case), fi is None and create should
return a numerical file handle.
- When raw_fi is True the file handle should be set directly by create
- and return 0."""
+
+ When raw_fi is True the file handle should be set directly by
+ create and return 0."""
raise FuseOSError(EROFS)
-
+
def destroy(self, path):
"""Called on filesystem destruction. Path is always /"""
pass
-
+
def flush(self, path, fh):
return 0
-
+
def fsync(self, path, datasync, fh):
return 0
-
+
def fsyncdir(self, path, datasync, fh):
return 0
-
+
def getattr(self, path, fh=None):
"""Returns a dictionary with keys identical to the stat C structure
of stat(2).
+
st_atime, st_mtime and st_ctime should be floats.
- NOTE: There is an incombatibility between Linux and Mac OS X concerning
- st_nlink of directories. Mac OS X counts all files inside the directory,
- while Linux counts only the subdirectories."""
-
+
+ NOTE: There is an incombatibility between Linux and Mac OS X
+ concerning st_nlink of directories. Mac OS X counts all files
+ inside the directory, while Linux counts only the
+ subdirectories."""
+
if path != '/':
raise FuseOSError(ENOENT)
return dict(st_mode=(S_IFDIR | 0755), st_nlink=2)
-
+
def getxattr(self, path, name, position=0):
raise FuseOSError(ENOTSUP)
-
+
def init(self, path):
- """Called on filesystem initialization. Path is always /
- Use it instead of __init__ if you start threads on initialization."""
+ """Called on filesystem initialization. (Path is always /)
+
+ Use it instead of __init__ if you start threads on
+ initialization."""
pass
-
+
def link(self, target, source):
raise FuseOSError(EROFS)
-
+
def listxattr(self, path):
return []
-
+
lock = None
-
+
def mkdir(self, path, mode):
raise FuseOSError(EROFS)
-
+
def mknod(self, path, mode, dev):
raise FuseOSError(EROFS)
-
+
def open(self, path, flags):
- """When raw_fi is False (default case), open should return a numerical
- file handle.
+ """When raw_fi is False (default case), open should return a
+ numerical file handle.
+
When raw_fi is True the signature of open becomes:
open(self, path, fi)
+
and the file handle should be set directly."""
return 0
-
+
def opendir(self, path):
"""Returns a numerical file handle."""
return 0
-
+
def read(self, path, size, offset, fh):
"""Returns a string containing the data requested."""
raise FuseOSError(EIO)
-
+
def readdir(self, path, fh):
- """Can return either a list of names, or a list of (name, attrs, offset)
- tuples. attrs is a dict as in getattr."""
+ """Can return either a list of names, or a list of
+ (name, attrs, offset) tuples. attrs is a dict as in getattr."""
return ['.', '..']
-
+
def readlink(self, path):
raise FuseOSError(ENOENT)
-
+
def release(self, path, fh):
return 0
-
+
def releasedir(self, path, fh):
return 0
-
+
def removexattr(self, path, name):
raise FuseOSError(ENOTSUP)
-
+
def rename(self, old, new):
raise FuseOSError(EROFS)
-
+
def rmdir(self, path):
raise FuseOSError(EROFS)
-
+
def setxattr(self, path, name, value, options, position=0):
raise FuseOSError(ENOTSUP)
-
+
def statfs(self, path):
- """Returns a dictionary with keys identical to the statvfs C structure
- of statvfs(3).
- On Mac OS X f_bsize and f_frsize must be a power of 2 (minimum 512)."""
+ """Returns a dictionary with keys identical to the statvfs C
+ structure of statvfs(3).
+
+ On Mac OS X f_bsize and f_frsize must be a power of 2
+ (minimum 512)."""
return {}
-
+
def symlink(self, target, source):
raise FuseOSError(EROFS)
-
+
def truncate(self, path, length, fh=None):
raise FuseOSError(EROFS)
-
+
def unlink(self, path):
raise FuseOSError(EROFS)
-
+
def utimens(self, path, times=None):
"""Times is a (atime, mtime) tuple. If None use current time."""
return 0
-
+
def write(self, path, data, offset, fh):
raise FuseOSError(EROFS)
class LoggingMixIn:
+ log = logging.getLogger('fuse.log-mixin')
+
def __call__(self, op, path, *args):
- print '->', op, path, repr(args)
+ self.log.debug('-> %s %s %s', op, path, repr(args))
ret = '[Unhandled Exception]'
try:
ret = getattr(self, op)(path, *args)
@@ -689,4 +829,4 @@ class LoggingMixIn:
ret = str(e)
raise
finally:
- print '<-', op, repr(ret)
+ self.log.debug('<- %s %s', op, repr(ret))