libfuse
libfuse
- Definition: libfuse (Filesystem in Userspace) is a library that provides a simple interface for userspace programs to export a virtual filesystem to the Linux kernel. It allows developers to create custom filesystems without writing kernel code.
- Function: Facilitates the creation and implementation of filesystems that run in user space, enabling the development of custom filesystem logic without requiring kernel-level programming.
- Components:
* '''libfuse Library''': The core library that provides the FUSE API for creating user-space filesystems. * '''fusermount Utility''': A helper program to mount and unmount FUSE filesystems. * '''FUSE Daemon''': A user-space process that implements the filesystem logic.
- Features:
* '''User-Space Filesystem Development''': Allows filesystems to be developed and run in user space. * '''Portability''': Supported on Linux and other Unix-like operating systems. * '''Flexibility''': Enables the creation of various types of filesystems, such as network filesystems, encrypted filesystems, and more. * '''Ease of Use''': Simplifies the development process by providing a high-level API.
- Usage: Commonly used for developing custom filesystems, network-based filesystems, and other specialized filesystems that require user-space implementation.
Examples
- Creating a simple FUSE filesystem in C:
```c #define FUSE_USE_VERSION 31 #include
#include
static const char *hello_str = "Hello World!\n"; static const char *hello_path = "/hello";
static int hello_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) { (void) fi; memset(stbuf, 0, sizeof(struct stat)); if (strcmp(path, "/") == 0) { stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 2; } else if (strcmp(path, hello_path) == 0) { stbuf->st_mode = S_IFREG | 0444; stbuf->st_nlink = 1; stbuf->st_size = strlen(hello_str); } else { return -ENOENT; } return 0; }
static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi, enum fuse_readdir_flags flags) { (void) offset; (void) fi; (void) flags; if (strcmp(path, "/") != 0) { return -ENOENT; } filler(buf, ".", NULL, 0, 0); filler(buf, "..", NULL, 0, 0); filler(buf, "hello", NULL, 0, 0); return 0; }
static int hello_open(const char *path, struct fuse_file_info *fi) { if (strcmp(path, hello_path) != 0) { return -ENOENT; } if ((fi->flags & O_ACCMODE) != O_RDONLY) { return -EACCES; } return 0; }
static int hello_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { size_t len; (void) fi; if (strcmp(path, hello_path) != 0) { return -ENOENT; } len = strlen(hello_str); if (offset < len) { if (offset + size > len) { size = len - offset; } memcpy(buf, hello_str + offset, size); } else { size = 0; } return size; }
static const struct fuse_operations hello_oper = { .getattr = hello_getattr, .readdir = hello_readdir, .open = hello_open, .read = hello_read, };
int main(int argc, char *argv[]) { return fuse_main(argc, argv, &hello_oper, NULL); } ```
- Using libfuse in a Python script (with the `fusepy` library):
```python from fuse import FUSE, Operations
class HelloFS(Operations): def getattr(self, path, fh=None): if path == '/': return dict(st_mode=(0o755 | 0o040000), st_nlink=2) elif path == '/hello': return dict(st_mode=(0o444 | 0o100000), st_nlink=1, st_size=len("Hello World!\n")) else: raise FuseOSError(ENOENT)
def readdir(self, path, fh): return ['.', '..', 'hello']
def open(self, path, flags): if path != '/hello': raise FuseOSError(ENOENT)
def read(self, path, size, offset, fh): return "Hello World!\n"[offset:offset + size]
if __name__ == '__main__': fuse = FUSE(HelloFS(), 'mnt', foreground=True) ```
- Using libfuse in a Java program (with a hypothetical Java binding):
```java import ru.serce.jnrfuse.FuseStubFS; import ru.serce.jnrfuse.struct.FileStat;
import java.nio.ByteBuffer; import java.nio.file.Paths;
public class HelloFS extends FuseStubFS { private static final String HELLO_PATH = "/hello"; private static final String HELLO_STR = "Hello World!\n";
@Override public int getattr(String path, FileStat stat) { if (path.equals("/")) { stat.st_mode.set(FileStat.S_IFDIR | 0755); stat.st_nlink.set(2); } else if (path.equals(HELLO_PATH)) { stat.st_mode.set(FileStat.S_IFREG | 0444); stat.st_nlink.set(1); stat.st_size.set(HELLO_STR.length()); } else { return -ErrorCodes.ENOENT(); } return 0; }
@Override public int readdir(String path, DirectoryFiller filler) { if (!path.equals("/")) { return -ErrorCodes.ENOENT(); } filler.add("."); filler.add(".."); filler.add("hello"); return 0; }
@Override public int open(String path, FuseFileInfo fi) { if (!path.equals(HELLO_PATH)) { return -ErrorCodes.ENOENT(); } return 0; }
@Override public int read(String path, ByteBuffer buf, long size, long offset, FuseFileInfo fi) { if (!path.equals(HELLO_PATH)) { return -ErrorCodes.ENOENT(); } String s = HELLO_STR; if (offset < s.length()) { if (offset + size > s.length()) { size = s.length() - offset; } buf.put(s.getBytes(), (int) offset, (int) size); } else { size = 0; } return (int) size; }
public static void main(String[] args) { HelloFS fs = new HelloFS(); try { fs.mount(Paths.get("/mnt"), true, false); } finally { fs.umount(); } } } ```
Summary
- libfuse: A library for creating user-space filesystems, allowing developers to implement custom filesystem logic without writing kernel code. It provides an API for filesystem development, supported on Linux and other Unix-like operating systems. libfuse is widely used for creating network filesystems, encrypted filesystems, and other specialized filesystems.
libfuse.txt · Last modified: 2024/08/12 05:26 by 127.0.0.1