Browse Source

Import Upstream version 2.0.4

tags/upstream/2.0.4^0
nextime 5 years ago
commit
63948c580e
11 changed files with 1238 additions and 0 deletions
  1. +1
    -0
      MANIFEST.in
  2. +61
    -0
      PKG-INFO
  3. +43
    -0
      README
  4. +43
    -0
      README.rst
  5. +978
    -0
      fuse.py
  6. +61
    -0
      fusepy.egg-info/PKG-INFO
  7. +10
    -0
      fusepy.egg-info/SOURCES.txt
  8. +1
    -0
      fusepy.egg-info/dependency_links.txt
  9. +1
    -0
      fusepy.egg-info/top_level.txt
  10. +5
    -0
      setup.cfg
  11. +34
    -0
      setup.py

+ 1
- 0
MANIFEST.in View File

@@ -0,0 +1 @@
include README*

+ 61
- 0
PKG-INFO View File

@@ -0,0 +1,61 @@
Metadata-Version: 1.1
Name: fusepy
Version: 2.0.4
Summary: Simple ctypes bindings for FUSE
Home-page: http://github.com/terencehonles/fusepy
Author: Terence Honles
Author-email: terence@honles.com
License: ISC
Description: 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 original version of ``fusepy`` was hosted on `Google Code`_, but is now
`officially hosted on GitHub`_.
``fusepy`` is written in 2x syntax, but trying to pay attention to bytes and
other changes 3x would care about.
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, arm64, MIPS)
- 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/
.. _officially hosted on GitHub: source_
.. _download: https://github.com/terencehonles/fusepy/zipball/master
.. _source: http://github.com/terencehonles/fusepy
.. examples
.. _memory: http://github.com/terencehonles/fusepy/blob/master/examples/memory.py
.. _loopback: http://github.com/terencehonles/fusepy/blob/master/examples/loopback.py
.. _context: http://github.com/terencehonles/fusepy/blob/master/examples/context.py
.. _sftp: http://github.com/terencehonles/fusepy/blob/master/examples/sftp.py
Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: ISC License (ISCL)
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX
Classifier: Operating System :: Unix
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: System :: Filesystems

+ 43
- 0
README View File

@@ -0,0 +1,43 @@
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 original version of ``fusepy`` was hosted on `Google Code`_, but is now
`officially hosted on GitHub`_.

``fusepy`` is written in 2x syntax, but trying to pay attention to bytes and
other changes 3x would care about.

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, arm64, MIPS)
- 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/

.. _officially hosted on GitHub: source_
.. _download: https://github.com/terencehonles/fusepy/zipball/master
.. _source: http://github.com/terencehonles/fusepy

.. examples
.. _memory: http://github.com/terencehonles/fusepy/blob/master/examples/memory.py
.. _loopback: http://github.com/terencehonles/fusepy/blob/master/examples/loopback.py
.. _context: http://github.com/terencehonles/fusepy/blob/master/examples/context.py
.. _sftp: http://github.com/terencehonles/fusepy/blob/master/examples/sftp.py

+ 43
- 0
README.rst View File

@@ -0,0 +1,43 @@
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 original version of ``fusepy`` was hosted on `Google Code`_, but is now
`officially hosted on GitHub`_.

``fusepy`` is written in 2x syntax, but trying to pay attention to bytes and
other changes 3x would care about.

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, arm64, MIPS)
- 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/

.. _officially hosted on GitHub: source_
.. _download: https://github.com/terencehonles/fusepy/zipball/master
.. _source: http://github.com/terencehonles/fusepy

.. examples
.. _memory: http://github.com/terencehonles/fusepy/blob/master/examples/memory.py
.. _loopback: http://github.com/terencehonles/fusepy/blob/master/examples/loopback.py
.. _context: http://github.com/terencehonles/fusepy/blob/master/examples/context.py
.. _sftp: http://github.com/terencehonles/fusepy/blob/master/examples/sftp.py

+ 978
- 0
fuse.py View File

@@ -0,0 +1,978 @@
# Copyright (c) 2012 Terence Honles <terence@honles.com> (maintainer)
# Copyright (c) 2008 Giorgos Verigakis <verigak@gmail.com> (author)
#
# 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 print_function, absolute_import, division

from ctypes import *
from ctypes.util import find_library
from errno import *
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

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

try:
basestring
except NameError:
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':
_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')
else:
_libfuse = CDLL(_libfuse_path)

if _system == 'Darwin' and hasattr(_libfuse, 'macfuse_version'):
_system = 'Darwin-MacFuse'


if _system in ('Darwin', 'Darwin-MacFuse', 'FreeBSD'):
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)
if _system == 'Darwin':
c_stat._fields_ = [
('st_dev', c_dev_t),
('st_mode', c_mode_t),
('st_nlink', c_uint16),
('st_ino', c_uint64),
('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_birthtimespec', c_timespec),
('st_size', c_off_t),
('st_blocks', c_int64),
('st_blksize', c_int32),
('st_flags', c_int32),
('st_gen', c_int32),
('st_lspare', c_int32),
('st_qspare', c_int64)]
else:
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)

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 == 'mips':
c_stat._fields_ = [
('st_dev', c_dev_t),
('__pad1_1', c_ulong),
('__pad1_2', c_ulong),
('__pad1_3', c_ulong),
('st_ino', c_ulong),
('st_mode', c_mode_t),
('st_nlink', c_ulong),
('st_uid', c_uid_t),
('st_gid', c_gid_t),
('st_rdev', c_dev_t),
('__pad2_1', c_ulong),
('__pad2_2', c_ulong),
('st_size', c_off_t),
('__pad3', c_ulong),
('st_atimespec', c_timespec),
('__pad4', c_ulong),
('st_mtimespec', c_timespec),
('__pad5', c_ulong),
('st_ctimespec', c_timespec),
('__pad6', c_ulong),
('st_blksize', c_long),
('st_blocks', c_long),
('__pad7_1', c_ulong),
('__pad7_2', c_ulong),
('__pad7_3', c_ulong),
('__pad7_4', c_ulong),
('__pad7_5', c_ulong),
('__pad7_6', c_ulong),
('__pad7_7', c_ulong),
('__pad7_8', c_ulong),
('__pad7_9', c_ulong),
('__pad7_10', c_ulong),
('__pad7_11', c_ulong),
('__pad7_12', c_ulong),
('__pad7_13', c_ulong),
('__pad7_14', c_ulong)]
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)]
elif _machine == 'aarch64':
c_stat._fields_ = [
('st_dev', c_dev_t),
('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),
('__pad1', c_ulong),
('st_size', c_off_t),
('st_blksize', c_int),
('__pad2', c_int),
('st_blocks', c_long),
('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),
('f_fsid', c_ulong),
#('unused', c_int),
('f_flag', c_ulong),
('f_namemax', c_ulong)]

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)]

_libfuse.fuse_get_context.restype = POINTER(fuse_context)


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))),
('flag_nullpath_ok', c_uint, 1),
('flag_nopath', c_uint, 1),
('flag_utime_omit_ok', c_uint, 1),
('flag_reserved', c_uint, 29),
]


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', 'st_birthtime'):
timespec = getattr(st, key + 'spec', None)
if timespec is None:
continue
timespec.tv_sec = int(val)
timespec.tv_nsec = int((val - timespec.tv_sec) * 10 ** 9)
elif hasattr(st, key):
setattr(st, key, val)


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 FuseOSError(OSError):
def __init__(self, errno):
super(FuseOSError, self).__init__(errno, strerror(errno))


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.
'''

OPTIONS = (
('foreground', '-f'),
('debug', '-d'),
('nothreads', '-s'),
)

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']

args.extend(flag for arg, flag in self.OPTIONS
if kwargs.pop(arg, False))

kwargs.setdefault('fsname', operations.__class__.__name__)
args.append('-o')
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 ent in fuse_operations._fields_:
name, prototype = ent[:2]

val = getattr(operations, name, None)
if val is None:
continue

# Function pointer members are tested for using the
# getattr(operations, name) above but are dynamically
# invoked using self.operations(name)
if hasattr(prototype, 'argtypes'):
val = prototype(partial(self._wrapper, getattr(self, name)))

setattr(fuse_ops, name, val)

try:
old_handler = signal(SIGINT, SIG_DFL)
except ValueError:
old_handler = SIG_DFL

err = _libfuse.fuse_main_real(len(args), argv, pointer(fuse_ops),
sizeof(fuse_ops), None)

try:
signal(SIGINT, old_handler)
except ValueError:
pass

del self.operations # Invoke the destructor
if err:
raise RuntimeError(err)

@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
except OSError as e:
return -(e.errno or EFAULT)
except:
print_exc()
return -EFAULT

def _decode_optional_path(self, path):
# NB: this method is intended for fuse operations that
# allow the path argument to be NULL,
# *not* as a generic path decoding method
if path is None:
return None
return path.decode(self.encoding)

def getattr(self, path, buf):
return self.fgetattr(path, buf, None)

def readlink(self, path, buf, bufsize):
ret = self.operations('readlink', path.decode(self.encoding)) \
.encode(self.encoding)

# copies a string into the given buffer
# (null terminated and truncated if necessary)
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.decode(self.encoding), mode, dev)

def mkdir(self, path, mode):
return self.operations('mkdir', path.decode(self.encoding), mode)

def unlink(self, path):
return self.operations('unlink', path.decode(self.encoding))

def rmdir(self, path):
return self.operations('rmdir', path.decode(self.encoding))

def symlink(self, source, target):
'creates a symlink `target -> source` (e.g. ln -s source target)'

return self.operations('symlink', target.decode(self.encoding),
source.decode(self.encoding))

def rename(self, old, new):
return self.operations('rename', old.decode(self.encoding),
new.decode(self.encoding))

def link(self, source, target):
'creates a hard link `target -> source` (e.g. ln source target)'

return self.operations('link', target.decode(self.encoding),
source.decode(self.encoding))

def chmod(self, 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.decode(self.encoding), uid, gid)

def truncate(self, 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.decode(self.encoding), fi)
else:
fi.fh = self.operations('open', path.decode(self.encoding),
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', self._decode_optional_path(path), size,
offset, fh)

if not ret: return 0

retsize = len(ret)
assert retsize <= size, \
'actual amount read %d greater than expected %d' % (retsize, size)

data = create_string_buffer(ret, retsize)
memmove(buf, data, retsize)
return retsize

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', self._decode_optional_path(path), data,
offset, fh)

def statfs(self, path, buf):
stv = buf.contents
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):
if self.raw_fi:
fh = fip.contents
else:
fh = fip.contents.fh

return self.operations('flush', self._decode_optional_path(path), fh)

def release(self, path, fip):
if self.raw_fi:
fh = fip.contents
else:
fh = fip.contents.fh

return self.operations('release', self._decode_optional_path(path), fh)

def fsync(self, path, datasync, fip):
if self.raw_fi:
fh = fip.contents
else:
fh = fip.contents.fh

return self.operations('fsync', self._decode_optional_path(path), datasync,
fh)

def setxattr(self, path, name, value, size, options, *args):
return self.operations('setxattr', path.decode(self.encoding),
name.decode(self.encoding),
string_at(value, size), options, *args)

def getxattr(self, path, name, value, size, *args):
ret = self.operations('getxattr', path.decode(self.encoding),
name.decode(self.encoding), *args)

retsize = len(ret)
# allow size queries
if not value: return retsize

# do not truncate
if retsize > size: return -ERANGE

buf = create_string_buffer(ret, retsize) # Does not add trailing 0
memmove(value, buf, retsize)

return retsize

def listxattr(self, path, namebuf, size):
attrs = self.operations('listxattr', path.decode(self.encoding)) or ''
ret = '\x00'.join(attrs).encode(self.encoding)
if len(ret) > 0:
ret += '\x00'.encode(self.encoding)

retsize = len(ret)
# allow size queries
if not namebuf: return retsize

# do not truncate
if retsize > size: return -ERANGE

buf = create_string_buffer(ret, retsize)
memmove(namebuf, buf, retsize)

return retsize

def removexattr(self, 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.decode(self.encoding))

return 0

def readdir(self, path, buf, filler, offset, fip):
# Ignore raw_fi
for item in self.operations('readdir', self._decode_optional_path(path),
fip.contents.fh):

if isinstance(item, basestring):
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(self.encoding), st, offset) != 0:
break

return 0

def releasedir(self, path, fip):
# Ignore raw_fi
return self.operations('releasedir', self._decode_optional_path(path),
fip.contents.fh)

def fsyncdir(self, path, datasync, fip):
# Ignore raw_fi
return self.operations('fsyncdir', self._decode_optional_path(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.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):
if self.raw_fi:
fh = fip.contents
else:
fh = fip.contents.fh

return self.operations('truncate', self._decode_optional_path(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', self._decode_optional_path(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', self._decode_optional_path(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.decode(self.encoding), times)

def bmap(self, 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.
'''

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.
'''

if path != '/':
raise FuseOSError(ENOENT)
return dict(st_mode=(S_IFDIR | 0o755), 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.
'''

pass

def link(self, target, source):
'creates a hard link `target -> source` (e.g. ln source target)'

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 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.
'''

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).
'''

return {}

def symlink(self, target, source):
'creates a symlink `target -> source` (e.g. ln -s source target)'

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):
self.log.debug('-> %s %s %s', op, path, repr(args))
ret = '[Unhandled Exception]'
try:
ret = getattr(self, op)(path, *args)
return ret
except OSError as e:
ret = str(e)
raise
finally:
self.log.debug('<- %s %s', op, repr(ret))

+ 61
- 0
fusepy.egg-info/PKG-INFO View File

@@ -0,0 +1,61 @@
Metadata-Version: 1.1
Name: fusepy
Version: 2.0.4
Summary: Simple ctypes bindings for FUSE
Home-page: http://github.com/terencehonles/fusepy
Author: Terence Honles
Author-email: terence@honles.com
License: ISC
Description: 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 original version of ``fusepy`` was hosted on `Google Code`_, but is now
`officially hosted on GitHub`_.
``fusepy`` is written in 2x syntax, but trying to pay attention to bytes and
other changes 3x would care about.
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, arm64, MIPS)
- 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/
.. _officially hosted on GitHub: source_
.. _download: https://github.com/terencehonles/fusepy/zipball/master
.. _source: http://github.com/terencehonles/fusepy
.. examples
.. _memory: http://github.com/terencehonles/fusepy/blob/master/examples/memory.py
.. _loopback: http://github.com/terencehonles/fusepy/blob/master/examples/loopback.py
.. _context: http://github.com/terencehonles/fusepy/blob/master/examples/context.py
.. _sftp: http://github.com/terencehonles/fusepy/blob/master/examples/sftp.py
Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: ISC License (ISCL)
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX
Classifier: Operating System :: Unix
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: System :: Filesystems

+ 10
- 0
fusepy.egg-info/SOURCES.txt View File

@@ -0,0 +1,10 @@
MANIFEST.in
README
README.rst
fuse.py
setup.cfg
setup.py
fusepy.egg-info/PKG-INFO
fusepy.egg-info/SOURCES.txt
fusepy.egg-info/dependency_links.txt
fusepy.egg-info/top_level.txt

+ 1
- 0
fusepy.egg-info/dependency_links.txt View File

@@ -0,0 +1 @@


+ 1
- 0
fusepy.egg-info/top_level.txt View File

@@ -0,0 +1 @@
fuse

+ 5
- 0
setup.cfg View File

@@ -0,0 +1,5 @@
[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0


+ 34
- 0
setup.py View File

@@ -0,0 +1,34 @@
#!/usr/bin/env python

from __future__ import with_statement

from setuptools import setup

with open('README') as readme:
documentation = readme.read()

setup(
name = 'fusepy',
version = '2.0.4',

description = 'Simple ctypes bindings for FUSE',
long_description = documentation,
author = 'Giorgos Verigakis',
author_email = 'verigak@gmail.com',
maintainer = 'Terence Honles',
maintainer_email = 'terence@honles.com',
license = 'ISC',
py_modules=['fuse'],
url = 'http://github.com/terencehonles/fusepy',

classifiers = [
'Intended Audience :: Developers',
'License :: OSI Approved :: ISC License (ISCL)',
'Operating System :: MacOS',
'Operating System :: POSIX',
'Operating System :: Unix',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 3',
'Topic :: System :: Filesystems',
]
)

Loading…
Cancel
Save