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

news2024/11/25 15:41:32

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.coloradmin.cn/o/1826447.html

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

相关文章

2000-2023年各省年末常住人口数据(无缺失)

2000-2023年各省年末常住人口数据&#xff08;无缺失&#xff09; 1、时间&#xff1a;2000-2023年 2、来源&#xff1a;国家统计局、各省年鉴 3、指标&#xff1a;年末常住人口 4、范围&#xff1a;31省 5、指标解释&#xff1a; 年末人口数指每年12月31日24时的人口数。…

对抗式生成模仿学习(GAIL)

目录 1 预先基础知识 1.1 对抗生成网络&#xff08;GAN&#xff09; 1.1.1 基本概念 1.1.2 损失函数 1.1.2.1 固定G&#xff0c;求解令损失函数最大的D 1.1.2.2 固定D&#xff0c;求解令损失函数最小的G 1.2 对抗式生成模仿学习特点 2 对抗式生成模仿学习&#xff08;…

Java数据库编程

引言 在现代应用开发中&#xff0c;与数据库交互是不可或缺的一部分。Java提供了JDBC&#xff08;Java Database Connectivity&#xff09; API&#xff0c;允许开发者方便地连接到数据库并执行SQL操作。本文将详细介绍Java数据库编程的基础知识&#xff0c;包括JDBC的基本概念…

为什么 JavaScript 在国外逐渐用于前端+后端开发

这个问题其实没人能给出可证伪的结论&#xff0c;那不如干脆给一个感性的答案: 因为阿里“不争气”。 确切的说&#xff0c;因为阿里的nodejs团队没卷赢&#xff0c;至少暂时还没卷赢&#xff0c;没拿到真正有价值的业务场景&#xff0c;做出真正有说服力的案例项目。刚好我有…

如何进行LLM大模型推理优化

解密LLM大模型推理优化本质 一、LLM推理的本质以及考量点 LLM推理聚焦Transformer架构的Decoder以生成文本。过程分两步&#xff1a;首先&#xff0c;模型初始化并加载输入文本&#xff1b;接着&#xff0c;进入解码阶段&#xff0c;模型自回归地生成文本&#xff0c;直至满足…

邮件钓鱼--有无SPF演示--Swaks

目录 临时邮箱网址: Swaks 简单使用说明&#xff1a;(kali自带) 操作流程: 无SPF:(直接伪造发信人) 演示1 演示2 演示3 ​编辑 有SPF:--演示 临时邮箱网址: http://24mail.chacuo.net/ https://www.linshi-email.com/ Swaks 简单使用说明&#xff1a;(kali自带) -t –t…

专题六——模拟

目录 一替换所有的问号 二提莫攻击 三N字形变换 四外观数列 五数青蛙 一替换所有的问号 oj链接&#xff1a;替换所有的问号 思路&#xff1a;简单模拟&#xff1b;注意i0和in是处理越界问题就行&#xff01;&#xff01; class Solution { public:string modifyString…

基于scikit-learn的机器学习分类任务实践——集成学习

一、传统机器学习分类流程与经典思想算法简述 传统机器学习是指&#xff0c;利用线性代数、数理统计与优化算法等数学方式从设计获取的数据集中构建预测学习器&#xff0c;进而对未知数据分类或回归。其主要流程大致可分为七个部分&#xff0c;依次为设计获取数据特征集&#x…

Reactor 网络模型、Java代码实例

文章目录 1. 概述2. Reactor 单线程模型2.1 ByteBufferUtil2.2 服务端代码2.3 客户端2.4 运行截图 3. Reactor多线程模型3.1 服务端代码3.2 运行截图 4. 主从 Reactor多线程模型4.1 服务端代码4.2 运行截图 参考文献 1. 概述 在 I/O 多路复用的场景下&#xff0c;当有数据处于…

ChatTTS-WebUI测试页面项目

概述 分享可以一个专门为对话场景设计的文本转语音模型ChatTTS&#xff0c;例如LLM助手对话任务。它支持英文和中文两种语言。最大的模型使用了10万小时以上的中英文数据进行训练。在HuggingFace中开源的版本为4万小时训练且未SFT的版本. 该模型能够预测和控制细粒度的韵律特…

跪求大数据把我推给做投资交易的红薯!

在qq群里认识了君诺金融Juno Markets外汇交易平台的业务经理&#xff0c;平台上大剌剌的打出20%交易返现活动&#xff0c;一时听信了他们的话在该平台有开户入金做交易&#xff0c;做了这家平台的代理&#xff0c;然而君诺金融Juno Markets平台却不给佣金&#xff0c;我都是属于…

浏览器必备插件:最新Allow copy万能网页复制下载,解锁网页限制!

今天阿星给大家安利一个超级实用的小工具&#xff0c;专治那些“禁止复制”的网页文字。学生党、资料搜集狂人&#xff0c;你们有福了&#xff01; 想象一下&#xff0c;你在网上冲浪&#xff0c;突然遇到一篇干货满满的文章&#xff0c;正想复制下来慢慢品味&#xff0c;结果…

值传递和址传递

值传递 上面的代码是想要交换x&#xff0c;y的值&#xff0c;把x&#xff0c;y传递给swap函数之后&#xff0c;执行下面的操作&#xff1a; 在swap中a和b交换了&#xff0c;但是和x&#xff0c;y没有关系&#xff0c;所以x&#xff0c;y在main中不会变。 址传递 下面再看把x…

springcloud gateway转发websocket请求的404问题定位

一、问题 前端小程序通过springcloud gateway接入并访问后端的诸多微服务&#xff0c;几十个微服务相关功能均正常&#xff0c;只有小程序到后端推送服务的websocket连接建立不起来&#xff0c;使用whireshark抓包&#xff0c;发现在小程序通过 GET ws://192.168.6.100:8888/w…

Apple Intelligence 横空出世!它的独家秘诀在哪里?

在 WWDC 2024 大会上&#xff0c;苹果公司揭晓了自家的生成式 AI 项目——Apple Intelligence&#xff0c;其策略核心在于采用 ⌈ 更为聚焦的小型模型 ⌋ &#xff0c;而非盲目追求大模型的普遍趋势。横空出世的它究竟有什么过人之处&#xff1f;一文带你探究竟&#xff01;生成…

[DDR4] DDR1 ~ DDR4 发展史导论

依公知及经验整理&#xff0c;原创保护&#xff0c;禁止转载。 专栏 《深入理解DDR4》 内存和硬盘是电脑的左膀右臂&#xff0c; 挑起存储的大梁。因为内存的存取速度超凡地快&#xff0c; 但内存上的数据掉电又会丢失&#xff0c;一直其中缓存的作用&#xff0c;就像是我们的工…

2786. 访问数组中的位置使分数最大

这并不是一个难题,但是我确实在做题中得到了一些启发,所以记录一下 先讲一讲这个题目的做法: 首先不难想到这是一个dp问题,(由 i 可以跳到 j ) 而且应该不难, 要不然就不是medium了,doge 那么,暴力的dp就是: dp[j] max (dp[i] nums OR dp[j] dp[i] nums - x) , i<j, 前…

mongodb 集群安装

1. 配置域名 Server1&#xff1a; OS version: CentOS Linux release 8.5.2111 hostnamectl --static set-hostname mongo01 vi /etc/sysconfig/network # Created by anaconda hostnamemong01 echo "192.168.88.20 mong1 mongo01.com mongo02.com" >> /…

【笔记】【矩阵的二分】668. 乘法表中第k小的数

力扣链接&#xff1a;题目 参考地址&#xff1a;参考 思路&#xff1a;二分查找 把矩阵想象成一维的已排好序的数组&#xff0c;用二分法找第k小的数字。 假设m行n列&#xff0c;则对应一维下标范围是从1到mn&#xff0c;初始&#xff1a; l1; rmn; mid(lr)/2 设mid在第i行&a…

【C++11】第一部分(一万六千多字)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 C11简介 统一的列表初始化 &#xff5b;&#xff5d;初始化 std::initializer_list 声明 auto decltype 右值引用和移动语义 左值引用和右值引用 左值引…