鸿蒙轻内核M核源码分析系列二一 03 文件系统LittleFS

打印 上一主题 下一主题

主题 820|帖子 820|积分 2460

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. ......
复制代码
小结

本文介绍了LFS的结构体和全局变量,全局变量的利用接口,分析了下LFS文件利用接口。
如果想更深入的学习 OpenHarmony (鸿蒙南向)全栈开辟的内容,可以参考以放学习文档:
OpenHarmony 开辟环境搭建:https://qr18.cn/CgxrRy


《OpenHarmony源码剖析》:https://qr18.cn/CgxrRy



  • 搭建开辟环境
  • Windows 开辟环境的搭建
  • Ubuntu 开辟环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……

系统架构分析:https://qr18.cn/CgxrRy



  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通讯子系统
  • 驱动子系统
  • ……

OpenHarmony 设备开辟学习手册:https://qr18.cn/CgxrRy


OpenHarmony面试题(内含参考答案):https://qr18.cn/CgxrRy


写在末了



  • 如果你觉得这篇内容对你还蛮有帮助,我想约请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

南飓风

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表