定义需要的函数要使用 FUSE 来创建一个文件系统,您需要声明一个 fuse_operations 类型的结构变量,并将其传递给 fuse_main 函数。fuse_operations 结构中有一个指针,指向在执行适当操作时需要调用的函数。清单 1 给出了 fuse_operations 结构。
清单 1. fuse_operation 结构中需要的函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| struct fuse_operations {
int (*getattr) (const char *, struct stat *);
int (*readlink) (const char *, char *, size_t);
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_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 statfs *);
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 *);
};
|
这些操作并非都是必需的,但是一个文件系统要想正常工作,就需要其中的很多函数。您可以实现一个具有特殊目的的 .flush、.release 或 .fsync 方法的功能完备的文件系统。(本文不会介绍任何 xattr 函数。)清单 1 中给出的函数如下所示:
- getattr: int (*getattr) (const char *, struct stat *);
这个函数与 stat() 类似。st_dev 和 st_blksize 域都可以忽略。st_ino 域也会被忽略,除非在执行 mount 时指定了 use_ino 选项。 - readlink: int (*readlink) (const char *, char *, size_t);
这个函数会读取一个符号链接的目标。缓冲区应该是一个以 null 结束的字符串。缓冲区的大小参数包括这个 null 结束字符的空间。如果链接名太长,不能保存到缓冲区中,就应该被截断。成功时的返回值应该是 “0”。 - getdir: int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
这个函数会读取一个目录中的内容。这个操作实际上是在一次调用中执行 opendir()、readdir()、...、closedir() 序列。对于每个目录项来说,都应该调用 filldir() 函数。 - mknod: int (*mknod) (const char *, mode_t, dev_t);
这个函数会创建一个文件节点。此处没有 create() 操作;mknod() 会在创建非目录、非符号链接的节点时调用。 - mkdir: int (*mkdir) (const char *, mode_t);
rmdir: int (*rmdir) (const char *);
这两个函数分别用来创建和删除一个目录。 - unlink: int (*unlink) (const char *);
rename: int (*rename) (const char *, const char *);
这两个函数分别用来删除和重命名一个文件。 - symlink: int (*symlink) (const char *, const char *);
这个函数用来创建一个符号链接。 - link: int (*link) (const char *, const char *);
这个函数创建一个到文件的硬链接。 - chmod: int (*chmod) (const char *, mode_t);
chown: int (*chown) (const char *, uid_t, gid_t);
truncate: int (*truncate) (const char *, off_t);
utime: int (*utime) (const char *, struct utimbuf *);
这 4 个函数分别用来修改文件的权限位、属主和用户、大小以及文件的访问/修改时间。 - open: int (*open) (const char *, struct fuse_file_info *);
这是文件的打开操作。对 open() 函数不能传递创建或截断标记(O_CREAT、O_EXCL、O_TRUNC)。这个函数应该检查是否允许执行给定的标记的操作。另外,open() 也可能在 fuse_file_info 结构中返回任意的文件句柄,这会传递给所有的文件操作。 - read: int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *);
这个函数从一个打开文件中读取数据。除非碰到 EOF 或出现错误,否则 read() 应该返回所请求的字节数的数据;否则,其余数据都会被替换成 0。一个例外是在执行 mount 命令时指定了 direct_io 选项,在这种情况中 read() 系统调用的返回值会影响这个操作的返回值。 - write: int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info *);
这个函数将数据写入一个打开的文件中。除非碰到 EOF 或出现错误,否则 write() 应该返回所请求的字节数的数据。一个例外是在执行 mount 命令时指定了 direct_io 选项(这于 read() 操作的情况类似)。 - statfs: int (*statfs) (const char *, struct statfs *);
这个函数获取文件系统的统计信息。f_type 和 f_fsid 域都会被忽略。 - flush: int (*flush) (const char *, struct fuse_file_info *);
这表示要刷新缓存数据。它并不等于 fsync() 函数 —— 也不是请求同步脏数据。每次对一个文件描述符执行 close() 函数时,都会调用 flush();因此如果文件系统希望在 close() 中返回写错误,并且这个文件已经缓存了脏数据,那么此处就是回写数据并返回错误的好地方。由于很多应用程序都会忽略 close() 错误,因此这通常用处不大。 注意:我们也可以对一个 open() 多次调用 flush() 方法。如果由于调用了 dup()、dup2() 或 fork() 而产生多个文件描述符指向一个打开文件的情况,就可能会需要这种用法。我们无法确定哪个 flush 操作是最后一次操作,因此每个 flush 都应该同等地对待。多个写刷新序列相当罕见,因此这并不是什么问题。
- release: int (*release) (const char *, struct fuse_file_info *);
这个函数释放一个打开文件。release() 是在对一个打开文件没有其他引用时调用的 —— 此时所有的文件描述符都会被关闭,所有的内存映射都会被取消。对于每个 open() 调用来说,都必须有一个使用完全相同标记和文件描述符的 release() 调用。对一个文件打开多次是可能的,在这种情况中只会考虑最后一次 release,然后就不能再对这个文件执行更多的读/写操作了。release 的返回值会被忽略。 - fsync: int (*fsync) (const char *, int, struct fuse_file_info *);
这个函数用来同步文件内容。如果 datasync 参数为非 0,那么就只会刷新用户数据,而不会刷新元数据。 - setxattr: int (*setxattr) (const char *, const char *, const char *, size_t, int);
getxattr: int (*getxattr) (const char *, const char *, char *, size_t);
listxattr: int (*listxattr) (const char *, char *, size_t);
removexattr: int (*removexattr) (const char *, const char *);
这些函数分别用来设置、获取、列出和删除扩展属性。 获得的文件系统您的文件系统将如下所示:
1
| afsfuse_client <--RX[RPC]--> afsfuse_server
|
afsfuse_client 会将传递给它的文件系统调用转发给另外一台机器上的 afsfuse_server。afsfuse_server 会对客户机传递给它的所有请求进行处理,并将结果返回给客户机。它会执行所有必需的工作。RPC 使用的机制是 RX。数据或原数据都不会涉及缓存的问题。 |