Filesystem in Userspace,是Linux 中用于挂载某些网络空间,如SSH,到本地文件系统的模块,在SourceForge上可以找到相关内容(http://sourceforge.net/)
//FUSE和内核的通信过程
+----------------+
| myfs /tmp/fuse |
+----------------+
| ^
+--------------+ v |
| ls /tmp/fuse | +--------------+
+--------------+ | libfuse |
^ | +--------------+
| v | |
+--------------+ +--------------+
| glibc | | glibc |
+--------------+ +--------------+
^ | | ^
~.~.~.|.~|~.~.~.~.~.~.~.~.|.~.|.~.~.~.~.~.~.~.~.
| v v |
+--------------+ +--------------+
| |----| FUSE |
| | +--------------+
| VFS | ...
| | +--------------+
| |----| Ext3 |
+--------------+ +--------------+
优点:
- 在用户空间实现,开发和调试都比较方便
- 可以把一些常用的服务以文件系统的形式展现,方便操作,如ftpfs,sshfs,mailfs等
- 可以避免一些版权问题,如linux上对ntfs,zfs的操作都是通过FUSE实现的
缺点:多次在用户态/内核态切换带来的性能下降
//编译方法
# gcc -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26 //FUSE_USE_VERSION分不同的版本
//详见/usr/include/fuse/fuse.h
/*
This header is for compatibility with older software using FUSE.
Please use 'pkg-config --cflags fuse' to set include path. The
correct usage is still '#include <fuse.h>', not '#include
<fuse/fuse.h>'.
*/
#include "fuse/fuse.h"
# ./a.out ./test/ //选择一个挂载点
# ls test/
hello
struct fuse_operations
{
int (*getattr) (const char *, struct stat *);
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 *);
...
};
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
gcc -Wall hello.c `pkg-config fuse --cflags --libs` -o hello
*/
#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;
}
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,
};
int main(int argc, char *argv[])
{
return fuse_main(argc, argv, &hello_oper, NULL);
}
根据不同的错误类型返回不同的值(errno.h)
//卸载文件系统
# fusermounu -uz ./test/
实现ls命令:readdir和getattr
实现touch命令:open和mknod
实现读写文件:read和write
常用参数:
-o allow_other allow access to other users
-o auto_unmount auto unmount on process termination
-o nonempty allow mounts over non-empty file/dir
-o default_permissions enable permission checking by kernel
-o fsname=NAME set filesystem name
-o subtype=NAME set filesystem type
-o large_read issue large read requests (2.4 only)
-o max_read=N set maximum size of read requests
允许其他用户
比如文件系统是以root用户挂载的,允许其他任何用户读写挂载目录,而不会去限制权限
配置fuse.conf
# vi /etc/fuse.conf
user_allow_other
应用-o allow_other选项挂载,即可