FUSE (Filesystem in Userspace) allows non-privileged users to create their own file systems. It works by mounting the file system within the userspace virtual file system. Python has a FUSE library called fusepy that provides a simple interface for implementing FUSE file systems in Python. PEPFS is an example of a FUSE file system implemented in Python that makes Python Enhancement Proposals (PEPs) available as read-only files organized in a file system structure. It uses fusepy and lazily downloads specific PEP files on demand when read.
2. File System
Application
Virtual File System (VFS)
Device Driver
Device (HDD, SSD, CD-ROM, NIC, etc)
User Space
Kernel Space Syscall Interface
Block Layer
Page CacheDirect I/O
Hardware
ext2, ext3,
ext4, btrfs
NFS,
smbfs
FUSE
procfs,
tmpfs
3. FUSE (File System In Userspace)
Available for Linux, FreeBSD, OpenBSD, NetBSD (as puffs), OpenSolaris, Minix 3,
Android and macOS [2]
In Linux kernel since version 2.6.14
Windows compatibility is provided by libraries and ports [3, 4, 5]
5. Example uses
GlusterFS: Clustered Distributed Filesystem
GmailFS: Filesystem which stores data as mail in Gmail
SSHFS: Provides access to a remote filesystem through SSH
WikipediaFS: View and edit Wikipedia articles as if they were real files
πfs: A file system that stores all files in the digits of Pi
6. struct fuse_operations {
int (*getattr) (const char *path, struct stat *stbuf);
...
int (*readdir) (const char *path, void *buf,
fuse_fill_dir_t filler, off_t offset,
struct fuse_file_info *fi);
...
int (*read) (const char *path, char *buf, size_t size,
off_t offset, struct fuse_file_info *fi);
...
};
libfuse API
8. PEPFS
Read-only file system with PEPs as the files [8]
Uses github repository with PEPs to get the current PEPs [9]
Implemented in Python and uses the fusepy module
Lazy PEP files' read (download specific PEP on demand)
9. PEPFS mount
$ ./pepfs.py /tmp/pepfs/
$ mount
...
PEPFS on /tmp/pepfs type fuse
(rw,nosuid,nodev,relatime,user_id=1000,group_id=1000)
...
11. Page Cache
To enable Page Cache, you need to set the flag keep_cache, in open() method:
def open(self, path, flags):
flags.keep_cache = 1
return 0
And also set raw_fi to True in FUSE(PEPFS(), ..., raw_fi=True)
NB: Invalidation of cache and updating of data occurs only if the file size changes