随着嵌入式设备功能的发展, 应用需要存储的数据越来越多,也越来越复杂。文件系统就是一种来应对这些繁琐复杂的数据管理方式。具体的文件系统(FATFS、SPIFFS等)都实现了一套数据的存储、分级组织、访问和获取等操作的抽象数据类型(Abstract data type),向用户提供了一种底层数据访问的机制,数据存储的基本单位为文件。

虚拟文件系统(Virtual File System)则提供了一种对具体文件系统类型的一个抽象,它可以将多个具体的文件系统接口统一起来,用户可通过虚拟文件系统屏蔽各个底层具体文件系统的操作接口、数据类型差异。用户也可通过注册接口将自己的文件系统挂载到VFS上进行操作访问。虚拟文件系统的风格与UNIX/Linux类似, 根目录及目录分隔符都用“/”来表示。

VFS对外提供aos_xxx接口,对应的头文件为aos/vfs.h,对应的接口实现位于:core/osal/aos/vfs.c中。

         +--------+    +---------+
         |  libc  |    |  posix  |
         +--------+    +---------+
    +-----------------------------------------------------+
    |                  OSAL                               |
    | +----------------------------------------+ +------+ |
    | |               aos                      | |      | |
    | |  +--------------------+ +-----------+  | |others| |
    | |  |      aos vfs API   | |rhino,kv...|  | |      | |
    | |  +--------------------+ +-----------+  | |      | |
    | +----------------------------------------+ +------+ |
    +-----------------------------------------------------+
         +--------------------+
         |       vfs API      |
         +--------------------+
         +--------------------+
         | +------+  +------+ |
         | | dev  |  |  FS  | |
         | +------+  +------+ |
         +--------------------+

严格来说,VFS是上图中vfs API这一层,对应的头文件是vfs_api.h,位于core/vfs/include/vfs_api.h,这些API仅供core内部使用。AliOS Things对应用开发提供统一的aos API,对于vfs提供aos vfs API。

API列表

名称 描述
aos_vfs_init 初始化VFS模块,申请系统资源
aos_open 打开文件
aos_close 关闭文件
aos_read 读取文件
aos_write 写入文件
aos_ioctl 执行特殊定义命令
aos_lseek 设置下次读取文件的位置
aos_sync 同步文件数据到存储设备
aos_stat 获取文件状态
aos_fstat 获取文件状态(POSIX)
aos_link 创建文件链接
aos_unlink 删除文件链接
aos_remove 删除文件或目录
aos_rename 重命名文件
aos_opendir 打开目录
aos_closedir 关闭目录
aos_readdir 读取目录
aos_mkdir 创建目录
aos_rmdir 删除目录
aos_rewinddir 重设读取目录的位置为开头
aos_telldir 获取目录的读取位置
aos_seekdir 设置下次读取目录的位置
aos_statfs 获取文件系统相关信息
aos_access 确定文件或目录的访问权限
aos_chdir 更改当前工作目录
aos_getcwd 获取当前工作目录
aos_pathconf 返回配置文件限制值
aos_fpathconf 返回配置文件限制值
aos_utime 设置文件访问或修改时间
aos_register_fs 挂载文件系统
aos_unregister_fs 卸载文件系统

使用

添加该组件

要使用上面 API列表中的API,需要同时添加vfs组件、osal_aos组件。vfs最终对接到文件系统或者设备驱动,所以应用要完整使用vfs,还需要添加文件系统(ramfs、spiffs、fatfs等)或者设备驱动组件。

例如,在某个在aos.mk文件中同时添加vfs、osal_aos和spiffs组件:

$(NAME)_COMPONENTS += vfs osal_aos spiffs

在AliOS Things中,由于组件vfs、osal_aos是基础组件,很多其他组件依赖这两个组件,如果选择了依赖vfs、或者osal_aos组件的其它组件,那么它(们)将被自动选中,无需额外再添加。

包含头文件

头文件所在位置:include/aos/vfs.h

#include "aos/vfs.h"

使用示例

这里以spiffs为例,演示应用中使用vfs API。作为示例,下面代码中注释了挂载spiffs的代码,用户可以添加真实的挂载文件系统的代码逻辑。

#include <stdio.h>
#include "aos/vfs.h"

// spiffs file operation structure
extern vfs_filesystem_ops_t spiffs_ops;

int fd;
int ret;

// mount spiffs firstly, add your mount logic here
// SPIFFS_mount(...);

// register spiffs filesystem
ret = aos_register_fs(path, &spiffs_ops, NULL);
if (ret < 0) {
    printf("register spiffs failed, errno %d\r\n", ret);
    return ret;
}

fd = aos_open("/data/a.txt", O_CREAT | O_RDWR);
if (fd < 0) {
    printf("open failed, errno %d\r\n", fd);
    return fd;
}

const char *str = "hello, world\n";
aos_write(fd, str, strlen(str));

aos_close(fd);

API详情

aos_vfs_init

函数原型

int aos_vfs_init(void);

详细说明

aos_vfs_init()初始化VFS系统。系统启动流程中组件初始化函数aos_components_init()函数调用了vfs_init()函数初始化VFS系统,和调用aos_vfs_init()效果相同。

输入参数

返回参数

返回值类型 返回值 描述
int 0 执行成功
负数 执行错误,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

int ret = 0;
ret = aos_vfs_init();
if (ret) {
    printf("aos_vfs_init() failed, errno %d\r\n", ret);
}

aos_open

函数原型

int aos_open(const char *path, int flags);

详细说明

aos_open()打开path所描述的文件或者设备,打开成功时返回系统分配的文件描述符fd,错误时返回对应的错误码。如果打开的文件不存在,但是参数flags指定了O_CREAT,那么就尝试创建文件。

打开文件时参数flags必须要包含O_RDONLY, O_WRONLY, O_RDWR三者之一。此外,打开文件是还可以指定文件创建标志位、文件状态标志位,这些标志位通过或‘|’操作到参数flags。在这里常用的标志位有O_CREAT, O_EXCL, O_TRUNC, O_APPEND。其他在Linux操作系统中的类似标志位,在AliOS Things上可能不支持,但是指定了也不会有副作用。

O_RDONLY 以只读方式打开文件
O_WRONLY 以只写方式打开
O_RDWR 以可读可写方式打开
O_CREAT 文件不存在时创建文件
O_EXCL 在打开文件时,如果文件存在而且同时指定的标志位O_CREAT,则返回-EEXIST;如果文件不存在,则创建文件
O_TRUNC 打开文件时,如果文件的长度不为0,则将文件的长度截短为0,下次写入文件时,从文件开始出写入数据
O_APPEND 打开文件后,将文件的写入点设置为文件末尾,下次写入文件时,新写入的数据会追加到文件末尾

输入参数

参数类型 参数名称 参数描述
const char * path 需打开的文件路径
int flags 文件打开时的访问模式和标志

返回参数

返回值类型 返回值 描述
int 正数 文件描述符
负数 文件打开错误,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *path = /sdcard/test.txt;
int fd;

/**
 * open file in read/write mode, if file doesn't exist, create it.
 */
fd = aos_open(path, O_RDWR | O_CREAT);
if (fd < 0) {
    printf("aos_open(%s, 0x%x) failed, errno %d\r\n", path, fd);
}

aos_close

函数原型

int aos_close(int fd);

详细说明

关闭已打开的文件描述符fd。该描述符fd后续会被打开其他文件时复用。

输入参数

参数类型 参数名称 参数描述
int fd 关闭文件的描述符

返回参数

返回值类型 返回值 描述
int 0 关闭成功
负数 关闭错误,返回错误码

调用示例

#include <stdio.h>
#include “aos/vfs.h”

int fd;
int ret;
/**
 * open file in read/write mode, if file doesn't exist, create it.
 */
fd = aos_open("helloworld.txt", O_RDWR | O_CREAT);
if (fd < 0) {
    printf("aos_open(%s, 0x%x) failed, errno %d\r\n", path, fd);
    // do error handle
}

// do your file operations, such as read/write. etc.

// close the file
ret = aos_close(fd);
if (ret < 0) {
    printf("aos_close(%d) failed, errno %d\r\n", ret);
}

aos_read

函数原型

int aos_read(int fd, void *buf, size_t nbytes);

详细说明

aos_read()从打开的文件中读取若干字节到buffer。如果文件支持seek,那么aos_read()将从文件当前偏移(offset)处开始读取,读取成功后将文件的偏移向后增加成功读取到的字节数。

读取成功,返回读取到的字节个数;如果读取时文件偏移已经到达文件末尾,则返回0。其他错误情况,返回错误码。

输入参数

参数类型 参数名称 参数描述
int fd 文件描述符
void * buf 文件读取的数据缓存
size_t nbytes 要读取的字节数

返回参数

返回值类型 返回值 描述
int 正数 成功读取到的字节数
0 已经读取到文件末尾,没有更多的数据可以读取
负数 读取失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

#define BUF_SIZE (64)
int fd;
char buf[BUF_SIZE];
int ret;

/**
 * open file in read/write mode, if file doesn't exist, create it.
 */
fd = aos_open("helloworld.txt", O_RDONLY | O_CREAT);
if (fd < 0) {
    printf("aos_open(%s, 0x%x) failed, errno %d\r\n", path, fd);
    // do error handle
}

// fd is the open file descriptor
ret = aos_read(fd, buf, BUF_SIZE);
if (ret < 0) {
    printf("aos_read() failed, errno %d\r\n", ret);
} else if (ret == 0) {
    printf("end of the file\r\n");
} else {
    // handle the data read from file
}

aos_write

函数原型

int aos_write(int fd, const void *buf, size_t nbytes);

详细说明

aos_write()buffer开始出的nbytes字节数据写入到已经打开的文件。如果文件支持seek,那么aos_write()将从文件当前偏移(offset)处开始写入,写入成功后将文件的偏移向后增加成功写入的字节数。

当以O_APPEND方式打开文件时,打开成功后,文件的偏移offset会被设置为文件末尾。

写入成功时,返回写入到文件的字节个数,实际写入的字节数有可能小于nbytes(文件空间不足);写入失败时返回错误码(负数)。

输入参数

参数类型 参数名称 参数描述
int fd fd 文件描述符
void * buf 文件写入数据的缓存
size_t nbytes 文件写入的长度

返回参数

返回值类型 返回值 描述
int 正数或0 成功写入文件的字节数
负数 读取失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *str="hello, aos_write";
int fd;
int ret;

/**
 * open file in read/write mode, if file doesn't exist, create it.
 */
fd = aos_open("helloworld.txt", O_WRONLY | O_CREAT | O_APPEND);
if (fd < 0) {
    printf("aos_open(%s, 0x%x) failed, errno %d\r\n", path, fd);
    // do error handle
}

// fd is the open file descriptor
ret = aos_write(fd, str, strlen(str));
if (ret < 0) {
    printf("aos_write() failed, errno %d\r\n", ret);
} else {
    printf("aos_write() writes %d char\r\n", ret);
}

aos_ioctl

函数原型

int aos_ioctl(int fd, int cmd, unsigned long arg);

详细说明

aos_ioctl()一般用于设置或者读取底层设备的参数。参数fd必须是已打开设备的描述符,cmd是设备相关的请求码,第三个参数arg是与cmd相关的参数。一般情况下,aos_ioctl()的输出参数通过第三个参数arg(将指针作为arg参数)返回,也有少数情况通过函数返回值返回。

输入参数

参数类型 参数名称 参数描述
int fd 文件描述符(FD)
int cmd 特殊命令标识
unsigned long arg 命令参数

返回参数

返回值 返回值 描述
int 0 成功
正数 一些用法中,将返回值作为aos_ioctl()的输出参数
负数 失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

#define CMD_SPEC 0
#define CMD_VAL  0

const char *dev = "/dev/i2c0";
int fd;
int ret;

/**
 * open file in read/write mode, if file doesn't exist, create it.
 */
fd = aos_open(dev, O_RDONLY);
if (fd < 0) {
    printf("aos_open(%s, 0x%x) failed, errno %d\r\n", path, fd);
    // do error handle
}

ret = aos_ioctl(fd, CMD_SPEC, CMD_VAL);
if (ret < 0) {
    printf("aos_ioctl() failed, errno %d\r\n", ret);
} else {
    // aos_ioctl() okay
}

aos_lseek

函数原型

off_t aos_lseek(int fd, off_t offset, int whence);

详细说明

aos_lseek()重新设置已打开文件的偏移,第二个参数offset是相对于第三个参数whence的偏移值,语义如下: SEEK_SET: 文件偏移设置为从文件开始处offset字节处。 SEEK_CUR文件偏移设置为相对于当前文件位置的offset字节处。 SEEK_END文件偏移摄者为文件末尾的offset字节处。

输入参数

参数类型 参数名称 参数描述
int fd 文件描述符
off_t offset 文件读写位置需偏移长度
int whence 文件读写位置偏移起始点

返回参数

返回值类型 返回值 int 描述
int 非负 成功,返回相对于文件开始处的偏移字节数,该值作为当前文件的偏移
负数 失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *file="helloworld.txt";
int fd;
int ret;

/**
 * open file in read/write mode, if file doesn't exist, create it.
 */
fd = aos_open(file, O_WRONLY);
if (fd < 0) {
    printf("aos_open(%s, 0x%x) failed, errno %d\r\n", path, fd);
    // do error handle
}

// set file offset to the end of the file.
ret = aos_lseek(fd, 0, SEEK_END);
if (ret < 0) {
    printf("aos_lseek() failed, errno %d\r\n", ret);
} else {
    printf("file %s size is %d Bytes\r\n", file, ret);
}

aos_sync

函数原型

int aos_sync(int fd);

详细说明

aos_sync()会将对文件系统元数据(metadata)的修改以及文件系统内部缓存中的数据写入底层文件系统中。

输入参数

参数类型 参数名称 参数描述
int fd 文件描述符

返回参数

返回值类型 返回值 描述
int 0 数据同步成功
负数 数据同步失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *str="hello, aos_write";
int fd;
int ret;

/**
 * open file in read/write mode, if file doesn't exist, create it.
 */
fd = aos_open("helloworld.txt", O_WRONLY | O_CREAT | O_APPEND);
if (fd < 0) {
    printf("aos_open(%s, 0x%x) failed, errno %d\r\n", path, fd);
    // do error handle
}

// fd is the open file descriptor
ret = aos_write(fd, str, strlen(str));
if (ret < 0) {
    printf("aos_write() failed, errno %d\r\n", ret);
} else {
    printf("aos_write() writes %d char\r\n", ret);
}

// flush metadata and/or data into underlying file system.
ret = aos_sync(fd);

// other file operations

aos_close(fd);

aos_stat

函数原型

int aos_stat(const char *path, struct aos_stat *st);

详细说明

aos_stat()读取文件的属性信息,如文件大小、文件模式(权限、文件/文件夹)等信息到st指针指向的buffer

输入参数

参数类型 参数名称 参数描述
const char * path 文件路径
struct aos_stat * st 文件状态信息结构体指针

返回参数

返回值类型 返回值 描述
int 0 获取文件信息成功
负数 获取文件信息失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *path = "/sdcard/test.txt";
struct aos_stat file_st;
int ret;
uint32_t size;
uint16_t mode;

/**
 * open file in read/write mode, if file doesn't exist, create it.
 */
fd = aos_open("helloworld.txt", O_WRONLY | O_CREAT | O_APPEND);
if (fd < 0) {
    printf("aos_open(%s, 0x%x) failed, errno %d\r\n", path, fd);
    // do error handle
}

ret = aos_fstat(fd, &file_st);
if (!ret) {
    size = file_st.st_size;
    mode = file_st.st_mode;
}

aos_fstat

函数原型

int aos_fstat(int fd, struct aos_stat *st);

详细说明

aos_fstat()函数的功能和aos_stat()相同,aos_fstat()读取文件的属性信息,如文件大小、文件模式(权限、文件/文件夹)等信息到st指针指向的buffer。区别在于,aos_fstat()函数使用文件描述符作为参数,而aos_stat()以文件的路径为参数。

输入参数

参数类型 参数名称 参数描述
int fd 文件描述符(File Descriptor)
struct aos_stat * st 文件状态信息结构体指针

返回参数

返回值类型 返回值 描述
int 0 获取文件信息成功
负数 获取文件信息失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *path = "/sdcard/test.txt";
struct aos_stat file_st;
int ret;
uint32_t size;
uint16_t mode;

ret = aos_stat(path, &file_st);
if (!ret) {
    size = file_st.st_size;
    mode = file_st.st_mode;
}

aos_link

函数原型

int aos_link(const char *oldpath, const char *newpath);

详细说明

aos_link()为文件创建一个新的链接文件。如果目标文件存在,则不会覆盖。使用老的文件名和新的文件名访问的是同一个文件,使用它们对文件的操作没有任何差异。

输入参数

参数类型 参数名称 参数描述
const char * oldpath 文件链接的源文件名
const char * newpath 文件链接的目标文件名

返回参数

返回值类型 返回值 int 描述
int 0 文件链接创建成功
负数 文件链接创建失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *oldname = "/sdcard/test1.txt";
const char *newname = "/sdcard/test2.txt";
int ret;

ret = aos_link(oldname, newname);
if (ret < 0) {
    printf("aos_link(%s, %s) failed, errno %d\r\n", oldname, newname, ret);
} else {
    printf("aos_link(%s, %s) success.\r\n", oldname, newname);
}

aos_unlink

函数原型

int aos_unlink(const char *path);

详细说明

aos_unlink()从文件系统中删除文件名。如果这个文件名是文件的最后一个链接,同时没有其他程序打开这个文件,那么aos_unlink()将会从文件系统中删除该文件,将该文件占用的空间释放出来。如果这个文件名是文件的最后一个链接,但是有其他程序打开了该文件,那么该文件将持续存在,直到最后一个打开该文件的程序关闭该文件。

输入参数

参数类型 参数名称 参数描述
const char *path path 需删除的文件路径

返回参数

返回值类型 返回值 描述
int 0 文件名删除成功
负数 文件名删除失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *filename = "/sdcard/test1.txt";
int ret;

int ret = aos_unlink(filename);
if (ret < 0) {
    printf("aos_unlink(%s) failed, errno %d\r\n", filename, ret);
} else {
    printf("aos_unlink(%s) success.\r\n", filename);
}

aos_remove

函数原型

int aos_remove(const char *path);

详细说明

aos_remove()从文件系统中删除文件名,它既可以删除文件,也可以删除目录。

输入参数

参数类型 参数名称 参数描述
const char * path 要被删除的文件或目录路径

返回参数

返回值类型 返回值 描述
int 0 文件或目录删除成功
负数 文件或目录删除失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *filename = "/sdcard/test1.txt";
int ret;

ret = aos_remove(filename);
if (ret < 0) {
    printf("aos_remove(%s) failed, errno %d\r\n", filename, ret);
} else {
    printf("aos_remove(%s) success.\r\n", filename);
}

aos_rename

函数原型

int aos_rename(const char *oldpath, const char *newpath);

详细说明

aos_rename()重命名一个文件,可以将文件从一个文件夹下通过重命名移动到另外一个文件夹下。

如果newpath指向的文件已经存在,aos_rename()将会自动替换它。

如果oldpathnewpath是指向同一个文件的连接文件,那么aos_rename()什么都不做,直接返回成功。

如果newpath指向的文件已经存在,但是aos_rename()由于某种原因失败了,系统会保证存在一份名为newpath的实例。

oldpath可以是一个文件夹,在这种情形下,newpath必须要么不存在,要么是一个空文件夹。

如果oldpath是一个链接,那么aos_rename()将重命名该链接;如果newpath是一个已经存在的链接,那么它将会被替换。

输入参数

参数类型 参数名称 参数描述
const char * oldpath 原文件路径名
const char * newpath 新文件路径名

返回参数

返回值类型 返回值 描述
int 0 文件重命名成功
负数 文件重命名失败,返回错误码

调用示例

#include <stdio.h>
#include “aos/vfs.h”

const char *oldpath = "/sdcard/origin.txt";
const char *newpath = "/sdcard/new.txt";
int ret;

ret = aos_rename(oldpath, newpath);
if (ret < 0) {
    printf("aos_rename(%s, %s) failed, errno %d\r\n", oldpath, newpath, ret);
} else {
    printf("aos_rename(%s, %s) success\r\n", oldpath, newpath);
}

aos_opendir

函数原型

aos_dir_t *aos_opendir(const char *path);

详细说明

aos_opendir()打开目录名path对应的目录流,并返回目录流指针。打开目录成功后,流位置指向目录的第一个成员。

输入参数

参数类型 参数名称 参数描述
const char * path 要打开的目录路径

返回参数

返回值类型 返回值 描述
aos_dir_t* 非NULL 打开目录成功
NULL 打开目录失败

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char dirpath = "/sdcard/dir";
aos_dir_t *dp;

dp = aos_opendir(dirpath);
if (NULL == dp) {
    printf("aos_opendir(%s) failed\r\n", dirpath);
} else {
    printf("aos_opendir(%s) success\r\n", dirpath);
}

aos_closedir

函数原型

int aos_closedir(aos_dir_t *dirp);

详细说明

aos_closedir()关闭目录流。调用aos_closedir()后,目录流指针不再可用。

输入参数

参数类型 参数名称 参数描述
aos_dir_t * dirp 要关闭的目录流指针

返回参数

返回值类型 返回值 描述
int 0 目录关闭成功
负数 目录关闭失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char dirpath = "/sdcard/dir";
aos_dir_t *dirp;

dirp = aos_opendir(dirpath);
if (NULL == dirp) {
    printf("aos_opendir(%s) failed\r\n", dirpath);
    // do error handle.
} else {
    printf("aos_opendir(%s) success\r\n", dirpath);
}

// do dir operations

ret = aos_closedir(dirp);
if (ret < 0) {
    printf("aos_closedir() failed, errno %d \r\n", ret);
} else {
    printf("aos_closedir() success\r\n");
}

aos_readdir

函数原型

aos_dirent_t *aos_readdir(aos_dir_t *dirp);

详细说明

aos_readdir()返回一个指向aos_dirent_t的指针,该指针关联的目录流dirp的成员指针指向下一个成员。当读取到目录的末尾或者读取失败,返回NULL

输入参数

参数类型 参数名称 参数描述
aos_dir_t * dirp 需读取的目录流指针

返回参数

返回值类型 返回值 aos_dirent_t * 描述
aos_dirent_t * 非NULL 读取目录成功,返回aos_dirent_t类型的指针
NULL 读取到目录的末尾或者读取失败

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char dirpath = "/sdcard/dir";
aos_dir_t *dirp;

dirp = aos_opendir(dirpath);
if (NULL == dirp) {
    printf("aos_opendir(%s) failed\r\n", dirpath);
    // do error handle.
} else {
    printf("aos_opendir(%s) success\r\n", dirpath);
}

aos_dirent_t *dirent;
while (dirent = aos_readdir(dirp)) {
    printf("dir name: %s\r\n" dirent->d_name);
}

ret = aos_closedir(dirp);
if (ret < 0) {
    printf("aos_closedir() failed, errno %d \r\n", ret);
} else {
    printf("aos_closedir() success\r\n");
}

aos_mkdir

函数原型

int aos_mkdir(const char *path);

详细说明

aos_mkdir()创建名为path的目录。如果已经存在path目录,则创建失败。

输入参数

参数类型 参数名称 参数描述
const char * path 需创建的目录路径

返回参数

返回值类型 返回值 描述
int 0 目录创建成功
负数 目录创建失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *path = "/sdcard/dir";
int ret;

ret = aos_mkdir(path);
if (ret < 0) {
    printf("aos_mkdir(%s) failed, errno %d\r\n", path, ret);
} else {
    printf("aos_mkdir(%s) success\r\n", path);
}

aos_rmdir

函数原型

int aos_rmdir(const char *path);

详细说明

aos_rmdir()删除一个目录。删除目录时,目录必须为空。

输入参数

参数类型 参数名称 参数描述
const char * path 需删除的目录路径

返回参数

返回值 返回值 int 描述
int 0 目录删除成功
负数 目录删除失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *path = "/sdcard/dir";
int ret;

ret = aos_mkdir(path);
if (ret < 0) {
    printf("aos_mkdir(%s) failed, errno %d\r\n", path, ret);
} else {
    printf("aos_mkdir(%s) success\r\n", path);
}

// do any operations

ret = aos_rmdir(path);
if (ret < 0) {
    printf("aos_rmdir(%s) failed, errno %d\r\n", path, ret);
} else {
    printf("aos_rmdir(%s) success.", path);
}

aos_rewinddir

函数原型

void aos_rewinddir(aos_dir_t *dirp);

详细说明

aos_rewinddir()将目录流dirp的位置重置为目录的开始处。

输入参数

参数类型 参数名称 参数描述
aos_dir_t * dir 要重置的目录流指针

返回参数

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char dirpath = "/sdcard/dir";
aos_dir_t *dirp;

dirp = aos_opendir(dirpath);
if (NULL == dirp) {
    printf("aos_opendir(%s) failed\r\n", dirpath);
    // do error handle.
} else {
    printf("aos_opendir(%s) success\r\n", dirpath);
}

aos_dirent_t *dirent;
while (dirent = aos_readdir(dirp)) {
    printf("dir name: %s\r\n" dirent->d_name);
}

// reset the position of the dirp
aos_rewinddir(dirp);

aos_telldir

函数原型

int aos_telldir(aos_dir_t *dirp);

详细说明

aos_telldir() 返回与目录流dirp相关联的目录流的当前位置。

输入参数

参数类型 参数名称 参数描述
aos_dir_t * dirp 要获取位置的目录流指针

返回参数

返回值类型 返回值 描述
int 非负数 获取成功,目录流当前的位置
负数 获取失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char dirpath = "/sdcard/dir";
aos_dir_t *dirp;

dirp = aos_opendir(dirpath);
if (dirp) {
    aos_dirent_t *dirent;
    int loc;
    while (dirent = aos_readdir(dirp)) {
        printf("dir name: %s\r\n" dirent->d_name);
        loc = aos_telldir(dirp);
        printf("loc %d\r\n", loc);
    }
    
    closedir(dirp);
}

aos_seekdir

函数原型

void aos_seekdir(aos_dir_t *dir, long loc);

详细说明

aos_seekdir()设置目录流的位置,下次调用aos_readdir()时目录流将从设置的位置开始读取目录。参数loc必须是之前通过调用aos_readdir()返回的值。

输入参数

参数名称 参数描述
aos_dir_t *dir 需设置读取位置的目录流指针
long loc 读取位置

返回参

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char dirpath = "/sdcard/dir";
aos_dir_t *dirp;

// open dir
dirp = aos_opendir(dirpath);
if (dirp) {
    aos_dirent_t *dirent;
    int loc;
    int seek_loc -1;
    // traverse the dir and record the location of "hello.txt"
    while (dirent = aos_readdir(dirp)) {
        printf("dir name: %s\r\n" dirent->d_name);
        loc = aos_telldir(dirp);
        printf("loc %d\r\n", loc);
        if (strcmp(dirent->d_name, "hello.txt") == 0) {
            seek_loc = loc;
        }
    }
    
    if (seek_loc != -1) {
        // seekdir, set the position of the dir to "hello.txt"
        aos_seekdir(dirp, (long)seek_loc);
    
        // traverse the dir from the position of "hello.txt"
        while (dirent = aos_readdir(dirp)) {
            printf("dir name: %s\r\n" dirent->d_name);
            loc = aos_telldir(dirp);
            printf("loc %d\r\n", loc);
            if (strcmp(dirent->d_name, "hello.txt") == 0) {
                seek_loc = loc;
            }
        }
    }
    
    closedir(dirp);
}

aos_statfs

函数原型

int aos_statfs(const char *path, struct aos_statfs *buf);

详细说明

aos_statfs()返回挂载的文件系统的信息。path是挂载的文件系统路径或者文件系统挂载路径下的任何文件路径,buf是指向struct aos_statfs结构体指针,用于获取文件系统的信息。

输入参数

参数类型 参数名称 参数描述
const char * path 挂载的文件系统路径或者文件系统挂载路径下的任何文件路径
struct aos_statfs * buf 文件系统信息结构缓存

返回参数

返回值 返回值 int 描述
int 0 文件系统信息获取成功
负数 文件系统信息获取失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *path = "/sdcard/a.txt";
struct aos_statfs statfs_buf;
int ret;

ret = aos_statfs(path, &statfs_buf);
if (!ret) {
    // print fs total size, free size
    printf("fs size %d Bytes, free %d Bytes\r\n",
           statfs_buf.f_bsize, statfs_buf.f_bfree);
}

aos_access

函数原型

int aos_access(const char *path, int amode);

详细说明

aos_access()检查当前程序是否可以访问path文件。amode指定访问权限,它的值可以是F_OK,或者R_OKW_OKX_OK的或“|”组合。F_OK用于测试文件是否存在,R_OKW_OKX_OK分别测试文件是否具有读、写、执行权限。

输入参数

参数类型 参数名称 参数描述
const char * path 文件目录路径
int amode 需查询的访问权限

返回参数

返回值类型 返回值 描述
int 0 允许该权限访问
负数 禁止该权限访问,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *path = "/sdcard/test.txt";

int ret = aos_access(path, F_OK);
if (!ret) {
    printf("file %s exists\r\n", path);
}

aos_chdir

函数原型

int aos_chdir(const char *path);

详细说明

aos_chdir()改变当前程序的工作目录到path路径。

要支持改变工作目录,VFS需要使能宏CURRENT_WORKING_DIRECTORY_ENABLE

输入参数

参数类型 参数名称 参数描述
const char * path 要变更的目标路径

返回参数

返回值类型 返回值 描述
int 0 当前工作目录变更成功
负数 当前工作目录变更失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *path = "/sdcard/dir";
int ret = aos_chdir(path);
if (ret) {
    printf("aos_chdir(%) failed, errno %d\r\n", path, ret);
} else {
    printf("aos_chdir(%) success\r\n", path);
}

aos_getcwd

函数原型

char *aos_getcwd(char *buf, size_t size);

详细说明

aos_getcwd()返回当当前程序的绝对工作目录字符串指针,同时如果buf参数不为空,也将当前工作目录字符串复制到buf中。参数sizebuf的的字节数。如果当前的工作目录字符串长度超过size字节(包括字符串末尾的'\0'),那么返回NULL

输入参数

参数类型 参数名称 参数描述
char * buf 获取当前工作目录的缓存
size_t size 缓存的长度

返回参数

返回值类型 返回值 描述
char * 非NULL 返回当前工作目录的指针
NULL 获取当前工作目录失败

调用示例

#include <stdio.h>
#include "aos/vfs.h"

char *cwd = NULL;
char buf[32];
int size = 32;
cwd = aos_getcwd(buf, size);
if (NULL != cwd) {
    printf("current work dir is %s\r\n", cwd);
}

aos_pathconf

函数原型

long aos_pathconf(const char *path, int name);

详细说明

aos_pathconf()函数返回配置文件的限制值,是与文件或目录相关联的运行时限制。path参数是限制值的路径,name是想得到限制值的名称,name的取值主要有以下几个取值:

限制名 说明 name参数
FILESIZEBITS 在指定目录中允许的普通文件最大长度所需的最少位数 _PC_FILESIZEBITS
LINK_MAX 文件链接数的最大值 _PC_LINK_MAX
MAX_CANON 终端规范输入队列的最大字节数 _PC_MAX_CANON
MAX_INPUT 终端输入队列可用空间的字节数 _PC_MAX_INPUT
NAME_MAX 文件名的最大字节数 _PC_NAME_MAX
PATH_MAX 相对路径名的最大字节数,包括null _PC_PATH_MAX
PIPE_BUF 能原子的写到管道的最大字节数 _PC_PIPE_BUF
SYMLINK_MAX 符号链接中的字节数 _PC_SYMLINK_MAX

输入参数

参数名称 参数名称 参数描述
const char * path 需获取配置信息的文件路径
int name 文件配置类型名

返回参数

返回值类型 返回值 描述
long 正数 成功,返回配置文件的限制值
负数 失败,返回错误码

返回文件配置类型值。

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *path = "/sdcard/test.txt";
long value = aos_pathconf(path, _PC_NAME_MAX);
if (value >= 0) {
    printf("name max is %d\r\n", value);
}

aos_fpathconf

函数原型

long aos_fpathconf(int fd, int name);

详细说明

aos_fpathconf()aos_pathconf()类似,返回配置文件的限制值,是与文件或目录相关联的运行时限制。aos_fpathconf()的第一个参数是已打开文件的描述符fdname是想得到限制值的名称,name的取值主要有以下几个取值:

限制名 说明 name参数
FILESIZEBITS 在指定目录中允许的普通文件最大长度所需的最少位数 _PC_FILESIZEBITS
LINK_MAX 文件链接数的最大值 _PC_LINK_MAX
MAX_CANON 终端规范输入队列的最大字节数 _PC_MAX_CANON
MAX_INPUT 终端输入队列可用空间的字节数 _PC_MAX_INPUT
NAME_MAX 文件名的最大字节数 _PC_NAME_MAX
PATH_MAX 相对路径名的最大字节数,包括null _PC_PATH_MAX
PIPE_BUF 能原子的写到管道的最大字节数 _PC_PIPE_BUF
SYMLINK_MAX 符号链接中的字节数 _PC_SYMLINK_MAX

输入参数

参数类型 参数名称 参数描述
int fd 需获取配置信息的文件描述符
int name 文件配置类型名

返回参数

返回值类型 返回值 描述
long 正数 成功,返回配置文件的限制值
负数 失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

int name = PATH_MAX;
long value = aos_fpathconf(fd, name);

#include <stdio.h>
#include "aos/vfs.h"

const char *path = "/sdcard/test.txt";
int fd;

fd = aos_open(path, O_RDONLY);
if (fd > 0) {
    long value = aos_pathconf(path, _PC_NAME_MAX);
    if (value >= 0) {
        printf("name max is %d\r\n", value);
    }
}

aos_close(fd);

aos_utime

函数原型

int aos_utime(const char *path, const struct aos_utimbuf *times);

详细说明

aos_utime()通过参数timesactimemodtime成员改变文件的访问时间和修改时间。

struct aos_utimbuf {
    time_t actime;  /**< time of last access */
    time_t modtime; /**< time of last modification */
};

输入参数

参数名称 参数描述
const char * path 要设置访问修改时间的文件路径
const struct aos_utimbuf * times 时间信息指针

返回参数

返回值类型 返回值 描述
int 0 时间修改成功
负数 时间修改失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

struct aos_utimbuf time;
const char *path = "/sdcard/test.txt";

time.actime = 100;
time.modtime = 1000;
int ret = aos_utime(path, &time);
if (ret < 0) {
    printf("modify %s time failed, errno %d\r\n", path, ret);
}

aos_register_fs

函数原型

int aos_register_fs(const char *path, fs_ops_t *ops, void *arg);

详细说明

aos_register_fs()向系统注册文件系统,path新注册文件系统要挂载的点,ops是文件系统的操作结构体指针,arg是向文件系统传递的挂载参数。

输入参数

参数名称 参数名称 参数描述
const char * path 文件系统挂载路径
fs_ops_t * ops 文件系统的操作结构体指针
void * arg 文件系统挂载参数

返回参数

返回值 返回值 描述
int 0 文件系统挂载成功
负数 文件系统挂载失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *path = "/spiffs";

static vfs_filesystem_ops_t spiffs_ops = {
    .open       = &spiffs_vfs_open,
    .close      = &spiffs_vfs_close,
    .read       = &spiffs_vfs_read,
    .write      = &spiffs_vfs_write,
    .lseek      = &spiffs_vfs_lseek,
    .sync       = &spiffs_vfs_sync,
    .stat       = &spiffs_vfs_stat,
    .unlink     = &spiffs_vfs_unlink,
    .rename     = &spiffs_vfs_rename,
    .opendir    = &spiffs_vfs_opendir,
    .readdir    = &spiffs_vfs_readdir,
    .closedir   = &spiffs_vfs_closedir,
    .mkdir      = NULL,
    .ioctl      = NULL
};

int ret;

// mount spiffs firstly, add your mount logic here
// SPIFFS_mount(...);

// register spiffs filesystem
ret = aos_register_fs(path, &spiffs_ops, NULL);
if (ret < 0) {
    printf("register spiffs failed, errno %d\r\n", ret);
}

aos_unregister_fs

函数原型

int aos_unregister_fs(const char *path);

详细说明

aos_unregister_fs()将文件系统从对应的挂载点卸载掉,path是文件系统的挂载点路径。

输入参数

参数类型 参数名称 参数描述
const char * path 要卸载的文件系统挂载路径

返回参数

返回值类型 返回值 描述
int 0 文件系统卸载成功
负数 文件系统卸载失败,返回错误码

调用示例

#include <stdio.h>
#include "aos/vfs.h"

const char *path = "/spiffs";
int ret;

ret = aos_unregister_fs(path);
if (ret < 0) {
    printf("unregister fs %s failed, errno %d\r\n", path, ret);
}

标准宏和结构体说明

VFS_DEVICE_NODES

宏VFS_DEVICE_NODES用于配置VFS最大设备节点数。

#ifndef VFS_CONFIG_DEVICE_NODES
#define VFS_DEVICE_NODES 25
#else
#define VFS_DEVICE_NODES VFS_CONFIG_DEVICE_NODES
#endif

VFS_FD_OFFSET

VFS_FD_OFFSET用于配置VFS文件描述符初始偏移量。

#ifndef VFS_CONFIG_FD_OFFSET
#define VFS_FD_OFFSET 512
#else
#define VFS_FD_OFFSET VFS_CONFIG_FD_OFFSET
#endif

VFS_PATH_MAX

宏VFS_PATH_MAX用于配置VFS路径最大长度。

#ifndef VFS_CONFIG_PATH_MAX
#define VFS_PATH_MAX 256
#else
#define VFS_PATH_MAX VFS_CONFIG_PATH_MAX
#endif

VFS_MAX_FILE_NUM

宏VFS_MAX_FILE_NUM用于配置VFS支持最大文件打开数。

#ifndef VFS_CONFIG_MAX_FILE_NUM
#define VFS_MAX_FILE_NUM (VFS_DEVICE_NODES * 2)
#else
#define VFS_MAX_FILE_NUM VFS_CONFIG_MAX_FILE_NUM
#endif

CURRENT_WORKING_DIRECTORY_ENABLE

宏CURRENT_WORKING_DIRECTORY_ENABLE用于使能VFS记录当前程序的工作目录。

#ifndef VFS_CONFIG_CURRENT_DIRECTORY_ENABLE
#define CURRENT_WORKING_DIRECTORY_ENABLE 0
#else
#define CURRENT_WORKING_DIRECTORY_ENABLE VFS_CONFIG_CURRENT_DIRECTORY_ENABLE
#endif

struct aos_utimbuf

结构体aos_utimbuf用于获取文件的访问时间和修改时间。该结构体定义在include/aos/vfs.h中。

struct aos_utimbuf {
    time_t actime;  /* time of last access */
    time_t modtime; /* time of last modification */
};

struct aos_statfs

结构体aos_statfs用于获取文件系统的信息。该结构体定义在include/aos/vfs.h中。

struct aos_statfs {
    long f_type;    /* fs type */
    long f_bsize;   /* optimized transport block size */
    long f_blocks;  /* total blocks */
    long f_bfree;   /* available blocks */
    long f_bavail;  /* number of blocks that non-super users can acquire */
    long f_files;   /* total number of file nodes */
    long f_ffree;   /* available file nodes */
    long f_fsid;    /* fs id */
    long f_namelen; /* max file name length */
};

struct aos_stat

结构体aos_stat用于获取文件的信息。该结构体定义在include/aos/vfs.h中。

struct aos_stat {
    uint16_t st_mode;    /* mode of file */
    uint32_t st_size;    /* bytes of file */
    time_t   st_actime;  /* time of last access */
    time_t   st_modtime; /* time of last modification */
};

aos_dirent_t

结构体aos_dirent_t用于描述目录文件。aos_readdir()成功返回后,返回一个指向aos_dirent_t的结构体指针,通过该指针访问到文件的类型、文件名。该结构体定义在include/aos/vfs.h中。

typedef struct {
    int32_t d_ino;    /* file number */
    uint8_t d_type;   /* type of file */
    char    d_name[]; /* file name */
} aos_dirent_t;

aos_dir_t

结构体aos_dir_t用于描述目录,aos_opendir()成功返回后,返回一个指向aos_dir_t的结构体指针。该结构体定义在include/aos/vfs.h中。

typedef struct {
    int32_t dd_vfs_fd;
    int32_t dd_rsv;
} aos_dir_t;

inode_ops_t

联合体inode_ops_t统一对inode的操作方法,一个inode要么是设备文件,要么是文件系统,将他们定义成一个联合体,可以节约内存。该结构体定义在include/aos/vfs.h中。

union inode_ops_t {
    const file_ops_t *i_ops;  /* char driver operations */
    const fs_ops_t   *i_fops; /* FS operations */
};

inode_t

结构体inode_t用于描述一个inode节点。一个文件、文件夹、设备在虚拟文件系统中被抽象成一个inode。该结构体定义在include/aos/vfs.h中。

typedef struct {
    union inode_ops_t  ops;     /* inode operations */
    void              *i_arg;   /* per inode private data */
    char              *i_name;  /* name of inode */
    int                i_flags; /* flags for inode */
    uint8_t            type;    /* type for inode */
    uint8_t            refs;    /* refs for inode */
} inode_t;

file_t

结构体file_t是虚拟文件系统的文件的抽象。该结构体定义在include/aos/vfs.h中。

typedef struct {
    inode_t *node;   /* node for file */
    void    *f_arg;  /* f_arg for file */
    size_t   offset; /* offset for file */
} file_t;

file_ops_t

定义file_ops_t结构。该结构体定义在include/aos/vfs.h中。

typedef const struct file_ops file_ops_t;

struct file_ops

结构体file_ops集成对文件操作的方法。该结构体定义在include/aos/vfs.h中。

struct file_ops {
    int     (*open)(inode_t *node, file_t *fp);
    int     (*close)(file_t *fp);
    ssize_t (*read)(file_t *fp, void *buf, size_t nbytes);
    ssize_t (*write)(file_t *fp, const void *buf, size_t nbytes);
    int     (*ioctl)(file_t *fp, int cmd, unsigned long arg);
    int     (*poll)(file_t *fp, int flag, poll_notify_t notify, void *fd, void *arg);
};

fs_ops_t

定义fs_ops_t结构。该结构体定义在include/aos/vfs.h中。

typedef const struct fs_ops   fs_ops_t;

struct fs_ops

结构体fs_ops集成对文件系统的操作方法。该结构体定义在include/aos/vfs.h中。

struct fs_ops {
    int           (*open)(file_t *fp, const char *path, int flags);
    int           (*close)(file_t *fp);
    ssize_t       (*read)(file_t *fp, char *buf, size_t len);
    ssize_t       (*write)(file_t *fp, const char *buf, size_t len);
    off_t         (*lseek)(file_t *fp, off_t off, int whence);
    int           (*sync)(file_t *fp);
    int           (*stat)(file_t *fp, const char *path, struct aos_stat *st);
    int           (*fstat)(file_t *fp, struct aos_stat *st);
    int           (*link)(file_t *fp, const char *path1, const char *path2);
    int           (*unlink)(file_t *fp, const char *path);
    int           (*remove)(file_t *fp, const char *path);
    int           (*rename)(file_t *fp, const char *oldpath, const char *newpath);
    aos_dir_t    *(*opendir)(file_t *fp, const char *path);
    aos_dirent_t *(*readdir)(file_t *fp, aos_dir_t *dir);
    int           (*closedir)(file_t *fp, aos_dir_t *dir);
    int           (*mkdir)(file_t *fp, const char *path);
    int           (*rmdir)(file_t *fp, const char *path);
    void          (*rewinddir)(file_t *fp, aos_dir_t *dir);
    long          (*telldir)(file_t *fp, aos_dir_t *dir);
    void          (*seekdir)(file_t *fp, aos_dir_t *dir, long loc);
    int           (*ioctl)(file_t *fp, int cmd, unsigned long arg);
    int           (*statfs)(file_t *fp, const char *path, struct aos_statfs *suf);
    int           (*access)(file_t *fp, const char *path, int amode);
    long          (*pathconf)(file_t *fp, const char *path, int name);
    long          (*fpathconf)(file_t *fp, int name);
    int           (*utime)(file_t *fp, const char *path, const struct aos_utimbuf *times);
};

配置说明

配置文件为./core/vfs/Config.in。进入menuconfig界面,如下所示:

-*- Kernel Core (rhino)                                                                              │ │
[ ] config micro kernel  ----                                                                        │ │
-*- Initialize Function                                                                              │ │
[ ] Power Management  ----                                                                           │ │
[ ] C++ Support                                                                                      │ │
-*- Newlib (C-library) adaptation layer                                                              │ │
[ ] Command-Line Interface  ----                                                                     │ │
[ ] Coredump debug Support  ----                                                                     │ │
-*- Key-value Storage  --->                                                                          │ │
-*- Virtual File System  --->                                                                        │ │
-*- AOS API Support  --->                                                                            │ │
[ ] POSIX API Support                                                                                │ │
[ ] CMSIS API Support

再进入Virtual File System,配置以下参数:

--- Virtual File System                                                                              │ │
(25)  The maximum number of VFS device nodes                                                         │ │
(512) The default offset of VFS file descriptor                                                      │ │
(256) The maximum length of device path (bytes)                                                      │ │
(50)  The maximum number of VFS files                                                                │ │
[ ]   Current Directory Recording Support

配置项

宏定义 默认值 描述
VFS_CONFIG_DEVICE_NODES 25 VFS最大设备节点数
VFS_CONFIG_FD_OFFSET 512 VFS文件描述符初始偏移量
VFS_CONFIG_PATH_MAX 256 VFS路径最大长度
VFS_CONFIG_MAX_FILE_NUM 50 VFS支持最大文件打开数
CURRENT_WORKING_DIRECTORY_ENABLE n 使能VFS记录当前程序的工作目录

移植说明

代码目录结构

头文件vfs.h的内容是aos vfs对外的数据结构和API。

include/aos/vfs.h

vfs.c是aos vfs对外API的实现文件。

core/osal/aos/vfs.c

目录core/vfs/里面是vfs的核心文件,包括头文件和C文件。这些头文件是vfs内部使用或者core内部使用的头文件,应用开发不应当访问这些头文件。

core/vfs/
├── aos.mk
├── Config.in
├── include
│   ├── vfs_adapt.h
│   ├── vfs_api.h
│   ├── vfs_conf.h
│   └── vfs_types.h
├── vfs_adapt.c
├── vfs.c
├── vfs_file.c
├── vfs_file.h
├── vfs_inode.c
└── vfs_inode.h