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

zhushangyuan_
发布于 2022-1-9 17:50
浏览
1收藏

鸿蒙轻内核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表示立即挂载。⑻设置对应的卷是否可读可写标记。

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;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.

接下来,看下卸载操作。函数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。⑹处处理强制卸载的情形,会首先关闭打开的文件和目录,然后再去执行⑺实现卸载操作。

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

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.

3.2 文件目录操作接口

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

......
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;
}
......
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.

小结

本文介绍了FatFS的结构体和全局变量,全局变量的操作接口,分析了下FatFS文件操作接口。时间仓促和能力关系,如有失误,欢迎指正。感谢阅读,如有任何问题、建议,都可以博客下留言给我,谢谢。

参考资料

【本文正在参与优质创作者激励】

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-1-9 17:50:57修改
3
收藏 1
回复
举报
3
1
回复
    相关推荐