diff options
| author | Terence Honles <terence@honles.com> | 2012-04-24 12:43:31 -0700 |
|---|---|---|
| committer | Terence Honles <terence@honles.com> | 2012-04-24 12:43:38 -0700 |
| commit | 5e9a1154cbda06c8ff39c80dcbd1fd70744140c5 (patch) | |
| tree | 5f50cb3a919973355cac0379e2c679b58a15078f | |
| parent | 7457fb93236222c7786e5fb468a3ff1732abbaa9 (diff) | |
| parent | 28658053cf8d9b5f25bb3e376346b06171aa4d19 (diff) | |
| download | fusepy-5e9a1154cbda06c8ff39c80dcbd1fd70744140c5.tar.gz | |
consolidating all the fuse versions into one file + organization
- consolidating all the fuse versions for maintenance reasons, the
syntax is py3k as long as it doesn't break py2k, and then using 2to3
to fix any minor issues (number literals and exceptions)
- examples are all moved into example subdirectory
| -rw-r--r-- | .gitignore | 11 | ||||
| l--------- | README | 1 | ||||
| -rw-r--r-- | README.rst | 47 | ||||
| -rw-r--r-- | __init__.py | 8 | ||||
| -rwxr-xr-x | examples/context.py (renamed from context.py) | 0 | ||||
| -rwxr-xr-x | examples/loopback.py (renamed from loopback.py) | 0 | ||||
| -rwxr-xr-x | examples/memory.py (renamed from memory.py) | 0 | ||||
| -rwxr-xr-x | examples/memory3.py (renamed from memory3.py) | 0 | ||||
| -rwxr-xr-x | examples/memoryll.py (renamed from memoryll.py) | 0 | ||||
| -rwxr-xr-x | examples/sftp.py (renamed from sftp.py) | 0 | ||||
| -rw-r--r-- | fuse.py | 518 | ||||
| -rw-r--r-- | fuse24.py | 669 | ||||
| -rw-r--r-- | fuse3.py | 637 | ||||
| -rwxr-xr-x | setup.py | 44 |
14 files changed, 423 insertions, 1512 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c7940cf --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +*.py[oc] +*~ +*.swp +/bin +/include +/lib +/lib64 +/system +/build +/dist +/fusepy.egg-info @@ -0,0 +1 @@ +README.rst
\ No newline at end of file diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..beff1d8 --- /dev/null +++ b/README.rst @@ -0,0 +1,47 @@ +fusepy +====== + +``fusepy`` is a Python module that provides a simple interface to FUSE_ and +MacFUSE_. It's just one file and is implemented using ctypes. + +The official version of ``fusepy`` is hosted on `Google Code`_, but was split +into 3 seperate files: fuse24.py, fuse.py, and fuse3.py. These versions were +for <Python2.5, <Python3.x, and Python3.x respectively. Unfortunately they were +not all maintained, and installing the package in Python3 did not work. + +This repo mereges bits from all 3 files and combines them into one file. The +file is written in 2x syntax, but trying to pay attention to bytes and other +changes 3x would care about. The only incompatible changes between 2x and 3x +are the change in syntax for number literals and exceptions. These issues are +fixed using the 2to3 tool when installing the package, or runnning:: + + 2to3 -f numliterals -f except -w fuse.py + + +examples +-------- +See some examples of how you can use fusepy: + +:memory_: A simple memory filesystem +:loopback_: A loopback filesystem +:context_: Sample usage of fuse_get_context() +:sftp_: A simple SFTP filesystem (requires paramiko) + +To get started download_ fusepy or just browse the source_. + +fusepy requires FUSE 2.6 (or later) and runs on: + +- Linux (i386, x86_64, PPC) +- Mac OS X (Intel, PowerPC) +- FreeBSD (i386, amd64) + + +.. _FUSE: http://fuse.sourceforge.net/ +.. _MacFUSE: http://code.google.com/p/macfuse/ +.. _`Google Code`: http://code.google.com/p/fusepy/ +.. _memory: http://github.com/terencehonles/fusepy/tree/master/examples/memory.py +.. _loopback: http://github.com/terencehonles/fusepy/tree/master/examples/loopback.py +.. _context: http://github.com/terencehonles/fusepy/tree/master/examples/context.py +.. _sftp: http://github.com/terencehonles/fusepy/tree/master/examples/sftp.py +.. _download: https://github.com/terencehonles/fusepy/zipball/master +.. _source: http://github.com/terencehonles/fusepy/tree/master/ diff --git a/__init__.py b/__init__.py deleted file mode 100644 index 4f327c1..0000000 --- a/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -import sys -pyver = sys.version_info[0:2] -if pyver <= (2, 4): - from fuse24 import * -elif pyver >= (3, 0): - from fuse3 import * -else: - from fuse import * diff --git a/context.py b/examples/context.py index 2609aa0..2609aa0 100755 --- a/context.py +++ b/examples/context.py diff --git a/loopback.py b/examples/loopback.py index 5ce16ed..5ce16ed 100755 --- a/loopback.py +++ b/examples/loopback.py diff --git a/memory.py b/examples/memory.py index 246b305..246b305 100755 --- a/memory.py +++ b/examples/memory.py diff --git a/memory3.py b/examples/memory3.py index e5cbad7..e5cbad7 100755 --- a/memory3.py +++ b/examples/memory3.py diff --git a/memoryll.py b/examples/memoryll.py index 307a1af..307a1af 100755 --- a/memoryll.py +++ b/examples/memoryll.py diff --git a/sftp.py b/examples/sftp.py index 019fb29..019fb29 100755 --- a/sftp.py +++ b/examples/sftp.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)) diff --git a/fuse24.py b/fuse24.py deleted file mode 100644 index 8c20679..0000000 --- a/fuse24.py +++ /dev/null @@ -1,669 +0,0 @@ -# Copyright (c) 2008 Giorgos Verigakis <verigak@gmail.com> -# -# Permission to use, copy, modify, and distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -from __future__ import division - -from ctypes import * -from ctypes.util import find_library -from errno import * -from platform import machine, system -from stat import S_IFDIR -from traceback import print_exc - - -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() -if _system in ('Darwin', 'FreeBSD'): - _libiconv = CDLL(find_library("iconv"), RTLD_GLOBAL) # libfuse dependency - ENOTSUP = 45 - c_dev_t = c_int32 - c_fsblkcnt_t = c_ulong - c_fsfilcnt_t = c_ulong - c_gid_t = c_uint32 - c_mode_t = c_uint16 - c_off_t = c_int64 - c_pid_t = c_int32 - c_uid_t = c_uint32 - setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), - c_size_t, c_int, c_uint32) - getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), - c_size_t, c_uint32) - c_stat._fields_ = [ - ('st_dev', c_dev_t), - ('st_ino', c_uint32), - ('st_mode', c_mode_t), - ('st_nlink', c_uint16), - ('st_uid', c_uid_t), - ('st_gid', c_gid_t), - ('st_rdev', c_dev_t), - ('st_atimespec', c_timespec), - ('st_mtimespec', c_timespec), - ('st_ctimespec', c_timespec), - ('st_size', c_off_t), - ('st_blocks', c_int64), - ('st_blksize', c_int32)] -elif _system == 'Linux': - ENOTSUP = 95 - c_dev_t = c_ulonglong - c_fsblkcnt_t = c_ulonglong - c_fsfilcnt_t = c_ulonglong - c_gid_t = c_uint - c_mode_t = c_uint - 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) - - _machine = machine() - if _machine == 'x86_64': - c_stat._fields_ = [ - ('st_dev', c_dev_t), - ('st_ino', c_ulong), - ('st_nlink', c_ulong), - ('st_mode', c_mode_t), - ('st_uid', c_uid_t), - ('st_gid', c_gid_t), - ('__pad0', c_int), - ('st_rdev', c_dev_t), - ('st_size', c_off_t), - ('st_blksize', c_long), - ('st_blocks', c_long), - ('st_atimespec', c_timespec), - ('st_mtimespec', c_timespec), - ('st_ctimespec', c_timespec)] - elif _machine == 'ppc': - c_stat._fields_ = [ - ('st_dev', c_dev_t), - ('st_ino', c_ulonglong), - ('st_mode', c_mode_t), - ('st_nlink', c_uint), - ('st_uid', c_uid_t), - ('st_gid', c_gid_t), - ('st_rdev', c_dev_t), - ('__pad2', c_ushort), - ('st_size', c_off_t), - ('st_blksize', c_long), - ('st_blocks', c_longlong), - ('st_atimespec', c_timespec), - ('st_mtimespec', c_timespec), - ('st_ctimespec', c_timespec)] - else: - # i686, use as fallback for everything else - c_stat._fields_ = [ - ('st_dev', c_dev_t), - ('__pad1', c_ushort), - ('__st_ino', c_ulong), - ('st_mode', c_mode_t), - ('st_nlink', c_uint), - ('st_uid', c_uid_t), - ('st_gid', c_gid_t), - ('st_rdev', c_dev_t), - ('__pad2', c_ushort), - ('st_size', c_off_t), - ('st_blksize', c_long), - ('st_blocks', c_longlong), - ('st_atimespec', c_timespec), - ('st_mtimespec', c_timespec), - ('st_ctimespec', c_timespec), - ('st_ino', c_ulonglong)] -else: - raise NotImplementedError('%s is not supported.' % _system) - - -class c_statvfs(Structure): - _fields_ = [ - ('f_bsize', c_ulong), - ('f_frsize', c_ulong), - ('f_blocks', c_fsblkcnt_t), - ('f_bfree', c_fsblkcnt_t), - ('f_bavail', c_fsblkcnt_t), - ('f_files', c_fsfilcnt_t), - ('f_ffree', c_fsfilcnt_t), - ('f_favail', c_fsfilcnt_t)] - -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) - class c_statvfs(Structure): - _fields_ = [ - ('f_bavail', c_fsblkcnt_t), - ('f_bfree', c_fsblkcnt_t), - ('f_blocks', c_fsblkcnt_t), - ('f_favail', c_fsfilcnt_t), - ('f_ffree', c_fsfilcnt_t), - ('f_files', c_fsfilcnt_t), - ('f_bsize', c_ulong), - ('f_flag', c_ulong), - ('f_frsize', c_ulong)] - -class fuse_file_info(Structure): - _fields_ = [ - ('flags', c_int), - ('fh_old', c_ulong), - ('writepage', c_int), - ('direct_io', c_uint, 1), - ('keep_cache', c_uint, 1), - ('flush', c_uint, 1), - ('padding', c_uint, 29), - ('fh', c_uint64), - ('lock_owner', c_uint64)] - -class fuse_context(Structure): - _fields_ = [ - ('fuse', c_voidp), - ('uid', c_uid_t), - ('gid', c_gid_t), - ('pid', c_pid_t), - ('private_data', c_voidp)] - -class fuse_operations(Structure): - _fields_ = [ - ('getattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_stat))), - ('readlink', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t)), - ('getdir', c_voidp), # Deprecated, use readdir - ('mknod', CFUNCTYPE(c_int, c_char_p, c_mode_t, c_dev_t)), - ('mkdir', CFUNCTYPE(c_int, c_char_p, c_mode_t)), - ('unlink', CFUNCTYPE(c_int, c_char_p)), - ('rmdir', CFUNCTYPE(c_int, c_char_p)), - ('symlink', CFUNCTYPE(c_int, c_char_p, c_char_p)), - ('rename', CFUNCTYPE(c_int, c_char_p, c_char_p)), - ('link', CFUNCTYPE(c_int, c_char_p, c_char_p)), - ('chmod', CFUNCTYPE(c_int, c_char_p, c_mode_t)), - ('chown', CFUNCTYPE(c_int, c_char_p, c_uid_t, c_gid_t)), - ('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))), - ('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))), - ('fsync', CFUNCTYPE(c_int, c_char_p, c_int, POINTER(fuse_file_info))), - ('setxattr', setxattr_t), - ('getxattr', getxattr_t), - ('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))), - ('releasedir', CFUNCTYPE(c_int, c_char_p, 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))), - ('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)), - ('utimens', CFUNCTYPE(c_int, c_char_p, POINTER(c_utimbuf))), - ('bmap', CFUNCTYPE(c_int, c_char_p, c_size_t, POINTER(c_ulonglong)))] - - -def time_of_timespec(ts): - return ts.tv_sec + ts.tv_nsec / 10 ** 9 - -def set_st_attrs(st, attrs): - for key, val in attrs.items(): - if key in ('st_atime', 'st_mtime', 'st_ctime'): - timespec = getattr(st, key + 'spec') - timespec.tv_sec = int(val) - timespec.tv_nsec = int((val - timespec.tv_sec) * 10 ** 9) - elif hasattr(st, key): - setattr(st, key, val) - - -_libfuse_path = find_library('fuse') -if not _libfuse_path: - raise EnvironmentError('Unable to find libfuse') -_libfuse = CDLL(_libfuse_path) -_libfuse.fuse_get_context.restype = POINTER(fuse_context) - - -def fuse_get_context(): - """Returns a (uid, gid, pid) tuple""" - ctxp = _libfuse.fuse_get_context() - ctx = ctxp.contents - return ctx.uid, ctx.gid, ctx.pid - - -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): - """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 - args = ['fuse'] - if kwargs.pop('foreground', False): - args.append('-f') - if kwargs.pop('debug', False): - args.append('-d') - if kwargs.pop('nothreads', False): - args.append('-s') - kwargs.setdefault('fsname', operations.__class__.__name__) - args.append('-o') - args.append(','.join(val is True and key or '%s=%s' % (key, val) - for key, val in kwargs.items())) - args.append(mountpoint) - 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 = self._create_wrapper_(getattr(self, name)) - setattr(fuse_ops, name, prototype(op)) - _libfuse.fuse_main_real(len(args), argv, pointer(fuse_ops), - sizeof(fuse_ops), None) - del self.operations # Invoke the destructor - - @staticmethod - def _create_wrapper_(func): - def _wrapper_(*args, **kwargs): - """Decorator for the methods that follow""" - try: - return func(*args, **kwargs) or 0 - except OSError, e: - return -(e.errno or EFAULT) - except: - print_exc() - return -EFAULT - return _wrapper_ - - def getattr(self, path, buf): - return self.fgetattr(path, buf, None) - - def readlink(self, path, buf, bufsize): - ret = self.operations('readlink', path) - 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) - - def mkdir(self, path, mode): - return self.operations('mkdir', path, mode) - - def unlink(self, path): - return self.operations('unlink', path) - - def rmdir(self, path): - return self.operations('rmdir', path) - - def symlink(self, source, target): - return self.operations('symlink', target, source) - - def rename(self, old, new): - return self.operations('rename', old, new) - - def link(self, source, target): - return self.operations('link', target, source) - - def chmod(self, path, mode): - return self.operations('chmod', path, mode) - - def chown(self, path, uid, gid): - return self.operations('chown', path, uid, gid) - - def truncate(self, path, length): - return self.operations('truncate', path, length) - - def open(self, path, fip): - fi = fip.contents - if self.raw_fi: - return self.operations('open', path, fi) - else: - fi.fh = self.operations('open', path, fi.flags) - return 0 - - def read(self, path, buf, size, offset, fip): - if self.raw_fi: - fh = fip.contents - else: - fh = fip.contents.fh - ret = self.operations('read', path, 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) - if self.raw_fi: - fh = fip.contents - else: - fh = fip.contents.fh - return self.operations('write', path, data, offset, fh) - - def statfs(self, path, buf): - stv = buf.contents - attrs = self.operations('statfs', path) - for key, val in attrs.items(): - if hasattr(stv, key): - setattr(stv, key, val) - return 0 - - def flush(self, path, fip): - if self.raw_fi: - fh = fip.contents - else: - fh = fip.contents.fh - return self.operations('flush', path, fh) - - def release(self, path, fip): - if self.raw_fi: - fh = fip.contents - else: - fh = fip.contents.fh - return self.operations('release', path, fh) - - def fsync(self, path, datasync, fip): - if self.raw_fi: - fh = fip.contents - else: - fh = fip.contents.fh - return self.operations('fsync', path, 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) - - def getxattr(self, path, name, value, size, *args): - ret = self.operations('getxattr', path, name, *args) - retsize = len(ret) - buf = create_string_buffer(ret, retsize) # Does not add trailing 0 - if bool(value): - if retsize > size: - return -ERANGE - memmove(value, buf, retsize) - return retsize - - def listxattr(self, path, namebuf, size): - ret = self.operations('listxattr', path) - if ret: - buf = create_string_buffer('\x00'.join(ret)) - else: - buf = '' - bufsize = len(buf) - if bool(namebuf): - if bufsize > size: - return -ERANGE - memmove(namebuf, buf, bufsize) - return bufsize - - def removexattr(self, path, name): - return self.operations('removexattr', path, name) - - def opendir(self, path, fip): - # Ignore raw_fi - fip.contents.fh = self.operations('opendir', path) - 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): - name, st, offset = item, None, 0 - else: - name, attrs, offset = item - if attrs: - st = c_stat() - set_st_attrs(st, attrs) - else: - st = None - if filler(buf, name, st, offset) != 0: - break - return 0 - - def releasedir(self, path, fip): - # Ignore raw_fi - return self.operations('releasedir', path, fip.contents.fh) - - def fsyncdir(self, path, datasync, fip): - # Ignore raw_fi - return self.operations('fsyncdir', path, 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) - - def create(self, path, mode, fip): - fi = fip.contents - 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): - if self.raw_fi: - fh = fip.contents - else: - fh = fip.contents.fh - return self.operations('truncate', path, length, fh) - - def fgetattr(self, path, buf, fip): - memset(buf, 0, sizeof(c_stat)) - st = buf.contents - if not fip: - fh = fip - elif self.raw_fi: - fh = fip.contents - else: - fh = fip.contents.fh - attrs = self.operations('getattr', path, fh) - set_st_attrs(st, attrs) - return 0 - - def lock(self, path, fip, cmd, lock): - if self.raw_fi: - fh = fip.contents - else: - fh = fip.contents.fh - return self.operations('lock', path, fh, cmd, lock) - - def utimens(self, path, buf): - if buf: - atime = time_of_timespec(buf.contents.actime) - mtime = time_of_timespec(buf.contents.modtime) - times = (atime, mtime) - else: - times = None - return self.operations('utimens', path, times) - - def bmap(self, path, blocksize, idx): - return self.operations('bmap', path, blocksize, idx) - - -class Operations(object): - """This class should be subclassed and passed as an argument to FUSE on - initialization. All operations should raise an OSError 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 OSError(EFAULT, '') - return getattr(self, op)(*args) - - def access(self, path, amode): - return 0 - - bmap = None - - def chmod(self, path, mode): - raise OSError(EROFS, '') - - def chown(self, path, uid, gid): - raise OSError(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.""" - raise OSError(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.""" - - if path != '/': - raise OSError(ENOENT, '') - return dict(st_mode=(S_IFDIR | 0755), st_nlink=2) - - def getxattr(self, path, name, position=0): - raise OSError(ENOTSUP, '') - - def init(self, path): - """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 OSError(EROFS, '') - - def listxattr(self, path): - return [] - - lock = None - - def mkdir(self, path, mode): - raise OSError(EROFS, '') - - def mknod(self, path, mode, dev): - raise OSError(EROFS, '') - - def open(self, path, flags): - """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 OSError(ENOENT, '') - - 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.""" - return ['.', '..'] - - def readlink(self, path): - raise OSError(ENOENT, '') - - def release(self, path, fh): - return 0 - - def releasedir(self, path, fh): - return 0 - - def removexattr(self, path, name): - raise OSError(ENOTSUP, '') - - def rename(self, old, new): - raise OSError(EROFS, '') - - def rmdir(self, path): - raise OSError(EROFS, '') - - def setxattr(self, path, name, value, options, position=0): - raise OSError(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).""" - return {} - - def symlink(self, target, source): - raise OSError(EROFS, '') - - def truncate(self, path, length, fh=None): - raise OSError(EROFS, '') - - def unlink(self, path): - raise OSError(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 OSError(EROFS, '') - - -class LoggingMixIn: - def __call__(self, op, path, *args): - print '->', op, path, repr(args) - ret = '[Unknown Error]' - try: - try: - ret = getattr(self, op)(path, *args) - return ret - except OSError, e: - ret = str(e) - raise - finally: - print '<-', op, repr(ret) diff --git a/fuse3.py b/fuse3.py deleted file mode 100644 index 8717b47..0000000 --- a/fuse3.py +++ /dev/null @@ -1,637 +0,0 @@ -# Copyright (c) 2008 Giorgos Verigakis <verigak@gmail.com> -# -# Permission to use, copy, modify, and distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -from ctypes import * -from ctypes.util import find_library -from errno import * -from functools import partial -from platform import machine, system -from stat import S_IFDIR -from traceback import print_exc - -import logging - - -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() -if _system in ('Darwin', 'FreeBSD'): - _libiconv = CDLL(find_library("iconv"), RTLD_GLOBAL) # libfuse dependency - ENOTSUP = 45 - c_dev_t = c_int32 - c_fsblkcnt_t = c_ulong - c_fsfilcnt_t = c_ulong - c_gid_t = c_uint32 - c_mode_t = c_uint16 - c_off_t = c_int64 - c_pid_t = c_int32 - c_uid_t = c_uint32 - setxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), - c_size_t, c_int, c_uint32) - getxattr_t = CFUNCTYPE(c_int, c_char_p, c_char_p, POINTER(c_byte), - c_size_t, c_uint32) - c_stat._fields_ = [ - ('st_dev', c_dev_t), - ('st_ino', c_uint32), - ('st_mode', c_mode_t), - ('st_nlink', c_uint16), - ('st_uid', c_uid_t), - ('st_gid', c_gid_t), - ('st_rdev', c_dev_t), - ('st_atimespec', c_timespec), - ('st_mtimespec', c_timespec), - ('st_ctimespec', c_timespec), - ('st_size', c_off_t), - ('st_blocks', c_int64), - ('st_blksize', c_int32)] -elif _system == 'Linux': - ENOTSUP = 95 - c_dev_t = c_ulonglong - c_fsblkcnt_t = c_ulonglong - c_fsfilcnt_t = c_ulonglong - c_gid_t = c_uint - c_mode_t = c_uint - 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) - - _machine = machine() - if _machine == 'x86_64': - c_stat._fields_ = [ - ('st_dev', c_dev_t), - ('st_ino', c_ulong), - ('st_nlink', c_ulong), - ('st_mode', c_mode_t), - ('st_uid', c_uid_t), - ('st_gid', c_gid_t), - ('__pad0', c_int), - ('st_rdev', c_dev_t), - ('st_size', c_off_t), - ('st_blksize', c_long), - ('st_blocks', c_long), - ('st_atimespec', c_timespec), - ('st_mtimespec', c_timespec), - ('st_ctimespec', c_timespec)] - elif _machine == 'ppc': - c_stat._fields_ = [ - ('st_dev', c_dev_t), - ('st_ino', c_ulonglong), - ('st_mode', c_mode_t), - ('st_nlink', c_uint), - ('st_uid', c_uid_t), - ('st_gid', c_gid_t), - ('st_rdev', c_dev_t), - ('__pad2', c_ushort), - ('st_size', c_off_t), - ('st_blksize', c_long), - ('st_blocks', c_longlong), - ('st_atimespec', c_timespec), - ('st_mtimespec', c_timespec), - ('st_ctimespec', c_timespec)] - else: - # i686, use as fallback for everything else - c_stat._fields_ = [ - ('st_dev', c_dev_t), - ('__pad1', c_ushort), - ('__st_ino', c_ulong), - ('st_mode', c_mode_t), - ('st_nlink', c_uint), - ('st_uid', c_uid_t), - ('st_gid', c_gid_t), - ('st_rdev', c_dev_t), - ('__pad2', c_ushort), - ('st_size', c_off_t), - ('st_blksize', c_long), - ('st_blocks', c_longlong), - ('st_atimespec', c_timespec), - ('st_mtimespec', c_timespec), - ('st_ctimespec', c_timespec), - ('st_ino', c_ulonglong)] -else: - raise NotImplementedError('%s is not supported.' % _system) - - -class c_statvfs(Structure): - _fields_ = [ - ('f_bsize', c_ulong), - ('f_frsize', c_ulong), - ('f_blocks', c_fsblkcnt_t), - ('f_bfree', c_fsblkcnt_t), - ('f_bavail', c_fsblkcnt_t), - ('f_files', c_fsfilcnt_t), - ('f_ffree', c_fsfilcnt_t), - ('f_favail', c_fsfilcnt_t)] - -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) - class c_statvfs(Structure): - _fields_ = [ - ('f_bavail', c_fsblkcnt_t), - ('f_bfree', c_fsblkcnt_t), - ('f_blocks', c_fsblkcnt_t), - ('f_favail', c_fsfilcnt_t), - ('f_ffree', c_fsfilcnt_t), - ('f_files', c_fsfilcnt_t), - ('f_bsize', c_ulong), - ('f_flag', c_ulong), - ('f_frsize', c_ulong)] - -class fuse_file_info(Structure): - _fields_ = [ - ('flags', c_int), - ('fh_old', c_ulong), - ('writepage', c_int), - ('direct_io', c_uint, 1), - ('keep_cache', c_uint, 1), - ('flush', c_uint, 1), - ('padding', c_uint, 29), - ('fh', c_uint64), - ('lock_owner', c_uint64)] - -class fuse_context(Structure): - _fields_ = [ - ('fuse', c_voidp), - ('uid', c_uid_t), - ('gid', c_gid_t), - ('pid', c_pid_t), - ('private_data', c_voidp)] - -class fuse_operations(Structure): - _fields_ = [ - ('getattr', CFUNCTYPE(c_int, c_char_p, POINTER(c_stat))), - ('readlink', CFUNCTYPE(c_int, c_char_p, POINTER(c_byte), c_size_t)), - ('getdir', c_voidp), # Deprecated, use readdir - ('mknod', CFUNCTYPE(c_int, c_char_p, c_mode_t, c_dev_t)), - ('mkdir', CFUNCTYPE(c_int, c_char_p, c_mode_t)), - ('unlink', CFUNCTYPE(c_int, c_char_p)), - ('rmdir', CFUNCTYPE(c_int, c_char_p)), - ('symlink', CFUNCTYPE(c_int, c_char_p, c_char_p)), - ('rename', CFUNCTYPE(c_int, c_char_p, c_char_p)), - ('link', CFUNCTYPE(c_int, c_char_p, c_char_p)), - ('chmod', CFUNCTYPE(c_int, c_char_p, c_mode_t)), - ('chown', CFUNCTYPE(c_int, c_char_p, c_uid_t, c_gid_t)), - ('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))), - ('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))), - ('fsync', CFUNCTYPE(c_int, c_char_p, c_int, POINTER(fuse_file_info))), - ('setxattr', setxattr_t), - ('getxattr', getxattr_t), - ('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))), - ('releasedir', CFUNCTYPE(c_int, c_char_p, 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))), - ('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)), - ('utimens', CFUNCTYPE(c_int, c_char_p, POINTER(c_utimbuf))), - ('bmap', CFUNCTYPE(c_int, c_char_p, c_size_t, POINTER(c_ulonglong)))] - - -def time_of_timespec(ts): - return ts.tv_sec + ts.tv_nsec / 10 ** 9 - -def set_st_attrs(st, attrs): - for key, val in attrs.items(): - if key in ('st_atime', 'st_mtime', 'st_ctime'): - timespec = getattr(st, key + 'spec') - timespec.tv_sec = int(val) - timespec.tv_nsec = int((val - timespec.tv_sec) * 10 ** 9) - elif hasattr(st, key): - setattr(st, key, val) - - -_libfuse_path = find_library('fuse') -if not _libfuse_path: - raise EnvironmentError('Unable to find libfuse') -_libfuse = CDLL(_libfuse_path) -_libfuse.fuse_get_context.restype = POINTER(fuse_context) - - -def fuse_get_context(): - """Returns a (uid, gid, pid) tuple""" - ctxp = _libfuse.fuse_get_context() - ctx = ctxp.contents - return ctx.uid, ctx.gid, ctx.pid - - -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): - """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 - args = ['fuse'] - if kwargs.pop('foreground', False): - args.append('-f') - if kwargs.pop('debug', False): - args.append('-d') - if kwargs.pop('nothreads', False): - 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(mountpoint) - 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)) - setattr(fuse_ops, name, prototype(op)) - _libfuse.fuse_main_real(len(args), argv, pointer(fuse_ops), - sizeof(fuse_ops), None) - del self.operations # Invoke the destructor - - def _wrapper_(self, func, *args, **kwargs): - """Decorator for the methods that follow""" - try: - return func(*args, **kwargs) or 0 - except OSError as e: - return -(e.errno or EFAULT) - 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).encode('utf-8') - 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) - - def mkdir(self, path, mode): - return self.operations('mkdir', path, mode) - - def unlink(self, path): - return self.operations('unlink', path) - - def rmdir(self, path): - return self.operations('rmdir', path) - - def symlink(self, source, target): - return self.operations('symlink', target, source) - - def rename(self, old, new): - return self.operations('rename', old, new) - - def link(self, source, target): - return self.operations('link', target, source) - - def chmod(self, path, mode): - return self.operations('chmod', path, mode) - - def chown(self, path, uid, gid): - return self.operations('chown', path, uid, gid) - - def truncate(self, path, length): - return self.operations('truncate', path, length) - - def open(self, path, fip): - fi = fip.contents - if self.raw_fi: - return self.operations('open', path, fi) - else: - fi.fh = self.operations('open', path, 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 - 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) - - def statfs(self, path, buf): - stv = buf.contents - attrs = self.operations('statfs', path) - 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) - - def release(self, path, fip): - fh = fip.contents if self.raw_fi else fip.contents.fh - return self.operations('release', path, 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) - - def setxattr(self, path, name, value, size, options, *args): - data = string_at(value, size) - return self.operations('setxattr', path, name, data, options, *args) - - def getxattr(self, path, name, value, size, *args): - ret = self.operations('getxattr', path, name, *args) - retsize = len(ret) - buf = create_string_buffer(ret, retsize) # Does not add trailing 0 - if bool(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 '' - bufsize = len(buf) - if bool(namebuf): - if bufsize > size: - return -ERANGE - memmove(namebuf, buf, bufsize) - return bufsize - - def removexattr(self, path, name): - return self.operations('removexattr', path, name) - - def opendir(self, path, fip): - # Ignore raw_fi - fip.contents.fh = self.operations('opendir', path) - 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): - name, st, offset = item, None, 0 - else: - name, attrs, offset = item - if attrs: - st = c_stat() - set_st_attrs(st, attrs) - else: - st = None - if filler(buf, name.encode('utf-8'), st, offset) != 0: - break - return 0 - - def releasedir(self, path, fip): - # Ignore raw_fi - return self.operations('releasedir', path, fip.contents.fh) - - def fsyncdir(self, path, datasync, fip): - # Ignore raw_fi - return self.operations('fsyncdir', path, 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) - - def create(self, path, mode, fip): - fi = fip.contents - 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) - - 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) - 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) - - def utimens(self, path, buf): - if buf: - atime = time_of_timespec(buf.contents.actime) - mtime = time_of_timespec(buf.contents.modtime) - times = (atime, mtime) - else: - times = None - return self.operations('utimens', path, times) - - def bmap(self, path, blocksize, idx): - return self.operations('bmap', path, blocksize, idx) - - -class Operations(object): - """This class should be subclassed and passed as an argument to FUSE on - initialization. All operations should raise an OSError 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 OSError(EFAULT, '') - return getattr(self, op)(*args) - - def access(self, path, amode): - return 0 - - bmap = None - - def chmod(self, path, mode): - raise OSError(EROFS, '') - - def chown(self, path, uid, gid): - raise OSError(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.""" - raise OSError(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.""" - - if path != '/': - raise OSError(ENOENT, '') - return dict(st_mode=(S_IFDIR | 0o755), st_nlink=2) - - def getxattr(self, path, name, position=0): - raise OSError(ENOTSUP, '') - - def init(self, path): - """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 OSError(EROFS, '') - - def listxattr(self, path): - return [] - - lock = None - - def mkdir(self, path, mode): - raise OSError(EROFS, '') - - def mknod(self, path, mode, dev): - raise OSError(EROFS, '') - - def open(self, path, flags): - """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 OSError(ENOENT, '') - - 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.""" - return ['.', '..'] - - def readlink(self, path): - raise OSError(ENOENT, '') - - def release(self, path, fh): - return 0 - - def releasedir(self, path, fh): - return 0 - - def removexattr(self, path, name): - raise OSError(ENOTSUP, '') - - def rename(self, old, new): - raise OSError(EROFS, '') - - def rmdir(self, path): - raise OSError(EROFS, '') - - def setxattr(self, path, name, value, options, position=0): - raise OSError(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).""" - return {} - - def symlink(self, target, source): - raise OSError(EROFS, '') - - def truncate(self, path, length, fh=None): - raise OSError(EROFS, '') - - def unlink(self, path): - raise OSError(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 OSError(EROFS, '') - - -class LoggingMixIn: - def __call__(self, op, path, *args): - logging.debug('-> %s %s %s', op, path, repr(args)) - ret = '[Unknown Error]' - try: - ret = getattr(self, op)(path, *args) - return ret - except OSError as e: - ret = str(e) - raise - finally: - logging.debug('<- %s %s', op, repr(ret)) @@ -2,16 +2,42 @@ from setuptools import setup -import fuse +try: + from lib2to3 import refactor + fixers = set(refactor.get_fixers_from_package('lib2to3.fixes')) +except ImportError: + fixers = set() +with open('README') as readme: + documentation = readme.read() setup( - name='fusepy', - version=fuse.__version__, - description='Simple ctypes bindings for FUSE', - author='Giorgos Verigakis', - author_email='verigak@gmail.com', - url='http://code.google.com/p/fusepy/', - license='ISC', - py_modules=['fuse'] + name = 'fusepy', + version = '1.2', + + description = 'Simple ctypes bindings for FUSE', + long_description = documentation, + author = 'Giorgos Verigakis', + author_email = 'verigak@gmail.com', + license = 'ISC', + py_modules=['fuse'], + + use_2to3 = True, + # only use the following fixers (everything else is already compatible) + use_2to3_exclude_fixers = fixers - set([ + 'lib2to3.fixes.fix_except', + 'lib2to3.fixes.fix_future', + 'lib2to3.fixes.fix_numliterals', + ]), + + classifiers = [ + 'Intended Audience :: Developers', + 'License :: OSI Approved :: ISC License (ISCL)', + 'Operating System :: MacOS', + 'Operating System :: POSIX', + 'Operating System :: Unix', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 3', + 'Topic :: System :: Filesystems', + ] ) |
