AliOS Things之romfs技术介绍

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的文件和目录结构如下:

截屏2020-12-11 20.19.51.png

通过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文件。

总结,其工作原理和基本流程如下:

  1. 用户准备好需要打包的目录,该目录下可以包含文件和子目录。
  2. 通过配套的mkromfs.py工具,将打包目录中的数据,转换成C语言代码,并将该代码加入romfs组件编译。

注意:目前mkromfs打包功能已集成到编译流程,即编译过程中会自动打包,不需要手动处理了,而只需要在编译前把需要打包的问题拷贝到components/fs/romfs/rootfs目录下。

  1. 用户(一般是文件系统模块,而最终用户是通过posix接口访问romfs的)通过romfs_root变量访问根目录。
  2. 通过根目录中记录的entry信息,逐步展开romfs目录树,可以依此访问根目录及其子目录下的文件数据

3、romfs文件访问

romfs文件系统,会在系统初始化阶段注册到VFS虚拟文件系统(挂载路径为/)。应用层无需关注上一章节中介绍的数据结构,而是通过标准的posix接口访问romfs中的目录和文件。

下图展示了romfs文件注册和访问的基本流程。

截屏2020-12-11 21.13.19.png

以下示例展示如何基于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/

猜你喜欢

转载自blog.csdn.net/HaaSTech/article/details/111828361