1.使用SQLite数据库加密敏感信息嵌入程序(3)
2.Linux内核源码解析---mount挂载原理
3.深入剖析Linux文件系统之文件系统挂载(一)(超详细~)
4.基于Fuse的码结最简单的文件系统
使用SQLite数据库加密敏感信息嵌入程序(3)
在前两篇文章中,我们探讨了如何使用工具和原生函数生成SQLite数据库,码结以及如何将生成的码结数据库作为资源嵌入到程序中使用。目标是码结实现程序运行时直接在内存中读取敏感信息,无需将资源保存到临时文件再获取信息的码结繁琐步骤。实现这一目标的码结webrtc源码网络传输关键在于SQLite的跨平台利器——虚拟文件系统(VFS)。
VFS是码结SQLite底层与操作系统交互的关键,它提供了一种抽象的码结文件系统接口,使得SQLite能够在不同操作系统上一致地工作。码结每当SQLite需要与操作系统通信时,码结它会调用VFS中的码结方法,VFS则调用具体的码结操作代码以满足请求。因此,码结将SQLite移植到新的码结操作系统仅需编写新的操作系统接口层,也就是码结“VFS”。
SQLite支持多个VFS,每个VFS都有唯一的名称,并且同一进程中的数据库连接可以同时使用不同的VFS。Windows版本自带多个内置VFS,其中“win”适用于大多数应用程序。VFS在SQLite源码中通过sqlite3_vfs对象结构定义。
要实现标准VFS,可以子类化三个对象:sqlite3_vfs(操作系统接口对象)、sqlite3_io_methods(操作系统接口文件虚拟方法对象)、sqlite3_file(操作系统文件对象)。实现时只需子类化sqlite3_vfs和sqlite3_io_methods,而sqlite3_file对象代表一个打开的开源掌机源码文件。
sqlite3_file对象在打开文件时由sqlite3_vfs的xOpen方法构造,它跟踪文件状态,包含指向sqlite3_io_methods对象的指针,该指针仅适用于当前sqlite3_file对象。sqlite3_io_methods对象执行文件读写、大小查找、锁定与解锁、文件关闭等操作。
新构造的sqlite3_vfs通过sqlite3_vfs_register函数注册,sqlite3_file对象则从sqlite3_vfs的xOpen方法返回,指向一个sqlite3_io_methods对象实例。SQLite源码中定义了sqlite3_io_methods和sqlite3_file结构。
TBNSQLiteFile和TBNSQLiteVfs结构是Delphi版中用于实现SQLite文件和VFS的子类化接口。TBNSQLitFile结构扩展了sqlite3_file接口,增加了额外字段如实际路径、数据缓冲区和访问标志等。TBNSQLiteVfs结构实现自定义的sqlite3_vfs,构建了一个链表结构,用于管理VFS。
为了方便读取嵌入程序中的SQLite数据库,我们实现了一个名为TBNSQLitIoMethodUtils的类,作为sqlite3_io_methods的子类化实现。这个类主要实现了xRead和xFileSize方法,用于读取数据库文件数据。其他方法如xWrite等因为操作为只读性质,此处忽略实现,进群支付源码返回值为SQLITE_OK即可。实现代码通过静态方法简化,以匹配SQLite原生函数调用方式。
总结,通过精心设计的VFS、文件对象和IO方法实现,我们能够高效、安全地将敏感信息存储在嵌入程序的SQLite数据库中,并在程序运行时直接在内存中读取,无需额外的文件操作步骤。接下来,我们将深入探讨如何实现TBNSQLiteVfsUtils类以进一步优化VFS功能。
Linux内核源码解析---mount挂载原理
Linux磁盘挂载命令"mount -t xxx /dev/sdb1 abc/def/"的底层实现原理非常值得深入了解。从内核初始化的vfsmount开始说起。
内核初始化过程中,主要关注"main.c"中的vfs_caches_init函数,这个方法与mount紧密相连。接着,跟进"mnt_init"和"namespace.c",关键在于最后的三个函数,它们控制了挂载过程的实现。
在"mount.c"中,sysfs_fs_type结构中包含了获取超级块的函数指针,而"init_rootfs"则注册了rootfs类型的文件系统。挂载系统调用sys_mount中的dev_name, dir_name和type参数,分别对应设备名称、诚信单透源码挂载目录和文件系统类型。
"do_mount"方法通过path_lookup收集挂载目录信息,创建nameidata结构,然后调用do_add_mount进行实际挂载。这个过程涉及do_kern_mount和graft_tree,尽管具体实现较为复杂,但核心在于创建vfsmount并将其与namespace关联。
在"graft_tree"中的判断逻辑中,vfsmount被创建并与其父mount和挂载目录的dentry建立关系。在"attach_mnt"方法中,新vfsmount与现有结构关联,设置挂载点和父vfsmount,最终形成挂载的概念,即为设备分配vfsmount,并将其与指定目录和vfsmount结合,成为vfs系统的一部分。
深入剖析Linux文件系统之文件系统挂载(一)(超详细~)
深入剖析Linux文件系统之文件系统挂载(一)(超详细~) 我们知道,在Linux系统中,将一个块设备上的文件系统挂载到特定目录才能访问该文件系统下的文件。本文将详细阐述文件系统挂载的核心逻辑,包括Linux内核为挂载文件系统所执行的操作以及为何必须挂载才能访问文件。本文分为上下两篇,上篇着重于挂载全貌及具体文件系统挂载方法,下篇则详细介绍挂载实例与挂载点、超级块的关系。 在Linux中,仟众部落源码虚拟文件系统层VFS通过统一所有具体文件系统的接口,屏蔽差异,向用户提供一致的访问方式。VFS作为接口层,向下连接具体的文件系统,向上提供用户进程访问文件的功能。接下来,我们探讨VFS中几个关键对象的作用。 VFS对象包括: file_system_type:描述文件系统类型,包括磁盘文件系统、内存文件系统、伪文件系统和网络文件系统。磁盘文件系统用于非易失性存储介质上的文件,如ext2、ext4、xfs等;内存文件系统在内存上存储文件;伪文件系统则是内核可见或用户可见的虚拟文件系统,如proc、sysfs等;网络文件系统允许访问远程计算机上的数据。 super_block:用于描述块设备上文件系统整体信息,如文件块大小、最大文件大小、文件系统标识等。磁盘文件系统仅有一个super_block描述整个文件系统。 mount:描述超级块与挂载点之间的联系,建立文件系统挂载的实例。磁盘文件系统可被多次挂载,每次挂载内存中创建一个mount对象。 inode:描述磁盘上文件的元数据,文件系统需要从块设备读取磁盘上的inode,创建内存中的inode对象,通常在文件首次打开时创建。 dentry:用于描述文件层次结构,构建目录树,存储目录或文件的名称和inode号,以便进程访问目录项。 file:描述进程打开的文件,创建文件对象加入进程的文件打开表,通过文件描述符进行读写操作。 挂载流程包括系统调用处理、挂载点路径查找、参数合法性检查、调用具体文件系统挂载方法、以及实例添加到全局文件系统树。挂载实例添加到全局文件系统树涉及vfs_get_tree和do_new_mount_fc函数,ext2对挂载的处理则包括初始化阶段、挂载时调用、以及通过mount_bdev执行实际挂载工作。 具体文件系统挂载方法包括: ext2对挂载的处理:启动阶段初始化,挂载时调用ext2_mount,执行mount_bdev来执行实际挂载,ext2_fill_super读取磁盘上的超级块并填充内存中的超级块。 mount_bdev源码分析:查找块设备描述符,创建或获取vfs超级块,调用具体文件系统的fill_super方法读取并填充超级块。 ext2_fill_super源码分析:读取磁盘上的超级块,填充并关联vfs超级块,读取块组描述符,读取磁盘根inode并建立根inode,创建根dentry关联到根inode。 挂载完成后,文件系统已准备好被访问,用户进程通过文件路径打开文件,但尚未关联至挂载点。为了将文件系统关联到挂载点,需要通过do_new_mount_fc将挂载实例加入全局文件系统树。下篇将详细讲解这一过程。基于Fuse的最简单的文件系统
从今天开始,我将在我的公众号“数据存储张”中创建一个合集,旨在从零开始,教大家如何开发一个文件系统。开发工作基于Ubuntu .,其他Linux版本亦可。通常,我们认为文件系统是内核模块,但实际情况并非如此,EMC的UFS就是一个用户态文件系统示例。开源分布式文件系统也多是用户态。
鉴于内核态开发难度较高,我决定采用FUSE来开发一个用户态文件系统。通过实践本合集的内容,希望能加深大家对《文件系统技术内幕》一书的理解。无论是内核态还是用户态,文件系统的原理基本一致。
若后续大家对Linux内核文件系统实现感兴趣,我也会继续基于内核开发功能,让大家全面了解内核文件系统。
回到文章主题,接下来我们将深入文件系统的概念。文件系统是将硬盘线性地址转换为层级结构的软件系统,核心是呈现目录树。文件系统中,文件与目录是两大关键概念:目录是容器,用于存储文件和子目录;文件则是数据存储实体,形式多样,如视频、音频、Word文档及文本文件等。
从普通用户角度看,文件系统提供层级式的文件组织方式,而程序开发视角下,文件系统提供API以访问文件和目录,如打开、关闭、读取和写入数据,以及目录的打开、遍历和关闭等操作。这些API在内核态有对应实现。
FUSE提供在用户态开发文件系统的框架,大大降低了开发门槛,无需了解Linux内核内容。FUSE由用户态库和内核模块组成,内核态模块与VFS和其他文件系统关系密切,可理解为内核态文件系统,其功能是转发文件系统访问请求至用户态。
FUSE用户态库提供一套API和接口规范,实现这些函数集合即完成文件系统开发。通过FUSE注册函数到内核模块后,内核态请求将调用用户态函数。例如,ceph_fuse就是基于FUSE实现的用户态文件系统,用于访问CephFS。
接下来,我们将开发一个最简单的文件系统,严格意义上并非真正文件系统。该系统仅模拟层级结构,包含“dir”目录和“helloworld”文件,以及“.”和“..”目录。实现中,我们仅关注“getattr”和“readdir”两个函数,分别用于获取文件或目录详细属性及读取目录项。
在头文件中,我们定义了文件系统类HelloWorldFS,并实现了上述两个函数。主函数文件简单实例化了HelloWorldFS类,并调用run函数完成文件系统挂载和注册等任务。
cmake工程文件用于管理整个项目。通过cmake生成Makefile,并使用make编译,得到可执行程序helloworld。通过挂载到/mnt/test目录,我们验证了系统功能。
本文实现的文件系统仅模拟层级结构,不具备创建、删除或读取文件内容功能。通过本教程,大家对文件系统概念和FUSE用法有了基础了解。后续,我们将基于当前实现,开发一个基于内存、可读写文件系统。
相关源代码可在GitHub的SunnyZhang-IT/fs-from-zero库中找到。