PyFilesystem / pyfilesystem

Python filesystem abstraction layer
http://pyfilesystem.org/
BSD 3-Clause "New" or "Revised" License
287 stars 63 forks source link

FUSE exposure and statfs #268

Open nimamox opened 7 years ago

nimamox commented 7 years ago

I’ve implemented a filesystem using pyfilesystem that works very well and can be mounted using Fuse in a Linux box. Now I need to create a network share on it via Samba. The problem is that when I access the Samba share, files can be successfully read, but fails to write new files, telling me there's not enough space. I have implemented getmeta() to provide values for free_space and total_space, but the method is not called at all.

I'm not sure but reckon the problem is with pyfilesystem. I've compared pyfilesystem’s OSFS with fusepy’s Loopback. OSFS is run as below:

cfs = OSFS("/tmp/")
fuse.mount(cfs,"/home/nima/mntOSFS", allow_other=True, foreground=True)

and fusepy's Loopback:

fuse = FUSE(Loopback('/tmp'), '/home/nima/mntFusepy', foreground=True, allow_other=True)

Running both codes, /tmp is mounted successfully under corresponding mount points, but df shows only the fusepy's. Samba can also correctly write to share on fusepy's loopback, but not on pyfilesystem's OSFS.

nima@nima-vm:~$ df -H
Filesystem      Size  Used Avail Use% Mounted on
[ommited]
Loopback         20G   15G  4.8G  75% /home/nima/mntFusepy

Upon running df, underlying FUSE.statfs is called for fusepy, but is not so for pyfilesystem.

nimamox commented 7 years ago

I realized that the delegating interface FSOperations misses a statfs() method and can be simply added to call getmeta() of the underlying FS. I prepend statvfs. to the names to distinguish these non-generic metadata in getmeta() as documentation specifies. Any thoughts?

#fs/expose/fuse/__init__.py
class FSOperations(Operations):

    @handle_fs_errors
    def statfs(self, path):
        stats = {}
        if hasattr(self.fs, 'getmeta'):
            for k in ['f_blocks', 'f_ffree', 'f_bsize', 'f_bavail', 'f_bfree', 
                      'f_flag', 'f_favail', 'f_files', 'f_frsize', 'f_namemax']:
                v = self.fs.getmeta('statvfs.' + k, None)
                if v:
                    stats[k] = v
        return stats