当前位置:   article > 正文

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

lfs_o_trunc
摘要:本文先介绍下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文件操作接口。文中所涉及的源码,均可以在开源站点kernel_liteos_m: LiteOS kernel for devices with few resources, such as the MCU | 适用于MCU等各种资源极小设备的LiteOS内核 获取。

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等等。

  1. // File types
  2. enum lfs_type {
  3. // file types
  4. LFS_TYPE_REG = 0x001,
  5. LFS_TYPE_DIR = 0x002,
  6. // internally used types
  7. LFS_TYPE_SPLICE = 0x400,
  8. LFS_TYPE_NAME = 0x000,
  9. LFS_TYPE_STRUCT = 0x200,
  10. LFS_TYPE_USERATTR = 0x300,
  11. LFS_TYPE_FROM = 0x100,
  12. LFS_TYPE_TAIL = 0x600,
  13. LFS_TYPE_GLOBALS = 0x700,
  14. LFS_TYPE_CRC = 0x500,
  15. // internally used type specializations
  16. LFS_TYPE_CREATE = 0x401,
  17. LFS_TYPE_DELETE = 0x4ff,
  18. LFS_TYPE_SUPERBLOCK = 0x0ff,
  19. LFS_TYPE_DIRSTRUCT = 0x200,
  20. LFS_TYPE_CTZSTRUCT = 0x202,
  21. LFS_TYPE_INLINESTRUCT = 0x201,
  22. LFS_TYPE_SOFTTAIL = 0x600,
  23. LFS_TYPE_HARDTAIL = 0x601,
  24. LFS_TYPE_MOVESTATE = 0x7ff,
  25. // internal chip sources
  26. LFS_FROM_NOOP = 0x000,
  27. LFS_FROM_MOVE = 0x101,
  28. LFS_FROM_USERATTRS = 0x102,
  29. };
  30. // File open flags
  31. enum lfs_open_flags {
  32. // open flags
  33. LFS_O_RDONLY = 1, // Open a file as read only
  34. #ifndef LFS_READONLY
  35. LFS_O_WRONLY = 2, // Open a file as write only
  36. LFS_O_RDWR = 3, // Open a file as read and write
  37. LFS_O_CREAT = 0x0100, // Create a file if it does not exist
  38. LFS_O_EXCL = 0x0200, // Fail if a file already exists
  39. LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size
  40. LFS_O_APPEND = 0x0800, // Move to end of file on every write
  41. #endif
  42. // internally used flags
  43. #ifndef LFS_READONLY
  44. LFS_F_DIRTY = 0x010000, // File does not match storage
  45. LFS_F_WRITING = 0x020000, // File has been written since last flush
  46. #endif
  47. LFS_F_READING = 0x040000, // File has been read since last flush
  48. #ifndef LFS_READONLY
  49. LFS_F_ERRED = 0x080000, // An error occurred during write
  50. #endif
  51. LFS_F_INLINE = 0x100000, // Currently inlined in directory entry
  52. };

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

  1. // The littlefs filesystem type
  2. typedef struct lfs {
  3. lfs_cache_t rcache;
  4. lfs_cache_t pcache;
  5. lfs_block_t root[2];
  6. struct lfs_mlist {
  7. struct lfs_mlist *next;
  8. uint16_t id;
  9. uint8_t type;
  10. lfs_mdir_t m;
  11. } *mlist;
  12. uint32_t seed;
  13. lfs_gstate_t gstate;
  14. lfs_gstate_t gdisk;
  15. lfs_gstate_t gdelta;
  16. struct lfs_free {
  17. lfs_block_t off;
  18. lfs_block_t size;
  19. lfs_block_t i;
  20. lfs_block_t ack;
  21. uint32_t *buffer;
  22. } free;
  23. const struct lfs_config *cfg;
  24. lfs_size_t name_max;
  25. lfs_size_t file_max;
  26. lfs_size_t attr_max;
  27. #ifdef LFS_MIGRATE
  28. struct lfs1 *lfs1;
  29. #endif
  30. } lfs_t;

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

  1. // littlefs directory type
  2. typedef struct lfs_dir {
  3. struct lfs_dir *next;
  4. uint16_t id;
  5. uint8_t type;
  6. lfs_mdir_t m;
  7. lfs_off_t pos;
  8. lfs_block_t head[2];
  9. } lfs_dir_t;
  10. // littlefs file type
  11. typedef struct lfs_file {
  12. struct lfs_file *next;
  13. uint16_t id;
  14. uint8_t type;
  15. lfs_mdir_t m;
  16. struct lfs_ctz {
  17. lfs_block_t head;
  18. lfs_size_t size;
  19. } ctz;
  20. uint32_t flags;
  21. lfs_off_t pos;
  22. lfs_block_t block;
  23. lfs_off_t off;
  24. lfs_cache_t cache;
  25. const struct lfs_file_config *cfg;
  26. } lfs_file_t;

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

  • read_size 每次读取的字节数,可以比物理读单元大以改善性能,这个数值决定了读缓存的大小,但值太大会带来更多的内存消耗。
  • prog_size 每次写入的字节数,可以比物理写单元大以改善性能,这个数值决定了写缓存的大小,必须是read_size的整数倍,但值太大会带来更多的内存消耗。
  • block_size 每个擦除块的字节数,可以比物理擦除单元大,但此数值应尽可能小因为每个文件至少会占用一个块。必须是prog_size的整数倍。
  • block_count 可以被擦除的块数量,这取决于块设备的容量及擦除块的大小。
  1. // Configuration provided during initialization of the littlefs
  2. struct lfs_config {
  3. // Opaque user provided context that can be used to pass
  4. // information to the block device operations
  5. void *context;
  6. int (*read)(const struct lfs_config *c, lfs_block_t block,
  7. lfs_off_t off, void *buffer, lfs_size_t size);
  8. int (*prog)(const struct lfs_config *c, lfs_block_t block,
  9. lfs_off_t off, const void *buffer, lfs_size_t size);
  10. int (*erase)(const struct lfs_config *c, lfs_block_t block);
  11. int (*sync)(const struct lfs_config *c);
  12. #ifdef LFS_THREADSAFE
  13. int (*lock)(const struct lfs_config *c);
  14. int (*unlock)(const struct lfs_config *c);
  15. #endif
  16. lfs_size_t read_size;
  17. lfs_size_t prog_size;
  18. lfs_size_t block_size;
  19. lfs_size_t block_count;
  20. int32_t block_cycles;
  21. lfs_size_t cache_size;
  22. lfs_size_t lookahead_size;
  23. void *read_buffer;
  24. void *prog_buffer;
  25. void *lookahead_buffer;
  26. lfs_size_t name_max;
  27. lfs_size_t file_max;
  28. lfs_size_t attr_max;
  29. lfs_size_t metadata_max;
  30. };

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

  1. // File info structure
  2. struct lfs_info {
  3. // Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR
  4. uint8_t type;
  5. // Size of the file, only valid for REG files. Limited to 32-bits.
  6. lfs_size_t size;
  7. // Name of the file stored as a null-terminated string. Limited to
  8. // LFS_NAME_MAX+1, which can be changed by redefining LFS_NAME_MAX to
  9. // reduce RAM. LFS_NAME_MAX is stored in superblock and must be
  10. // respected by other littlefs drivers.
  11. char name[LFS_NAME_MAX+1];
  12. };

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维护文件操作信息。

  1. typedef struct {
  2. uint8_t useFlag;
  3. const char *pathName;
  4. lfs_t *lfsHandle;
  5. lfs_file_t file;
  6. } LittleFsHandleStruct;
  7. struct FileOpInfo {
  8. uint8_t useFlag;
  9. const struct FileOps *fsVops;
  10. char *dirName;
  11. lfs_t lfsInfo;
  12. };
  13. typedef struct {
  14. uint8_t useFlag;
  15. char *dirName;
  16. lfs_t *lfsHandle;
  17. lfs_dir_t dir;
  18. } 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在虚拟文件系统中被使用。

  1. ⑴ FileDirInfo g_lfsDir[LFS_MAX_OPEN_DIRS] = {0};
  2. ⑵ struct FileOpInfo g_fsOp[LOSCFG_LFS_MAX_MOUNT_SIZE] = {0};
  3. ⑶ static LittleFsHandleStruct g_handle[LITTLE_FS_MAX_OPEN_FILES] = {0};
  4. ⑷ struct dirent g_nameValue;
  5. static pthread_mutex_t g_FslocalMutex = PTHREAD_MUTEX_INITIALIZER;
  6. static const char *g_littlefsMntName[LOSCFG_LFS_MAX_MOUNT_SIZE] = {"/a", "/b", "/c"};
  7. ......
  8. ⑸ const struct MountOps g_lfsMnt = {
  9. .Mount = LfsMount,
  10. .Umount = LfsUmount,
  11. };
  12. const struct FileOps g_lfsFops = {
  13. .Mkdir = LfsMkdir,
  14. .Unlink = LfsUnlink,
  15. .Rmdir = LfsRmdir,
  16. .Opendir = LfsOpendir,
  17. .Readdir = LfsReaddir,
  18. .Closedir = LfsClosedir,
  19. .Open = LfsOpen,
  20. .Close = LfsClose,
  21. .Write = LfsWrite,
  22. .Read = LfsRead,
  23. .Seek = LfsSeek,
  24. .Rename = LfsRename,
  25. .Getattr = LfsStat,
  26. .Fsync = LfsFsync,
  27. .Fstat = LfsFstat,
  28. };

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

2.1 目录信息数组操作

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

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

  1. FileDirInfo *GetFreeDir(const char *dirName)
  2. {
  3. pthread_mutex_lock(&g_FslocalMutex);
  4. for (int i = 0; i < LFS_MAX_OPEN_DIRS; i++) {
  5. if (g_lfsDir[i].useFlag == 0) {
  6. g_lfsDir[i].useFlag = 1;
  7. g_lfsDir[i].dirName = strdup(dirName);
  8. pthread_mutex_unlock(&g_FslocalMutex);
  9. return &(g_lfsDir[i]);
  10. }
  11. }
  12. pthread_mutex_unlock(&g_FslocalMutex);
  13. return NULL;
  14. }
  15. void FreeDirInfo(const char *dirName)
  16. {
  17. pthread_mutex_lock(&g_FslocalMutex);
  18. for (int i = 0; i < LFS_MAX_OPEN_DIRS; i++) {
  19. if (g_lfsDir[i].useFlag == 1 && strcmp(g_lfsDir[i].dirName, dirName) == 0) {
  20. g_lfsDir[i].useFlag = 0;
  21. if (g_lfsDir[i].dirName) {
  22. free(g_lfsDir[i].dirName);
  23. g_lfsDir[i].dirName = NULL;
  24. }
  25. pthread_mutex_unlock(&g_FslocalMutex);
  26. }
  27. }
  28. pthread_mutex_unlock(&g_FslocalMutex);
  29. }
  30. BOOL CheckDirIsOpen(const char *dirName)
  31. {
  32. pthread_mutex_lock(&g_FslocalMutex);
  33. for (int i = 0; i < LFS_MAX_OPEN_DIRS; i++) {
  34. if (g_lfsDir[i].useFlag == 1) {
  35. if (strcmp(g_lfsDir[i].dirName, dirName) == 0) {
  36. pthread_mutex_unlock(&g_FslocalMutex);
  37. return TRUE;
  38. }
  39. }
  40. }
  41. pthread_mutex_unlock(&g_FslocalMutex);
  42. return FALSE;
  43. }

2.2 文件信息数组操作

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

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

  1. LittleFsHandleStruct *LfsAllocFd(const char *fileName, int *fd)
  2. {
  3. pthread_mutex_lock(&g_FslocalMutex);
  4. for (int i = 0; i < LITTLE_FS_MAX_OPEN_FILES; i++) {
  5. if (g_handle[i].useFlag == 0) {
  6. *fd = i;
  7. g_handle[i].useFlag = 1;
  8. g_handle[i].pathName = strdup(fileName);
  9. pthread_mutex_unlock(&g_FslocalMutex);
  10. return &(g_handle[i]);
  11. }
  12. }
  13. pthread_mutex_unlock(&g_FslocalMutex);
  14. *fd = INVALID_FD;
  15. return NULL;
  16. }
  17. static void LfsFreeFd(int fd)
  18. {
  19. pthread_mutex_lock(&g_FslocalMutex);
  20. g_handle[fd].useFlag = 0;
  21. if (g_handle[fd].pathName != NULL) {
  22. free((void *)g_handle[fd].pathName);
  23. g_handle[fd].pathName = NULL;
  24. }
  25. if (g_handle[fd].lfsHandle != NULL) {
  26. g_handle[fd].lfsHandle = NULL;
  27. }
  28. pthread_mutex_unlock(&g_FslocalMutex);
  29. }
  30. BOOL CheckFileIsOpen(const char *fileName)
  31. {
  32. pthread_mutex_lock(&g_FslocalMutex);
  33. for (int i = 0; i < LITTLE_FS_MAX_OPEN_FILES; i++) {
  34. if (g_handle[i].useFlag == 1) {
  35. if (strcmp(g_handle[i].pathName, fileName) == 0) {
  36. pthread_mutex_unlock(&g_FslocalMutex);
  37. return TRUE;
  38. }
  39. }
  40. }
  41. pthread_mutex_unlock(&g_FslocalMutex);
  42. return FALSE;
  43. }
  44. static BOOL LfsFdIsValid(int fd)
  45. {
  46. if (fd >= LITTLE_FS_MAX_OPEN_FILES || fd < 0) {
  47. return FALSE;
  48. }
  49. if (g_handle[fd].lfsHandle == NULL) {
  50. return FALSE;
  51. }
  52. return TRUE;
  53. }

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

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

  1. struct FileOpInfo *AllocMountRes(const char* target, const struct FileOps *fileOps)
  2. {
  3. pthread_mutex_lock(&g_FslocalMutex);
  4. for (int i = 0; i < LOSCFG_LFS_MAX_MOUNT_SIZE; i++) {
  5. if (g_fsOp[i].useFlag == 0 && strcmp(target, g_littlefsMntName[i]) == 0) {
  6. g_fsOp[i].useFlag = 1;
  7. g_fsOp[i].fsVops = fileOps;
  8. g_fsOp[i].dirName = strdup(target);
  9. pthread_mutex_unlock(&g_FslocalMutex);
  10. return &(g_fsOp[i]);
  11. }
  12. }
  13. pthread_mutex_unlock(&g_FslocalMutex);
  14. return NULL;
  15. }
  16. int SetDefaultMountPath(int pathNameIndex, const char* target)
  17. {
  18. if (pathNameIndex >= LOSCFG_LFS_MAX_MOUNT_SIZE) {
  19. return VFS_ERROR;
  20. }
  21. pthread_mutex_lock(&g_FslocalMutex);
  22. g_littlefsMntName[pathNameIndex] = strdup(target);
  23. pthread_mutex_unlock(&g_FslocalMutex);
  24. return VFS_OK;
  25. }

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

  1. struct FileOpInfo *GetMountRes(const char *target, int *mountIndex)
  2. {
  3. pthread_mutex_lock(&g_FslocalMutex);
  4. for (int i = 0; i < LOSCFG_LFS_MAX_MOUNT_SIZE; i++) {
  5. if (g_fsOp[i].useFlag == 1) {
  6. if (g_fsOp[i].dirName && strcmp(target, g_fsOp[i].dirName) == 0) {
  7. *mountIndex = i;
  8. pthread_mutex_unlock(&g_FslocalMutex);
  9. return &(g_fsOp[i]);
  10. }
  11. }
  12. }
  13. pthread_mutex_unlock(&g_FslocalMutex);
  14. return NULL;
  15. }

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

  1. int FreeMountResByIndex(int mountIndex)
  2. {
  3. if (mountIndex < 0 || mountIndex >= LOSCFG_LFS_MAX_MOUNT_SIZE) {
  4. return VFS_ERROR;
  5. }
  6. pthread_mutex_lock(&g_FslocalMutex);
  7. if (g_fsOp[mountIndex].useFlag == 1 && g_fsOp[mountIndex].dirName != NULL) {
  8. g_fsOp[mountIndex].useFlag = 0;
  9. free(g_fsOp[mountIndex].dirName);
  10. g_fsOp[mountIndex].dirName = NULL;
  11. }
  12. pthread_mutex_unlock(&g_FslocalMutex);
  13. return VFS_OK;
  14. }
  15. int FreeMountRes(const char *target)
  16. {
  17. pthread_mutex_lock(&g_FslocalMutex);
  18. for (int i = 0; i < LOSCFG_LFS_MAX_MOUNT_SIZE; i++) {
  19. if (g_fsOp[i].useFlag == 1) {
  20. if (g_fsOp[i].dirName && strcmp(target, g_fsOp[i].dirName) == 0) {
  21. g_fsOp[i].useFlag = 0;
  22. free(g_fsOp[i].dirName);
  23. g_fsOp[i].dirName = NULL;
  24. pthread_mutex_unlock(&g_FslocalMutex);
  25. return VFS_OK;
  26. }
  27. }
  28. }
  29. pthread_mutex_unlock(&g_FslocalMutex);
  30. return VFS_ERROR;
  31. }

2.4 路径是否已挂载CheckPathIsMounted

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

  1. int GetFirstLevelPathLen(const char *pathName)
  2. {
  3. int len = 1;
  4. for (int i = 1; i < strlen(pathName) + 1; i++) {
  5. if (pathName[i] == '/') {
  6. break;
  7. }
  8. len++;
  9. }
  10. return len;
  11. }
  12. BOOL CheckPathIsMounted(const char *pathName, struct FileOpInfo **fileOpInfo)
  13. {
  14. char tmpName[LITTLEFS_MAX_LFN_LEN] = {0};
  15. ⑴ int len = GetFirstLevelPathLen(pathName);
  16. pthread_mutex_lock(&g_FslocalMutex);
  17. for (int i = 0; i < LOSCFG_LFS_MAX_MOUNT_SIZE; i++) {
  18. if (g_fsOp[i].useFlag == 1) {
  19. (void)strncpy_s(tmpName, LITTLEFS_MAX_LFN_LEN, pathName, len);
  20. if (strcmp(tmpName, g_fsOp[i].dirName) == 0) {
  21. *fileOpInfo = &(g_fsOp[i]);
  22. pthread_mutex_unlock(&g_FslocalMutex);
  23. return TRUE;
  24. }
  25. }
  26. }
  27. pthread_mutex_unlock(&g_FslocalMutex);
  28. return FALSE;
  29. }

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函数实现卸载,然后执行⑻释放挂载点文件操作信息。

  1. int LfsMount(const char *source, const char *target, const char *fileSystemType, unsigned long mountflags,
  2. const void *data)
  3. {
  4. int ret;
  5. struct FileOpInfo *fileOpInfo = NULL;
  6. if (target == NULL || fileSystemType == NULL || data == NULL) {
  7. errno = EFAULT;
  8. ret = VFS_ERROR;
  9. goto errout;
  10. }
  11. if (strcmp(fileSystemType, "littlefs") != 0) {
  12. errno = ENODEV;
  13. ret = VFS_ERROR;
  14. goto errout;
  15. }
  16. if (CheckPathIsMounted(target, &fileOpInfo)) {
  17. errno = EBUSY;
  18. ret = VFS_ERROR;
  19. goto errout;
  20. }
  21. // select free mount resource
  22. ⑶ fileOpInfo = AllocMountRes(target, &g_lfsFops);
  23. if (fileOpInfo == NULL) {
  24. errno = ENODEV;
  25. ret = VFS_ERROR;
  26. goto errout;
  27. }
  28. ⑷ ret = lfs_mount(&(fileOpInfo->lfsInfo), (struct lfs_config*)data);
  29. if (ret != 0) {
  30. ⑸ ret = lfs_format(&(fileOpInfo->lfsInfo), (struct lfs_config*)data);
  31. if (ret == 0) {
  32. ret = lfs_mount(&(fileOpInfo->lfsInfo), (struct lfs_config*)data);
  33. }
  34. }
  35. if (ret != 0) {
  36. errno = LittlefsErrno(ret);
  37. ret = VFS_ERROR;
  38. }
  39. errout:
  40. return ret;
  41. }
  42. int LfsUmount(const char *target)
  43. {
  44. int ret;
  45. int mountIndex = -1;
  46. struct FileOpInfo *fileOpInfo = NULL;
  47. if (target == NULL) {
  48. errno = EFAULT;
  49. return VFS_ERROR;
  50. }
  51. ⑹ fileOpInfo = GetMountRes(target, &mountIndex);
  52. if (fileOpInfo == NULL) {
  53. errno = ENOENT;
  54. return VFS_ERROR;
  55. }
  56. ⑺ ret = lfs_unmount(&(fileOpInfo->lfsInfo));
  57. if (ret != 0) {
  58. errno = LittlefsErrno(ret);
  59. ret = VFS_ERROR;
  60. }
  61. ⑻ (void)FreeMountResByIndex(mountIndex);
  62. return ret;
  63. }

3.2 文件目录操作接口

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

  1. ......
  2. int LfsUnlink(const char *fileName)
  3. {
  4. int ret;
  5. struct FileOpInfo *fileOpInfo = NULL;
  6. if (fileName == NULL) {
  7. errno = EFAULT;
  8. return VFS_ERROR;
  9. }
  10. if (CheckPathIsMounted(fileName, &fileOpInfo) == FALSE || fileOpInfo == NULL) {
  11. errno = ENOENT;
  12. return VFS_ERROR;
  13. }
  14. ret = lfs_remove(&(fileOpInfo->lfsInfo), fileName);
  15. if (ret != 0) {
  16. errno = LittlefsErrno(ret);
  17. ret = VFS_ERROR;
  18. }
  19. return ret;
  20. }
  21. int LfsMkdir(const char *dirName, mode_t mode)
  22. {
  23. int ret;
  24. struct FileOpInfo *fileOpInfo = NULL;
  25. if (dirName == NULL) {
  26. errno = EFAULT;
  27. return VFS_ERROR;
  28. }
  29. if (CheckPathIsMounted(dirName, &fileOpInfo) == FALSE || fileOpInfo == NULL) {
  30. errno = ENOENT;
  31. return VFS_ERROR;
  32. }
  33. ret = lfs_mkdir(&(fileOpInfo->lfsInfo), dirName);
  34. if (ret != 0) {
  35. errno = LittlefsErrno(ret);
  36. ret = VFS_ERROR;
  37. }
  38. return ret;
  39. }
  40. ......

参考资料

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/288527
推荐阅读
相关标签
  

闽ICP备14008679号