This article is shared from Huawei cloud community< Hongmeng light kernel M core source code analysis series 21 03 file system FatFS >, author: zhushy.
Fat file system is the abbreviation of File Allocation Table, which mainly includes three areas: DBR area, fat area and DATA area. Among them, each table item in the fat area records the information of the corresponding cluster in the storage device, including whether the cluster is used, the number of the next cluster in the file, whether the end of the file, etc. Fat file system has FAT12, FAT16, FAT32 and other formats. Among them, 12, 16 and 32 represent the number of bits of fat table entries in the corresponding format. Fat file system supports a variety of media, especially widely used in removable storage media (U SB flash disk, SD card, mobile hard disk, etc.), so that embedded devices maintain good compatibility with desktop systems such as Windows and Linux, and it is convenient for users to manage and operate files. LiteOS-M kernel supports fat file systems in FAT12, FAT16 and FAT32 formats. It has the characteristics of small amount of code, small resource occupation, can be cut and supports a variety of physical media. It is compatible with Windows, Linux and other systems, and supports multi device, multi partition identification and other functions. LiteOS-M kernel supports multi partition of hard disk, and fat file system can be created on primary partition and logical partition.
This paper first introduces the structure and global variables of the FatFS file system structure, and then analyzes the FatFS file operation interface. The source code involved in this article can be found on the open source site https://gitee.com/openharmony/kernel_liteos_m Get.
1. Introduction to FatFS file system structure
There will be two parts to introduce the structure part. First introduce the structure of FatFS file system, and then introduce some structures related to FatFS provided in LiteOS-M kernel.
1.1 structure of FatFs
In openharmony / third_ party/FatFS/source/ff. The structure of FatFS is defined in the H header file. Let's briefly understand it first and use it later.
First look at the relevant macro definitions, including File access mode, Format options, and so on. The file opening method is inconsistent with the POSIX file opening options and needs to be converted, which will be discussed later.
/*--------------------------------------------------------------*/ /* Flags and offset address */ /* File access mode and open method flags (3rd argument of f_open) */ #define FA_READ 0x01 #define FA_WRITE 0x02 #define FA_OPEN_EXISTING 0x00 #define FA_CREATE_NEW 0x04 #define FA_CREATE_ALWAYS 0x08 #define FA_OPEN_ALWAYS 0x10 #define FA_OPEN_APPEND 0x30 /* Fast seek controls (2nd argument of f_lseek) */ #define CREATE_LINKMAP ((FSIZE_t)0 - 1) /* Format options (2nd argument of f_mkfs) */ #define FM_FAT 0x01 #define FM_FAT32 0x02 #define FM_ANY 0x07 #define FM_SFD 0x08 ......
In openharmony/third_party/FatFs/source/ffconf.h header file defines some configuration information of FatFS. For example, the following driver and volume configuration information. For LiteOS-M, 4 volumes are supported by default. Macro definition FS_MAX_SS indicates sector size.
/*---------------------------------------------------------------------------/ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ #ifndef __LITEOS_M__ #define FF_VOLUMES LOSCFG_FS_FAT_VOLUMES #else #define FF_VOLUMES 4 #endif /* Number of volumes (logical drives) to be used. (1-10) */ #ifdef LOSCFG_FS_FAT_VIRTUAL_PARTITION #define _DEFAULT_VIRVOLUEMS 4 #define _MIN_CLST 0x4000 #define _FLOAT_ACC 0.00000001 #endif #ifndef __LITEOS_M__ #define FF_STR_VOLUME_ID 0 #define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" #else #define FF_STR_VOLUME_ID 2 #endif #define FF_MULTI_PARTITION 1 #define FF_MIN_SS 512 #ifndef __LITEOS_M__ #define FF_MAX_SS 4096 #else #define FF_MAX_SS FS_MAX_SS #endif
For the development board adapted to LiteOS-M kernel, the header file liteos needs to be provided when using FatFS file system_ m\board\fs\fs_ config. h. For example: openharmony\device\qemu\arm_mps2_an386\liteos_m\board\fs\fs_config.h.
#define FF_VOLUME_STRS "system", "inner", "update", "user" #define FS_MAX_SS 512 #define FAT_MAX_OPEN_FILES 50
Next, let's look at the important structures. Structure FatFs is a FatFs file system type structure. Member variable byte FS_ When type is 0, it means it is not mounted. After mounting, it is generally FS_FAT12,FS_FAT16 or FS_FAT32; WORD id indicates the mount number of the volume. Other member variables can not be understood temporarily.
/* Filesystem object structure (FATFS) */ typedef struct { BYTE fs_type; /* Filesystem type (0:not mounted) */ BYTE pdrv; /* Associated physical drive */ BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE wflag; /* win[] flag (b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ WORD id; /* Volume mount ID */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ WORD csize; /* Cluster size [sectors] */ #if FF_MAX_SS != FF_MIN_SS size_t ssize; /* Sector size (512, 1024, 2048 or 4096) */ #endif #if FF_USE_LFN WCHAR* lfnbuf; /* LFN working buffer */ #endif #if FF_FS_REENTRANT FF_SYNC_t sobj; /* Identifier of sync object */ #endif #if !FF_FS_READONLY DWORD last_clst; /* Last allocated cluster */ DWORD free_clst; /* Number of free clusters */ #endif #if FF_FS_RPATH DWORD cdir; /* Current directory start cluster (0:root) */ #endif DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */ DWORD fsize; /* Sectors per FAT */ LBA_t volbase; /* Volume base sector */ LBA_t fatbase; /* FAT base sector */ LBA_t dirbase; /* Root directory base sector/cluster */ LBA_t database; /* Data base sector */ LBA_t winsect; /* Current sector appearing in the win[] */ BYTE* win; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ #ifdef LOSCFG_FS_FAT_VIRTUAL_PARTITION DWORD st_clst; DWORD ct_clst; BYTE vir_flag; /* Flag of Virtual Filesystem Object, b0 : 1 for virtual Fatfs object, 0 for reality Fatfs object */ BYTE vir_avail; DWORD vir_amount; VOID* parent_fs; /* Point to the reality Fatfs object, only available in virtual Fatfs object */ CHAR namelabel[_MAX_ENTRYLENGTH + 1]; /* The name label point to the each virtual Fatfs object ,only available in virtual Fatfs obj */ VOID** child_fs; /* Point to the child Fatfs object ,only available in reality Fatfs object */ #endif #ifndef __LITEOS_M__ int fs_uid; int fs_gid; mode_t fs_mode; #endif unsigned short fs_dmask; unsigned short fs_fmask; } FATFS;
The structures FIL and dir are the file and directory type structures of FatFS respectively, and dir is__ The alias of the dirstream structure is usually in the file dirent.com of Musl or Newlib C library H will have typedef struct__ dirstream DIR;. Both structures contain the member variable FFOBJID obj. The FFOBJID structure contains the FATFS* fs member, which can be associated with file volume information. You don't need to care about the details of other member variables, just know the purpose of the structure.
/* Object ID and allocation information (FFOBJID) */ typedef struct { FATFS* fs; /* Pointer to the hosting volume of this object */ WORD id; /* Hosting volume mount ID */ BYTE attr; /* Object attribute */ BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ FSIZE_t objsize; /* Object size (valid when sclust != 0) */ #if FF_FS_LOCK UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ #endif } FFOBJID; /* File object structure (FIL) */ typedef struct { FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ BYTE flag; /* File status flags */ BYTE err; /* Abort flag (error code) */ FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */ LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */ #if !FF_FS_READONLY LBA_t dir_sect; /* Sector number containing the directory entry */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ #endif #if FF_USE_FASTSEEK DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ #endif #if !FF_FS_TINY BYTE* buf; /* File private data read/write window */ #endif #ifndef __LITEOS_M__ LOS_DL_LIST fp_entry; #endif } FIL; /* Directory object structure (DIR) */ struct __dirstream { FFOBJID obj; /* Object identifier */ DWORD dptr; /* Current read/write offset */ DWORD clust; /* Current cluster */ LBA_t sect; /* Current sector (0:Read operation has terminated) */ BYTE* dir; /* Pointer to the directory item in the win[] */ BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ #if FF_USE_LFN DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ #endif #if FF_USE_FIND const TCHAR* pat; /* Pointer to the name matching pattern */ #endif #ifdef LOSCFG_FS_FAT_VIRTUAL_PARTITION BYTE atrootdir; #endif };
Structure FILINFO is used to maintain file information, including file modification time, size, file name and other information.
/* File information structure (FILINFO) */ typedef struct { FSIZE_t fsize; /* File size */ WORD fdate; /* Modified date */ WORD ftime; /* Modified time */ BYTE fattrib; /* File attribute */ #if FF_USE_LFN TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ #else TCHAR fname[12 + 1]; /* File name */ #endif DWORD sclst; #ifndef __LITEOS_M__ LOS_DL_LIST fp_list; #endif } FILINFO;
1.2 structure of liteos-m FatFs
Let's look at the file components \ FS \ FatFs \ FatFs Structure defined in C. The structure FatHandleStruct maintains the information related to the file. The structure is very simple and adds whether to use member variables on the basis of FIL.
typedef struct { UINT8 useFlag; FIL fil; } FatHandleStruct;
2. Important global variables and operations of LiteOS-M FatFS
Learn about the file components \ FS \ FatFs \ FatFs Common global variables defined in C. (1) g at_ Handle array maintains file information. The number of files supported by default is FAT_MAX_OPEN_FILES; g_dir array maintains directory information. The default number of supported directories is FAT_MAX_OPEN_DIRS. (2) g at_ FatFs array maintains the file system information of each volume. The default number of file volumes is FF_ There are 4 volumes. Other variables related to file volumes are g_volPath array maintains the string path of each volume, G_ The volwriteenable array maintains whether each volume is writable. (3) g at_ Workbuffer maintains the cache of each sector. (4) g starting at_ fileNum,g_dirNum is the number of files and directories opened respectively; struct dirent g_retValue is the variable of the directory item structure, which is used in the function fatfs_readdir(); pthread_mutex_t g_fsMutex is a mutex variable; (5) start of variable loading_ Fatfsmnt, file operation global variable G_ Fatfsfoss, which is used in virtual file systems.
⑴ static FatHandleStruct g_handle[FAT_MAX_OPEN_FILES] = {0}; static DIR g_dir[FAT_MAX_OPEN_DIRS] = {0}; ⑵ static FATFS g_fatfs[FF_VOLUMES] = {0}; ⑶ static UINT8 g_workBuffer[FF_MAX_SS]; ⑷ static UINT32 g_fileNum = 0; static UINT32 g_dirNum = 0; static struct dirent g_retValue; static pthread_mutex_t g_fsMutex = PTHREAD_MUTEX_INITIALIZER; static const char * const g_volPath[FF_VOLUMES] = {FF_VOLUME_STRS}; static BOOL g_volWriteEnable[FF_VOLUMES] = {FALSE}; ...... ⑸ struct MountOps g_fatfsMnt = { .Mount = fatfs_mount, .Umount = fatfs_umount, .Umount2 = fatfs_umount2, .Statfs = fatfs_statfs, }; struct FileOps g_fatfsFops = { .Mkdir = fatfs_mkdir, .Unlink = fatfs_unlink, .Rmdir = fatfs_rmdir, .Opendir = fatfs_opendir, .Readdir = fatfs_readdir, .Closedir = fatfs_closedir, .Open = fatfs_open, .Close = fatfs_close, .Write = fatfs_write, .Read = fatfs_read, .Seek = fatfs_lseek, .Rename = fatfs_rename, .Getattr = fatfs_stat, .Fsync = fatfs_fsync, .Fstat = fatfs_fstat, };
The following continues to introduce the internal operation interfaces related to these variables.
2.1 file system Mutex
The FatFS file system uses timeout locking. In the function FsLock(), the system real-time time time is obtained at (1), and the 15 second timeout is set at (2), FS_LOCK_TIMEOUT_SEC defaults to 15 seconds. (3) lock the mutex at. After the timeout, the mutex will not be locked again. The function FsUnlock() is used to unlock.
static int FsLock(void) { INT32 ret = 0; struct timespec absTimeout = {0}; if (osKernelGetState() != osKernelRunning) { return ret; } ⑴ ret = clock_gettime(CLOCK_REALTIME, &absTimeout); if (ret != 0) { PRINTK("clock gettime err 0x%x!\r\n", errno); return errno; } ⑵ absTimeout.tv_sec += FS_LOCK_TIMEOUT_SEC; ⑶ ret = pthread_mutex_timedlock(&g_fsMutex, &absTimeout); return ret; } static void FsUnlock(void) { if (osKernelGetState() != osKernelRunning) { return; } (void)pthread_mutex_unlock(&g_fsMutex); }
2.2 judging the validity of file descriptor
The function IsValidFd() is used to judge whether the file descriptor is valid. If the file descriptor exceeds the valid range or the file is not in use, it returns false, otherwise it returns true.
static bool IsValidFd(int fd) { if ((fd < 0) || (fd >= FAT_MAX_OPEN_FILES) || (g_handle[fd].useFlag == 0)) { return false; } return true; }
2.3 switching driver
The path of the incoming drive () is switched according to the drive letter of the incoming drive (). The string array tmpPath is used to save the drive name, where the maximum value of the drive name is FS_DRIVE_NAME_MAX_LEN. (2) handle the case where the length of the path is greater than the length of the drive name. Get the name of the drive from the path, then call the interface f_. Chdrive() switches the drive. In the file operation interface, this function will be called to switch drives, such as fatfs_open,fatfs_unlink,fatfs_stat,fatfs_mkdir,fatfs_opendir,fatfs_rmdir,fatfs_rename and fatfs_statfs. The parameters of these functions involve the file path char *path or directory char *dirName.
static int FsChangeDrive(const char *path) { INT32 res; ⑴ CHAR tmpPath[FS_DRIVE_NAME_MAX_LEN] = { "/" }; /* the max name length of different parts is 16 */ errno_t retErr; UINT16 pathLen; pathLen = strlen((char const *)path); /* make sure the path begin with "/", the path like /xxx/yyy/... */ ⑵ if (pathLen >= (FS_DRIVE_NAME_MAX_LEN - 1)) { /* 2: except first flag "/" and last end flag */ pathLen = FS_DRIVE_NAME_MAX_LEN - 2; } ⑶ retErr = strncpy_s(tmpPath + 1, (FS_DRIVE_NAME_MAX_LEN - 1), (char const *)path, pathLen); if (retErr != EOK) { return FS_FAILURE; } res = f_chdrive(tmpPath); if (res != FR_OK) { return FS_FAILURE; } return FS_SUCCESS; }
2.4 matching file volumes
The function FsPartitionMatch() obtains the corresponding volume index according to the incoming file path and is used in mount, unmount, format and other interfaces. (1) if the volume name is passed in, obtain the top-level directory name, that is, the first level directory of the path, without the path separator /. (2) if the path name is passed in, get the top-level path until the first separator /. Otherwise, execute (3) and assign the name in the path. Then traverse each volume. If the obtained top-level directory name is equal to the volume name, the corresponding volume array index is returned. Otherwise, FS is returned_ FAILURE.
static int FsPartitionMatch(const char *path, int flag) { INT32 ret; UINT32 index; CHAR tmpName[FF_MAX_LFN] = {0}; if (path == NULL) { return FS_FAILURE; } switch ((UINT32)flag & NAME_MASK) { case VOLUME_NAME: ⑴ ret = sscanf_s(path, "/%[^/]", tmpName, FF_MAX_LFN); if (ret <= 0) { return FS_FAILURE; } break; case PATH_NAME: ⑵ ret = sscanf_s(path, "%[^/]", tmpName, FF_MAX_LFN); if (ret <= 0) { return FS_FAILURE; } break; case PART_NAME: default: ⑶ ret = strcpy_s(tmpName, FF_MAX_LFN, path); if (ret != EOK) { return FS_FAILURE; } } for (index = 0; index < FF_VOLUMES; index++) { ⑷ if (strcmp(tmpName, g_volPath[index]) == 0) { return index; } } return FS_FAILURE; }
2.5 judge whether the file volume is writable
The functions FsCheckByPath() and FsCheckByID() are used to judge whether the file volume is writable. The transfer parameters are different. The former passes in the file path, which is determined after being converted into the volume index. The latter passes in the mount number. Traverse each volume to determine whether the number of the corresponding volume is equal to the incoming parameters.
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; }
2.6 label conversion
The function FatFsGetMode() is used to convert the file opening label in POSIX format to the file opening label in FatFS file system format. FatfsErrno() converts the error number in the FatFS file system format to the error number in POSIX format.
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. File system operation interface of LiteOS-M FATFS
Quickly record each operation interface, and the purpose and usage of each interface will not be described. You can refer to the previous series of articles, "Hongmeng light kernel M core source code analysis series 19 Musl LibC", which introduces the relevant interfaces. Those interfaces will call the operation interface in the VFS file system, and then further call the FatFS file operation interface.
3.1 mount and unload operations
Take a look at the mount operation first. FatFS supports the re mount operation. If the mount option contains MS_ When remount, the function Remount() will be called to mount again. In the function Remount(), FsPartitionMatch() is called at (1) to obtain the volume index. If the volume is not mounted at (2), it is not allowed to mount again, and the error code is returned. (3) set whether the corresponding volume is readable or writable at. From this point of view, re mounting is mainly to update the readability and writability of the volume.
Look at the mount function fatfs_mount(), start to judge the validity of the parameter at (4), which cannot be empty, the file system type must be "fat", call FsPartitionMatch() at (5) to obtain the volume index, and return the error code if the volume has been mounted at (6). (7) call f at_ Mount() implements mount, and the third parameter 1 indicates mount immediately. (8) set whether the corresponding volume is readable or writable.
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; }
Next, look at the uninstall operation. Function FatFs_ In umount(), first perform basic checks such as parameter validity and whether to mount, and call function f at ⑴_ Check openlock() to determine whether there are open files or directories in the volume to be unloaded, and call f at (2)_ Mount(), the first parameter is NULL, which means to unmount the file system specified by the target;, The third parameter 0 indicates that mounting is not required. If the unloading is wrong, convert the corresponding error code. (3) if the Disk access window for Directory is not empty, perform the corresponding release operation. (4) set the element corresponding to the file volume array to zero.
The function CloseAll() traverses every open file and directory to close according to the file volume number. Function fatfs_umount2(), the supported uninstall options indicated at (5) are: MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW. (6) in the case of forced unloading, first close the open files and directories, and then execute (7) to realize the unloading operation.
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 file directory operation interface
The file directory operation interface contains fatfs_mkdir,fatfs_unlink,fatfs_rmdir,fatfs_readdir,fatfs_closedir,fatfs_open,fatfs_close, etc. will further call the file directory operation interface of FatFS for encapsulation. The code is relatively simple and can be read by yourself. Some code fragments are as follows.
...... 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; } ......
Summary
This paper introduces the structure and global variables of FatFS, the operation interface of global variables, and analyzes the operation interface of FatFS file. Hurry of time is related to ability. If there is any mistake, you are welcome to correct it. Thank you for reading. If you have any questions and suggestions, you can leave a message to me under the blog. Thank you.
reference material
- Harmonyos device > documentation Guide > basic capabilities - FatFS
Please pay more attention to learning content IoT IOT community
Click follow to learn about Huawei's new cloud technology for the first time~