基于FUSE的简单文件系统

简介: 基于FUSE的简单文件系统

文件系统


文件系统是一种用来存储和组织计算机文件、目录及其包含的数据的方法,它使文件、目录以及数据的查找和访问得到简化。如果您正在使用一台计算机,很可能使用了多个文件系统。文件系统能提供丰富的扩展能力。它可以编写成底层文件系统的一个封装程序,从而对其中的数据进行管理,并提供一个增强的、具有丰富特性的文件系统(例如 cvsfs-fuse,它为 CVS 提供了一个文件系统的接口;或 Wayback 文件系统,它提供了一种用于保留原始数据文件的文件备份机制)。


在用户空间的文件系统出现之前,文件系统的开发曾是内核开发人员的工作。创建文件系统需要了解内核编程和内核技术(例如 vfs)方面的知识。调试则需要 C 和 C++ 方面的专业技能。但是其他开发人员需要熟练地操作文件系统以添加个性化特性(例如添加历史记录或转发缓存)及对其改进


2.项目介绍


使用 FUSE 您可以开发功能完备的文件系统:其具有简单的 API 库,可以被非特权用户访问,并可以安全的实施。更重要的是,FUSE 以往的表现充分证明了其稳定性。


使用 FUSE,您可以像可执行二进制文件一样来开发文件系统,它们需要链接到 FUSE 库上 ------ 换言之,这个文件系统框架并不需要您了解文件系统的内幕和内核模块编程的知识。


就文件系统来说,用户空间的文件系统就不再是新奇的设计了。用户空间文件系统的商业实现与学术实现的实例包括:


LUFS 是一个混合用户空间的文件系统框架,它对用于任何应用程序无数的文件系统提供透明支持。大部分LUFS 包括一个内核模块和一个用户空间的守护进程。从根本上来说,它将大部分 VFS 调用都委托给一个专用的守护进程来处理。


UserFS 让用户进程可以像普通的文件系统一样进行加载。这种概念性的原型提供了 ftpfs,这可以使用文件系统接口提供匿名 FTP 访问。


Ufo Project 是为 Solaris 提供的一个全局文件系统,它允许用户将远程文件真正当作本地文件一样对待。


OpenAFS 是 Andrew FileSystem 的一个开源版本。


CIFS 是 Common Internet FileSystem 的简称。


与这些商业实现和学术实现不同,FUSE 将这种文件系统的设计能力带到了 Linux 中来。由于 FUSE 使用的是可执行程序(而不像 LUFS 一样使用的是共享对象),因此可以简化程序的调试和开发。FUSE 可以在linux 的内核上使用,现在可以支持 Java™ 绑定,因此您可以不必限定于使用 C 和 C++ 来编写文件系统了。(有关更多使用 FUSE 的用户层的文件系统的内容,请参阅 [参考资料]{.ul}。)


要在 FUSE 中创建一个文件系统,您需要安装一个 FUSE 内核模块,然后使用 FUSE 库和 API 来创建自己的文件系统。


二、FUSE operations


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

struct fuse_operations {
int (*getattr) (const char *, struct stat *, struct fuse_file_info *fi);
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 *, unsigned int flags);
int (*link) (const char *, const char *);
int (*chmod) (const char *, mode_t, struct fuse_file_info *fi);
int (*chown) (const char *, uid_t, gid_t, struct fuse_file_info *fi);
int (*truncate) (const char *, off_t, struct fuse_file_info *fi);
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 *, enum fuse_readdir_flags);
int (*releasedir) (const char *, struct fuse_file_info *);
int (*fsyncdir) (const char *, int, struct fuse_file_info *);
void *(*init) (struct fuse_conn_info *conn,
struct fuse_config *cfg);
void (*destroy) (void *private_data);
int (*access) (const char *, int);
int (*create) (const char *, mode_t, 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],
struct fuse_file_info *fi);
int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
int (*ioctl) (const char *, int cmd, void *arg,
struct fuse_file_info *, unsigned int flags, void *data);
int (*poll) (const char *, struct fuse_file_info *,
struct fuse_pollhandle *ph, unsigned *reventsp);
int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off,
struct fuse_file_info *);
int (*read_buf) (const char *, struct fuse_bufvec **bufp,
size_t size, off_t off, struct fuse_file_info *);
int (*flock) (const char *, struct fuse_file_info *, int op);
int (*fallocate) (const char *, int, off_t, off_t,
struct fuse_file_info *);
};

三、hello示例文件系统分析


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

/\*FUSE:FilesysteminUserspaceCopyright(C)2001-2007MiklosSzeredi\<miklos\@szeredi.hu>ThisprogramcanbedistributedunderthetermsoftheGNUGPL.SeethefileCOPYING.\*//\*\*\@file\*\*minimalexamplefilesystemusinghigh-levelAPI\*\*Compilewith:\*\*gcc-Wallhello.c\`pkg-configfuse3\--cflags\--libs\`-ohello\*\*##Sourcecode##\*\\includehello.c\*/#define FUSE_USE_VERSION 31
#include\<fuse.h>
#include\<stdio.h>
#include\<string.h>
#include\<errno.h>
#include\<fcntl.h>
#include\<stddef.h>
#include\<assert.h>
/\*\*Commandlineoptions\*\*Wecan\'tsetdefaultvaluesforthechar\*fieldsherebecause\*fuse_opt_parsewouldattempttofree()themwhentheuserspecifies\*differentvaluesonthecommandline.\*/staticstructoptions{constchar\*filename;constchar\*contents;intshow_help;}options;#define OPTION(t, p) \\
{t,offsetof(structoptions,p),1}staticconststructfuse_optoption_spec\[\]={OPTION(\"\--name=%s\", filename),OPTION(\"\--contents=%s\", contents),OPTION(\"-h\", show_help),OPTION(\"\--help\", show_help),FUSE_OPT_END};staticvoid\*hello_init(structfuse_conn_info\*conn,structfuse_config\*cfg){(void)conn;cfg-\>kernel_cache=1;returnNULL;}staticinthello_getattr(constchar\*path,structstat\*stbuf,structfuse_file_info\*fi){(void)fi;intres=0;memset(stbuf,0,sizeof(structstat));if(strcmp(path,\"/\") == 0) {stbuf-\>st_mode=S_IFDIR\|0755;stbuf-\>st_nlink=2;}elseif(strcmp(path+1,options.filename)==0){stbuf-\>st_mode=S_IFREG\|0444;stbuf-\>st_nlink=1;stbuf-\>st_size=strlen(options.contents);//文件长度
}elseres=-ENOENT;returnres;}staticinthello_readdir(constchar\*path,void\*buf,fuse_fill_dir_tfiller,off_toffset,structfuse_file_info\*fi,enumfuse_readdir_flagsflags){(void)offset;(void)fi;(void)flags;if(strcmp(path,\"/\") != 0)return-ENOENT;filler(buf,\".\", NULL, 0, 0);filler(buf,\"..\", NULL, 0, 0);filler(buf,options.filename,NULL,0,0);return0;}

fill的定义:


typedefint(\*fuse_fill_dir_t)(void\*buf,constchar\*name,conststructstat\*stbuf,off_toff);\
     其作用是在readdir函数中增加一个目录项\
 \*-/staticinthello_open(constchar\*path,structfuse_file_info\*fi)//用于打开hello文件
{if(strcmp(path+1,options.filename)!=0)//不是hello文件
return-ENOENT;if((fi-\>flags&O_ACCMODE)!=O_RDONLY)return-EACCES;return0;}//读取hello文件时的操作,
staticinthello_read(constchar\*path,char\*buf,size_tsize,off_toffset,structfuse_file_info\*fi){size_tlen;(void)fi;if(strcmp(path+1,options.filename)!=0)return-ENOENT;len=strlen(options.contents);if(offset\<len){if(offset+size\>len)size=len-offset;memcpy(buf,options.contents+offset,size);}elsesize=0;returnsize;}staticstructfuse_operationshello_oper={.init=hello_init,.getattr=hello_getattr,.readdir=hello_readdir,.open=hello_open,.read=hello_read,};staticvoidshow_help(constchar\*progname){printf(\"usage: %s \[options\] \<mountpoint>\\n\\n\", progname);printf(\"File-system specific options:\\n\"\" \--name=\<s> Name of the \\\"hello\\\" file\\n\"\" (default: \\\"hello\\\")\\n\"\" \--contents=\<s> Contents \\\"hello\\\" file\\n\"\" (default \\\"Hello, World!\\\\n\\\")\\n\"\"\\n\");}intmain(intargc,char\*argv\[\]){intret;structfuse_argsargs=FUSE_ARGS_INIT(argc,argv);/\*Setdefaults\--wehavetousestrdupsothatfuse_opt_parsecanfreethedefaultsifothervaluesarespecified\*/options.filename=strdup(\"hello\");options.contents=strdup(\"Hello World!\\n\");/\*Parseoptions\*/if(fuse_opt_parse(&args,&options,option_spec,NULL)==-1)return1;/\*When\--helpisspecified,firstprintourownfile-systemspecifichelptext,thensignalfuse_maintoshowadditionalhelp(byadding\`\--help\`totheoptionsagain)withoutusage:line(bysettingargv\[0\]totheemptystring)\*/if(options.show_help){show_help(argv\[0\]);assert(fuse_opt_add_arg(&args,\"\--help\") == 0);args.argv\[0\]=(char\*)\"\";}ret=fuse_main(args.argc,args.argv,&hello_oper,NULL);fuse_opt_free_args(&args);returnret;}

终端运行

\
\~/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。


完整代码:https://download.csdn.net/download/qq_38735017/87404423

相关文章
|
安全 数据库
通过E-R理解 主键和外键的关系
实例 现有课程和教师两个实体,课程实体的属性有课程名称、课程编号、课程属性、考试类型;教师实体的属性包括姓名、工号、职称;一门课程可以有多个教师,且每一位教师可以教授多门课程。教师每教授一门课有课序号。
6592 1
通过E-R理解 主键和外键的关系
|
网络协议 Linux 网络安全
文件共享同步5种方式:NFS、NAS、rsync、scp、ftp
谈到文件同步,我们最直接的同步方式是采用rsync的同步软件,rsync同步可以保持server和client的强一致(server中的增删改都会同步client),但在实际场景中rsync可能并不能被采纳。
18812 0
|
10月前
|
消息中间件 存储 缓存
kafka 的数据是放在磁盘上还是内存上,为什么速度会快?
Kafka的数据存储机制通过将数据同时写入磁盘和内存,确保高吞吐量与持久性。其日志文件按主题和分区组织,使用预写日志(WAL)保证数据持久性,并借助操作系统的页缓存加速读取。Kafka采用顺序I/O、零拷贝技术和批量处理优化性能,支持分区分段以实现并行处理。示例代码展示了如何使用KafkaProducer发送消息。
|
11月前
|
数据采集 人工智能 自然语言处理
FineWeb 2:开源的多语言预训练数据集,覆盖超过 1000 种语言
FineWeb 2 是由 Hugging Face 推出的多语言预训练数据集,覆盖超过 1000 种语言,支持多种 NLP 任务,如机器翻译和文本分类。该数据集通过定制化的数据处理流程,包括语言识别、去重、内容过滤和 PII 匿名化,提升了多语言模型的性能和泛化能力。
650 5
FineWeb 2:开源的多语言预训练数据集,覆盖超过 1000 种语言
|
11月前
|
物联网 调度 vr&ar
鸿蒙HarmonyOS应用开发 |鸿蒙技术分享HarmonyOS Next 深度解析:分布式能力与跨设备协作实战
鸿蒙技术分享:HarmonyOS Next 深度解析 随着万物互联时代的到来,华为发布的 HarmonyOS Next 在技术架构和生态体验上实现了重大升级。本文从技术架构、生态优势和开发实践三方面深入探讨其特点,并通过跨设备笔记应用实战案例,展示其强大的分布式能力和多设备协作功能。核心亮点包括新一代微内核架构、统一开发语言 ArkTS 和多模态交互支持。开发者可借助 DevEco Studio 4.0 快速上手,体验高效、灵活的开发过程。 239个字符
979 13
鸿蒙HarmonyOS应用开发 |鸿蒙技术分享HarmonyOS Next 深度解析:分布式能力与跨设备协作实战
|
11月前
|
数据处理 API 流计算
XDMA与FPGA:高效数据传输的艺术
XDMA(Xilinx&#39;s DMA/Bridge Subsystem for PCI Express)是Xilinx推出的一种高效数据传输引擎,专为PCIe总线设计。通过封装PCIe协议,XDMA提供简化的API接口,支持Scatter-Gather DMA和Block DMA模式,特别适用于高性能计算、实时视频处理和大数据分析等领域的数据传输。XDMA通过链表传输和高效的PCIe接口,减少了主机CPU的负担,提高了数据传输效率。AXI4和AXI4-Stream接口进一步增强了XDMA与FPGA的协同工作能力,使其在现代计算系统中发挥重要作用。
|
JavaScript API
Qt HTTP和HttpServer
Qt HTTP和HttpServer
590 1
|
存储 前端开发 数据管理
为LTO磁带而生的文件系统LTFS|主线任务—夺回"秋雅"
在LTO第一代到第四代,如果我们想要访问LTO磁带的内容,都需要厂商提供的特殊软件来支持,软件需要全部加在整个磁带的内容,才能展示你要查找的文件,保存文件的过程也需要特有的软件来处理。提供的磁带存储的厂商还有多个这就导致用户在使用磁带过程中,非常的痛苦地面对来回之间复杂的搬运场景。
|
存储 Unix 程序员
非常详细!操作系统基础【文件系统实现】
非常详细!操作系统基础【文件系统实现】
|
C++
【SPSS】两独立样本的曼-惠特尼U检验详细操作教程(附案例实战)
【SPSS】两独立样本的曼-惠特尼U检验详细操作教程(附案例实战)
3090 0