1、概述
romfs主要在Linux和一些类Unix系统上被使用,它具有体积小、可靠性好、性能高等特点,非常适合在构造最小内核阶段使用。AliOS Things中也提供了romfs功能,主要用于只读文件系统、微内核阶段最小系统等场景下。
romfs的主要特点和用途如下:
- 体积小,节省资源,可以在构造最小内核时使用。
- 只读文件系统,防止文件内容被篡改。
- 文件顺序存储,读取性能高。
- 不需要写入,操作简单,可靠性高。
- 可以做到不依赖驱动,可被独立加载。
2、romfs的数据存储
AliOS Things中提供的romfs,将文件、目录等数据打包在只读代码段中。因此,romfs文件系统没有独立的镜像,而是被包含在内核镜像中。系统启动后,用户可以通过一个指定的数据结构访问romfs文件系统的数据。
mkromfs.py
工具是romfs的一个配套转换工具,它可以将目录树数据转换成一种C语言结构体(struct romfs_dirent
),用户通过访问该类型的结构体变量访问文件数据。
该结构体的定义如下:
struct romfs_dirent
{
uint32_t type; /* dirent type */
const char *name; /* dirent name */
const uint8_t *data; /* file date ptr */
size_t size; /* file size */
};
其中,type表明某个entry(每个entry对应一个文件或目录项)的类型、名称、数据指针、数据大小等信息。
entry指向的data和size根据type的不同而不同。
如文件类型的entry,其data指针指向一个二进制数组,该数组的内容就是文件的二进制内容,其size就是文件的长度;
如果是目录类型的entry,则其data指针指向一个struct romfs_dirent
结构体,即下一个目录记录,size则表示该目录记录中的成员个数,依此类推。
例如,需要打包成romfs的文件和目录结构如下:
通过mkromfs.py工具转换后,生成的C语言文件(components/fs/romfs/romfs.c)如下:
/* Generated by mkromfs. Edit with caution. */
#include "romfs_def.h"
static const uint8_t _romfs_root_README[] = {
0x48,0x65,0x6c,0x6c,0x6f,0x20,0x48,0x61,0x61,0x73,0x0a
};
static const uint8_t _romfs_root_bin_README[] = {
0x48,0x65,0x6c,0x6c,0x6f,0x77,0x6f,0x72,0x6c,0x64,0x0a
};
static const struct romfs_dirent _romfs_root_bin[] = {
{ROMFS_DIRENT_FILE, "README", (uint8_t *)_romfs_root_bin_README, sizeof(_romfs_root_bin_README)/sizeof(_romfs_root_bin_README[0])}
};
static const struct romfs_dirent _romfs_root[] = {
{ROMFS_DIRENT_FILE, "README", (uint8_t *)_romfs_root_README, sizeof(_romfs_root_README)/sizeof(_romfs_root_README[0])},
{ROMFS_DIRENT_DIR, "bin", (uint8_t *)_romfs_root_bin, sizeof(_romfs_root_bin)/sizeof(_romfs_root_bin[0])}
};
const struct romfs_dirent romfs_root = {
ROMFS_DIRENT_DIR, "/", (uint8_t *)_romfs_root, sizeof(_romfs_root)/sizeof(_romfs_root[0])
};
即:
(1)romfs的根目录信息记录在一个名为romfs_root
的全局变量中。该变量是一个struct romfs_dirent
类型的结构体变量,它记录了根目录的如下数据:类型(DIR)、名称(“/”)、data指针(指向_romfs_root
变量)、数据大小。
(2)通过data指针,又可以继续访问根目录下的成员(即bin目录和REAMDE文件)。根目录下的成员,每个entry都是一个struct romfs_dirent
类型的结构体变量。
(3)通过_romfs_root中的第一个entry,可以访问REAMDE文件的信息。该entry的data指针指向一个名为_romfs_root_REAMDE
的结构体变量,类型为文件(FILE)。_romfs_root_REAMDE
中存储了根目录下README文件的内容(即“Helloworld”字符串的二进制数据)。
(4)通过_romfs_root
的第二个entry,可以访问bin目录的信息。该entry的data指针指向一个名为_romfs_root_bin
的结构体变量,类型为(DIR)。_romfs_root_bin
中存储了bin目录下的数据信息。
(5)_romfs_root_bin
结构体包含一个entry,是FILE类型的数据,对应bin目录下的README文件。
总结,其工作原理和基本流程如下:
- 用户准备好需要打包的目录,该目录下可以包含文件和子目录。
- 通过配套的
mkromfs.py
工具,将打包目录中的数据,转换成C语言代码,并将该代码加入romfs组件编译。
注意:目前mkromfs打包功能已集成到编译流程,即编译过程中会自动打包,不需要手动处理了,而只需要在编译前把需要打包的问题拷贝到components/fs/romfs/rootfs
目录下。
- 用户(一般是文件系统模块,而最终用户是通过posix接口访问romfs的)通过
romfs_root
变量访问根目录。 - 通过根目录中记录的entry信息,逐步展开romfs目录树,可以依此访问根目录及其子目录下的文件数据
3、romfs文件访问
romfs文件系统,会在系统初始化阶段注册到VFS虚拟文件系统(挂载路径为/
)。应用层无需关注上一章节中介绍的数据结构,而是通过标准的posix接口访问romfs中的目录和文件。
下图展示了romfs文件注册和访问的基本流程。
以下示例展示如何基于helloworld_demo添加访问romfs的逻辑。
1、修改application/example/helloworld_demo/aos.mk文件,添加romfs组件依赖。
diff --git a/application/example/helloworld_demo/aos.mk b/application/example/helloworld_demo/aos.mk
index 233896d..a5db41b 100644
--- a/application/example/helloworld_demo/aos.mk
+++ b/application/example/helloworld_demo/aos.mk
@@ -5,7 +5,7 @@ $(NAME)_VERSION := 1.0.1
$(NAME)_SUMMARY := helloworld demo
$(NAME)_SOURCES := maintask.c appdemo.c
-$(NAME)_COMPONENTS += osal_aos
+$(NAME)_COMPONENTS += osal_aos romfs
GLOBAL_DEFINES += AOS_NO_WIFI
2、修改application/example/helloworld_demo/appdemo.c文件,添加romfs文件测试逻辑,读取romfs中/bin/README
文件的内容。
diff --git a/application/example/helloworld_demo/appdemo.c b/application/example/helloworld_demo/appdemo.c
index 50b153e..7c9462b 100644
--- a/application/example/helloworld_demo/appdemo.c
+++ b/application/example/helloworld_demo/appdemo.c
@@ -8,6 +8,9 @@
#include "aos/init.h"
#include "board.h"
#include <k_api.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
int application_start(int argc, char *argv[])
{
@@ -18,6 +21,19 @@ int application_start(int argc, char *argv[])
//fd = board_lcd_create("name");
//board_lcd_write(fd,buffer,len);
+ int fd, ret;
+ const char *file = "/bin/README";
+ char fcontent[64] = {0};
+
+ fd = open(file, O_RDONLY);
+ if (fd >= 0) {
+ ret = read(fd, fcontent, sizeof(fcontent));
+ if (ret > 0) {
+ printf("Content read from file %s: %s\r\n", file, fcontent);
+ }
+ close(fd);
+ }
+
while(1) {
printf("hello world! count %d \r\n", count++);
3、编译和烧录固件,系统运行后将会看到如下打印输出:
Content read from file /bin/README: Helloworld
注意:romfs为只读文件系统,文件不支持写入。
4、总结
本文介绍了romfs的用途和特点,并重点说明了AliOS Things中romfs的数据存储方式,以及应用层访问romfs数据的方法。
想了解更多关于AliOS Things的知识,请加入我们的钉钉开发者群。
更多技术与解决方案介绍,请访问阿里云AIoT首页https://iot.aliyun.com/