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

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;
}
......

小结

本文介绍了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🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:https://qr21.cn/FV7h05

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1452705.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

C++ 45 之 赋值运算符的重载

#include <iostream> #include <string> #include <cstring> using namespace std;class Students05{ public:int m_age;char* m_name;Students05(){}Students05(const char* name,int age){// 申请堆空间保存m_name;this->m_name new char[strlen(name)…

宝藏速成秘籍(7)堆排序法

一、前言 1.1、概念 堆排序&#xff08;Heapsort&#xff09;是指利用堆这种数据结构所设计的一种排序算法 。堆是一个近似 完全二叉树 的结构&#xff0c;并同时满足堆积的性质&#xff1a;即子结点的键值或索引总是小于&#xff08;或者大于&#xff09;它的父节点。 1.2、排…

本地靶场搭建

1、windows service2003 链接&#xff1a;https://pan.baidu.com/s/1RIealrcfcDWKu1AIuYFbAQ?pwd4bv8 提取码&#xff1a;4bv8 2、asp环境搭建&#xff08;虚拟机内&#xff09; ①asp工作原理&#xff1a; 客户发送网站请求&#xff0c;iis接收客户请求&#xff0c;解析…

[图解]《分析模式》漫谈04-Martin Fowler叫的是哪家的士

1 00:00:01,230 --> 00:00:04,190 今天我们来探讨一个有趣的话题 2 00:00:05,130 --> 00:00:08,350 Martin Fowler&#xff0c;他叫的是哪一家的的士 3 00:00:11,980 --> 00:00:15,240 第2章这里&#xff0c;Martin Fowler写 4 00:00:15,250 --> 00:00:18,550 他…

【redis的基本数据类型】

基本数据类型 Redis的基本数据类型有五种&#xff0c;分别是 StringListHashSetSortedSet 这些基本的数据类型构成了其他数据类型的基石&#xff0c;而这些基本数据类型又对应着不同的底层实现&#xff0c;不同的底层实现往往是针对不同的使用场景做的特殊的优化&#xff0c;…

自然资源-地理知识收藏好

自然资源-地理知识收藏好 每个华夏儿女应该知道的中国地理知识&#xff0c;中国&#xff0c;全称中华人民共和国&#xff0c;位于亚洲东部&#xff0c;太平洋西岸&#xff0c;是世界四大文明古国之一&#xff0c;华夏文明的发源地&#xff0c;陆地面积约960万平方千米&#xf…

50【Aseprite 作图】模糊工具 笔刷

1 模糊工具 2 笔刷 然后 选中 后 Ctrl B&#xff0c;就变成笔刷了 可以按住shift &#xff0c;像画一条线一样 或者用矩形、圆形工具、油漆桶工具 在上方可以选择笔刷的不同形式&#xff0c;如果是“图案与来源对齐”&#xff0c;就是来源不变&#xff0c;笔刷不会覆盖之前…

⭐Unity 控制任意UI的渐隐渐显

使用脚本之前先给要控制的UI加上CanvasGroup组件 解释: 这个脚本使用协程来逐渐改变CanvasGroup的alpha值&#xff0c;从而实现渐隐和渐显的效果。 Mathf.Lerp函数用于在指定的时间内平滑地从当前透明度过渡到目标透明度。 通过调用FadeIn和FadeOut方法&#xff0c;你可以在任…

Python 小市值股票模型代码及回测分析

目录 一、模型介绍 二、代码详解 2.1 初始化函数 2.2 股票筛选过滤函数 2.3 止损函数 2.4 开盘时运行函数 2.5 调仓函数 三、回测结果分析 3.1 收益净值图与概述 3.2 模型收益概览 3.3 年度收益图 3.4 月度收益的时间序列 3.5 月度收益热力图 3.6 月度收益频次分…

业务动态校验框架应用实现

目录 一、业务背景 二、配置内容展示 三、商品动态配置内容展示 &#xff08;一&#xff09;商品spu校验信息数据 &#xff08;二&#xff09;商品sku校验信息数据 &#xff08;三&#xff09;组包商品校验信息数据 &#xff08;四&#xff09;商品数据校验数据持有者 &…

嵌入式软件工程师入何突破瓶颈?

各位关注嵌入式软件工程师发展的朋友们&#xff0c;下面来探讨一下嵌入式软件工程师该如何突破瓶颈。首先要强调的是&#xff0c;不要仅仅将自己局限在嵌入式软件工程师这一角色定位上。 事实上&#xff0c;嵌入式软件工程师已经掌握了诸多业务层面的内容&#xff0c;完全有能力…

【博客718】时序数据库基石:LSM Tree(log-structured merge-tree)

时序数据库基石&#xff1a;LSM Tree(log-structured merge-tree) 1、为什么需要LSM Tree LSM被设计来提供比传统的B树更好的写操作吞吐量&#xff0c;通过消去随机的本地更新操作来达到这个目标&#xff0c;使得写入都是顺序写&#xff0c;而不是随机写。 那么为什么这是一个…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 特惠寿司(100分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 📎在线评测链接 特惠寿司(100分) 🌍 评测功能需要订阅专栏后私信联系清隆解…

探索档案未来,尽在ARCHE-2024

2024年第三届上海国际智慧档案展览会暨高峰论坛&#xff08;ARCHE-2024&#xff09;将于2024年6月19日至21日在上海跨国采购会展中心隆重举行。深圳市铨顺宏科技有限公司应邀参展&#xff0c;将以全新形象盛装亮相&#xff0c;展示其在档案管理领域的最新技术和解决方案。 ARC…

Apple - Cocoa Text Architecture Guide

翻译整理自&#xff1a;Cocoa Text Architecture Guide https://developer.apple.com/library/archive/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009459 文章目录 一、关于 Cocoa 文本系统1、概览大…

Python使用策略模式生成TCP数据包

使用策略模式&#xff08;Strategy Pattern&#xff09;来灵活地生成不同类型的TCP数据包。 包括三次握手、数据传输和四次挥手。 from scapy.all import * from scapy.all import Ether, IP, TCP, UDP, wrpcap from abc import ABC, abstractmethodclass TcpPacketStrategy(A…

「C系列」C 结构体

文章目录 一、C 结构体1. 定义结构体2. 声明结构体变量3. 初始化结构体变量4. 访问结构体成员5. 结构体数组6. 结构体指针7. 结构体嵌套 二、C 如何使用结构体1. 定义结构体类型2. 声明结构体变量3. 初始化结构体变量4. 访问结构体成员5. 结构体指针6. 在函数中使用结构体7. 注…

简单实现linux下redis后台启动,开机自动启动(2024)

1.要实现redis后台启动&#xff0c;必须修改redis的配置文件&#xff0c;先cd /usr/local/src/redis-6.2.6到此目录后&#xff0c;先备份一份配置文件&#xff08;避免配置操作失误&#xff09;输入cp redis.conf redis.conf.bck再输入vi redis.conf修改配置文件 2.按/进入搜…

Linux-Tomcat服务配置到系统服务

目录 前言一、系统环境二、配置步骤step1 了解环境的安装路径step2 配置生成tomcat.pid文件step3 配置tomcat.service文件 三、测试systemctl命令管理Tomcat服务3.1 systemctl命令启动Tomcat服务3.2 systemctl命令查看Tomcat服务3.3 systemctl命令关闭Tomcat服务3.4 systemctl命…

leetcode 56合并区间

思路 合并就是首先应该按照left左边界排序&#xff0c;排完序以后&#xff0c;如果i的左边界小于等于i-1的右边界&#xff0c;说明有重合&#xff0c;此时这两个可以合并&#xff0c;右边界应该取最大值。 代码 排序 我是定义了一个类,存储左右边界&#xff0c;先将数组转化…