refer: http://blog.csdn.net/langeldep/article/details/6401567
FUSE 虚拟文件系统集成到我们的应用程序时,有两种使用策略,一种是使用比较上层的API,
主循环我们只能调用 ret = fuse_main (fargc, fargv, &my_handler, NULL) 这个主循环的接口,
my_handler我们只取我们关心API属性,如下所示
- static struct fuse_operations my_handler =
- {
- .getattr = xmp_getattr,
- .opendir = xmp_opendir,
- .readdir = xmp_readdir,
- .mkdir = xmp_mkdir,
- .unlink = xmp_unlink,
- .rmdir = xmp_rmdir,
- .rename = xmp_rename,
- .link = xmp_link,
- .truncate = xmp_truncate,
- .create = xmp_create,
- .open = xmp_open,
- .read = xmp_read,
- .write = xmp_write,
- .flush = xmp_flush,
- .release = xmp_release,
- };
然后我们自己要来实现上面的各种 xmp_ 开头的函数。
还有一种是使用 fuse_session_loop 这个比较底层的函数来实现,这个时候我们要实现的API都是一些比较底层
的API, 比如下面的代码所示 :
- static struct fuse_lowlevel_ops lowlevel_handler =
- {
- .lookup = lowlevel_lookup,
- .getattr = lowlevel_getattr,
- .readdir = lowlevel_readdir,
- .mkdir = lowlevel_mkdir,
- .rmdir = lowlevel_rmdir,
- .open = lowlevel_open,
- .read = lowlevel_read,
- .write = lowlevel_write,
- .unlink = lowlevel_unlink,
- .rename = lowlevel_rename,
- };
具体的使用方法如下 :
- struct fuse_chan *ch;
- fargc = 3;
- fargv[0] = g_Config.processName;
- fargv[1] = g_Config.mountSource;
- fargv[2] = g_Config.mountPath;
- struct fuse_args args = FUSE_ARGS_INIT(fargc, fargv);
- snprintf (buf, sizeof(buf)-1, "umount -l %s", g_Config.mountPath);
- system(buf);
- ret = fuse_parse_cmdline(&args, &g_Config.mountPath, NULL, NULL);
- ch = fuse_mount(g_Config.mountPath, &args);
- if (ret == -1 || ch == NULL)
- {
- fprintf (stderr, "fuse mout fail/n");
- exit(1);
- }
- struct fuse_session *se;
- se = fuse_lowlevel_new(&args, &lowlevel_handler, sizeof(lowlevel_handler), NULL);
- if (se != NULL)
- {
- if (fuse_set_signal_handlers(se) != -1)
- {
- fuse_session_add_chan(se, ch);
- ret = fuse_session_loop(se);
- fuse_remove_signal_handlers(se);
- fuse_session_remove_chan(ch);
- }
- fuse_session_destroy(se);
- }
- fuse_unmount(g_Config.mountPath, ch);
- fuse_opt_free_args(&args);;
底层的API使用起来相对灵活性大一点,本人推荐使用底层的API。当然了,上层的API使用起来相对简单一点。
下面复制了一个具体的底层API的实现,供大家参考。
- void lowlevel_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
- {
- writelog (LOG_DEBUG, "call user function_______%s______fuse_ino_t = %d", __FUNCTION__, ino);
- if (ino != 2)
- fuse_reply_err(req, EISDIR);
- else if ((fi->flags & 3) != O_RDONLY)
- fuse_reply_err(req, EACCES);
- else
- {
- /* direct_io is supposed to allow partial reads. However, setting
- * the flag causes read length max at 4096 bytes which leads to
- * *many* requests, poor performance, and errors. Some resources
- * like TCP ports are recycled too fast for Linux to cope.
- */
- //fi->direct_io = 1;
- fuse_reply_open(req, fi);
- }
- }
另外在使用fuse的时候,要注意的是 struct fuse_file_info *fi 这个结构体数据的填充,
其中最关键的是 direct_io 和 nonseekable。
具体如下 :
fi->fh = socket(PF_INET, SOCK_STREAM, 0);
fi->direct_io = 1;
fi->nonseekable = 0;
设置了direct_io=1 可以提高文件读写的速度,一次IO的大小就不在局限于4K,
设置 nonseekable=0, 上层的应用才可以调用seek函数进行,否则无法seek。
这两个地方时很关键的。