【转载】【FS】FATFS文件系统介绍(未完待续........2018.4.1)
一、這是個什么玩意
它是一個文件系統,那文件系統是個什么玩意,直接從字面意思理解,它就是個管理文件的系統,所以叫文件系統,直白吧,也可以說是文件存儲協議。但是繼續追問的話會問,怎么來管理文件呢?好,基于怎么管理文件這個問題,就會產生不同的文件系統,不同的文件系統管理的策略都有不同(這里就不展開了說了,只說fatfs,有精力的話可以多了解幾種通用的文件系統,yaffs,jffs等,或者對于嵌入式開發有限的資源可以自己編寫文件系統)。下面說下fatfs。
fatfs是開源的。可以從官網下載源碼。當前的fatfs文件系統有兩個版本,一個是標準完整的fatfs,另一個是Tiny版本,適合ram比較小的設備,部分功能被禁止。不過兩個版本都支持FAT12,FAT16和FAT32。通過宏_FS_TINY可以配置。從官網下載(http://elm-chan.org/fsw/ff/00index_e.html)下來解壓會有兩個文件夾,doc和src。doc里是關于FatFs的說明,包括特性,系統函數介紹,en是英語,ja是日語,res是資源文件夾,剩下官網主頁。src里是文件系統實現源碼。option文件夾是代碼頁表,可以不用管。剩下各個文件的功能可以參考00readme.txt。
??00readme.txt???This file.
??00history.txt??Revision history.
??ff.c???????????FatFs module.
??ffconf.h???????Configuration file of FatFs module.
??ff.h???????????Common include file for FatFs and application module.
??diskio.h???????Common include file for FatFs and disk I/O module.
??diskio.c???????An example of glue function to attach existing disk I/O module to FatFs.
??integer.h??????Integer type definitions for FatFs.
??option?????????Optional external modules.
二、有毛用啊
文件系統在整個系統中的作用非常重要。對上(對用戶或應用)可以方便的管理文件,上層可以隨意管理文件(夾)。對下(各種設備)也可以合理的管理使用設備(硬盤,SD卡,Flash等)。對于硬盤還好點可以隨意擦寫,但是對于flash的話在寫之前比如先擦,如果沒有文件系統的話,上層直接訪問操作的是物理空間,這就相當不方便了。
三、怎么用啊
所謂怎么用其實就是移植fatfs到你的系統,能夠新建,打開,讀,寫,刪出文件。fatfs的設計分層已經幫你設計好了,文件系統的實現已經和具體的硬件介質無關,只需要實現和介質相關的訪問介質的各個接口(disk_initialize,disk_read,disk_write和disk_ioctl),除此之外就是修改配置文件,主要是兩個,一個是interger.h文件,這個是文件系統所需的變量類型,和具體的處理器相關,可能會修改。另一個是ffconf.h文件,這個文件是具體配置文件系統的,根據自己的項目需求對文件系統進行裁剪。
在上面調試完成后,怎么使用fatfa就相對容易多了,主要是以下幾個接口。format,mount,open,wirte,read,close。
下圖是FAT32文件系統的結構:(FAT12、FAT16可能會有調整,這個得源碼了,下面內容參考于https://www.cnblogs.com/amanlikethis/p/3793077.html#lab5?該部分講的比較好,在此感謝)
概念與分區功能簡述:
MBR:
保存了磁盤的分區信息(分區的起始地址、分區大小、分區結束地址)
DBR:
保存了當前分區的詳細參數(比如FAT表的位置、FAT表的的大小、簇大小、扇區大小、根目錄中最大目錄項數等等)
FAT表:
以簇的形式對數據區重新劃分空間,在FAT表中建立了簇的使用情況,哪些已經被占用,哪些沒有被占用;簇鏈的結構,也即是簇與簇之間的連接關系。
目錄:
在目錄中,存在眾多的目錄項,目錄項記錄了文件名、大小、起始地址等等。
目錄項:
目錄中的存儲單位,記錄了每一個文件或者目錄的信息。
數據區:
數據區中純粹的文件數據
扇區:
SD卡最小的讀寫單位,512字節,也就是說一次最少讀取或者寫入的數據是512字節。
☆??說明
<1> 有些SD卡格式化后,并沒有MBR部分,而且SD卡格式化后磁盤上只存在一個磁盤分區。也就是說,即使SD卡上有MBR部分,在MBR的DPT(硬盤分區表)中也只有一個分區記錄。
<2> 位于數據區之前的可以稱之為文件系統管理區,此區域是以物理扇區為單位進行管理的,數據區則是以簇為單位進行管理的。
筆者認為1:
狹義上的文件專指普通文件,目錄則是位于普通文件的上層,用于管理處在其中的文件或者目錄欄。筆者認為廣義上的文件包含”目錄和普通文件”。這樣說目錄,表示目錄實際上也是一個文件,只不過是一個管理文件信息的特殊文件。
可以說文件與目錄既有區別,又有聯系。普通文件在文件管理的時候,給文件設計了一個管理變量—文件指針,用于指示文件當前讀取或者寫入的位置,它是以字節為單位進行計算的;而目錄其實也有一個管理讀取或者寫入的位置的變量—目錄指針,它則是以目錄項(32字節)為單位進行計算的。
筆者認為2:
文件 = 目錄中的目錄項、FAT表、文件對應的數據區內容
<1> 查看磁盤信息就是查看DBR和FAT表
<2> 讀取文件就是查看目錄項、FAT表和文件對應的數據區內容
<3> 寫文件就是修改目錄項、FAT表、文件對應的數據區內容
(參考結束,在此感謝)上述的內容如有理解不深入,直接擼代碼。
本人用的是R0.12C版本,算是比較新的代碼了,由于代碼量還是不小,我只列部分,如有需要請郵件624801474@qq.com
1、首先來看ffconf.h文件
/*-----------------------------------------------------------------------------/
/ Function Configurations功能配置
/-----------------------------------------------------------------------------*/
#define _FS_READONLY?????????0??????/* 0 to 1?*/配置讀寫或只讀,配成只讀的話不支持一些接口如 f_write(), f_sync()等
#define _FS_MINIMIZE?????????0??????/* 0 to 3 */函數功能支持,具體定義不同的值支持的函數也不同
#define _USE_STRFUNC?????????2??????/* 0:Disable or 1-2:Enable */使能或禁止字符串函數
#define _USE_FIND????????????0??????/* 0 to 1?*/能或禁用在指定目錄內搜索指定文件函數
#define _USE_MKFS????????????1????/* 0 to 1?*/使能或禁用f_mkfs函數
#define _USE_FASTSEEK????????1/* 0 to 1?*/使能或禁用快速搜索功能
#define?_USE_EXPAND???1????/* 0 to 1?*/使能或禁用f_expand函數,該函數可以為文件分配連續數據區域
#define _USE_CHMOD??0??/* 0 to 1?*/使能或禁用元數據控制函數:f_chmod和f_utime。
#define _USE_LABEL???????????0???/* 0 to 1?*/使能或禁用卷標簽API函數:f_getlabel和f_setlabel。
#define _USE_FORWARD?????????0????/* 0 to 1?*/使能或禁用f_forward函數。
/*-----------------------------------------------------------------------------/
/ Locale and Namespace Configurations命名空間和本地環境配置
/-----------------------------------------------------------------------------*/
#define _CODE_PAGE?????????850?????規定目標系統使用的OEM代碼。如果該代碼設置的不正確,可能會引起文件打開失敗。如果沒有根本沒有使用擴展字符,則使用任何代碼都沒區別。
/???1???- ASCII (No extended character. Non-LFN cfg. only)
/???437 - U.S.
/???720 - Arabic
/???737 - Greek
/???771 - KBL
/???775 - Baltic
/???850 - Latin 1
/???852 - Latin 2
/???855 - Cyrillic
/???857 - Turkish
/???860 - Portuguese
/???861 - Icelandic
/???862 - Hebrew
/???863 - Canadian French
/???864 - Arabic
/???865 - Nordic
/???866 - Russian
/???869 - Greek 2
/???932 - Japanese (DBCS)
/???936 - Simplified Chinese (DBCS)
/???949 - Korean (DBCS)
/???950 - Traditional Chinese (DBCS)
*/
#define _USE_LFN?????0????/* 0 to 3 */??使能或禁用長文件名(LFN)
#define _MAX_LFN?????255??定義長文件名工作緩沖區大小,可以為12~255字節。當禁用長文件名時,此選項無效。
#define _LFN_UNICODE????0 /* 0:ANSI/OEM or 1:Unicode */使能或禁用Unicode
#define _STRF_ENCODE????3 /* 0 to 3 */??通過設置_LFN_UNICODE為1使能Unicode API函數時,這個選項定義通過字符串I/O函數讀寫的文件字符編碼。
#define _FS_RPATH???????0 /* 0 to 2 */配置相對路徑函數。
/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations卷/驅動器配置
/----------------------------------------------------------------------------*/
#define _VOLUMES????2 配置可用卷的數目,可設置為1~10。
/* USER CODE BEGIN Volumes */??
#define _STR_VOLUME_ID??????????0?/* 0:Use only 0-9 for drive ID, 1:Use strings for drive ID */使能或禁用字符串卷標識
#define _VOLUME_STRS????????????"RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"定義每一個邏輯驅動器ID。ID數目不能少于_VOLUMES。驅動器ID有效字符只能為A-Z和0-9。
#define _MULTI_PARTITION?????0 /* 0:Single partition, 1:Multiple partition */使能或禁止多分區函數。
#define _MIN_SS????512??/* 512, 1024, 2048 or 4096 */
#define _MAX_SS????4096??/* 512, 1024, 2048 or 4096 */定義扇區大小,有效值為512、1024、2048、4096,需要根據硬件配置來定義。_MIN_SS定義最小扇區大小,_MAX_SS定義最大扇區大小。
#define?_USE_TRIM??????0 /* 0 to?1 */使能或禁用ATA-TRIM函數。
#define _FS_NOFSINFO????0 /* 0,1,2 or 3 */使能或禁用空閑簇計數和最后分配的簇計數。
/*---------------------------------------------------------------------------/
/ System Configurations系統配置
/----------------------------------------------------------------------------*/
#define _FS_TINY????1??????/* 0:Normal or 1:Tiny */配置FatFs為正常模式或者微型(TINY)模式。
#define _FS_EXFAT?0?????/* 0 to?1 */???使能或禁用exFAT文件系統。
#define _FS_NORTC?0??/* 0 to?1 */???使能或禁用時間戳函數。
#define _NORTC_MON?1
#define _NORTC_MDAY?1
#define _NORTC_YEAR?2018???如果系統沒有RTC,這些宏用來定義固定時間戳。只讀或者_FS_NORTC=0時,這些宏無意義。
#define _FS_LOCK????4?????/* 0:Disable or >=1:Enable */使能或禁用文件鎖功能。控制重復打開文件和非法打開文件對象。注意:文件鎖功能不具有可重入性。只讀模式下,這個宏必須為0。
#define _FS_REENTRANT????1/* 0:Disable or 1:Enable */使能或禁用FatFs模塊的可重入特性。
#define _FS_TIMEOUT??????1000 /* Timeout period in unit of time ticks */設置超時時間,單位為系統時鐘滴答周期,當宏_FS_REENTRANT=0時,本設置無效。
#define _SYNC_t??????????osSemaphoreId 定義同步對象類型,取決于O/S。
2、integer.h文件忽略。
3、ff.h文件系統頭文件,這個文件都是文件系統使用的各種宏定義、頭文件和函數聲明
/* Definitions of volume management */ 定義卷管理
#if _MULTI_PARTITION??/* Multiple partition configuration */
typedef struct {
?BYTE pd;?/* Physical drive number */
?BYTE pt;?/* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION;分區表,定義了物理設備和邏輯分區的映射關系
extern PARTITION VolToPart[];?/* Volume - Partition resolution table */
#endif
/* Type of path name strings on FatFs API */文件系統源碼中暫時沒什么用,先不用管
#if _LFN_UNICODE???/* Unicode (UTF-16) string */
#if _USE_LFN == 0
#error _LFN_UNICODE must be 0 at non-LFN cfg.
#endif
#ifndef _INC_TCHAR
typedef WCHAR TCHAR;
#define _T(x) L ## x
#define _TEXT(x) L ## x
#endif
#else??????/* ANSI/OEM string */
#ifndef _INC_TCHAR
typedef char TCHAR;
#define _T(x) x
#define _TEXT(x) x
#endif
#endif
/* Type of file size variables */文件大小變量類型
#if _FS_EXFAT
#if _USE_LFN == 0
#error LFN must be enabled when enable exFAT
#endif
typedef QWORD FSIZE_t;
#else
typedef DWORD FSIZE_t;
#endif
/* File system object structure (FATFS) */文件系統結構體(重要之一)
typedef struct {
?BYTE?fs_type;??/* File system type (0:N/A) */FAT文件系統的類型
?BYTE?drv;???/* Physical drive number */物理驅動號
?BYTE?n_fats;???/* Number of FATs (1 or 2) */FAT表數量
?BYTE?wflag;???/* win[] flag (b0:dirty) */win是否回寫標志
?BYTE?fsi_flag;??/* FSINFO flags (b7:disabled, b0:dirty) */FSINFO臟標志
?WORD?id;????/* File system mount ID */文件系統mountID
?WORD?n_rootdir;??/* Number of root directory entries (FAT12/16) */根目錄中的目錄項項數
?WORD?csize;???/* Cluster size [sectors] */簇數目
#if _MAX_SS != _MIN_SS
?WORD?ssize;???/* Sector size (512, 1024, 2048 or 4096) */扇區大小
#endif
#if _USE_LFN != 0
?WCHAR*?lfnbuf;???/* LFN working buffer */LFN工作緩沖
#endif
#if _FS_EXFAT
?BYTE*?dirbuf;???/* Directory entry block scratchpad buffer */目錄塊暫存
#endif
#if _FS_REENTRANT
?_SYNC_t?sobj;???/* Identifier of sync object */同步對象
#endif
#if !_FS_READONLY
?DWORD?last_clst;??/* Last allocated cluster */最后分配的簇
?DWORD?free_clst;??/* Number of free clusters */空閑簇的數量
#endif
#if _FS_RPATH != 0
?DWORD?cdir;???/* Current directory start cluster (0:root) */當前目錄的起始簇
#if _FS_EXFAT這三個不懂
?DWORD?cdc_scl;??/* Containing directory start cluster (invalid when cdir is 0) */
?DWORD?cdc_size;??/* b31-b8:Size of containing directory, b7-b0: Chain status */
?DWORD?cdc_ofs;??/* Offset in the containing directory (invalid when cdir is 0) */
#endif
#endif
?DWORD?n_fatent;??/* Number of FAT entries (number of clusters + 2) */
?DWORD?fsize;???/* Size of an FAT [sectors] */FAT表的大小(扇區數)
?DWORD?volbase;??/* Volume base sector */卷起始扇區
?DWORD?fatbase;??/* FAT base sector */FAT起始扇區
?DWORD?dirbase;??/* Root directory base sector/cluster */根目錄起始扇區
?DWORD?database;??/* Data base sector */數據起始扇區
?DWORD?winsect;??/* Current sector appearing in the win[] */保存在win[]中的當前扇區地址
?BYTE?win[_MAX_SS];?/* Disk access window for Directory, FAT (and file data at tiny cfg) */目錄和FAT分配表的緩沖區
} FATFS;
/* Object ID and allocation information (_FDID) */該結構體是后來的版本才有的,個人理解是在FILE和DIR中抽象出來的共同體,分配信息對象
typedef struct {
?FATFS*?fs;???/* Pointer to the owner file system object */
?WORD?id;???/* Owner file system mount ID */
?BYTE?attr;??/* Object attribute */
?BYTE?stat;??/* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:flagmented in this session, b2:sub-directory stretched) */
?DWORD?sclust;??/* Object start cluster (0:no cluster or root directory) */
?FSIZE_t?objsize;?/* Object size (valid when sclust != 0) */
#if _FS_EXFAT
?DWORD?n_cont;??/* Size of first fragment, clusters - 1 (valid when stat == 3) */
?DWORD?n_frag;??/* Size of last fragment needs to be written (valid when not zero) */
?DWORD?c_scl;??/* Containing directory start cluster (valid when sclust != 0) */
?DWORD?c_size;??/* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
?DWORD?c_ofs;??/* Offset in the containing directory (valid when sclust != 0 and non-directory object) */
#endif
#if _FS_LOCK != 0
?UINT?lockid;??/* File lock ID origin from 1 (index of file semaphore table Files[]) */
#endif
} _FDID;
/* File object structure (FIL) */
typedef struct {
?_FDID?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) */
?DWORD?sect;???/* Sector number appearing in buf[] (0:invalid) */
#if !_FS_READONLY
?DWORD?dir_sect;??/* Sector number containing the directory entry */
?BYTE*?dir_ptr;??/* Pointer to the directory entry in the win[] */
#endif
#if _USE_FASTSEEK
?DWORD*?cltbl;???/* Pointer to the cluster link map table (nulled on open, set by application) */
#endif
#if !_FS_TINY
?BYTE?buf[_MAX_SS];?/* File private data read/write window */
#endif
} FIL;
/* Directory object structure (DIR) */
typedef struct {
?_FDID?obj;???/* Object identifier */
?DWORD?dptr;???/* Current read/write offset */
?DWORD?clust;???/* Current cluster */
?DWORD?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 _USE_LFN != 0
?DWORD?blk_ofs;??/* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
#endif
#if _USE_FIND
?const TCHAR* pat;??/* Pointer to the name matching pattern */
#endif
} DIR;
/* File information structure (FILINFO) */
typedef struct {
?FSIZE_t?fsize;???/* File size */
?WORD?fdate;???/* Modified date */
?WORD?ftime;???/* Modified time */
?BYTE?fattrib;??/* File attribute */
#if _USE_LFN != 0
?TCHAR?altname[13];???/* Alternative file name */
?TCHAR?fname[_MAX_LFN + 1];?/* Primary file name */
#else
?TCHAR?fname[13];??/* File name */
#endif
} FILINFO;
/* File function return code (FRESULT) */
typedef enum {
?FR_OK = 0,????/* (0) Succeeded */
?FR_DISK_ERR,???/* (1) A hard error occurred in the low level disk I/O layer */
?FR_INT_ERR,????/* (2) Assertion failed */
?FR_NOT_READY,???/* (3) The physical drive cannot work */
?FR_NO_FILE,????/* (4) Could not find the file */
?FR_NO_PATH,????/* (5) Could not find the path */
?FR_INVALID_NAME,??/* (6) The path name format is invalid */
?FR_DENIED,????/* (7) Access denied due to prohibited access or directory full */
?FR_EXIST,????/* (8) Access denied due to prohibited access */
?FR_INVALID_OBJECT,??/* (9) The file/directory object is invalid */
?FR_WRITE_PROTECTED,??/* (10) The physical drive is write protected */
?FR_INVALID_DRIVE,??/* (11) The logical drive number is invalid */
?FR_NOT_ENABLED,???/* (12) The volume has no work area */
?FR_NO_FILESYSTEM,??/* (13) There is no valid FAT volume */
?FR_MKFS_ABORTED,??/* (14) The f_mkfs() aborted due to any problem */
?FR_TIMEOUT,????/* (15) Could not get a grant to access the volume within defined period */
?FR_LOCKED,????/* (16) The operation is rejected according to the file sharing policy */
?FR_NOT_ENOUGH_CORE,??/* (17) LFN working buffer could not be allocated */
?FR_TOO_MANY_OPEN_FILES,?/* (18) Number of open files > _FS_LOCK */
?FR_INVALID_PARAMETER?/* (19) Given parameter is invalid */
} FRESULT;
/*--------------------------------------------------------------*/
/* FatFs module application interface???????????????????????????*/
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode);????/* Open or create a file */
FRESULT f_close (FIL* fp);???????????/* Close an open file object */
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br);???/* Read data from the file */
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw);?/* Write data to the file */
FRESULT f_lseek (FIL* fp, FSIZE_t ofs);????????/* Move file pointer of the file object */
FRESULT f_truncate (FIL* fp);??????????/* Truncate the file */
FRESULT f_sync (FIL* fp);???????????/* Flush cached data of the writing file */
FRESULT f_opendir (DIR* dp, const TCHAR* path);??????/* Open a directory */
FRESULT f_closedir (DIR* dp);??????????/* Close an open directory */
FRESULT f_readdir (DIR* dp, FILINFO* fno);???????/* Read a directory item */
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern);?/* Find first file */
FRESULT f_findnext (DIR* dp, FILINFO* fno);???????/* Find next file */
FRESULT f_mkdir (const TCHAR* path);????????/* Create a sub directory */
FRESULT f_unlink (const TCHAR* path);????????/* Delete an existing file or directory */
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new);?/* Rename/Move a file or directory */
FRESULT f_stat (const TCHAR* path, FILINFO* fno);?????/* Get file status */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask);???/* Change attribute of a file/dir */
FRESULT f_utime (const TCHAR* path, const FILINFO* fno);???/* Change timestamp of a file/dir */
FRESULT f_chdir (const TCHAR* path);????????/* Change current directory */
FRESULT f_chdrive (const TCHAR* path);????????/* Change current drive */
FRESULT f_getcwd (TCHAR* buff, UINT len);???????/* Get current directory */
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs);?/* Get number of free clusters on the drive */
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn);?/* Get volume label */
FRESULT f_setlabel (const TCHAR* label);???????/* Set volume label */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf);?/* Forward data to the stream */
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt);?????/* Allocate a contiguous block to the file */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt);???/* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len);?/* Create a FAT volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work);???/* Divide a physical drive into some partitions */
int f_putc (TCHAR c, FIL* fp);??????????/* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp);????????/* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...);??????/* Put a formatted string to the file */
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp);??????/* Get a string from the file */
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
#define f_error(fp) ((fp)->err)
#define f_tell(fp) ((fp)->fptr)
#define f_size(fp) ((fp)->obj.objsize)
#define f_rewind(fp) f_lseek((fp), 0)
#define f_rewinddir(dp) f_readdir((dp), 0)
#define f_rmdir(path) f_unlink(path)
#ifndef EOF
#define EOF (-1)
#endif
/*--------------------------------------------------------------*/
/* Additional user defined functions????????????????????????????*/
/* RTC function */
#if !_FS_READONLY && !_FS_NORTC
DWORD get_fattime (void);
#endif
/* Unicode support functions */
#if _USE_LFN != 0??????/* Unicode - OEM code conversion */
WCHAR ff_convert (WCHAR chr, UINT dir);?/* OEM-Unicode bidirectional conversion */
WCHAR ff_wtoupper (WCHAR chr);???/* Unicode upper-case conversion */
#if _USE_LFN == 3??????/* Memory functions */
void* ff_memalloc (UINT msize);???/* Allocate memory block */
void ff_memfree (void* mblock);???/* Free memory block */
#endif
#endif
/* Sync functions */
#if _FS_REENTRANT
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj);?/* Create a sync object */
int ff_req_grant (_SYNC_t sobj);????/* Lock sync object */
void ff_rel_grant (_SYNC_t sobj);????/* Unlock sync object */
int ff_del_syncobj (_SYNC_t sobj);????/* Delete a sync object */
#endif
/*--------------------------------------------------------------*/
/* 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_EXFAT?0x04
#define FM_ANY??0x07
#define FM_SFD??0x08
/* Filesystem type (FATFS.fs_type) */
#define FS_FAT12?1
#define FS_FAT16?2
#define FS_FAT32?3
#define FS_EXFAT?4
/* File attribute bits for directory entry (FILINFO.fattrib) */
#define?AM_RDO?0x01?/* Read only */
#define?AM_HID?0x02?/* Hidden */
#define?AM_SYS?0x04?/* System */
#define AM_DIR?0x10?/* Directory */
#define AM_ARC?0x20?/* Archive */
4、ff.c(部分內容)
f_mkfs函數,比較重要
/*-----------------------------------------------------------------------*/
/* Create an FAT/exFAT volume????????????????????????????????????????????*/
/*-----------------------------------------------------------------------*/
FRESULT f_mkfs (
?const TCHAR* path,?/* Logical drive number */
?BYTE opt,???/* Format option */
?DWORD au,???/* Size of allocation unit (cluster) [byte] */
?void* work,???/* Pointer to working buffer */
?UINT len???/* Size of working buffer */
)
{
?const UINT n_fats = 2;??/* Number of FATs for FAT12/16/32 volume (1 or 2) */
?const UINT n_rootdir = 512;?/* Number of root directory entries for FAT12/16 volume */
?static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0};?/* Cluster size boundary for FAT12/16 volume (4Ks unit) */
?static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0};?/* Cluster size boundary for FAT32 volume (128Ks unit) */
?BYTE fmt, sys, *buf, *pte, pdrv, part;
?WORD ss;
?DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n;
?DWORD b_vol, b_fat, b_data;????/* Base LBA for volume, fat, data */
?DWORD sz_vol, sz_rsv, sz_fat, sz_dir;?/* Size for volume, fat, dir, data */
?UINT i;
?int vol;
?DSTATUS stat;
#if _USE_TRIM || _FS_EXFAT
?DWORD tbl[3];
#endif
?/* Check mounted drive and clear work area */
?vol = get_ldnumber(&path);?????/* Get target logical drive */
?if (vol < 0) return FR_INVALID_DRIVE;
?if (FatFs[vol]) FatFs[vol]->fs_type = 0;?/* Clear the volume */
?pdrv = LD2PD(vol);?/* Physical drive */
?part = LD2PT(vol);?/* Partition (0:create as new, 1-4:get from partition table) */
?/* Check physical drive status */
?stat = disk_initialize(pdrv);
?if (stat & STA_NOINIT) return FR_NOT_READY;
?if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
?if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1;?/* Erase block to align data area */
#if _MAX_SS != _MIN_SS??/* Get sector size of the medium if variable sector size cfg. */
?if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR;
?if (ss > _MAX_SS || ss < _MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR;
#else
?ss = _MAX_SS;
#endif
?if ((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER;?/* Check if au is valid */
?au /= ss;?/* Cluster size in unit of sector */
?/* Get working buffer */
?buf = (BYTE*)work;??/* Working buffer */
?sz_buf = len / ss;??/* Size of working buffer (sector) */
?szb_buf = sz_buf * ss;?/* Size of working buffer (byte) */
?if (!szb_buf) return FR_MKFS_ABORTED;
?/* Determine where the volume to be located (b_vol, sz_vol) */
?if (_MULTI_PARTITION && part != 0) {
??/* Get partition information from partition table in the MBR */
??if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR;?/* Load MBR */
??if (ld_word(buf + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED;?/* Check if MBR is valid */
??pte = buf + (MBR_Table + (part - 1) * SZ_PTE);
??if (!pte[PTE_System]) return FR_MKFS_ABORTED;?/* No partition? */
??b_vol = ld_dword(pte + PTE_StLba);??/* Get volume start sector */
??sz_vol = ld_dword(pte + PTE_SizLba);?/* Get volume size */
?} else {
??/* Create a single-partition in this function */
??if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) return FR_DISK_ERR;
??b_vol = (opt & FM_SFD) ? 0 : 63;??/* Volume start sector */
??if (sz_vol < b_vol) return FR_MKFS_ABORTED;
??sz_vol -= b_vol;??????/* Volume size */
?}
?if (sz_vol < 128) return FR_MKFS_ABORTED;?/* Check if volume size is >=128s */
?/* Pre-determine the FAT type */
?do {
??if (_FS_EXFAT && (opt & FM_EXFAT)) {?/* exFAT possible? */
???if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) {?/* exFAT only, vol >= 64Ms or au > 128s ? */
????fmt = FS_EXFAT; break;
???}
??}
??if (au > 128) return FR_INVALID_PARAMETER;?/* Too large au for FAT/FAT32 */
??if (opt & FM_FAT32) {?/* FAT32 possible? */
???if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) {?/* FAT32 only or no-FAT? */
????fmt = FS_FAT32; break;
???}
??}
??if (!(opt & FM_FAT)) return FR_INVALID_PARAMETER;?/* no-FAT? */
??fmt = FS_FAT16;
?} while (0);
#if _FS_EXFAT
?if (fmt == FS_EXFAT) {?/* Create an exFAT volume */
??DWORD szb_bit, szb_case, sum, nb, cl;
??WCHAR ch, si;
??UINT j, st;
??BYTE b;
??if (sz_vol < 0x1000) return FR_MKFS_ABORTED;?/* Too small volume? */
#if _USE_TRIM
??tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1;?/* Inform the device the volume area may be erased */
??disk_ioctl(pdrv, CTRL_TRIM, tbl);
#endif
??/* Determine FAT location, data location and number of clusters */
??if (!au) {?/* au auto-selection */
???au = 8;
???if (sz_vol >= 0x80000) au = 64;??/* >= 512Ks */
???if (sz_vol >= 0x4000000) au = 256;?/* >= 64Ms */
??}
??b_fat = b_vol + 32;??????????/* FAT start at offset 32 */
??sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss;???/* Number of FAT sectors */
??b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1);?/* Align data area to the erase block boundary */
??if (b_data >= sz_vol / 2) return FR_MKFS_ABORTED;??/* Too small volume? */
??n_clst = (sz_vol - (b_data - b_vol)) / au;????/* Number of clusters */
??if (n_clst <16) return FR_MKFS_ABORTED;?????/* Too few clusters? */
??if (n_clst > MAX_EXFAT) return FR_MKFS_ABORTED;???/* Too many clusters? */
??szb_bit = (n_clst + 7) / 8;??????/* Size of allocation bitmap */
??tbl[0] = (szb_bit + au * ss - 1) / (au * ss);?/* Number of allocation bitmap clusters */
??/* Create a compressed up-case table */
??sect = b_data + au * tbl[0];?/* Table start sector */
??sum = 0;??????/* Table checksum to be stored in the 82 entry */
??st = si = i = j = szb_case = 0;
??do {
???switch (st) {
???case 0:
????ch = ff_wtoupper(si);?/* Get an up-case char */
????if (ch != si) {
?????si++; break;??/* Store the up-case char if exist */
????}
????for (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ;?/* Get run length of no-case block */
????if (j >= 128) {
?????ch = 0xFFFF; st = 2; break;?/* Compress the no-case block if run is >= 128 */
????}
????st = 1;???/* Do not compress short run */
????/* go to next case */
???case 1:
????ch = si++;??/* Fill the short run */
????if (--j == 0) st = 0;
????break;
???default:
????ch = (WCHAR)j; si += j;?/* Number of chars to skip */
????st = 0;
???}
???sum = xsum32(buf[i + 0] = (BYTE)ch, sum);??/* Put it into the write buffer */
???sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum);
???i += 2; szb_case += 2;
???if (!si || i == szb_buf) {??/* Write buffered data when buffer full or end of process */
????n = (i + ss - 1) / ss;
????if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR;
????sect += n; i = 0;
???}
??} while (si);
??tbl[1] = (szb_case + au * ss - 1) / (au * ss);?/* Number of up-case table clusters */
??tbl[2] = 1;??????????/* Number of root dir clusters */
??/* Initialize the allocation bitmap */
??sect = b_data; nsect = (szb_bit + ss - 1) / ss;?/* Start of bitmap and number of sectors */
??nb = tbl[0] + tbl[1] + tbl[2];?????/* Number of clusters in-use by system */
??do {
???mem_set(buf, 0, szb_buf);
???for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ;
???for (b = 1; nb && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ;
???n = (nsect > sz_buf) ? sz_buf : nsect;??/* Write the buffered data */
???if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR;
???sect += n; nsect -= n;
??} while (nsect);
??/* Initialize the FAT */
??sect = b_fat; nsect = sz_fat;?/* Start of FAT and number of FAT sectors */
??j = nb = cl = 0;
??do {
???mem_set(buf, 0, szb_buf); i = 0;?/* Clear work area and reset write index */
???if (cl == 0) {?/* Set entry 0 and 1 */
????st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++;
????st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++;
???}
???do {???/* Create chains of bitmap, up-case and root dir */
????while (nb && i < szb_buf) {???/* Create a chain */
?????st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF);
?????i += 4; cl++; nb--;
????}
????if (!nb && j < 3) nb = tbl[j++];?/* Next chain */
???} while (nb && i < szb_buf);
???n = (nsect > sz_buf) ? sz_buf : nsect;?/* Write the buffered data */
???if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR;
???sect += n; nsect -= n;
??} while (nsect);
??/* Initialize the root directory */
??mem_set(buf, 0, szb_buf);
??buf[SZDIRE * 0 + 0] = 0x83;??/* 83 entry (volume label) */
??buf[SZDIRE * 1 + 0] = 0x81;??/* 81 entry (allocation bitmap) */
??st_dword(buf + SZDIRE * 1 + 20, 2);
??st_dword(buf + SZDIRE * 1 + 24, szb_bit);
??buf[SZDIRE * 2 + 0] = 0x82;??/* 82 entry (up-case table) */
??st_dword(buf + SZDIRE * 2 + 4, sum);
??st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]);
??st_dword(buf + SZDIRE * 2 + 24, szb_case);
??sect = b_data + au * (tbl[0] + tbl[1]);?nsect = au;?/* Start of the root directory and number of sectors */
??do {?/* Fill root directory sectors */
???n = (nsect > sz_buf) ? sz_buf : nsect;
???if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR;
???mem_set(buf, 0, ss);
???sect += n; nsect -= n;
??} while (nsect);
??/* Create two set of the exFAT VBR blocks */
??sect = b_vol;
??for (n = 0; n < 2; n++) {
???/* Main record (+0) */
???mem_set(buf, 0, ss);
???mem_cpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT???", 11);?/* Boot jump code (x86), OEM name */
???st_dword(buf + BPB_VolOfsEx, b_vol);?????/* Volume offset in the physical drive [sector] */
???st_dword(buf + BPB_TotSecEx, sz_vol);?????/* Volume size [sector] */
???st_dword(buf + BPB_FatOfsEx, b_fat - b_vol);???/* FAT offset [sector] */
???st_dword(buf + BPB_FatSzEx, sz_fat);?????/* FAT size [sector] */
???st_dword(buf + BPB_DataOfsEx, b_data - b_vol);???/* Data offset [sector] */
???st_dword(buf + BPB_NumClusEx, n_clst);?????/* Number of clusters */
???st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]);?/* Root dir cluster # */
???st_dword(buf + BPB_VolIDEx, GET_FATTIME());????/* VSN */
???st_word(buf + BPB_FSVerEx, 0x100);??????/* File system version (1.00) */
???for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ;?/* Log2 of sector size [byte] */
???for (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ;?/* Log2 of cluster size [sector] */
???buf[BPB_NumFATsEx] = 1;?????/* Number of FATs */
???buf[BPB_DrvNumEx] = 0x80;????/* Drive number (for int13) */
???st_word(buf + BS_BootCodeEx, 0xFEEB);?/* Boot code (x86) */
???st_word(buf + BS_55AA, 0xAA55);???/* Signature (placed here regardless of sector size) */
???for (i = sum = 0; i < ss; i++) {??/* VBR checksum */
????if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum);
???}
???if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR;
???/* Extended bootstrap record (+1..+8) */
???mem_set(buf, 0, ss);
???st_word(buf + ss - 2, 0xAA55);?/* Signature (placed at end of sector) */
???for (j = 1; j < 9; j++) {
????for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ;?/* VBR checksum */
????if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR;
???}
???/* OEM/Reserved record (+9..+10) */
???mem_set(buf, 0, ss);
???for ( ; j < 11; j++) {
????for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ;?/* VBR checksum */
????if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR;
???}
???/* Sum record (+11) */
???for (i = 0; i < ss; i += 4) st_dword(buf + i, sum);??/* Fill with checksum value */
???if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR;
??}
?} else
#endif?/* _FS_EXFAT */
?{?/* Create an FAT12/16/32 volume */
??do {
???pau = au;
???/* Pre-determine number of clusters and FAT sub-type */
???if (fmt == FS_FAT32) {?/* FAT32 volume */
????if (!pau) {?/* au auto-selection */
?????n = sz_vol / 0x20000;?/* Volume size in unit of 128KS */
?????for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ;?/* Get from table */
????}
????n_clst = sz_vol / pau;?/* Number of clusters */
????sz_fat = (n_clst * 4 + 8 + ss - 1) / ss;?/* FAT size [sector] */
????sz_rsv = 32;?/* Number of reserved sectors */
????sz_dir = 0;??/* No static directory */
????if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) return FR_MKFS_ABORTED;
???} else {????/* FAT12/16 volume */
????if (!pau) {?/* au auto-selection */
?????n = sz_vol / 0x1000;?/* Volume size in unit of 4KS */
?????for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ;?/* Get from table */
????}
????n_clst = sz_vol / pau;
????if (n_clst > MAX_FAT12) {
?????n = n_clst * 2 + 4;??/* FAT size [byte] */
????} else {
?????fmt = FS_FAT12;
?????n = (n_clst * 3 + 1) / 2 + 3;?/* FAT size [byte] */
????}
????sz_fat = (n + ss - 1) / ss;??/* FAT size [sector] */
????sz_rsv = 1;??????/* Number of reserved sectors */
????sz_dir = (DWORD)n_rootdir * SZDIRE / ss;?/* Rootdir size [sector] */
???}
???b_fat = b_vol + sz_rsv;??????/* FAT base */
???b_data = b_fat + sz_fat * n_fats + sz_dir;?/* Data base */
???/* Align data base to erase block boundary (for flash memory media) */
???n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data;?/* Next nearest erase block from current data base */
???if (fmt == FS_FAT32) {??/* FAT32: Move FAT base */
????sz_rsv += n; b_fat += n;
???} else {?????/* FAT12/16: Expand FAT size */
????sz_fat += n / n_fats;
???}
???/* Determine number of clusters and final check of validity of the FAT sub-type */
???if (sz_vol < b_data + pau * 16 - b_vol) return FR_MKFS_ABORTED;?/* Too small volume */
???n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau;
???if (fmt == FS_FAT32) {
????if (n_clst <= MAX_FAT16) {?/* Too few clusters for FAT32 */
?????if (!au && (au = pau / 2) != 0) continue;?/* Adjust cluster size and retry */
?????return FR_MKFS_ABORTED;
????}
???}
???if (fmt == FS_FAT16) {
????if (n_clst > MAX_FAT16) {?/* Too many clusters for FAT16 */
?????if (!au && (pau * 2) <= 64) {
??????au = pau * 2; continue;??/* Adjust cluster size and retry */
?????}
?????if ((opt & FM_FAT32)) {
??????fmt = FS_FAT32; continue;?/* Switch type to FAT32 and retry */
?????}
?????if (!au && (au = pau * 2) <= 128) continue;?/* Adjust cluster size and retry */
?????return FR_MKFS_ABORTED;
????}
????if??(n_clst <= MAX_FAT12) {?/* Too few clusters for FAT16 */
?????if (!au && (au = pau * 2) <= 128) continue;?/* Adjust cluster size and retry */
?????return FR_MKFS_ABORTED;
????}
???}
???if (fmt == FS_FAT12 && n_clst > MAX_FAT12) return FR_MKFS_ABORTED;?/* Too many clusters for FAT12 */
???/* Ok, it is the valid cluster configuration */
???break;
??} while (1);
#if _USE_TRIM
??tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1;?/* Inform the device the volume area can be erased */
??disk_ioctl(pdrv, CTRL_TRIM, tbl);
#endif
??/* Create FAT VBR */
??mem_set(buf, 0, ss);
??mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code (x86), OEM name */
??st_word(buf + BPB_BytsPerSec, ss);????/* Sector size [byte] */
??buf[BPB_SecPerClus] = (BYTE)pau;????/* Cluster size [sector] */
??st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv);?/* Size of reserved area */
??buf[BPB_NumFATs] = (BYTE)n_fats;????/* Number of FATs */
??st_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir));?/* Number of root directory entries */
??if (sz_vol < 0x10000) {
???st_word(buf + BPB_TotSec16, (WORD)sz_vol);?/* Volume size in 16-bit LBA */
??} else {
???st_dword(buf + BPB_TotSec32, sz_vol);??/* Volume size in 32-bit LBA */
??}
??buf[BPB_Media] = 0xF8;???????/* Media descriptor byte */
??st_word(buf + BPB_SecPerTrk, 63);????/* Number of sectors per track (for int13) */
??st_word(buf + BPB_NumHeads, 255);????/* Number of heads (for int13) */
??st_dword(buf + BPB_HiddSec, b_vol);????/* Volume offset in the physical drive [sector] */
??if (fmt == FS_FAT32) {
???st_dword(buf + BS_VolID32, GET_FATTIME());?/* VSN */
???st_dword(buf + BPB_FATSz32, sz_fat);??/* FAT size [sector] */
???st_dword(buf + BPB_RootClus32, 2);???/* Root directory cluster # (2) */
???st_word(buf + BPB_FSInfo32, 1);????/* Offset of FSINFO sector (VBR + 1) */
???st_word(buf + BPB_BkBootSec32, 6);???/* Offset of backup VBR (VBR + 6) */
???buf[BS_DrvNum32] = 0x80;?????/* Drive number (for int13) */
???buf[BS_BootSig32] = 0x29;?????/* Extended boot signature */
???mem_cpy(buf + BS_VolLab32, "NO NAME????" "FAT32???", 19);?/* Volume label, FAT signature */
??} else {
???st_dword(buf + BS_VolID, GET_FATTIME());?/* VSN */
???st_word(buf + BPB_FATSz16, (WORD)sz_fat);?/* FAT size [sector] */
???buf[BS_DrvNum] = 0x80;??????/* Drive number (for int13) */
???buf[BS_BootSig] = 0x29;??????/* Extended boot signature */
???mem_cpy(buf + BS_VolLab, "NO NAME????" "FAT?????", 19);?/* Volume label, FAT signature */
??}
??st_word(buf + BS_55AA, 0xAA55);?????/* Signature (offset is fixed here regardless of sector size) */
??if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) return FR_DISK_ERR;?/* Write it to the VBR sector */
??/* Create FSINFO record if needed */
??if (fmt == FS_FAT32) {
???disk_write(pdrv, buf, b_vol + 6, 1);??/* Write backup VBR (VBR + 6) */
???mem_set(buf, 0, ss);
???st_dword(buf + FSI_LeadSig, 0x41615252);
???st_dword(buf + FSI_StrucSig, 0x61417272);
???st_dword(buf + FSI_Free_Count, n_clst - 1);?/* Number of free clusters */
???st_dword(buf + FSI_Nxt_Free, 2);???/* Last allocated cluster# */
???st_word(buf + BS_55AA, 0xAA55);
???disk_write(pdrv, buf, b_vol + 7, 1);??/* Write backup FSINFO (VBR + 7) */
???disk_write(pdrv, buf, b_vol + 1, 1);??/* Write original FSINFO (VBR + 1) */
??}
??/* Initialize FAT area */
??mem_set(buf, 0, (UINT)szb_buf);
??sect = b_fat;??/* FAT start sector */
??for (i = 0; i < n_fats; i++) {???/* Initialize FATs each */
???if (fmt == FS_FAT32) {
????st_dword(buf + 0, 0xFFFFFFF8);?/* Entry 0 */
????st_dword(buf + 4, 0xFFFFFFFF);?/* Entry 1 */
????st_dword(buf + 8, 0x0FFFFFFF);?/* Entry 2 (root directory) */
???} else {
????st_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8);?/* Entry 0 and 1 */
???}
???nsect = sz_fat;??/* Number of FAT sectors */
???do {?/* Fill FAT sectors */
????n = (nsect > sz_buf) ? sz_buf : nsect;
????if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR;
????mem_set(buf, 0, ss);
????sect += n; nsect -= n;
???} while (nsect);
??}
??/* Initialize root directory (fill with zero) */
??nsect = (fmt == FS_FAT32) ? pau : sz_dir;?/* Number of root directory sectors */
??do {
???n = (nsect > sz_buf) ? sz_buf : nsect;
???if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR;
???sect += n; nsect -= n;
??} while (nsect);
?}
?/* Determine system ID in the partition table */
?if (_FS_EXFAT && fmt == FS_EXFAT) {
??sys = 0x07;???/* HPFS/NTFS/exFAT */
?} else {
??if (fmt == FS_FAT32) {
???sys = 0x0C;??/* FAT32X */
??} else {
???if (sz_vol >= 0x10000) {
????sys = 0x06;?/* FAT12/16 (>=64KS) */
???} else {
????sys = (fmt == FS_FAT16) ? 0x04 : 0x01;?/* FAT16 (<64KS) : FAT12 (<64KS) */
???}
??}
?}
?/* Update partition information */
?if (_MULTI_PARTITION && part != 0) {?/* Created in the existing partition */
??/* Update system ID in the partition table */
??if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR;?/* Read the MBR */
??buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys;??/* Set system ID */
??if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR;?/* Write it back to the MBR */
?} else {????????/* Created as a new single partition */
??if (!(opt & FM_SFD)) {?/* Create partition table if in FDISK format */
???mem_set(buf, 0, ss);
???st_word(buf + BS_55AA, 0xAA55);??/* MBR signature */
???pte = buf + MBR_Table;????/* Create partition table for single partition in the drive */
???pte[PTE_Boot] = 0;?????/* Boot indicator */
???pte[PTE_StHead] = 1;????/* Start head */
???pte[PTE_StSec] = 1;?????/* Start sector */
???pte[PTE_StCyl] = 0;?????/* Start cylinder */
???pte[PTE_System] = sys;????/* System type */
???n = (b_vol + sz_vol) / (63 * 255);?/* (End CHS may be invalid) */
???pte[PTE_EdHead] = 254;????/* End head */
???pte[PTE_EdSec] = (BYTE)(n >> 2 | 63);?/* End sector */
???pte[PTE_EdCyl] = (BYTE)n;???/* End cylinder */
???st_dword(pte + PTE_StLba, b_vol);?/* Start offset in LBA */
???st_dword(pte + PTE_SizLba, sz_vol);?/* Size in sectors */
???if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR;?/* Write it to the MBR */
??}
?}
?if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) return FR_DISK_ERR;
?return FR_OK;
}
f_mount函數
/*---------------------------------------------------------------------------
???Public Functions (FatFs API)
----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/* Mount/Unmount a Logical Drive?????????????????????????????????????????*/
/*-----------------------------------------------------------------------*/
FRESULT f_mount (
?FATFS* fs,???/* Pointer to the file system object (NULL:unmount)*/
?const TCHAR* path,?/* Logical drive number to be mounted/unmounted */
?BYTE opt???/* Mode option 0:Do not mount (delayed mount), 1:Mount immediately */
)
{
?FATFS *cfs;
?int vol;
?FRESULT res;
?const TCHAR *rp = path;
?/* Get logical drive number */
?vol = get_ldnumber(&rp);
?if (vol < 0) return FR_INVALID_DRIVE;
?cfs = FatFs[vol];?????/* Pointer to fs object */
?if (cfs) {
#if _FS_LOCK != 0
??clear_lock(cfs);
#endif
#if _FS_REENTRANT??????/* Discard sync object of the current volume */
??if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR;
#endif
??cfs->fs_type = 0;????/* Clear old fs object */
?}
?if (fs) {
??fs->fs_type = 0;????/* Clear new fs object */
#if _FS_REENTRANT??????/* Create sync object for the new volume */
??if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR;
#endif
?}
?FatFs[vol] = fs;?????/* Register new fs object */
?if (!fs || opt != 1) return FR_OK;?/* Do not mount now, it will be mounted later */
?res = find_volume(&path, &fs, 0);?/* Force mounted the volume */
?LEAVE_FF(fs, res);
}
這里面最重要的find_volume函數就不粘貼了,太多了……
5、diskio.h
#define _USE_WRITE?1?/* 1: Enable disk_write function */
#define _USE_IOCTL?1?/* 1: Enable disk_ioctl function */
#include "integer.h"
/* Status of Disk Functions */
typedef BYTE?DSTATUS;
/* Results of Disk Functions */
typedef enum {
?RES_OK = 0,??/* 0: Successful */
?RES_ERROR,??/* 1: R/W Error */
?RES_WRPRT,??/* 2: Write Protected */
?RES_NOTRDY,??/* 3: Not Ready */
?RES_PARERR??/* 4: Invalid Parameter */
} DRESULT;
/*---------------------------------------*/
/* Prototypes for disk control functions */
DSTATUS disk_initialize (BYTE pdrv);
DSTATUS disk_status (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
DWORD get_fattime (void);
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT??0x01?/* Drive not initialized */
#define STA_NODISK??0x02?/* No medium in the drive */
#define STA_PROTECT??0x04?/* Write protected */
/* Command code for disk_ioctrl fucntion */
/* Generic command (Used by FatFs) */
#define CTRL_SYNC??0?/* Complete pending write process (needed at _FS_READONLY == 0) */
#define GET_SECTOR_COUNT?1?/* Get media size (needed at _USE_MKFS == 1) */
#define GET_SECTOR_SIZE??2?/* Get sector size (needed at _MAX_SS != _MIN_SS) */
#define GET_BLOCK_SIZE??3?/* Get erase block size (needed at _USE_MKFS == 1) */
#define CTRL_TRIM??4?/* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
/* Generic command (Not used by FatFs) */
#define CTRL_POWER???5?/* Get/Set power status */
#define CTRL_LOCK???6?/* Lock/Unlock media removal */
#define CTRL_EJECT???7?/* Eject media */
#define CTRL_FORMAT???8?/* Create physical format on the media */
/* MMC/SDC specific ioctl command */
#define MMC_GET_TYPE??10?/* Get card type */
#define MMC_GET_CSD???11?/* Get CSD */
#define MMC_GET_CID???12?/* Get CID */
#define MMC_GET_OCR???13?/* Get OCR */
#define MMC_GET_SDSTAT??14?/* Get SD status */
/* ATA/CF specific ioctl command */
#define ATA_GET_REV???20?/* Get F/W revision */
#define ATA_GET_MODEL??21?/* Get model name */
#define ATA_GET_SN???22?/* Get serial number */
6、diskio.c文件
DSTATUS disk_status (
?BYTE pdrv??/* Physical drive number to identify the drive */
)
{
??DSTATUS stat;
??stat = disk.drv[pdrv]->disk_status(disk.lun[pdrv]);
??return stat;
}
/**
??* @brief??Initializes a Drive
??* @param??pdrv: Physical drive number (0..)
??* @retval DSTATUS: Operation status
??*/
DSTATUS disk_initialize (
?BYTE pdrv????/* Physical drive nmuber to identify the drive */
)
{
??DSTATUS stat = RES_OK;
??if(disk.is_initialized[pdrv] == 0)
??{
????disk.is_initialized[pdrv] = 1;
????stat = disk.drv[pdrv]->disk_initialize(disk.lun[pdrv]);
??}
??return stat;
}
/**
??* @brief??Reads Sector(s)
??* @param??pdrv: Physical drive number (0..)
??* @param??*buff: Data buffer to store read data
??* @param??sector: Sector address (LBA)
??* @param??count: Number of sectors to read (1..128)
??* @retval DRESULT: Operation result
??*/
DRESULT disk_read (
?BYTE pdrv,??/* Physical drive nmuber to identify the drive */
?BYTE *buff,??/* Data buffer to store read data */
?DWORD sector,?????????/* Sector address in LBA */
?UINT count??/* Number of sectors to read */
)
{
??DRESULT res;
??res = disk.drv[pdrv]->disk_read(disk.lun[pdrv], buff, sector, count);
??return res;
}
/**
??* @brief??Writes Sector(s)
??* @param??pdrv: Physical drive number (0..)
??* @param??*buff: Data to be written
??* @param??sector: Sector address (LBA)
??* @param??count: Number of sectors to write (1..128)
??* @retval DRESULT: Operation result
??*/
#if _USE_WRITE == 1
DRESULT disk_write (
?BYTE pdrv,??/* Physical drive nmuber to identify the drive */
?const BYTE *buff,?/* Data to be written */
?DWORD sector,??/* Sector address in LBA */
?UINT count?????????/* Number of sectors to write */
)
{
??DRESULT res;
??res = disk.drv[pdrv]->disk_write(disk.lun[pdrv], buff, sector, count);
??return res;
}
#endif /* _USE_WRITE == 1 */
/**
??* @brief??I/O control operation
??* @param??pdrv: Physical drive number (0..)
??* @param??cmd: Control code
??* @param??*buff: Buffer to send/receive control data
??* @retval DRESULT: Operation result
??*/
#if _USE_IOCTL == 1
DRESULT disk_ioctl (
?BYTE pdrv,??/* Physical drive nmuber (0..) */
?BYTE cmd,??/* Control code */
?void *buff??/* Buffer to send/receive control data */
)
{
??DRESULT res;
??res = disk.drv[pdrv]->disk_ioctl(disk.lun[pdrv], cmd, buff);
??return res;
}
#endif /* _USE_IOCTL == 1 */
/**
??* @brief??Gets Time from RTC
??* @param??None
??* @retval Time in DWORD
??*/
__weak DWORD get_fattime (void)
{
??return 0;
}
上面就是整個文件系統我的理解添加的注釋
1. FatFs中有兩個重要的緩沖區:win[]和buffer。win[]在FATFS結構體中,buffer在FIL結構體中。
????win[]:系統緩沖區。當操作MBR,DBR,FAT表,根目錄區時,使用該緩沖區;
????buffer:文件緩沖區。當對文件的內容進行操作時,如讀、寫、修改時,才使用該緩沖區。
2. 在對文件的f_read和f_write過程中(不考慮f_lseek的情況),只有需要讀寫的最后一個扇區(內容小于512字節)才會被暫存到buffer中,而前面的扇區內容是直接通過磁盤驅動disk_read/disk_write在用戶緩沖區和物理磁盤之間進行交互的。
---------------------?
作者:m0_37580896?
來源:CSDN?
原文:https://blog.csdn.net/m0_37580896/article/details/79753135?
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!
總結
以上是生活随笔為你收集整理的【转载】【FS】FATFS文件系统介绍(未完待续........2018.4.1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 二维数组动态分配内存
- 下一篇: [转载] FatFs模块功能配置选项