鸿蒙内核M核源码分析系列二一 03 文件系统FatFS(2)

网友投稿 552 2022-05-29

2.4 判断文件卷是否可写

函数FsCheckByPath()、FsCheckByID()用于判断文件卷是否可写,传递参数不同。前者传入的是文件路径,转化为卷索引后判断。后者传入的是挂载编号,遍历每一个卷,判断相应卷的编号与传入参数是否相等。

static bool FsCheckByPath(const char *path) { INT32 index; index = FsPartitionMatch(path, PATH_NAME); if (index == FS_FAILURE) { return FS_FAILURE; } return g_volWriteEnable[index]; } static bool FsCheckByID(int id) { INT32 index; for (index = 0; index < FF_VOLUMES; index++) { if (g_fatfs[index].id == id) { return g_volWriteEnable[index]; } } return false; }

鸿蒙轻内核M核源码分析系列二一 03 文件系统FatFS(2)

2.5 标签转换

函数FatFsGetMode()用于把POSIX格式的文件打开标签转换为FatFS文件系统格式的文件打开标签。FatfsErrno()把FatFS文件系统格式的错误号转换为POSIX格式的错误号。

static unsigned int FatFsGetMode(int oflags) { UINT32 fmode = FA_READ; if ((UINT32)oflags & O_WRONLY) { fmode |= FA_WRITE; } if (((UINT32)oflags & O_ACCMODE) & O_RDWR) { fmode |= FA_WRITE; } /* Creates a new file if the file is not existing, otherwise, just open it. */ if ((UINT32)oflags & O_CREAT) { fmode |= FA_OPEN_ALWAYS; /* Creates a new file. If the file already exists, the function shall fail. */ if ((UINT32)oflags & O_EXCL) { fmode |= FA_CREATE_NEW; } } /* Creates a new file. If the file already exists, its length shall be truncated to 0. */ if ((UINT32)oflags & O_TRUNC) { fmode |= FA_CREATE_ALWAYS; } return fmode; } static int FatfsErrno(int result) { INT32 status = 0; if (result < 0) { return result; } /* FatFs errno to Libc errno */ switch (result) { case FR_OK: break; case FR_NO_FILE: case FR_NO_PATH: case FR_NO_FILESYSTEM: status = ENOENT; break; ...... default: status = result; break; } return status; }

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

接下来,看下卸载操作。函数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; }

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

小结

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

参考资料

HarmonyOS Device>文档指南>基础能力-FatFS

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:基于AI算法开发套件进行水表读数识别
下一篇:MySQL 传输表空间
相关文章