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

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

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

3.1 挂载和卸载操作

先看下挂载操作,FatFS支持重新挂载操作。如果挂载选项包含MS_REMOUNT时,会调用函数Remount()重新挂载。函数Remount()中,⑴处调用FsPartitionMatch()获取卷索引,⑵处如果卷未被挂载,不允许重新挂载,返回错误码。⑶处设置对应的卷是否可读可写标记。由此看来,重新挂载,主要是更新卷的可读可写能力。

看下挂载函数fatfs_mount(),⑷处开始判断参数有效性,不能为空,文件系统类型必须为"fat",⑸处调用FsPartitionMatch()获取卷索引,⑹处如果卷已经被挂载,则返回错误码。⑺处调用f_mount()实现挂载,第3个参数1表示立即挂载。⑻设置对应的卷是否可读可写标记。

ini 复制代码
static int Remount(const char *path, unsigned long mountflags)
{
    INT32 index;

⑴  index = FsPartitionMatch(path, PART_NAME);
    if (index == FS_FAILURE) {
        PRINTK("Wrong volume path!\r\n");
        errno = ENOENT;
        return FS_FAILURE;
    }

    /* remount is not allowed when the device is not mounted. */
⑵  if (g_fatfs[index].fs_type == 0) {
        errno = EINVAL;
        return FS_FAILURE;
    }
⑶  g_volWriteEnable[index] = (mountflags & MS_RDONLY) ? FALSE : TRUE;

    return FS_SUCCESS;
}
......
int fatfs_mount(const char *source, const char *target,
                const char *filesystemtype, unsigned long mountflags,
                const void *data)
{
    INT32 index;
    FRESULT res;
    INT32 ret;

⑷  if ((target == NULL) || (filesystemtype == NULL)) {
        errno = EFAULT;
        return FS_FAILURE;
    }

    ret = FsLock();
    if (ret != 0) {
        errno = ret;
        return FS_FAILURE;
    }

    if (mountflags & MS_REMOUNT) {
        ret = Remount(target, mountflags);
        goto OUT;
    }

    if (strcmp(filesystemtype, "fat") != 0) {
        errno = ENODEV;
        ret = FS_FAILURE;
        goto OUT;
    }

⑸  index = FsPartitionMatch(target, VOLUME_NAME);
    if (index == FS_FAILURE) {
        errno = ENODEV;
        ret = FS_FAILURE;
        goto OUT;
    }

    /* If the volume has been mounted */
⑹  if (g_fatfs[index].fs_type != 0) {
        errno = EBUSY;
        ret = FS_FAILURE;
        goto OUT;
    }

⑺  res = f_mount(&g_fatfs[index], target, 1);
    if (res != FR_OK) {
        errno = FatfsErrno(res);
        ret = FS_FAILURE;
        goto OUT;
    }

⑻  g_volWriteEnable[index] = (mountflags & MS_RDONLY) ? FALSE : TRUE;
    ret = FS_SUCCESS;

OUT:
    FsUnlock();
    return ret;
}

接下来,看下卸载操作。函数fatfs_umount()中,先进行参数有效性,是否挂载等基础检查,⑴处调用函数f_checkopenlock()来判断要卸载的卷中是否有打开的文件或目录,⑵处调用f_mount(),第一个参数为NULL,表示卸载target指定的文件系统;,第3个参数0表示不需要挂载。如果卸载错误,转换相应的错误码。⑶处如果磁盘访问窗口(Disk access window for Directory)不为空,执行相应的释放操作。⑷处把文件卷数组对应的元素置零。

函数CloseAll()根据文件卷编号,遍历每一个打开的文件和目录进行关闭。函数fatfs_umount2()中,⑸处表示支持的卸载选项有:MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW。⑹处处理强制卸载的情形,会首先关闭打开的文件和目录,然后再去执行⑺实现卸载操作。

ini 复制代码
int fatfs_umount(const char *target)
{
    FRESULT res;
    INT32 ret;
    INT32 index;

    if (target == NULL) {
        errno = EFAULT;
        return FS_FAILURE;
    }

    ret = FsLock();
    if (ret != 0) {
        errno = ret;
        return FS_FAILURE;
    }

    index = FsPartitionMatch(target, VOLUME_NAME);
    if (index == FS_FAILURE) {
        errno = ENOENT;
        ret = FS_FAILURE;
        goto OUT;
    }

    /* The volume is not mounted */
    if (g_fatfs[index].fs_type == 0) {
        errno = EINVAL;
        ret = FS_FAILURE;
        goto OUT;
    }

    /* umount is not allowed when a file or diretory is opened. */
⑴  if (f_checkopenlock(index) != FR_OK) {
        errno = EBUSY;
        ret = FS_FAILURE;
        goto OUT;
    }

⑵  res = f_mount((FATFS *)NULL, target, 0);
    if (res != FR_OK) {
        errno = FatfsErrno(res);
        ret = FS_FAILURE;
        goto OUT;
    }

⑶  if (g_fatfs[index].win != NULL) {
        ff_memfree(g_fatfs[index].win);
    }

⑷  (void)memset_s(&g_fatfs[index], sizeof(FATFS), 0x0, sizeof(FATFS));

    ret = FS_SUCCESS;

OUT:
    FsUnlock();
    return ret;
}

static int CloseAll(int index)
{
    INT32 i;
    FRESULT res;

    for (i = 0; i < FAT_MAX_OPEN_FILES; i++) {
        if (g_fileNum <= 0) {
            break;
        }
        if ((g_handle[i].useFlag == 1) && (g_handle[i].fil.obj.fs == &g_fatfs[index])) {
            res = f_close(&g_handle[i].fil);
            if (res != FR_OK) {
                errno = FatfsErrno(res);
                return FS_FAILURE;
            }
            (void)memset_s(&g_handle[i], sizeof(FatHandleStruct), 0x0, sizeof(FatHandleStruct));
            g_fileNum--;
        }
    }

    for (i = 0; i < FAT_MAX_OPEN_DIRS; i++) {
        if (g_dirNum <= 0) {
            break;
        }
        if (g_dir[i].obj.fs == &g_fatfs[index]) {
            res = f_closedir(&g_dir[i]);
            if (res != FR_OK) {
                errno = FatfsErrno(res);
                return FS_FAILURE;
            }
            (void)memset_s(&g_dir[i], sizeof(DIR), 0x0, sizeof(DIR));
            g_dirNum--;
        }
    }

    return FS_SUCCESS;
}

int fatfs_umount2(const char *target, int flag)
{
    INT32 index;
    INT32 ret;
    UINT32 flags;
    FRESULT res;

    if (target == NULL) {
        errno = EFAULT;
        return FS_FAILURE;
    }

⑸  flags = MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW;
    if ((UINT32)flag & ~flags) {
        errno = EINVAL;
        return FS_FAILURE;
    }

    ret = FsLock();
    if (ret != 0) {
        errno = ret;
        return FS_FAILURE;
    }

    index = FsPartitionMatch(target, VOLUME_NAME);
    if (index == FS_FAILURE) {
        errno = ENOENT;
        ret =  FS_FAILURE;
        goto OUT;
    }

    /* The volume is not mounted */
    if (g_fatfs[index].fs_type == 0) {
        errno = EINVAL;
        ret = FS_FAILURE;
        goto OUT;
    }

⑹  if ((UINT32)flag & MNT_FORCE) {
        ret = CloseAll(index);
        if (ret != FS_SUCCESS) {
            goto OUT;
        }
    }

⑺  res = f_mount((FATFS *)NULL, target, 0);
    if (res != FR_OK) {
        errno = FatfsErrno(res);
        ret = FS_FAILURE;
        goto OUT;
    }

    if (g_fatfs[index].win != NULL) {
        ff_memfree(g_fatfs[index].win);
    }

    (void)memset_s(&g_fatfs[index], sizeof(FATFS), 0x0, sizeof(FATFS));
    ret = FS_SUCCESS;

OUT:
    FsUnlock();
    return ret;
}
DD一下: 欢迎大家关注公众号<程序猿百晓生>,可以了解到一下知识点。
erlang 复制代码
1.OpenHarmony开发基础
2.OpenHarmony北向开发环境搭建
3.鸿蒙南向开发环境的搭建
4.鸿蒙生态应用开发白皮书V2.0 & V3.0
5.鸿蒙开发面试真题(含参考答案) 
6.TypeScript入门学习手册
7.OpenHarmony 经典面试题(含参考答案)
8.OpenHarmony设备开发入门【最新版】
9.沉浸式剖析OpenHarmony源代码
10.系统定制指南
11.【OpenHarmony】Uboot 驱动加载流程
12.OpenHarmony构建系统--GN与子系统、部件、模块详解
13.ohos开机init启动流程
14.鸿蒙版性能优化指南
.......

3.2 文件目录操作接口

文件目录操作接口包含fatfs_mkdir、fatfs_unlink、fatfs_rmdir、fatfs_readdir、fatfs_closedir、fatfs_open、fatfs_close等等,会进一步调用FatFS的文件目录操作接口进行封装,代码比较简单,自行阅读即可,部分代码片段如下。

ini 复制代码
......
int fatfs_close(int fd)
{
    FRESULT res;
    INT32 ret;

    ret = FsLock();
    if (ret != 0) {
        errno = ret;
        return FS_FAILURE;
    }

    if (!IsValidFd(fd)) {
        FsUnlock();
        errno = EBADF;
        return FS_FAILURE;
    }

    if (g_handle[fd].fil.obj.fs == NULL) {
        FsUnlock();
        errno = ENOENT;
        return FS_FAILURE;
    }

    res = f_close(&g_handle[fd].fil);
    if (res != FR_OK) {
        PRINTK("FAT close err 0x%x!\r\n", res);
        FsUnlock();
        errno = FatfsErrno(res);
        return FS_FAILURE;
    }

#if !FF_FS_TINY
    if (g_handle[fd].fil.buf != NULL) {
        (void)ff_memfree(g_handle[fd].fil.buf);
    }
#endif

    (void)memset_s(&g_handle[fd], sizeof(FatHandleStruct), 0x0, sizeof(FatHandleStruct));

    if (g_fileNum > 0) {
        g_fileNum--;
    }

    FsUnlock();

    return FS_SUCCESS;
}
......

小结

本文介绍了FatFS的结构体和全局变量,全局变量的操作接口,分析了下FatFS文件操作接口。

相关推荐
花先锋队长5 小时前
鸿蒙生态日日新,鸿蒙原生版支付宝下载量突破230万
华为·harmonyos
星之卡比*5 小时前
前端知识点---库和包的概念
前端·harmonyos·鸿蒙
刘大猫266 小时前
二、搭建MyBatis采用xml方式,验证CRUD(增删改查操作)
操作系统·自动化运维·设计
别说我什么都不会6 小时前
使用Multipass编译OpenHarmony工程
操作系统·嵌入式·harmonyos
轻口味9 小时前
【每日学点HarmonyOS Next知识】多继承、swiper容器、事件传递、滚动安全区域、提前加载网络图片
华为·harmonyos·harmonyosnext
Georgewu10 小时前
【HarmonyOS Next】鸿蒙应用故障处理思路详解
前端·vue.js·harmonyos
盖世栗子10 小时前
HarmonyOS中Image组件的缩放模式
harmonyos
蓝天下小溪旁戴着耳机去放羊10 小时前
详解数据传输——零拷贝、direct IO
性能优化·操作系统
银色火焰战车14 小时前
基于编译器特性浅析C++程序性能优化
开发语言·c++·重构·系统架构·操作系统