FUSE Python tutorial
FUSE Python Tutorial
FUSE filesystems can be written in any language that has a binding to the FUSE libraries. Python is one such language. Writing a FUSE filesystem in Python is as easy as subclassing the Fuse object in the fuse module and writing your desired functionality into the proper class methods.
On Debian Linux (and derivatives such as Ubuntu), installing FUSE and its Python binding is as easy as using apt-get install python-fuse. On Fedora, using yum install fuse-python will install the FUSE Python binding. In such a case you may need to locate and install the packages manually or even compile from source. On Debian the newest Python binding for FUSE seems to be for version 2.3 of Python.
The FUSE Python binding can be found in the Gentoo's Portage repository as dev-python/fuse-python. To install it just run emerge fuse-python.
With the Python FUSE package comes an example filesystem called Xmp.py. This covers the basics of what you need to know to get started but doesn't provide much guidance beyond that point. It's also rather confussing as it isn't very well documented and is full of garbage documentation that makes it difficult to read. It's worth looking at but here we'll start with something a little cleaner. This class prints out a line when each function is called, along with the arguments as passed to that function, and then returns a "Not Implemented" value. Obviously, this class will not run as-is. This example code includes also a couple helper functions.
#!/usr/bin/python from fuse import Fuse from time import time import stat # for file properties import os # for filesystem modes (O_RDONLY, etc) import errno # for error number codes (ENOENT, etc) # - note: these must be returned as negatives def dirFromList(list): """ Return a properly formatted list of items suitable to a directory listing. [['a', 'b', 'c']] => [[('a', 0), ('b', 0), ('c', 0)]] """ return [[(x, 0) for x in list]] def getDepth(path): """ Return the depth of a given path, zero-based from root ('/') """ if path <code></code> '/': return 0 else: return path.count('/') def getParts(path): """ Return the slash-separated parts of a given path as a list """ if path <code></code> '/': return [['/']] else: return path.split('/') class NullFS(Fuse): """ """ def __init__(self, *args, **kw): Fuse.__init__(self, *args, **kw) print 'Init complete.' def getattr(self, path): """ - st_mode (protection bits) - st_ino (inode number) - st_dev (device) - st_nlink (number of hard links) - st_uid (user ID of owner) - st_gid (group ID of owner) - st_size (size of file, in bytes) - st_atime (time of most recent access) - st_mtime (time of most recent content modification) - st_ctime (platform dependent; time of most recent metadata change on Unix, or the time of creation on Windows). """ print '*** getattr', path depth = getDepth(path) # depth of path, zero-based from root pathparts = getParts(path) # the actual parts of the path return -errno.ENOSYS def getdir(self, path): """ return: [[('file1', 0), ('file2', 0), ... ]] """ print '*** getdir', path return -errno.ENOSYS def mythread ( self ): print '*** mythread' return -errno.ENOSYS def chmod ( self, path, mode ): print '*** chmod', path, oct(mode) return -errno.ENOSYS def chown ( self, path, uid, gid ): print '*** chown', path, uid, gid return -errno.ENOSYS def fsync ( self, path, isFsyncFile ): print '*** fsync', path, isFsyncFile return -errno.ENOSYS def link ( self, targetPath, linkPath ): print '*** link', targetPath, linkPath return -errno.ENOSYS def mkdir ( self, path, mode ): print '*** mkdir', path, oct(mode) return -errno.ENOSYS def mknod ( self, path, mode, dev ): print '*** mknod', path, oct(mode), dev return -errno.ENOSYS def open ( self, path, flags ): print '*** open', path, flags return -errno.ENOSYS def read ( self, path, length, offset ): print '*** read', path, length, offset return -errno.ENOSYS def readlink ( self, path ): print '*** readlink', path return -errno.ENOSYS def release ( self, path, flags ): print '*** release', path, flags return -errno.ENOSYS def rename ( self, oldPath, newPath ): print '*** rename', oldPath, newPath return -errno.ENOSYS def rmdir ( self, path ): print '*** rmdir', path return -errno.ENOSYS def statfs ( self ): print '*** statfs' return -errno.ENOSYS def symlink ( self, targetPath, linkPath ): print '*** symlink', targetPath, linkPath return -errno.ENOSYS def truncate ( self, path, size ): print '*** truncate', path, size return -errno.ENOSYS def unlink ( self, path ): print '*** unlink', path return -errno.ENOSYS def utime ( self, path, times ): print '*** utime', path, times return -errno.ENOSYS def write ( self, path, buf, offset ): print '*** write', path, buf, offset return -errno.ENOSYS if __name__ == __main__: fs = NullFS() fs.flags = 0 fs.multithreaded = 0 fs.main()
The normal object constructor. It needs to pass its inputs along to the constructor in the Fuse class. Besides that you can use it for whatever your filesystem needs to happen when it's initialized.