当前位置: 首页 > 工具软件 > FUSE > 使用案例 >

FUSE简介

申屠无尘
2023-12-01

一、FUSE简介

    FUSE(用户空间文件系统)是这样一个框架:它使得FUSE用户在用户态下编写文件系统成为可能,而不必和内核打交道。

    FUSE由三个部分组成:linux内核模块、FUSE库 以及mount 工具。

    用户关心的只是FUSE库和mount工具,内核模块仅仅提供kernel的接入口,给了文件系统一个框架,而文件系统本身的主要实现代示位于用户空间中。FUSE库给用户提供了编程的接口,而mount工具则用于挂在用户编写的文件系统。

    FUSE起初是为了研究AVFS(A Virtual Filesystem)而设计的,而现在已经成为 SourceForge的一个独立项目,目前适用的平台有Linux, FreeBSD, NetBSD, OpenSolaris和 Mac OS X。

    官方的linux kernel版本到 2.6.14 才添加了FUSE模块,因此 2.4 的内核模块下,用户如果要在FUSE中创建一个文件系统,需要先安装一个FUSE内核模块,然后使用 FUSE库和API来创建。

二、FUSE特性

  1 库文件和API简单,极大地方便了用户的使用

  2 安装简便,不需要加补丁或者重新编译 kernel

  3 执行安全,使用稳定

  4 高效,相对于其它用户态文件系统实现

  5 非特权用户可以使用

  6 基于 linux2.4.x 和 2.6.x 内核,现在可以支持JavaTM 绑定,不必限定使用C和C++来 编写文件系统。

三、源代码目录

  1 ./doc 包含FUSE相关文档
  2 ./include 包含了FUSE API头,对创建文件系统有用,主要用fuse.h
  3 ./lib 存放FUSE库
  4 ./util 包含了FUSE工具库
  5 ./example 参考的例子

四、安装

    FUSE的示示安装类似于其他软件,只需要在FUSE的目录下以root身份执行执行如下命令即可,如:

./configure --disable-kernel-module

make

make install

    如果在配置时提示

configure: error: no acceptable C compiler found in $PATH

    则需要安装gcc:

yum install gcc

五、FUSE operations

  FUSE使用fuse_operations来给用户提供编程结构,让用户通过注册自己编写的函数到该结构体来实现自己的文件系统。

struct fuse_operations {
     int (*getattr) (const char *, struct stat *);
     int (*readlink) (const char *, char *, size_t);
     int (*mknod) (const char *, mode_t, dev_t);
     int (*mkdir) (const char *, mode_t);
     int (*unlink) (const char *); int (*rmdir) (const char *);
     int (*symlink) (const char *, const char *);
     int (*rename) (const char *, const char *);
     int (*link) (const char *, const char *);
     int (*chmod) (const char *, mode_t);
     int (*chown) (const char *, uid_t, gid_t);
     int (*truncate) (const char *, off_t);
     int (*utime) (const char *, struct utimbuf *);
     int (*open) (const char *, struct fuse_file_info *);
     int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *);
     int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info *);
     int (*statfs) (const char *, struct statvfs *);
     int (*flush) (const char *, struct fuse_file_info *);
     int (*release) (const char *, struct fuse_file_info *);
     int (*fsync) (const char *, int, struct fuse_file_info *);
     int (*setxattr) (const char *, const char *, const char *, size_t, int);
     int (*getxattr) (const char *, const char *, char *, size_t);
     int (*listxattr) (const char *, char *, size_t);
     int (*removexattr) (const char *, const char *);
     int (*opendir) (const char *, struct fuse_file_info *);
     int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *);
     int (*releasedir) (const char *, struct fuse_file_info *);
     int (*fsyncdir) (const char *, int, struct fuse_file_info *);
     void *(*init) (struct fuse_conn_info *conn);
     void (*destroy) (void *); int (*access) (const char *, int);
     int (*create) (const char *, mode_t, struct fuse_file_info *);
     int (*ftruncate) (const char *, off_t, struct fuse_file_info *);
     int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *);
     int (*lock) (const char *, struct fuse_file_info *, int cmd, struct flock *);
     int (*utimens) (const char *, const struct timespec tv[2]);
     int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
 };

六、hello示例文件系统分析

   FUSE在实例目录example下有一些示例文件系统,通过阅读这些示例文件系统可以掌握FUSE用户态文件系统的编写规范。下面以hello.c为示分析FUSE的编写规范:

 #define FUSE_USE_VERSION 26
 #include <fuse.h>
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
 
 static const char *hello_str = "Hello World!\n";
 static const char *hello_path = "/hello";
 

static int hello_getattr(const char *path, struct stat *stbuf) {
   int res = 0;
  
   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
        res = -ENOENT; 
       
   return res; 
}   
 
 

static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t     filler, off_t offset, struct fuse_file_info *fi)  {
    (void) offset;
    (void) fi;

    if(strcmp(path, "/") != 0)
        return -ENOENT;

    filler(buf, ".", NULL, 0); 
    filler(buf, "..", NULL, 0); 
    filler(buf, hello_path + 1, NULL, 0);  

    return 0;
}

 /-* fill的定义:
     typedef int (*fuse_fill_dir_t) (void *buf, const char *name, const struct stat *stbuf, off_t off);
     其作用是在readdir函数中增加一个目录项
 *-/

 
 
static int hello_open(const char *path, struct fuse_file_info *fi) {
    if(strcmp(path, hello_path) != 0)
        return -ENOENT;

    if((fi->flags & 3) != 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 struct fuse_operations hello_oper =
 {
   .getattr = hello_getattr,
   .readdir = hello_readdir,
   .open    = hello_open,
   .read    = hello_read,
 };
 
 /-*用户只需要调用fuse_main(),剩下的事就交给FUSE了*-/
 int main(int argc, char *argv[])
 {
     return fuse_main(argc, argv, &hello_oper, NULL);
 }

 终端运行:
 
 ~/fuse/example$ mkdir /tmp/fuse 

~/fuse/example$ ./hello /tmp/fuse   

~/fuse/example$ ls -l /tmp/fuse hello   

-r--r--r-- 1 root root 13 1970-01-01 07:00 hello

~/fuse/example$ cat /tmp/fuse/hello Hello World!   


~/fuse/example$ fusermount -u /tmp/fuse 

  通过上述的分析可以知道,使用FUSE必须要自己实现对文件或目录的操作, 系统调用也会最终调用到用户自己实现的函数。

  用户实现的函数需要在结构体fuse_operations中注册。而在main()函数中,用户只需要调用fuse_main()函数就可以了,剩下的复杂工作可以交给FUSE。

 

 

 类似资料: