写点什么

鸿蒙轻内核源码分析:文件系统 LittleFS

  • 2022 年 2 月 08 日
  • 本文字数:10883 字

    阅读完需:约 36 分钟

摘要:本文先介绍下 LFS 文件系统结构体的结构体和全局变量,然后分析下 LFS 文件操作接口。


本文分享自华为云社区《# 鸿蒙轻内核M核源码分析系列二一 02 文件系统LittleFS》,作者:zhushy 。


LittleFS 是一个小型的 Flash 文件系统,它结合日志结构(log-structured)文件系统和 COW(copy-on-write)文件系统的思想,以日志结构存储元数据,以 COW 结构存储数据。这种特殊的存储方式,使 LittleFS 具有强大的掉电恢复能力(power-loss resilience)。分配 COW 数据块时 LittleFS 采用了名为统计损耗均衡的动态损耗均衡算法,使 Flash 设备的寿命得到有效保障。同时 LittleFS 针对资源紧缺的小型设备进行设计,具有极其有限的 ROM 和 RAM 占用,并且所有 RAM 的使用都通过一个可配置的固定大小缓冲区进行分配,不会随文件系统的扩大占据更多的系统资源。当在一个资源非常紧缺的小型设备上,寻找一个具有掉电恢复能力并支持损耗均衡的 Flash 文件系统时,LittleFS 是一个比较好的选择。本文先介绍下 LFS 文件系统结构体的结构体和全局变量,然后分析下 LFS 文件操作接口。文中所涉及的源码,均可以在开源站点https://gitee.com/openharmony/kernel_liteos_m获取。

1、LFS 文件系统结构体介绍


会分 2 部分来介绍结构体部分,先介绍 LittleFS 文件系统的结构体,然后介绍 LiteOS-M 内核中提供的和 LittleFS 相关的一些结构体。

1.1 LittleFS 的枚举结构体


在 openharmony/third_party/littlefs/lfs.h 头文件中定义 LittleFS 的枚举、结构体,我们先简单了解下,后文会使用到的。


枚举 lfs_type 定义文件类型,了解下普通文件 LFS_TYPE_REG 和目录 LFS_TYPE_DIR 即可。枚举 lfs_open_flags 定义文件系统的打开标签属性信息,需要熟悉常用的只读 LFS_O_RDONLY、只写 LFS_O_WRONLY、读写 LFS_O_RDWR 等等。


// File typesenum lfs_type {    // file types    LFS_TYPE_REG            = 0x001,    LFS_TYPE_DIR            = 0x002,
// internally used types LFS_TYPE_SPLICE = 0x400, LFS_TYPE_NAME = 0x000, LFS_TYPE_STRUCT = 0x200, LFS_TYPE_USERATTR = 0x300, LFS_TYPE_FROM = 0x100, LFS_TYPE_TAIL = 0x600, LFS_TYPE_GLOBALS = 0x700, LFS_TYPE_CRC = 0x500,
// internally used type specializations LFS_TYPE_CREATE = 0x401, LFS_TYPE_DELETE = 0x4ff, LFS_TYPE_SUPERBLOCK = 0x0ff, LFS_TYPE_DIRSTRUCT = 0x200, LFS_TYPE_CTZSTRUCT = 0x202, LFS_TYPE_INLINESTRUCT = 0x201, LFS_TYPE_SOFTTAIL = 0x600, LFS_TYPE_HARDTAIL = 0x601, LFS_TYPE_MOVESTATE = 0x7ff,
// internal chip sources LFS_FROM_NOOP = 0x000, LFS_FROM_MOVE = 0x101, LFS_FROM_USERATTRS = 0x102,};
// File open flagsenum lfs_open_flags { // open flags LFS_O_RDONLY = 1, // Open a file as read only#ifndef LFS_READONLY LFS_O_WRONLY = 2, // Open a file as write only LFS_O_RDWR = 3, // Open a file as read and write LFS_O_CREAT = 0x0100, // Create a file if it does not exist LFS_O_EXCL = 0x0200, // Fail if a file already exists LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size LFS_O_APPEND = 0x0800, // Move to end of file on every write#endif
// internally used flags#ifndef LFS_READONLY LFS_F_DIRTY = 0x010000, // File does not match storage LFS_F_WRITING = 0x020000, // File has been written since last flush#endif LFS_F_READING = 0x040000, // File has been read since last flush#ifndef LFS_READONLY LFS_F_ERRED = 0x080000, // An error occurred during write#endif LFS_F_INLINE = 0x100000, // Currently inlined in directory entry};
复制代码


结构体 lfs_t 是 littlefs 文件系统类型结构体,lfs 文件系统操作接口的第一个参数一般为这个结构体。成员变量 struct lfs_config *cfg 下文会涉及,其他成员变量可以暂不了解。


// The littlefs filesystem typetypedef struct lfs {    lfs_cache_t rcache;    lfs_cache_t pcache;
lfs_block_t root[2]; struct lfs_mlist { struct lfs_mlist *next; uint16_t id; uint8_t type; lfs_mdir_t m; } *mlist; uint32_t seed;
lfs_gstate_t gstate; lfs_gstate_t gdisk; lfs_gstate_t gdelta;
struct lfs_free { lfs_block_t off; lfs_block_t size; lfs_block_t i; lfs_block_t ack; uint32_t *buffer; } free;
const struct lfs_config *cfg; lfs_size_t name_max; lfs_size_t file_max; lfs_size_t attr_max;
#ifdef LFS_MIGRATE struct lfs1 *lfs1;#endif} lfs_t;
复制代码


结构体 lfs_file_t、lfs_dir_t 分别是 littlefs 的文件和目录类型结构体,暂不需要关心成员变量细节,知道结构体的用途即可。


// littlefs directory typetypedef struct lfs_dir {    struct lfs_dir *next;    uint16_t id;    uint8_t type;    lfs_mdir_t m;
lfs_off_t pos; lfs_block_t head[2];} lfs_dir_t;
// littlefs file typetypedef struct lfs_file { struct lfs_file *next; uint16_t id; uint8_t type; lfs_mdir_t m;
struct lfs_ctz { lfs_block_t head; lfs_size_t size; } ctz;
uint32_t flags; lfs_off_t pos; lfs_block_t block; lfs_off_t off; lfs_cache_t cache;
const struct lfs_file_config *cfg;} lfs_file_t;
复制代码


结构体 lfs_config 用于提供初始化 littlefs 文件系统的一些配置。其中.read,.prog,.erase,.sync 分别对应该硬件平台上的底层的读写\擦除\同步等接口。


  • read_size 每次读取的字节数,可以比物理读单元大以改善性能,这个数值决定了读缓存的大小,但值太大会带来更多的内存消耗。

  • prog_size 每次写入的字节数,可以比物理写单元大以改善性能,这个数值决定了写缓存的大小,必须是 read_size 的整数倍,但值太大会带来更多的内存消耗。

  • block_size 每个擦除块的字节数,可以比物理擦除单元大,但此数值应尽可能小因为每个文件至少会占用一个块。必须是 prog_size 的整数倍。

  • block_count 可以被擦除的块数量,这取决于块设备的容量及擦除块的大小。


// Configuration provided during initialization of the littlefsstruct lfs_config {    // Opaque user provided context that can be used to pass    // information to the block device operations    void *context;
int (*read)(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size); int (*prog)(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size); int (*erase)(const struct lfs_config *c, lfs_block_t block); int (*sync)(const struct lfs_config *c);
#ifdef LFS_THREADSAFE int (*lock)(const struct lfs_config *c); int (*unlock)(const struct lfs_config *c);#endif
lfs_size_t read_size; lfs_size_t prog_size; lfs_size_t block_size; lfs_size_t block_count;
int32_t block_cycles; lfs_size_t cache_size; lfs_size_t lookahead_size; void *read_buffer; void *prog_buffer; void *lookahead_buffer; lfs_size_t name_max; lfs_size_t file_max; lfs_size_t attr_max; lfs_size_t metadata_max;};
复制代码


结构体 lfs_info 用于维护文件信息,包含文件类型,大小和文件名信息。


// File info structurestruct lfs_info {    // Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR    uint8_t type;
// Size of the file, only valid for REG files. Limited to 32-bits. lfs_size_t size;
// Name of the file stored as a null-terminated string. Limited to // LFS_NAME_MAX+1, which can be changed by redefining LFS_NAME_MAX to // reduce RAM. LFS_NAME_MAX is stored in superblock and must be // respected by other littlefs drivers. char name[LFS_NAME_MAX+1];};
复制代码


1.2 LiteOS-M LittleFS 的结构体


我们来看下在文件 components\fs\littlefs\lfs_api.h 里定义的几个结构体。结构体 LittleFsHandleStruct 维护文件相关的信息,该结构体的成员包含是否使用,文件路径和 lfs 文件系统类型结构体 lfs_t *lfsHandle 和文件类型结构体 lfs_file_t file。类似的,结构体 FileDirInfo 维护目录相关的信息,该结构体成员包含包含是否使用,目录名称和 lfs 文件系统类型结构体 lfs_t *lfsHandle 和目录类型结构体 lfs_dir_t dir。另外一个结构体 FileOpInfo 维护文件操作信息。


typedef struct {    uint8_t useFlag;    const char *pathName;    lfs_t *lfsHandle;    lfs_file_t file;} LittleFsHandleStruct;
struct FileOpInfo { uint8_t useFlag; const struct FileOps *fsVops; char *dirName; lfs_t lfsInfo;};
typedef struct { uint8_t useFlag; char *dirName; lfs_t *lfsHandle; lfs_dir_t dir;} FileDirInfo;
复制代码


2、LiteOS-M LittleFS 的重要全局变量及操作


了解下文件 components\fs\littlefs\lfs_api.c 定义的常用全局变量。⑴处的 g_lfsDir 数组维护目录信息,默认支持的目录数目为 LFS_MAX_OPEN_DIRS,等于 10。⑵处的 g_fsOp 数组维护针对每个挂载点的文件操作信息,默认挂载点数目 LOSCFG_LFS_MAX_MOUNT_SIZE 为 3 个。⑶处的 g_handle 数组维护文件信息,默认支持文件的数量 LITTLE_FS_MAX_OPEN_FILES 为 100 个。⑷处开始的 struct dirent g_nameValue 是目录项结构体变量,用于函数 LfsReaddir();pthread_mutex_t g_FslocalMutex 是互斥锁变量;g_littlefsMntName 是挂载点名称数组。⑸处开始的挂载操作变量 g_lfsMnt、文件操作操作全局变量 g_lfsFops 在虚拟文件系统中被使用。


⑴  FileDirInfo g_lfsDir[LFS_MAX_OPEN_DIRS] = {0};
⑵ struct FileOpInfo g_fsOp[LOSCFG_LFS_MAX_MOUNT_SIZE] = {0};⑶ static LittleFsHandleStruct g_handle[LITTLE_FS_MAX_OPEN_FILES] = {0};⑷ struct dirent g_nameValue; static pthread_mutex_t g_FslocalMutex = PTHREAD_MUTEX_INITIALIZER; static const char *g_littlefsMntName[LOSCFG_LFS_MAX_MOUNT_SIZE] = {"/a", "/b", "/c"}; ......⑸ const struct MountOps g_lfsMnt = { .Mount = LfsMount, .Umount = LfsUmount, };
const struct FileOps g_lfsFops = { .Mkdir = LfsMkdir, .Unlink = LfsUnlink, .Rmdir = LfsRmdir, .Opendir = LfsOpendir, .Readdir = LfsReaddir, .Closedir = LfsClosedir, .Open = LfsOpen, .Close = LfsClose, .Write = LfsWrite, .Read = LfsRead, .Seek = LfsSeek, .Rename = LfsRename, .Getattr = LfsStat, .Fsync = LfsFsync, .Fstat = LfsFstat, };
复制代码


下文继续介绍下和这些变量相关的内部操作接口。

2.1 目录信息数组操作


GetFreeDir()设置目录信息数组元素信息。参数 dirName 为目录名称。遍历目录信息数组,遍历到第一个未使用的元素标记其为已使用状态,设置目录名称,返回目录信息元素指针地址。如果遍历失败,返回 NULL。函数 FreeDirInfo()为函数 GetFreeDir()的反向操作,根据目录名称设置对应的数组元素为未使用状态,并把 GetFreeDir 设置为 NULL。


函数 CheckDirIsOpen()用于检测目录是否已经打开。如果目录信息数组中记录着对应的目录信息,则标志着该目录已经打开。


FileDirInfo *GetFreeDir(const char *dirName){    pthread_mutex_lock(&g_FslocalMutex);    for (int i = 0; i < LFS_MAX_OPEN_DIRS; i++) {        if (g_lfsDir[i].useFlag == 0) {            g_lfsDir[i].useFlag = 1;            g_lfsDir[i].dirName = strdup(dirName);            pthread_mutex_unlock(&g_FslocalMutex);            return &(g_lfsDir[i]);        }    }    pthread_mutex_unlock(&g_FslocalMutex);    return NULL;}
void FreeDirInfo(const char *dirName){ pthread_mutex_lock(&g_FslocalMutex); for (int i = 0; i < LFS_MAX_OPEN_DIRS; i++) { if (g_lfsDir[i].useFlag == 1 && strcmp(g_lfsDir[i].dirName, dirName) == 0) { g_lfsDir[i].useFlag = 0; if (g_lfsDir[i].dirName) { free(g_lfsDir[i].dirName); g_lfsDir[i].dirName = NULL; } pthread_mutex_unlock(&g_FslocalMutex); } } pthread_mutex_unlock(&g_FslocalMutex);}
BOOL CheckDirIsOpen(const char *dirName){ pthread_mutex_lock(&g_FslocalMutex); for (int i = 0; i < LFS_MAX_OPEN_DIRS; i++) { if (g_lfsDir[i].useFlag == 1) { if (strcmp(g_lfsDir[i].dirName, dirName) == 0) { pthread_mutex_unlock(&g_FslocalMutex); return TRUE; } } } pthread_mutex_unlock(&g_FslocalMutex); return FALSE;}
复制代码


2.2 文件信息数组操作


函数 LfsAllocFd()设置文件信息数组元素信息。参数 fileName 为文件路径信息,传出参数 fd 为文件描述符即数组索引。遍历文件信息数组,遍历到第一个未使用的元素标记其为已使用状态,设置文件路径信息,把数组索引赋值给文件描述符 fd,返回文件信息元素指针地址。如果遍历失败,返回 NULL。函数 LfsFreeFd()为函数 LfsAllocFd()的反向操作,根据文件描述符设置对应的数组元素为未使用状态,并把路径信息等设置为 NULL。


函数 CheckFileIsOpen()用于检测文件是否已经打开,文件如果打开过,则表示获取过该文件的文件描述符,根据对应的 fd 文件描述符,可以对文件进行更多的操作。如果文件信息数组中记录着对应的文件路径信息,则标志着该文件已经打开。函数 LfsFdIsValid()用于判断文件描述符是否有效。


LittleFsHandleStruct *LfsAllocFd(const char *fileName, int *fd){    pthread_mutex_lock(&g_FslocalMutex);    for (int i = 0; i < LITTLE_FS_MAX_OPEN_FILES; i++) {        if (g_handle[i].useFlag == 0) {            *fd = i;            g_handle[i].useFlag = 1;            g_handle[i].pathName = strdup(fileName);            pthread_mutex_unlock(&g_FslocalMutex);            return &(g_handle[i]);        }    }    pthread_mutex_unlock(&g_FslocalMutex);    *fd = INVALID_FD;    return NULL;}
static void LfsFreeFd(int fd){ pthread_mutex_lock(&g_FslocalMutex); g_handle[fd].useFlag = 0; if (g_handle[fd].pathName != NULL) { free((void *)g_handle[fd].pathName); g_handle[fd].pathName = NULL; }
if (g_handle[fd].lfsHandle != NULL) { g_handle[fd].lfsHandle = NULL; } pthread_mutex_unlock(&g_FslocalMutex);}
BOOL CheckFileIsOpen(const char *fileName){ pthread_mutex_lock(&g_FslocalMutex); for (int i = 0; i < LITTLE_FS_MAX_OPEN_FILES; i++) { if (g_handle[i].useFlag == 1) { if (strcmp(g_handle[i].pathName, fileName) == 0) { pthread_mutex_unlock(&g_FslocalMutex); return TRUE; } } } pthread_mutex_unlock(&g_FslocalMutex); return FALSE;}
static BOOL LfsFdIsValid(int fd){ if (fd >= LITTLE_FS_MAX_OPEN_FILES || fd < 0) { return FALSE; } if (g_handle[fd].lfsHandle == NULL) { return FALSE; } return TRUE;}
复制代码


2.3 挂载点文件操作信息相关操作


函数 AllocMountRes()用于设置挂载点文件操作信息。参数 target 为挂载点名称,参数 fileOps 为文件操作信息。遍历每个挂载点,如果遍历到的挂载点未使用,并且挂载点名称相等,则设置其使用标记为已使用,设置目录名称,设置文件操作信息,然后返回文件操作信息指针。如果没有遍历到,返回 NULL。挂载点数组 g_littlefsMntName 的元素默认为/a,/b,/c 等,可以使用函数 SetDefaultMountPath()设置指定位置的挂载点名称。


struct FileOpInfo *AllocMountRes(const char* target, const struct FileOps *fileOps){    pthread_mutex_lock(&g_FslocalMutex);    for (int i = 0; i < LOSCFG_LFS_MAX_MOUNT_SIZE; i++) {        if (g_fsOp[i].useFlag == 0 && strcmp(target, g_littlefsMntName[i]) == 0) {            g_fsOp[i].useFlag = 1;            g_fsOp[i].fsVops = fileOps;            g_fsOp[i].dirName = strdup(target);            pthread_mutex_unlock(&g_FslocalMutex);            return &(g_fsOp[i]);        }    }
pthread_mutex_unlock(&g_FslocalMutex); return NULL;}
int SetDefaultMountPath(int pathNameIndex, const char* target){ if (pathNameIndex >= LOSCFG_LFS_MAX_MOUNT_SIZE) { return VFS_ERROR; }
pthread_mutex_lock(&g_FslocalMutex); g_littlefsMntName[pathNameIndex] = strdup(target); pthread_mutex_unlock(&g_FslocalMutex); return VFS_OK;}
复制代码


函数 GetMountRes()用于获取给定挂载点在挂载点文件操作信息数组中的索引值。参数 target 为挂载点名称,参数 mountIndex 用于输出文件操作信息数组索引值。遍历每个挂载点,如果遍历到的挂载点已使用,并且挂载点名称相等,则返回相应的数组索引,否则返回 NULL。


struct FileOpInfo *GetMountRes(const char *target, int *mountIndex){    pthread_mutex_lock(&g_FslocalMutex);    for (int i = 0; i < LOSCFG_LFS_MAX_MOUNT_SIZE; i++) {        if (g_fsOp[i].useFlag == 1) {            if (g_fsOp[i].dirName && strcmp(target, g_fsOp[i].dirName) == 0) {                *mountIndex = i;                pthread_mutex_unlock(&g_FslocalMutex);                return &(g_fsOp[i]);            }        }    }
pthread_mutex_unlock(&g_FslocalMutex); return NULL;}
复制代码


函数 FreeMountResByIndex()属于函数 AllocMountRes()的反向操作,用于释放挂载点文件操作信息。传入参数 mountIndex 对应的文件操作信息标记为未使用状态,释放挂载点名称占用的内存。函数 FreeMountRes()实现的功能一样,传入参数为挂载点名称。遍历每一个挂载点,如果存在和传入参数相同的挂载点,则进行释放。


int FreeMountResByIndex(int mountIndex){    if (mountIndex < 0 || mountIndex >= LOSCFG_LFS_MAX_MOUNT_SIZE) {        return VFS_ERROR;    }
pthread_mutex_lock(&g_FslocalMutex); if (g_fsOp[mountIndex].useFlag == 1 && g_fsOp[mountIndex].dirName != NULL) { g_fsOp[mountIndex].useFlag = 0; free(g_fsOp[mountIndex].dirName); g_fsOp[mountIndex].dirName = NULL; } pthread_mutex_unlock(&g_FslocalMutex);
return VFS_OK;}
int FreeMountRes(const char *target){ pthread_mutex_lock(&g_FslocalMutex); for (int i = 0; i < LOSCFG_LFS_MAX_MOUNT_SIZE; i++) { if (g_fsOp[i].useFlag == 1) { if (g_fsOp[i].dirName && strcmp(target, g_fsOp[i].dirName) == 0) { g_fsOp[i].useFlag = 0; free(g_fsOp[i].dirName); g_fsOp[i].dirName = NULL; pthread_mutex_unlock(&g_FslocalMutex); return VFS_OK; } } }
pthread_mutex_unlock(&g_FslocalMutex); return VFS_ERROR;}
复制代码


2.4 路径是否已挂载 CheckPathIsMounted


函数 CheckPathIsMounted()用于检查给定的路径是否已经挂载,如果挂载上把对应挂载点的文件操作信息由参数 struct FileOpInfo **fileOpInfo 输出。⑴处先获取路径的第一级目录的长度。⑵处遍历每一个挂载点的文件操作数组,如果文件操作处于使用状态,则执行⑶比对相应的挂载点名称和路径的第一级目录名称是否相等。如果相等,则输出文件操作信息,并返回 TRUE。否则返回 FALSE。


int GetFirstLevelPathLen(const char *pathName){    int len = 1;    for (int i = 1; i < strlen(pathName) + 1; i++) {        if (pathName[i] == '/') {            break;        }        len++;    }
return len;}
BOOL CheckPathIsMounted(const char *pathName, struct FileOpInfo **fileOpInfo){ char tmpName[LITTLEFS_MAX_LFN_LEN] = {0};⑴ int len = GetFirstLevelPathLen(pathName);
pthread_mutex_lock(&g_FslocalMutex); for (int i = 0; i < LOSCFG_LFS_MAX_MOUNT_SIZE; i++) {⑵ if (g_fsOp[i].useFlag == 1) { (void)strncpy_s(tmpName, LITTLEFS_MAX_LFN_LEN, pathName, len);⑶ if (strcmp(tmpName, g_fsOp[i].dirName) == 0) { *fileOpInfo = &(g_fsOp[i]); pthread_mutex_unlock(&g_FslocalMutex); return TRUE; } } } pthread_mutex_unlock(&g_FslocalMutex); return FALSE;}
复制代码


3、LiteOS-M LittleFS 的文件系统操作接口


快速记录下各个操作接口,对每个接口的用途用法不再描述。可以参考之前的系列文章,《鸿蒙轻内核 M 核源码分析系列十九 Musl LibC》中介绍了相关的接口,那些接口会调用 VFS 文件系统中操作接口,然后进一步调用 LFS 文件操作接口。

3.1 挂载 LfsMount 和卸载 LfsUmounts 操作


挂载卸载操作包含 LfsMount、LfsUmounts 等 2 个操作。对于函数 LfsMount(),需要注意下参数 const void *data,这个需要是 struct lfs_config 指针类型变量。⑴处在挂载文件系统之前,对输入参数进行检测。⑵处判断是否已经挂载,不允许重复挂载。⑶处设置挂载点信息,⑷处调用 LFS 的函数实现挂载,如果挂载失败,则执行⑸尝试格式化,然后重新挂载。


对于函数 LfsUmount(),⑹处根据挂载点获取文件操作信息和挂载点索引值。⑺处调用 LFS 函数实现卸载,然后执行⑻释放挂载点文件操作信息。


int LfsMount(const char *source, const char *target, const char *fileSystemType, unsigned long mountflags,    const void *data){    int ret;    struct FileOpInfo *fileOpInfo = NULL;
⑴ if (target == NULL || fileSystemType == NULL || data == NULL) { errno = EFAULT; ret = VFS_ERROR; goto errout; }
if (strcmp(fileSystemType, "littlefs") != 0) { errno = ENODEV; ret = VFS_ERROR; goto errout; }
⑵ if (CheckPathIsMounted(target, &fileOpInfo)) { errno = EBUSY; ret = VFS_ERROR; goto errout; }
// select free mount resource⑶ fileOpInfo = AllocMountRes(target, &g_lfsFops); if (fileOpInfo == NULL) { errno = ENODEV; ret = VFS_ERROR; goto errout; }
⑷ ret = lfs_mount(&(fileOpInfo->lfsInfo), (struct lfs_config*)data); if (ret != 0) {⑸ ret = lfs_format(&(fileOpInfo->lfsInfo), (struct lfs_config*)data); if (ret == 0) { ret = lfs_mount(&(fileOpInfo->lfsInfo), (struct lfs_config*)data); } }
if (ret != 0) { errno = LittlefsErrno(ret); ret = VFS_ERROR; }
errout: return ret;}
int LfsUmount(const char *target){ int ret; int mountIndex = -1; struct FileOpInfo *fileOpInfo = NULL;
if (target == NULL) { errno = EFAULT; return VFS_ERROR; }
⑹ fileOpInfo = GetMountRes(target, &mountIndex); if (fileOpInfo == NULL) { errno = ENOENT; return VFS_ERROR; }
⑺ ret = lfs_unmount(&(fileOpInfo->lfsInfo)); if (ret != 0) { errno = LittlefsErrno(ret); ret = VFS_ERROR; }
⑻ (void)FreeMountResByIndex(mountIndex); return ret;}
复制代码


3.2 文件目录操作接口


文件目录操作接口包含 LfsMkdir、LfsUnlink、LfsRmdir、LfsReaddir、LfsClosedir、LfsOpen、LfsClose 等等,会进一步调用 LFS 的文件目录操作接口进行封装,代码比较简单,自行阅读即可,部分代码片段如下。


......int LfsUnlink(const char *fileName){    int ret;    struct FileOpInfo *fileOpInfo = NULL;
if (fileName == NULL) { errno = EFAULT; return VFS_ERROR; }
if (CheckPathIsMounted(fileName, &fileOpInfo) == FALSE || fileOpInfo == NULL) { errno = ENOENT; return VFS_ERROR; }
ret = lfs_remove(&(fileOpInfo->lfsInfo), fileName); if (ret != 0) { errno = LittlefsErrno(ret); ret = VFS_ERROR; }
return ret;}
int LfsMkdir(const char *dirName, mode_t mode){ int ret; struct FileOpInfo *fileOpInfo = NULL;
if (dirName == NULL) { errno = EFAULT; return VFS_ERROR; }
if (CheckPathIsMounted(dirName, &fileOpInfo) == FALSE || fileOpInfo == NULL) { errno = ENOENT; return VFS_ERROR; }
ret = lfs_mkdir(&(fileOpInfo->lfsInfo), dirName); if (ret != 0) { errno = LittlefsErrno(ret); ret = VFS_ERROR; }
return ret;}......
复制代码


参考资料


  • HarmonyOS Device>文档指南>基础能力-LittleFS


点击关注,第一时间了解华为云新鲜技术~

发布于: 刚刚阅读数: 2
用户头像

提供全面深入的云计算技术干货 2020.07.14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
鸿蒙轻内核源码分析:文件系统LittleFS