鴻蒙輕內核M核源碼分析系列二一 03 文件系統(tǒng)FatFS(1)
鴻蒙輕內核M核源碼分析系列二一 03 文件系統(tǒng)FatFS
FAT文件系統(tǒng)是File Allocation Table(文件配置表)的簡稱,主要包括DBR區(qū)、FAT區(qū)、DATA區(qū)三個區(qū)域。其中,F(xiàn)AT區(qū)各個表項記錄存儲設備中對應簇的信息,包括簇是否被使用、文件下一個簇的編號、是否文件結尾等。FAT文件系統(tǒng)有FAT12、FAT16、FAT32等多種格式,其中,12、16、32表示對應格式中FAT表項的比特數(shù)。FAT文件系統(tǒng)支持多種介質,特別在可移動存儲介質(U盤、SD卡、移動硬盤等)上廣泛使用,使嵌入式設備和Windows、Linux等桌面系統(tǒng)保持很好的兼容性,方便用戶管理操作文件。LiteOS-M內核支持FAT12、FAT16與FAT32三種格式的FAT文件系統(tǒng),具有代碼量小、資源占用小、可裁切、支持多種物理介質等特性,并且與Windows、Linux等系統(tǒng)保持兼容,支持多設備、多分區(qū)識別等功能。LiteOS-M內核支持硬盤多分區(qū),可以在主分區(qū)以及邏輯分區(qū)上創(chuàng)建FAT文件系統(tǒng)。
本文先介紹下FatFS文件系統(tǒng)結構體的結構體和全局變量,然后分析下FatFS文件操作接口。文中所涉及的源碼,均可以在開源站點https://gitee.com/openharmony/kernel_liteos_m 獲取。
1、FatFS文件系統(tǒng)結構體介紹
會分2部分來介紹結構體部分,先介紹FatFS文件系統(tǒng)的結構體,然后介紹LiteOS-M內核中提供的和FatFS相關的一些結構體。
1.1 FatFS的結構體
在openharmony/third_party/FatFs/source/ff.h頭文件中定義FatFS的結構體,我們先簡單了解下,后文會使用到的。
先看下相關的宏定義,包含文件訪問模式(File access mode),格式化選項(Format options)等等。文件打開方式和POSIX文件打開選項不一致,需要轉換,后文會涉及。
/*--------------------------------------------------------------*/ /* 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 ......
在openharmony/third_party/FatFs/source/ffconf.h頭文件中定義FatFS的一些配置信息。如下文的驅動和卷的配置信息等。對于LiteOS-M,默認是支持4個卷。宏定義FS_MAX_SS表示扇區(qū)大小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
對于適配LiteOS-M內核的開發(fā)板,使用FatFS文件系統(tǒng)時,需要提供頭文件liteos_m\board\fs\fs_config.h,例如: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
接下來看看重要的結構體。結構體FATFS是FatFS文件系統(tǒng)類型結構體。成員變量BYTE fs_type等0時表示未掛載,掛載后一般取值為FS_FAT12、FS_FAT16或FS_FAT32;WORD id表示卷的掛載編號。 其他成員變量可以暫不了解。
/* 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;
結構體FIL、DIR分別是FatFS的文件和目錄類型結構體,DIR是__dirstream結構體的別名,一般在Musl或Newlib C庫的文件dirent.h會有typedef struct __dirstream DIR;。這兩個結構體都包含F(xiàn)FOBJID obj這個成員變量,F(xiàn)FOBJID結構體體包含F(xiàn)ATFS* fs成員,可以關聯(lián)文件卷信息。暫不需要關心其他成員變量細節(jié),知道結構體的用途即可。
/* 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 };
結構體FILINFO用于維護文件信息,包含文件修改時間,大小和文件名等信息。
/* 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 LiteOS-M FatFS的結構體
我們來看下在文件components\fs\fatfs\fatfs.c里定義的結構體。結構體FatHandleStruct維護文件相關的信息,該結構體非常簡單,在FIL的基礎上增加了是否使用成員變量。
typedef struct { UINT8 useFlag; FIL fil; } FatHandleStruct;
2、LiteOS-M FatFS的重要全局變量及操作
了解下文件components\fs\fatfs\fatfs.c中定義的常用全局變量。⑴處的g_handle數(shù)組維護文件信息,默認支持的文件數(shù)目為FAT_MAX_OPEN_FILES;g_dir數(shù)組維護目錄信息,默認支持的目錄數(shù)目為FAT_MAX_OPEN_DIRS。 ⑵處的g_fatfs數(shù)組維護每個卷的的文件系統(tǒng)信息,默認文件卷數(shù)目FF_VOLUMES為4個。和文件卷相關的變量還有g_volPath數(shù)組維護每個卷的字符串路徑,g_volWriteEnable數(shù)組維護每個卷是否可寫。⑶處的g_workBuffer維護每個扇區(qū)的緩存。⑷處開始的g_fileNum、g_dirNum分別是文件和目錄打開的數(shù)目;struct dirent g_retValue是目錄項結構體變量,用于函數(shù)fatfs_readdir();pthread_mutex_t g_fsMutex是互斥鎖變量;⑸處開始的掛載操作變量g_fatfsMnt、文件操作操作全局變量g_fatfsFops,在虛擬文件系統(tǒng)中被使用。
⑴ 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, };
下文繼續(xù)介紹下和這些變量相關的內部操作接口。
2.1 文件系統(tǒng)互斥鎖
FatFS文件系統(tǒng)使用的是超時加鎖。函數(shù)FsLock()中,⑴處獲取系統(tǒng)實時時間,⑵處設置15秒超時,F(xiàn)S_LOCK_TIMEOUT_SEC默認為15秒。⑶處對互斥量進行加鎖,超時后不會再對互斥量加鎖。函數(shù)FsUnlock()用于解鎖。
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 判斷文件描述符有效性
函數(shù)IsValidFd()用于判斷文件描述符的是否有效,如果文件描述符超出有效范圍,或者文件未使用狀態(tài),返回false,否則返回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 切換驅動器
函數(shù)FsChangeDrive()根據(jù)傳入的路徑切換驅動器(盤符)。字符串數(shù)組tmpPath用于保存驅動器名稱,其中驅動器名稱最大值FS_DRIVE_NAME_MAX_LEN。⑵處處理路徑長度大于驅動器名稱長度的情況。⑶處從路徑中獲取驅動器名稱,然后調用接口f_chdrive()切換驅動器。在文件操作接口中,會調用該函數(shù)來切換驅動器,如fatfs_open、fatfs_unlink、fatfs_stat、fatfs_mkdir、fatfs_opendir、fatfs_rmdir、fatfs_rename和fatfs_statfs,這些函數(shù)的參數(shù)涉及文件路徑char *path或者目錄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 匹配文件卷
函數(shù)FsPartitionMatch()根據(jù)傳入的文件路徑獲取對應的卷索引,在掛載、卸載、格式化等接口中使用。⑴處如果傳入的是卷名稱,獲取頂級目錄名稱,即路徑的第一級目錄,前后不包含路徑分隔符/。⑵如果傳入的是路徑名稱,獲取頂級路徑,截止到第一個分隔符/。否則執(zhí)行⑶,賦值路徑中的名稱。然后遍歷每一個卷,如果獲取的頂級目錄名稱等于卷名稱,則返回對應的卷數(shù)組索引。否則返回FS_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; }
IoT 輕量級操作系統(tǒng) LiteOS
版權聲明:本文內容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內刪除侵權內容。
版權聲明:本文內容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內刪除侵權內容。