Git Product home page Git Product logo

fusepy's Introduction

fusepy

NOTE: This project has moved to be under a GitHub organization and can be found at https://github.com/fusepy/fusepy. The project has new maintainers and will be looking to incorporate pull requests in a more timely manner. If you would like to help maintain this package please open a pull request and demonstrate willingness to help (we will leave maintainer criteria up to the current maintainers).

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)

fusepy's People

Contributors

billziss-gh avatar cbenhagen avatar eestrada avatar jaikrishnats avatar johannesbuchner avatar jwilk avatar lpzummer avatar n-coder avatar nickcoutsos avatar nirs avatar nmtadam avatar paulo-raca avatar rianhunter avatar rncry avatar ssssam avatar steinbeck65 avatar terencehonles avatar tonyo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fusepy's Issues

link() arguments is backward from standard

Almost everywhere, the standard for link(a, b) is to create a link at b to a. It seems that the link(source, target) in Operations is meant to create a link at target to source. To replicate, write a simple Operations with logging mixin and try to ln a b and see which direction it's going.

Exit from inside, without fusermount

Hi!

I don't know if this is possible, but can you exit the filesystem from inside the program?
I tried with sys.exit, but it just raises an Exception instead of shutting down the program:

File "cloudfusion/fuse.py", line 301, in _wrapper_
    return func(*args, **kwargs) or 0
  File "cloudfusion/fuse.py", line 324, in unlink
    return self.operations('unlink', path)
  File "cloudfusion/fuse.py", line 507, in __call__
    return getattr(self, op)(*args)
  File "cloudfusion/pyfusebox/configurable_pyfusebox.py", line 118, in unlink
    exit(0)
  File "/usr/lib/python2.6/site.py", line 337, in __call__
    raise SystemExit(code)
SystemExit: 0

IOCTL and fusepy

Fuse 2.6 has ioctl integration. Should we expect fusepy to support ioctl anytime sooner?

No f_namemax (or f_namelen) in the statvfs structure

I've been using fusepy for an implementation of a filesystem and wanted to test the correctness of the implementation using one of the publicly available FS test suites. Unfortunately that did work because as one of the first operations it tries to determine the maximum length of name for the filesystem.

In C API, there is a field in the statfs/statvfs structures which returns the maximum name length. It is not currently present in the structure definition. Surprisingly, even after adding the required fields to the structure declarations in fuse.py I could not get it to work for whatever reason.

Py3 getxattr throws TypeError

I think it's the same as #24
fuse.py line 558

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

seems to solve it.

Python versions

Right now we support Python2.6+ and Python3 works, but there may be places where it is rough around the edges or is broken. With a proper test suite (#80) we can make sure Python3 is working properly.

Do we still need to support Python2.6? Can we write things targeting Python3, but Python2.7 compatible?

Irritating default behavior of Operations class - raising FuseOSError(EROFS) where it really should not

This issue can be understood as a suggestions with respect to #80.


The "usual procedure" for writing a filesystem against the high level API begins with sub-classing from Operations. While libfuse follows the philosophy of "do not implement what you do not need", the original Operations class in fusepy contains an implementation for virtually every method supported by FUSE's high level API and adds a non-standard behavior to them. It appears that many methods return EROFS in one way or the other, indicating a read-only filesystem.

This approach becomes highly problematic when a developer follows the guidelines of libfuse by leaving unwanted methods unimplemented. For instance, a read-write filesystem can work perfectly fine without the create method if the filesystem already offers properly implemented mknod and open methods. Nevertheless, FUSE will attempt to call create first, if it is implemented. If it is not implemented, FUSE will subsequently instead call the equivalent sequence of getattr, mknod and open. fusepy breaks this behavior by offering a create method by default, which will raise FuseOSError(EROFS) (read-only file system). As per the guidelines, it should either not exist or at least raise FuseOSError(errno.ENOSYS) (which does in fact work just fine). In a read-write filesystem this causes quite literally havoc and is, if ones does not know what to look for, fairly hard to debug.

Looking at the code of the Operations class, my impression is that it is designed to make it as easy as possible to write a simple read-only filesystem. It's apparently its primary focus, completely ignoring all other use-cases of FUSE. I felt into this trap and searched errors in my code for ever before I figured out that fusepy was really doing something it should not do - falsely assuming it would follow the design patterns of the library it is offering bindings for.

As a developer, the current way out of this mess is by not sub-classing from Operations. When doing so, one must implement the __call__ method which is required for fusepy to work correctly (copy&paste does the job ...). Alternatively, one can subclass from Operations but, instead, has to overwrite (!) every single unwanted method and raise FuseOSError(errno.ENOSYS) when they are called. Either way, the situation is not satisfying.

Solving this without breaking backwards compatibility ... There should be a "clean" Operations class to subclass from (probably under another/new name), containing nothing but the __call__ method. Everything else can be "moved" into something like a Operations_template_RO_mixin class along the lines of the LoggingMixIn class.

When offering a clean Operations class, it is probably also a good idea to "zero-out" the fuse_operations ctypes structure fuse_ops after its initialization and before it is filled with pointers to methods.

Py3: FUSE.listxattr throws TypeError

Under python3.3, I get a TypeError thrown on listxattr:

Traceback (most recent call last):
  File "/home/kernow/proj/fuse.py", line 420, in _wrapper
    return func(*args, **kwargs) or 0
  File "/home/kernow/proj/fuse.py", line 580, in listxattr
    ret = '\x00'.join(attrs).encode(self.encoding) + '\x00'
TypeError: can't concat bytes to str

I think the problem is in:

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

The attrs returned from the operation are unicode, and so the first '\x00' is rightly also unicode, and then the joined string is encoded into bytes.

The second '\x00' should then be explicitly bytes - b'\x00'. Of course, the byes literal only works in v3, so you would probably need '\x00'.encode('ascii')

Is this project maintained?

No offense, this is voluntary labor after all - I am just interest to know. In the issue tracker and pull requests, I see a lot of stuff happening, which has not been addressed or touched by the maintainer(s) for almost two years. Besides, folks point each other to the furthest progressed forks of this repository. However, as of writing this, non of the forks seems to have developed into a mature "replacement" project of its own (?).

As far as I can tell, fusepy is the best / most up-to-date / most feature-complete high-level FUSE-binding for Python. The status of its alternatives:

  • python-fuse: Legacy Python only. As of February 2016 declared "orphaned" by the libfuse maintainer.
  • python-llfuse: Maintained, Python 3 support - but Low Level API only.

I tested my way through fusepy with pjdfstest, which pointed me to a number of (potential) issues in fusepy. I also experimented with fusepy and libfuse versions 3.x - long story short, at a first glance it appears there are a number of issues in fusepy prohibiting its use with libfuse 3. I do not mind reporting / bisecting / fixing (some of) them if there is an detectable interest in those issues or accepting pull requests.

only call ctypes.utils.find_library if basic searches fail?

Ran into this issue (and fixed it) in pyrtlsdr - as it happens, find_library is a true heavyweight function, invoking (on Linux) a bunch of build tools in an attempt to find the path to the shared object. On most Linux distros, a search of LD_LIBRARY_PATH (if present), followed by globbing /lib/*, /usr/lib/*, and /usr/local/lib/* would suffice. If these cheap glob matches fail, then find_library can be invoked as a last ditch effort.

See also - https://github.com/roger-/pyrtlsdr/pull/75

Create `CONTRIBUTING.md`

  • Mention that this repo doesn't track distro specific packages, only the pypi package (via setup.py). See PR #73 as an example.
  • Mention that pull requests should first be proceeded by an issue (that potential contributors won't make work that may not ever be merged)

inotify integration

Hi,

First off, thanks for writing and maintaining fusepy. And a late welcome to GitHub :)
I successfully use fusepy for connecting to file hosters like Dropbox and Sugarsync,
as well as for a manga reader.
Do you happen to know of a way to use inotify on a fusepy file system or a similar solution?
It would be nice to get notifications of file changes without cyclic polling.

Thanks a lot!

update memory.py with mem.py from kungfuse?

kungfuse updates memory.py with support for arbitrary directory depth and is permissively licensed. Might be worth merging in the updated example.

would also close #65.

kungfuse's mem.py is ~200 SLOC vs memory.py's ~140 SLOC - not a big difference.

Problems with getattr?

I'm having trouble getting a basic FUSE up and running. I'm using python 3 and I did the 2to3 thing on fuse.py. When I tried a stat on the mount point, I get input output error. According to the mixin log, I'm pretty sure I've implemented getattr right. Perhaps I'm forgetting something?

2013-02-07 23:13:27,941 DEBUG @fuse.log-mixin -> getattr / (None,)
2013-02-07 23:13:27,943 DEBUG @fuse.log-mixin <- getattr {'st_mtime': 1360296806.2537441, 'st_size': 4096, 'st_atime': 1360296806.2537441, 'st_gid': 1003, 'st_uid': 1000, 'st_mode': 448, 'st_ctime': 1360296806.2537441, 'st_nlink': 4}

fusepy speed

Hi, I wonder if the fuse.py speed is compromised someplace?

I have fusepy-2.0.1 and OSXFUSE version 2.5.1

I"ve made two mounts, one using the fuse.py loopback example and one using the 'c' Loopback that comes with OSXFUSE. Reading through a 1.1GByte file I get the following times (in seconds):

filesystem 4.681068
c-Loopback 5.231013
py-Loopback 141.796592

so, I didn't think Python would be as quick as c but nearly 30 times slower is a major surprise.

any ideas what might be going on here?

JJ (aka ijiraq)

README is a link to the missing README.rst in the pypi tarball

gcbirzan@coin:~$ pip install fusepy
Downloading/unpacking fusepy
Downloading fusepy-2.0.1.tar.gz
Running setup.py egg_info for package fusepy
Traceback (most recent call last):
File "", line 14, in
File "/home/gcbirzan/build/fusepy/setup.py", line 11, in
with open('README') as readme:
IOError: [Errno 2] No such file or directory: 'README'
Complete output from command python setup.py egg_info:
Traceback (most recent call last):

File "", line 14, in

File "/home/gcbirzan/build/fusepy/setup.py", line 11, in

with open('README') as readme:

IOError: [Errno 2] No such file or directory: 'README'

Downloading the .tar.gz:

gcbirzan@coin:/fusepy-2.0.1$ ls -l README*
lrwxrwxrwx 1 gcbirzan gcbirzan 10 Apr 24 23:28 README -> README.rst
gcbirzan@coin:
/fusepy-2.0.1$

reading big file and memory usage

hello world,

I have written a xb360hd module that allows me a read-only access to the contents of an xtaf partition (xbox360).

now, I'm trying to make this content accessible with fuse, but I'm having a little problem with reading files : a file can be very large (and discontinuous), so I try to avoid storing it in memory using the yield instruction, but I've not been able to use it in the read function of the xtaffuse module.

I would very much appreciate some advice or hints from you on how to carry out my project successfully.

regards, lacsaP.

link to wiki from readme

Hi terence,

I wrote a basic wiki article including information I think would have helped me a lot when starting development with FUSE, and fusepy.
Maybe you could link to the wiki entry from the readme file so that other developers know to look it up and possibly contribute their own experience.

Thx,
joe42

time precision inside utimens causes rsync misses

Some file modify times cannot be represented well by python's float, and the rounding that occurs is sometimes high enough to cause rsync to believe that a file has changed.

For example, I have a number of files with modify times very close to the second boundary:

# stat some.file | grep Modify
Modify: 2011-04-08 08:08:45.999999900 -0400

And rsyncing them into a fusepy mount will round up to the next second on conversion to float inside time_of_timespec in utimens, since python floats can't quite contain values like 1490219287.9999999.

Since some times cannot be represented as python floats, would it be possible to have some higher precision handling, perhaps:

  1. have the raw timespec structs go to a higher precision handler if one is available
  2. pass decimals into utimens rather than doubles

Unexpected write arguments when running printf 'test\nhello\nworld'

If I try to do something like:
printf 'test\nhello\nworld' > mount_point/some_file
I get 3 writes:

  • offset: 0, data: test\n
  • offset: 0, data: test\nhello\n
  • offset: 0, data: test\nhello\nworld

I was expecting 'test', 'hello', and 'world' to get sent separately and I was not expecting to see the entire string sent to the 3rd write.

If I do a dtruss on that printf to a file in my normal filesystem I get the writes that I expect showing up ('test' then 'hello' then 'world').

Not sure if it is a fusepy thing, a memory.py thing or a bad assumption on my part.

My setup: OSX 10.6 with osxfuse in bash running the example filesystem memory.py.

File Locking

Is there an example of how to implement locking?

There's a "lock = None" implementation for the "lock" method on Operations(), which seems to imply that it's not supported. There's also the following signature for FUSE.lock(), which diverges quite a bit from the original FUSE implementation:

def lock(self, path, fip, cmd, lock):

What are are the possible values, and are there constants defined somewhere?

read() operations cause zero-filled files of 'size' to be written on errors

As part of a test I'm doing (on Mac OS 10.8) I decided to cause every read() to fail with errno.EPERM. The Finder is displaying the appropriate error when I try to copy a file out of the FUSE drive, but the operation still returns a zero-filled byte array. As a result a zero-filled file corresponding to the 'size' of the read is created.

Is this fusepy or FUSE driver related? A cursory reading of the fusepy module seems to pin this particular issue on the underlying FUSE driver implementation. Thoughts?

Edit

After more reading the point in the fusepy code that seems most related to the issue is the _wrapper() static method. My understanding of the FUSE operations is that all errors (destined for errno) are returned as negative values of the errno in question.

I'm not currently clear on how this affects read() as 0 and -1 are significant return values in the cases of EOF or error.

Next steps/road map for the near future

As per @s-m-e's comment in issue #75, this issue is to propose, discuss, and prioritize the future road map for fusepy. Here is a quote from @s-m-e's comment on the other issue:

The following points come to mind:

  • Analysis of open pull requests and issues
  • Python 2 and/or 3 support? 2017 saw a long awaited trend towards moving to Python 3 as the default in Linux distributions. At the same time, many significant packages have begun to drop Python 2 support.

See #99 for Python version discussion

  • Windows support (as has been developed in different flavors in some forks). It's an amazing feature to have.

See #54 for PR with windows support

See #80 for testing dicussion

  • Support for libfuse version 3 (and, at the same time, version 2?). At least in the Linux space, very few distributions adopted version 3 (or offer packages), so version 2 will remain relevant for the foreseeable future. On the other hand, version 2 has not seen development other than bug fixes for 2 years.

See #100 for libfuse version discussion

  • Notifying downstream projects about the changed project status
  • Asking downstream projects maintaining their own forks of fusepy about their interest / potential motivation in merging their changes and patches back into "upstream" fusepy
  • Contacting maintainers of forks of fusepy itself, exploring their interest in merging their developments back into "upstream"
  • Moving the module's code into a src folder, making it easier to maintain
  • Breaking the files fuse.py and fusell.py into files (sub-modules) specific to operating systems and architectures and common files. (And for people loving single-file modules, if requested, adding a "compiler" script for producing a single-file distribution/release version.)

See #85 for fuse organization discussion

I'd also like to suggest at least another maintenance release, like 2.0.x, for fixing bugs in the current code base - while development of a new release might happen in its own separate branch. It'll take time. There is also the option of releasing a package with breaking API changes under a new name like "fusepy3". I'd really like to keep the API as stable as possible.

broken exception handling

Exceptions from init and destroy

According to the libfuse docs, the return value of the init function is not interpreted, but simply stored as private_data field of struct fuse_context without further looking at it. If the init function now throws a Python exception, the handler defined in _wrapper will consume the exception and simply return EFAULT. FUSE just stores that value, effectively suppressing the exception and continuing to mount a driver in a now possibly invalid state.
My recommendation would be to shut down the driver if init (or destroy) raises an exception and reraise the exception once the native driver terminated.

reporting uncaught exceptions

The LoggingMixIn already correctly uses python logging instead of stdout printing, which comes in very handy when FUSE forks to background (and closes stdout), allowing log output being written to a file or even the syslog depending on the logging. Unfortunately, the _wrapper function uses traceback.print_exc to report about an uncaught exception, which will go to a closed sys.stderr if FUSE forked to background.
I'd highly recommend using something like log.error("Uncaught exception from FUSE operation %s, returning errno.EINVAL.", func.__name__, exc_info=True).

handling SystemExit

Unfortunately, the exception handling will consume all exceptions no matter their nature, including SystemExit. This means that the driver can't be shutdown from any of the handlers, even using sys.exit(). This has also been mentioned in issue #21, although this problem is not related to threads or processes as mentioned in the comments to the issue, but to the broken exception handler of fusepy.

As python exceptions can't be propagated from within the python operations to the libfuse C code, I use the following function to shut down the driver in case of any problems:

def fuse_exit():
    from fuse import _libfuse, c_void_p

    fuse_ptr = c_void_p(_libfuse.fuse_get_context().contents.fuse)
    _libfuse.fuse_exit(fuse_ptr)

    # alternative without directly invoking native code
    # os.kill(os.getpid(), signal.SIGINT)

As mentioned in the other issue, if you don't want to call native code directly in that function, you could have the OS send SIGINT to your own process via os.kill(os.getpid(), signal.SIGINT), invoking the libfuse SIGINT handler finally leading to the shutdown of the mount.
I'd vote for calling the native fuse_exit and making this function publicly available and thus fixing issue #21.

OSErrors with invalid errnos

Some subclasses OSErrors (like herror and gaierror) use errnos for values that don't correspond to the normal OS errnos (but to host name resolution or getaddrinfo error code).
On my system, the errnos for gaierror are:

{'EAI_ADDRFAMILY': -9, 'EAI_AGAIN': -3, 'EAI_BADFLAGS': -1, 'EAI_FAIL': -4, 'EAI_FAMILY': -6, 'EAI_MEMORY': -10, 'EAI_NODATA': -5, 'EAI_NONAME': -2, 'EAI_OVERFLOW': -12, 'EAI_SERVICE': -8, 'EAI_SOCKTYPE': -7, 'EAI_SYSTEM': -11}

If such an error code (note the negative sign for the EAI_* errors, while the normal OS errnos have a positive sign) is returned to libfuse, a warning about an invalid error code might be issued, or the file system operation might return an error code or even data that makes no sense.
So those exception should be translated to standard errnos, e.g. EHOSTUNREACH, instead.

Errors that are no subclass of OSError but can be mapped to an errno

There are some exceptions that are not a subclass of OSError, but can directly mapped to an errno. Examples include:

  • concurrent.futures.CancelledError and asyncio.CancelledError -> ECANCELED
  • concurrent.futures.TimeoutError and asyncio.TimeoutError -> ETIMEDOUT
  • requests.exceptions.ConnectionError -> ECONNRESET
  • requests.exceptions.Timeout -> ETIMEDOUT
  • aiohttp.ServerDisconnectedError -> ECONNRESET
  • ...

As users might want to define handlers for further exceptions, the handler/mapper should probably be extensible.

Summary

To sum up, I see the following problems:

  • exceptions from init and destroy should not be consumed silently, but should be logged using the python logging facility and ultimately lead to termination of the driver
  • sys.exit() is consumed by the exception handler and can't be sent to the native driver, so we need a function for explicitly shutting down the driver
  • some OSErrors (e.g. herror and gaierror) have negative errnos, which should be translated to standard errnos
  • some python errors (e.g. CancelledError) have no errnos, but could be mapped to one

My attempt at fixing these issues can be found here. If you like my solution, I'd be glad to make a pull request out if it.

Implement read_buf() and write_buf()

Would it make sense to implement read_buf() and write_buf() FUSE operations in order to avoid copying data back and forth between user land and kernel memory?

[openbsd] fuse_main_real not existing, there's fuse_main

Hi,

there's still an issue with fusepy on OpenBSD but first thing is there is no 'fuse_main_real' on OpenBSD. I renamed it and I could proceed with loopback.py a little bit.

(I'm not a developer, so my way was try & test...)

# objdump -t /usr/lib/libfuse.so.1.1  | grep fuse_main 
0000000000003150 g     F .text  0000000000000068 fuse_main

http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man9/fb_delete.9?query=fb_setup&sec=9
http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/fuse_chan_fd.3?query=fuse_main

http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libfuse/

Fuse support on "aarch64" architecture

I'm not sure of the proper way to submit a patch to fuse.py, but the following change enables fuse.py to work on "aarch64" running Linux. I tested this on a Juno ARMv8 development platform system running Debian Jessie (with a 4.3 kernel and some additional ARM patches) and used the memory.py example script.

Without this change the memory.py script fails with the following error:
*** stack smashing detected ***: python terminated
Aborted

diff --git a/fuse.py b/fuse.py
index 7a03d61..5150453 100644
--- a/fuse.py
+++ b/fuse.py
@@ -171,6 +171,23 @@ elif _system == 'Linux':
             ('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_ = [

Greg Pearson
[email protected]

listxattr appears to not work...

From the CLI, when I type the following, nothing appears (next line is sh prompt):

getfattr -d bar

Debugging shows these two lines:

DEBUG:fuse.log-mixin:-> listxattr /bar ()
DEBUG:fuse.log-mixin:<- listxattr ['table-name', 'master', 'file-type', 'no-db-update', 'primary-keys']

Getting a single attribute works fine:

vagrant@ubuntu:~/projects/kangaroo/test$ getfattr -n file-type bar
# file: bar
file-type="regular"

Running on Ubuntu 16.04 / Python 2.7.11

How to install fusepy

I've already used following command to download the entire repository.
git clone https://github.com/terencehonles/fusepy
However, when I use following command to test the system, I meet some problems.
cd fusepy
mkdir fusemount
cp examples/memory.py .
python memory.py fusemount

ls: ./mnt: Input/output error

Starting the "loopback" on a normal server works fine. Running it on other devices where the python dependencies are installed afterwards results in "input/output" errors and the mount directory isn't listed at a "ls".

I cannot debug what's going wrong. The script is started but does not tell me whats going on. Just a:

ls -la
ls: ./mnt: Input/output error

Perhaps a missing method? Already turned on the debug feature of fuse.py, but didn't help either...

memoryfs: how to support multiple directory levels

Thanks for fusepy - it's probably the best Python binding to FUSE available.

fusepy/examples/memory.py has this comment:

'Example memory filesystem. Supports only one level of files.'

and indeed this is the case.

How could I support a proper memoryfs (i.e. one that works for multiple levels of directories)? Could you please share some hints? Please point me in the right direction?

Test infrastructure and suite

As per @s-m-e's comment in issue #75, this issue is to propose, discuss, and prioritize the future road map for fusepy. Here is a quote from @s-m-e's comment on the other issue:

The following points come to mind:

  • Analysis of open pull requests and issues
  • Python 2 and/or 3 support? 2017 saw a long awaited trend towards moving to Python 3 as the default in Linux distributions. At the same time, many significant packages have begun to drop Python 2 support.
  • Windows support (as has been developed in different flavors in some forks). It's an amazing feature to have.
  • CI testing. Travis for instance offers Linux and OS X (but lacks *BSD). Different architectures can be covered with Qemu (assuming speed does not matter while testing). Qemu can also be used on top of Travis for running BSD.
  • Support for libfuse version 3 (and, at the same time, version 2?). At least in the Linux space, very few distributions adopted version 3 (or offer packages), so version 2 will remain relevant for the foreseeable future. On the other hand, version 2 has not seen development other than bug fixes for 2 years.
  • Notifying downstream projects about the changed project status
  • Asking downstream projects maintaining their own forks of fusepy about their interest / potential motivation in merging their changes and patches back into "upstream" fusepy
  • Contacting maintainers of forks of fusepy itself, exploring their interest in merging their developments back into "upstream"
  • Moving the module's code into a src folder, making it easier to maintain
  • Breaking the files fuse.py and fusell.py into files (sub-modules) specific to operating systems and architectures and common files. (And for people loving single-file modules, if requested, adding a "compiler" script for producing a single-file distribution/release version.)

I'd also like to suggest at least another maintenance release, like 2.0.x, for fixing bugs in the current code base - while development of a new release might happen in its own separate branch. It'll take time. There is also the option of releasing a package with breaking API changes under a new name like "fusepy3". I'd really like to keep the API as stable as possible.

Unable to deal with non-UTF-8 filenames

Fusepy was recently modified to treat all filenames and metadata as Unicode strings instead of byte strings. This works when filenames are UTF-8, but breaks when filenames or other metadata contain byte sequences that are not valid UTF-8 characters.

As I originally reported here, user code should be written to deal with bytes, not the other way around. On POSIX operating systems, file paths are NOT specified as being UTF-8 or any specific Unicode encoding. The only correct way to deal with filenames on Unix is to treat them as byte strings. Most software I've seen treats them as UTF-8, but at the file system level, they are binary strings and any FUSE implementation would be broken if it didn't support non-UTF-8 filenames.

In other words, I need to be able to cd to a FUSE-mounted file system, open Python 3, and type this:

>>> import os
>>> open(b'd\xe9j\xe0_vu.txt', 'w').close()
>>> os.listdir(b'.')
[b'd\xe9j\xe0_vu.txt']

In most shells, if you ls this file, it will display as d?j?_vu.txt. But it is a perfectly valid Latin-1-encoded filename. If fusepy encoded the filename as a Unicode string before sending it to the user code, it would either throw an exception in this case, or corrupt the filename.

The current version of fusepy (the GitHub version) breaks this assumption. Commit 2590f48 adds an 'encoding' argument to the FUSE constructor, and then decodes all the bytes values to strs with this encoding before giving them to the user-supplied operations, and encodes all strs supplied by user code before giving them back to the operating system. Unfortunately, it isn't a correct solution to simply say "pick an encoding before you start". File systems must be able to support different files with different encodings on their names.

If you run memory.py and then perform my above example, you get this:

Traceback (most recent call last):
  File "fuse.py", line 402, in _wrapper
    return func(*args, **kwargs) or 0
  File "fuse.py", line 410, in getattr
    return self.fgetattr(path, buf, None)
  File "fuse.py", line 640, in fgetattr
    attrs = self.operations('getattr', path.decode(self.encoding), fh)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 2: invalid continuation byte

Alternatively, create the b'd\xe9j\xe0_vu.txt' file somewhere on a normal drive, and then run the loopback.py example on the directory containing that file. Attempting to 'ls' the directory results in this exception:

Traceback (most recent call last):
  File "fuse.py", line 402, in _wrapper
    return func(*args, **kwargs) or 0
  File "fuse.py", line 586, in readdir
    if filler(buf, name.encode(self.encoding), st, offset) != 0:
UnicodeEncodeError: 'utf-8' codec can't encode character '\udce9' in position 1: surrogates not allowed

First things first: I have created a relatively incomplete test script which is in my tests branch. It tests mounting the memory filesystem and creating a binary filename, and this test currently fails in both Python 2 and 3. (Note that this test passes in Python 2 on the latest Google Code version of fusepy, SVN r65.)

I have also prepared a branch which fixes this issue in the ideal way for me: bytes. This branch removes all of the encode/decode calls and the encoding parameter to the FUSE constructor. All Operation methods accept and return plain bytes objects. This is ideally the way it should work. I have made sure this works on Python 2.7 and 3.2 (with 2to3). Note that I have updated the memory, loopback and context examples, but not the sftp example, as I was unable to test it.

However, it may be too drastic to accept this change: for one thing, it breaks on Python 2.5 and earlier, because it introduces b'' notation. (This is necessary to properly run on Python 3.) For another thing, it may break existing users who have adopted the Unicode strings in the current version.

I have thought a bit about another less drastic solution: work the way that Python 3's os.listdir works. The Python docs explain a bit about how this works here. Basically, byte strings are converted into unicode strings, but if any bytes are invalid in that encoding, they are replaced with U+DCxx where xx is the byte value. This is a bit hacky, but it allows the user to deal with Unicode strings, and then roundtrip properly back into bytes objects. Fusepy could employ the same technique on Python 3 when sending and receiving strings from the user's Operations methods. It is easy to implement: just call encode and decode with errors='surrogateescape'.

However, this only works in Python 3. In Python 2, you should absolutely not be encoding filenames and metadata as Unicode strings, because the Python 2 str type allows you to represent binary data but treat it as text.

If you go with this approach, I would also like the option of using bytes in my own code. Perhaps if I call the FUSE constructor with encoding=None, it will deal with bytes objects, and if I specify an encoding, it will use surrogateescape?

I'm happy to help work on the solution to this problem. I recognise that my branch is not a final solution, but the start of a discussion (which is why I haven't made a pull request). But I think it is necessary to resolve this issue in one way or another, because the current behaviour makes it impossible to implement a robust filesystem, and that is unacceptable to me.

Incorrect read() behaviour with direct_io enabled

FUSE.read() should return the number of bytes returned by actual implementation instead of number of bytes requested.

According to http://fuse.sourceforge.net/doxygen/structfuse__operations.html#2a1c6b4ce1845de56863f8b7939501b5 , FUSE itself fill substitute the remaining data with zeroes.

Proposed patch:

--- fuse.py.orig    2012-07-06 00:41:30.383794756 +0400
+++ fuse.py 2012-07-06 00:41:03.419408677 +0400
@@ -477,7 +477,7 @@

         data = create_string_buffer(ret[:size], size)
         memmove(buf, data, size)
-        return size
+        return min(size, len(ret))

     def write(self, path, buf, size, offset, fip):
         data = string_at(buf, size)

Can't start class of fuse.Operations in multiple processes.

Hello, I'm trying to write own encrypted filesystem with fusepy. I have already done console version and now I'm creating GUI for it. It is pretty simple, just "volume" manager with mount buttons. My idea is that I click on mount button and then program calls fuse.FUSE with appropriate arguments. But it only works for the first mount. If I try to mount second attribute, fuse.FUSE init method fails on following code
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))

I start thread like this
p = Process(target=fuse.FUSE, args=(Filecrypter(self.source_dir, password), self.mount_dir), kwargs=kargs)
p.start()
which should work, in my opinion. That's why I worry if it is not any bug in fuse class. What do you think?

No way to suppress call to signal.signal

In Python, you can only call signal.signal from the main thread.

http://docs.python.org/2.7/library/signal.html#signal.signal
http://docs.python.org/3/library/signal.html#signal.signal

Attempting to do so in a non-main thread causes ValueError to be raised. Attempting to invoke FUSE from the non-main thread thus dies, as there's no way to suppress the call to signal.signal in FUSE.__init__.

https://github.com/terencehonles/fusepy/blob/master/fuse.py#L390

Is there a reason why adding a keyword argument to the FUSE constructor to suppress this call to signal.signal would be bad?

performance with large numbers of files

Using lots of file within a directory (only tried /) results in a massive loss in performance. I tried to debug the issue, and did make some head-way, but I am stuck now. I don't know if I am doing something wrong, or something else is amiss. I would really welcome a pointer or hint.

In a test case (below) I count the number of calls to getattr() during a mount of a filesystem with a fixed number of files in it. As expected, there are calls to read_dir(), and then one call of getattr() for each file that is present (plus a few more 'common' names). However, if the number of files in the directory (N) exceeds a certain number (and the exact number is not deterministic, can vary from run to run; usually ~8000 for me), I get a lot more than N calls. Looking at which names are requested, I see that it is the files that are present, over and over again; sometimes the complete list, sometimes not. Plotting the numbers suggests a quadratic scaling after this point, possibly even worse for even higher numbers (it gets really slow then).

Thus: something calls getattr() a lot of times for large numbers of files in a directory. I couldn't figure out what though. I am not an expert in fuse, nor pyfuse. The calls are calls to pyfuse's fgetattr().

I couldn't attach the test case directly (unsupported file type). To advance the script, fusermount -u the directory from time to time (quick and dirty, but works). The output is, on my system (number of files) (number of calls to getattr)

10 16
25 31
50 56
100 106
250 256
500 506
1000 1006
2000 2006
5000 5006
7500 7506
10000 20008
15000 45008
20000 72402
30000 216842
40000 600008
50000 1150008

Note that this isn't meant to be pretty, but as short as possible to show the problem.

#!/usr/bin/env python3

from __future__ import print_function, absolute_import, division

from stat import S_IFDIR, S_IFLNK, S_IFREG
from time import time

from fuse import FUSE, Operations, LoggingMixIn

class TestFS(Operations):

  def __init__(self, nItems):
    self.nItems = nItems
    self.time = time()
    self.calls = 0

  def getattr(self, path, fh=None):
    if path == '/':
      st = dict(st_mode=(S_IFDIR | 0o755), st_nlink=2)
    else:
      st = dict(st_mode=(S_IFREG | 0o444), st_size=0)
    st['st_ctime'] = st['st_mtime'] = st['st_atime'] = self.time
    self.calls += 1
    return st

  def readdir(self, path, fh):
    return map(str, range(self.nItems))      

for n in [10,25,50,100,250,500,1000,2000,5000,7500,10000,15000,20000,30000,40000,50000]:
  fs = TestFS(n)
  fuse = FUSE(fs, "TestFS", foreground=True, ro=True)
  print(n, fs.calls)

Input/output error when getattr() called

when I entered my mount point,

getattr() returned the following dict:

{'st_ctime': 1393850496, 'st_nlink': 2, 'bd_blocklist': 0, 'st_gid': 0, 'st_dev': 0, 'st_ino': 0, 'st_mode': 16895, 'st_mtime': 1393850496, 'bd_md5': 0, 'st_size': 0, 'st_uid': 0, 'bd_fsid': 0, 'st_atime': 0}

(st_mode is stat.S_IFDIR | 0777)
then

root@Hiwifi:/tmp/baidu-fuse# cd mnt
-bash: cd: mnt: Input/output error

Does anyone could tell me what's wrong with this?
sorry for my English.

LICENSE

Which license is it? MIT?

readonly option

Hi there,

Is there a reason for the read only ('-r') option to not be included?

Thanks,
Adrian

Version mismatch on github and pipy

Hi,

The last release listed on github is 2.0.2 (here) but there is a 2.0.3 version on pipy here since quite some time. Github is described as the only official release source, so it would be nice if version numbers catched up.

Support init options and parameters

The initialization function of fuse accepts a fuse_conn_info structure, which can be used to investigate and control the system's capabilities.

The components of this structure are:
proto_major and proto_minor: Major and minor versions of the FUSE protocol (read-only).
async_read: On entry, this is nonzero if asynchronous reads are supported. The initialization function can modify this as desired. Note that this field is duplicated by the FUSE_CAP_ASYNC_READ flag; asynchronous reads are controlled by the logical OR of the field and the flag. (Yes, this is a silly hangover from the past.)
max_write: The maximum size of a write buffer. This can be modified by the init function. If it is set to less than 4096, it is increased to that value.
max_readahead: The maximum readahead size. This can be modified by the init function.
capable: The capabilities supported by the FUSE kernel module, encoded as bit flags (read-only).
want: The capabilities desired by the FUSE client, encoded as bit flags.

The capabilities that can be requested are:
FUSE_CAP_ASYNC_READ
Use asynchronous reads (default). To disable this option, the client must clear both this capability (in the want flags) and the async_read field. If synchronous reads are chosen, Fuse will wait for reads to complete before issuing any other requests.
FUSE_CAP_POSIX_LOCKS
Set if the client supports "remote" locking via the lock call.
FUSE_CAP_ATOMIC_O_TRUNC
Set if the filesystem supports the O_TRUNC open flag.
FUSE_CAP_EXPORT_SUPPORT
Set if the client handles lookups of "." and ".." itself. Otherwise, FUSE traps these and handles them.
FUSE_CAP_BIG_WRITES
Set if the filesystem can handle writes larger than 4 KB.
FUSE_CAP_DONT_MASK
Set to prevent the umask from being applied to files on create operations. (Note: as far as I can tell from examining the code, this flag isn't actually implemented.)

See also: https://www.cs.hmc.edu/~geoff/classes/hmc.cs135.201001/homework/fuse/fuse_doc.html

raise EnvironmentError('Unable to find libfuse')

HI i am trying to compile GDriveFS for thecus NAS.
All cross compile went fine with Fuse library in my Prefix directory
but fusepy remain an error

N2800:/raid/data/module/GDrive/sys/bin# ./gdfstool --help
Traceback (most recent call last):
File "./gdfstool", line 16, in
from gdrivefs.gdfs.gdfuse import set_auth_cache_filepath, mount,
File "/raid/data/module/GDrive/sys/lib/python2.7/site-packages/gdrivefs/gdfs/gdfuse.py", line 12, in
from fuse import FUSE, Operations, FuseOSError, c_statvfs, fuse_get_context,
File "/raid/data/module/GDrive/sys/lib/python2.7/site-packages/fusepy-2.0.2-py2.7.egg/fuse.py", line 69, in
raise EnvironmentError('Unable to find libfuse')
EnvironmentError: Unable to find libfuse

doing an import fuse also show up the same error

N2800:/raid/data/module/GDrive/sys/bin# ./python
Python 2.7.6 (default, Apr 12 2014, 12:45:45)
[GCC 4.5.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.

import fuse
Traceback (most recent call last):
File "", line 1, in
File "/raid0/data/module/GDrive/sys/lib/python2.7/site-packages/fusepy-2.0.2-py2.7.egg/fuse.py", line 69, in
raise EnvironmentError('Unable to find libfuse')
EnvironmentError: Unable to find libfuse

I think fusepy doesnt link correctly my fuse lib in my prefix directory, can someone please help me on this issue.

i even dont find any flags while compiling to point the right location for the include, or libs, I tried compile fusepy independently with the following :

CXX=${HOST}-g++
LD=${HOST}-ld
AS=${HOST}-as
AR=${HOST}-ar
CC=${HOST}-gcc
PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig"
CFLAGS="-O2 -I$PREFIX/include "
CXXFLAGS="-O2 -I$PREFIX/include"
LDFLAGS="-L$PREFIX/lib -Wl,-rpath,$PREFIX/lib"
CPPFLAGS="-O2 -I$PREFIX/include"
$PREFIX/bin/python setup.py install --prefix=$PREFIX

als o tried to do some export

export LD_LIBRARY_PATH=$PREFIX/lib:$LD_LIBRARY_PATH
export PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig"

no effect... :(

Wont install from pipi becasue README file is missing

I get the following output:

$ ~/pythonenv/bin/easy_install fusepy
Searching for fusepy
Reading http://pypi.python.org/simple/fusepy/
Reading http://code.google.com/p/fusepy/
Reading http://github.com/terencehonles/fusepy
Best match: fusepy 2.0.1
Downloading http://pypi.python.org/packages/source/f/fusepy/fusepy-2.0.1.tar.gz#md5=00e8b212bc8cd4fdaa012a0a5f5ba9f4
Processing fusepy-2.0.1.tar.gz
Running fusepy-2.0.1/setup.py -q bdist_egg --dist-dir /tmp/easy_install-SAq4jc/fusepy-2.0.1/egg-dist-tmp-N5EARj
error: README: No such file or directory

Any idea why this is happening? I see there is a README file

`fuse_file_info` doesn't have `nonseekable`

I have a socket-like file that can be read, but not seeked.

On the C api, I can use fi.nonseekable = 1 to indicate that, but this doesn't seem to be present on fusepy.

Is that an error, or is there something I am missing?

Include license text in its own file

I'm packaging this module for Fedora and I see that you don't include the license text in its own file. Our policy [1] is to notify upstream about this and encourage you to add it.

In the source code files you could leave the copyright notice and a note of the license used and where is the license text.

I could make a pull request if you wish.

Kind regards.

[1] https://fedoraproject.org/wiki/Packaging:LicensingGuidelines?rd=Packaging/LicensingGuidelines#License_Text

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.