日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

FatFs源码分析

發(fā)布時(shí)間:2025/3/15 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 FatFs源码分析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
#include "ff.h" #include "diskio.h"/* 擴(kuò)展字符范圍 */ #define _DF1S 0x81 #define _DF1E 0xFE #define _DS1S 0x40 #define _DS1E 0x7E #define _DS2S 0x80 #define _DS2E 0xFE/* 字符類型相關(guān)宏定義 */ #define IsUpper(c) (((c)>='A')&&((c)<='Z')) #define IsLower(c) (((c)>='a')&&((c)<='z')) #define IsDigit(c) (((c)>='0')&&((c)<='9'))/* 是否是擴(kuò)展字符 */ #define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) #define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))/* 文件屬性位 */ #define AM_VOL 0x08 /* 卷標(biāo) */ #define AM_LFN 0x0F /* 長(zhǎng)文件名 */ #define AM_MASK 0x3F /* 屬性有效位掩碼 *//* Additional file access control and file status flags for internal use */ #define FA_SEEKEND 0x20 /* 打開(kāi)文件的時(shí)候?qū)⑵屏恐赶蛭募Y(jié)果 */ #define FA_MODIFIED 0x40 /* 文件已經(jīng)被修改 */ #define FA_DIRTY 0x80 /* 數(shù)據(jù)緩沖窗口數(shù)據(jù)需要回寫 *//* Name status flags in fn[] */ #define NSFLAG 11 /* 路徑名狀態(tài)字節(jié)偏移量 */ #define NS_LOSS 0x01 /* Out of 8.3 format */ #define NS_LFN 0x02 /* Force to create LFN entry */ #define NS_LAST 0x04 /* 最后一段路徑 */ #define NS_BODY 0x08 /* Lower case flag (body) */ #define NS_EXT 0x10 /* Lower case flag (ext) */ #define NS_DOT 0x20 /* Dot entry */ #define NS_NOLFN 0x40 /* Do not find LFN */ #define NS_NONAME 0x80 /* 無(wú)文件名 *//* 限制和邊界 */ #define MAX_DIR 0x200000 /* FAT最大目錄項(xiàng)數(shù) */ #define MAX_DIR_EX 0x10000000 /* exFAT最大目錄項(xiàng)數(shù) */ #define MAX_FAT12 0xFF5 /* FAT12最大簇?cái)?shù) */ #define MAX_FAT16 0xFFF5 /* FAT16最大簇?cái)?shù) */ #define MAX_FAT32 0x0FFFFFF5 /* FAT32最大簇?cái)?shù) */ #define MAX_EXFAT 0x7FFFFFFD /* exFAT最大簇?cái)?shù) *//* boot扇區(qū)各字段偏移量 */ #define BS_JmpBoot 0 /* x86跳轉(zhuǎn)指令 */ #define BS_OEMName 3 /* 創(chuàng)建該卷的系統(tǒng)的名稱 */ #define BPB_BytsPerSec 11 /* FAT12/16:扇區(qū)大小 FAT32:0 */ #define BPB_SecPerClus 13 /* 簇的扇區(qū)數(shù) */ #define BPB_RsvdSecCnt 14 /* 保留區(qū)的扇區(qū)數(shù) */ #define BPB_NumFATs 16 /* FAT表個(gè)數(shù) */ #define BPB_RootEntCnt 17 /* FAT12/16:根目錄中目錄項(xiàng)個(gè)數(shù) FAT32:0 */ #define BPB_TotSec16 19 /* FAT12/16卷的總扇區(qū)數(shù) FAT32:0 */ #define BPB_Media 21 /* 媒體確定,不再用于任何目的 */ #define BPB_FATSz16 22 /* FAT占用的扇區(qū)數(shù) */ #define BPB_SecPerTrk 24 /* 每個(gè)軌道的扇區(qū)數(shù) */ #define BPB_NumHeads 26 /* 磁頭數(shù) */ #define BPB_HiddSec 28 /* FAT卷之前隱藏的物理扇區(qū)數(shù) */ #define BPB_TotSec32 32 /* FAT32卷的總扇區(qū)數(shù) */ #define BS_DrvNum 36 /* 驅(qū)動(dòng)器號(hào) */ #define BS_NTres 37 /* 保留 */ #define BS_BootSig 38 /* 擴(kuò)展引導(dǎo)簽名 */ #define BS_VolID 39 /* 卷序列號(hào) */ #define BS_VolLab 43 /* 卷標(biāo) */ #define BS_FilSysType 54 /* 取值"FAT12", "FAT16" or "FAT"之一 */ #define BS_BootCode 62 /* Bootstrap程序 */ #define BS_55AA 510 /* 引導(dǎo)簽名 */#define BPB_FATSz32 36 /* FAT32:FAT占用的扇區(qū)數(shù) */ #define BPB_ExtFlags32 40 /* FAT32:Extended flags (WORD) */ #define BPB_FSVer32 42 /* FAT32:版本 */ #define BPB_RootClus32 44 /* FAT32:根目錄起始簇號(hào) */ #define BPB_FSInfo32 48 /* FAT32:FSInfo的扇區(qū)相對(duì)于FAT32卷的頂部的偏移 */ #define BPB_BkBootSec32 50 /* FAT32:備份引導(dǎo)扇區(qū)相對(duì)于FAT32卷頂部的偏移扇區(qū) */ #define BS_DrvNum32 64 /* FAT32:驅(qū)動(dòng)器號(hào) */ #define BS_NTres32 65 /* FAT32:保留 */ #define BS_BootSig32 66 /* FAT32:擴(kuò)展引導(dǎo)簽名 */ #define BS_VolID32 67 /* FAT32:卷序列號(hào) */ #define BS_VolLab32 71 /* FAT32:卷標(biāo) */ #define BS_FilSysType32 82 /* FAT32:取值"FAT32" */ #define BS_BootCode32 90 /* FAT32:引導(dǎo)簽名 *//* 目錄項(xiàng)各字段偏移量 */ #define DIR_Name 0 /* 短文件名 */ #define DIR_Attr 11 /* 屬性 */ #define DIR_NTres 12 /* 0x08:文件名為小寫 0x10:擴(kuò)展名為小寫 */ #define DIR_CrtTime10 13 /* 創(chuàng)建時(shí)間分辨率 */ #define DIR_CrtTime 14 /* 創(chuàng)建時(shí)間 */ #define DIR_LstAccDate 18 /* 上次訪問(wèn)日期 */ #define DIR_FstClusHI 20 /* 文件起始簇號(hào)高16位 */ #define DIR_ModTime 22 /* 修改時(shí)間 */ #define DIR_FstClusLO 26 /* 文件起始簇號(hào)低16位 */ #define DIR_FileSize 28 /* 文件大小(字節(jié)) *//* 目錄項(xiàng)相關(guān)定義 */ #define SZDIRE 32 /* 目錄項(xiàng)大小 */ #define DDEM 0xE5 /* 目錄項(xiàng)未被使用(刪除),(0:最后一個(gè)目錄項(xiàng) 0xE5:不一定最后一個(gè)目錄項(xiàng)) */ #define RDDEM 0x05 /* 文件名第一個(gè)字符為0xE5,則替換成0x05 *//* FSInfo各字段偏移量 */ #define FSI_LeadSig 0 /* FSInfo的主要簽名 */ #define FSI_StrucSig 484 /* FSInfo的主要簽名 */ #define FSI_Free_Count 488 /* 空閑簇?cái)?shù) */ #define FSI_Nxt_Free 492 /* 最后一個(gè)被分配的簇號(hào),程序應(yīng)該從此開(kāi)始尋找空閑簇 *//* MBR分區(qū)表各字段偏移量 */ #define MBR_Table 446 /* 分區(qū)表在MBR中的偏移量 */ #define SZ_PTE 16 /* 每個(gè)分區(qū)表大小 */ #define PTE_Boot 0 /* 引導(dǎo)標(biāo)志 0x80:活動(dòng)分區(qū) 0x00:非活動(dòng)分區(qū) */ #define PTE_StHead 1 /* 起始磁頭號(hào) */ #define PTE_StSec 2 /* 起始扇區(qū)號(hào) */ #define PTE_StCyl 3 /* 起始柱面號(hào) */ #define PTE_System 4 /* 分區(qū)類型 0x00:未用 0x06:FAT16 0x0B:FAT32 0x05:擴(kuò)展分區(qū) 0x07:NTFS分區(qū) 0x0F:擴(kuò)展分區(qū)(LBA模式) 0x83:Linux分區(qū) */ #define PTE_EdHead 5 /* 結(jié)束磁頭號(hào) */ #define PTE_EdSec 6 /* 結(jié)束扇區(qū)號(hào) */ #define PTE_EdCyl 7 /* 結(jié)束柱面號(hào) */ #define PTE_StLba 8 /* 邏輯起始扇區(qū)號(hào) */ #define PTE_SizLba 12 /* 總扇區(qū)數(shù) *//* 錯(cuò)誤中止 */ #define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); }/* 重新進(jìn)入相關(guān) */ #define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; } #define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; }/* 分區(qū)轉(zhuǎn)換 */ #define LD2PD(vol) (BYTE)(vol) #define LD2PT(vol) 0/* 扇區(qū)大小 */ #define SS(fs) ((UINT)_MAX_SS)/* 時(shí)間戳 */ #define GET_FATTIME() get_fattime()/* 文件鎖 */ typedef struct {FATFS *fs; /* 卷ID(NULL:blank entry) */DWORD clu; /* 簇ID,包含目錄(0:root) */DWORD ofs; /* 偏移量ID,目錄中偏移量 */WORD ctr; /* 文件打開(kāi)次數(shù), 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ }FILESEM;/* 文件系統(tǒng)指針數(shù)組 */ static FATFS *FatFs[_VOLUMES]; /* 文件系統(tǒng)掛載ID */ static WORD Fsid;/* 文件鎖 */ static FILESEM Files[_FS_LOCK];/// /* 加載2字節(jié)小端數(shù)據(jù) */ static WORD ld_word(const BYTE *ptr) {WORD rv;rv = ptr[1];rv = rv << 8 | ptr[0];return rv; }/* 加載4字節(jié)小端數(shù)據(jù) */ static DWORD ld_dword(const BYTE *ptr) {DWORD rv;rv = ptr[3];rv = rv << 8 | ptr[2];rv = rv << 8 | ptr[1];rv = rv << 8 | ptr[0];return rv; }/* 以小端模式存儲(chǔ)2字節(jié)數(shù)據(jù) */ static void st_word(BYTE *ptr, WORD val) {*ptr++ = (BYTE)val; val >>= 8;*ptr++ = (BYTE)val; }/* 以小端模式存儲(chǔ)4字節(jié)數(shù)據(jù) */ static void st_dword(BYTE *ptr, DWORD val) {*ptr++ = (BYTE)val; val >>= 8;*ptr++ = (BYTE)val; val >>= 8;*ptr++ = (BYTE)val; val >>= 8;*ptr++ = (BYTE)val; }/// /* 內(nèi)存拷貝 */ static void mem_cpy(void *dst, const void *src, UINT cnt) {BYTE *d = (BYTE *)dst;const BYTE *s = (const BYTE *)src;if(cnt) {do {*d++ = *s++;}while(--cnt);} }/* 內(nèi)存塊填充 */ static void mem_set(void *dst, int val, UINT cnt) {BYTE *d = (BYTE *)dst;do {*d++ = (BYTE)val;}while(--cnt); }/* 內(nèi)存塊比較 */ static int mem_cmp(const void *dst, const void *src, UINT cnt) {const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src;int r = 0;do {r = *d++ - *s++;}while(--cnt && r == 0);return r; }/* 檢查字符串是否包含字符 */ static int chk_chr(const char *str, int chr) {while(*str && *str != chr) str++;return *str; }/// /* 請(qǐng)求互斥鎖 */ static int lock_fs(FATFS *fs) {return (fs && ff_req_grant(fs->sobj)) ? 1 : 0; }/* 釋放互斥鎖 */ static void unlock_fs(FATFS *fs, FRESULT res) {if(fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) {ff_rel_grant(fs->sobj);} }/// /* 檢查文件是否可以采用acc方式進(jìn)行訪問(wèn) */ static FRESULT chk_lock(DIR *dp, int acc) {UINT i, be;/* 搜索文件鎖列表 */for(i = be = 0; i < _FS_LOCK; i++) {/* 該文件鎖被占用 */if(Files[i].fs) { /* 該文件已經(jīng)被打開(kāi) */if(Files[i].fs == dp->obj.fs && Files[i].clu == dp->obj.sclust && Files[i].ofs == dp->dptr) break;}/* 存在空文件鎖 */else {be = 1;}}/* 文件沒(méi)有打開(kāi) */if(i == _FS_LOCK) { /* 存在空文件鎖或者刪除/重命名操作 則文件允許訪問(wèn);不存在文件鎖不允許讀寫操作 */return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES;}/* 文件被打開(kāi),不允許同時(shí)讀寫/同時(shí)寫寫 */return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; }/* 檢查是否存在空文件鎖 */ static int enq_lock(void) {UINT i;for(i = 0; i < _FS_LOCK && Files[i].fs; i++) ;return (i == _FS_LOCK) ? 0 : 1; }/* 文件訪問(wèn)次數(shù)加一 acc(0:Read, 1:Write, 2:Delete/Rename) */ static UINT inc_lock(DIR *dp, int acc) {UINT i;/* 搜索文件鎖列表 */for(i = 0; i < _FS_LOCK; i++) { /* 該文件已經(jīng)被打開(kāi) */if(Files[i].fs == dp->obj.fs && Files[i].clu == dp->obj.sclust && Files[i].ofs == dp->dptr) break;}/* 該文件未被打開(kāi) */if(i == _FS_LOCK) { /* 查找空的文件鎖 */for(i = 0; i < _FS_LOCK && Files[i].fs; i++) ;/* 沒(méi)有空的文件鎖 */if(i == _FS_LOCK) return 0;/* 注冊(cè)文件持有該文件鎖 */Files[i].fs = dp->obj.fs;Files[i].clu = dp->obj.sclust;Files[i].ofs = dp->dptr;Files[i].ctr = 0;}/* 不允許同時(shí)讀以外的同時(shí)操作 */if (acc && Files[i].ctr) return 0;/* 讀訪問(wèn)次數(shù)加一,寫訪問(wèn)次數(shù)設(shè)為0x100 */Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1;return i + 1; }/* 文件訪問(wèn)次數(shù)減一 */ static FRESULT dec_lock(UINT i) {WORD n;FRESULT res;if(--i < _FS_LOCK) {/* 取出訪問(wèn)模式 */n = Files[i].ctr;/* 寫訪問(wèn)直接訪問(wèn)次數(shù)設(shè)為0 */if(n == 0x100) n = 0;/* 讀訪問(wèn)次數(shù)減一 */if(n > 0) n--;Files[i].ctr = n;/* 訪問(wèn)次數(shù)為0,釋放文件鎖 */if(n == 0) Files[i].fs = 0;res = FR_OK;} else {res = FR_INT_ERR;}return res; }/* 釋放該卷占用的所有文件鎖 */ static void clear_lock(FATFS *fs) {UINT i;for(i = 0; i < _FS_LOCK; i++) {if(Files[i].fs == fs) Files[i].fs = 0;} }/// /* 將緩存窗口數(shù)據(jù)同步到扇區(qū)中 */ static FRESULT sync_window(FATFS *fs) {DWORD wsect;UINT nf;FRESULT res = FR_OK;/* 請(qǐng)求將緩存窗口數(shù)據(jù)回寫到扇區(qū) */if(fs->wflag) {/* 將緩存窗口數(shù)據(jù)回寫到扇區(qū) */wsect = fs->winsect;if(disk_write(fs->drv, fs->win, wsect, 1) != RES_OK) {res = FR_DISK_ERR;} else {fs->wflag = 0;/* 該扇區(qū)在FAT表區(qū)域 */if(wsect - fs->fatbase < fs->fsize) {/* 更新備份FAT表 */for(nf = fs->n_fats; nf >= 2; nf--) {wsect += fs->fsize;disk_write(fs->drv, fs->win, wsect, 1);}}}}return res; }/* 移動(dòng)緩存窗口 */ static FRESULT move_window(FATFS *fs, DWORD sector) {FRESULT res = FR_OK;/* 緩存窗口需要移動(dòng) */if(sector != fs->winsect) {/* 將緩存窗口數(shù)據(jù)同步到原扇區(qū)中 */res = sync_window(fs);if(res == FR_OK) { /* 將新扇區(qū)中數(shù)據(jù)讀取到緩存窗口中 */if(disk_read(fs->drv, fs->win, sector, 1) != RES_OK) {sector = 0xFFFFFFFF;res = FR_DISK_ERR;}/* 變更緩存窗口扇區(qū)號(hào) */fs->winsect = sector;}}return res; }/* 將數(shù)據(jù)同步到文件系統(tǒng) 包括緩存窗口數(shù)據(jù)和FSInfo數(shù)據(jù) */ static FRESULT sync_fs(FATFS *fs) {FRESULT res;/* 將緩存窗口數(shù)據(jù)同步到扇區(qū)中 */res = sync_window(fs);if(res == FR_OK) {/* FAT32文件系統(tǒng),需要將FSInfo數(shù)據(jù)更新到扇區(qū)中 */if(fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) {/* 將FSInfo內(nèi)容拷貝到緩存窗口中 */mem_set(fs->win, 0, SS(fs));st_word(fs->win + BS_55AA, 0xAA55); //FSInfo簽名st_dword(fs->win + FSI_LeadSig, 0x41615252); //FSInfo簽名st_dword(fs->win + FSI_StrucSig, 0x61417272); //FSInfo簽名st_dword(fs->win + FSI_Free_Count, fs->free_clst);//空閑簇?cái)?shù)st_dword(fs->win + FSI_Nxt_Free, fs->last_clst); //最后一個(gè)被分配的簇號(hào)/* FSInfo扇區(qū)為卷的第二扇區(qū),緊挨著引導(dǎo)扇區(qū) */fs->winsect = fs->volbase + 1;/* 將FSInfo數(shù)據(jù)更新到扇區(qū)中 */disk_write(fs->drv, fs->win, fs->winsect, 1);fs->fsi_flag = 0;}/* 立即寫入,不允許掛起 */if(disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR;}return res; }/// /* 將數(shù)據(jù)區(qū)簇號(hào)轉(zhuǎn)換為扇區(qū)號(hào) */ static DWORD clust2sect(FATFS *fs, DWORD clst) {clst -= 2;if(clst >= fs->n_fatent - 2) return 0;return clst * fs->csize + fs->database; }/// /* 獲取指定簇對(duì)應(yīng)FAT表項(xiàng)的內(nèi)容 */ static DWORD get_fat(_FDID *obj, DWORD clst) {UINT wc, bc;DWORD val;FATFS *fs = obj->fs;/* 錯(cuò)誤簇號(hào) */if(clst < 2 || clst >= fs->n_fatent) {val = 1;}/* 有效簇號(hào) */else {val = 0xFFFFFFFF;/* 獲取該簇對(duì)應(yīng)FAT表項(xiàng)的內(nèi)容 */switch(fs->fs_type) {case FS_FAT12:bc = (UINT)clst; bc += bc / 2;if(move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break;wc = fs->win[bc++ % SS(fs)];if(move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break;wc |= fs->win[bc % SS(fs)] << 8;val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF);break;case FS_FAT16 :if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break;val = ld_word(fs->win + clst * 2 % SS(fs));break;case FS_FAT32 :if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break;val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF;break;default:val = 1;}}return val; }/* 將數(shù)據(jù)寫入指定簇對(duì)應(yīng)的FAT表項(xiàng)中 */ static FRESULT put_fat(FATFS *fs, DWORD clst, DWORD val) {UINT bc;BYTE *p;FRESULT res = FR_INT_ERR;/* 有效簇號(hào) */if(clst >= 2 && clst < fs->n_fatent) {/* 將數(shù)據(jù)寫入該簇對(duì)應(yīng)FAT表項(xiàng) */switch(fs->fs_type) {case FS_FAT12 :bc = (UINT)clst; bc += bc / 2;res = move_window(fs, fs->fatbase + (bc / SS(fs)));if (res != FR_OK) break;p = fs->win + bc++ % SS(fs);*p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;fs->wflag = 1;res = move_window(fs, fs->fatbase + (bc / SS(fs)));if (res != FR_OK) break;p = fs->win + bc % SS(fs);*p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));fs->wflag = 1;break;case FS_FAT16:res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));if (res != FR_OK) break;st_word(fs->win + clst * 2 % SS(fs), (WORD)val);fs->wflag = 1;break;case FS_FAT32:res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));if (res != FR_OK) break;if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) {val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000);}st_dword(fs->win + clst * 4 % SS(fs), val);fs->wflag = 1;break;}}return res; }/* 移除簇鏈中指定簇后面的所有簇 */ static FRESULT remove_chain(_FDID *obj, DWORD clst, DWORD pclst) {FRESULT res = FR_OK;DWORD nxt;FATFS *fs = obj->fs;if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR;/* 將前一個(gè)簇對(duì)應(yīng)的FAT表項(xiàng)設(shè)置為'EOC',即文件最后一個(gè)簇 */if(pclst) {res = put_fat(fs, pclst, 0xFFFFFFFF);if(res != FR_OK) return res;}/* 移除(設(shè)為空閑)簇鏈中指定簇后面的所有簇 */do {/* 獲取當(dāng)前簇對(duì)應(yīng)的FAT表項(xiàng)內(nèi)容 */nxt = get_fat(obj, clst);/* 空簇,說(shuō)明上一個(gè)簇就是最后一個(gè)簇 */if(nxt == 0) break;/* 非法參數(shù)錯(cuò)誤 */if(nxt == 1) return FR_INT_ERR;/* 讀取失敗 */if (nxt == 0xFFFFFFFF) return FR_DISK_ERR;/* 當(dāng)前簇對(duì)應(yīng)的FAT表項(xiàng)內(nèi)容設(shè)置為空閑 */res = put_fat(fs, clst, 0);if(res != FR_OK) return res;/* 更新FSINFO內(nèi)容 */if(fs->free_clst < fs->n_fatent - 2) {fs->free_clst++; //空閑簇?cái)?shù)加一fs->fsi_flag |= 1; //FSINFO數(shù)據(jù)變化需要更新}clst = nxt;}while(clst < fs->n_fatent);return FR_OK; }/* 在指定簇后面再擴(kuò)展一個(gè)簇 clst(0:創(chuàng)建新簇鏈) */ static DWORD create_chain(_FDID *obj, DWORD clst) {DWORD cs, ncl, scl;FRESULT res;FATFS *fs = obj->fs;/* 創(chuàng)建一個(gè)簇鏈 */if(clst == 0) {/* 從建議的簇(最后一個(gè)被分配的簇)開(kāi)始尋找空閑簇 */scl = fs->last_clst;if(scl == 0 || scl >= fs->n_fatent) scl = 1;}/* 擴(kuò)展指定簇鏈 */else {/* 獲取指定簇對(duì)應(yīng)FAT表項(xiàng)的內(nèi)容 */cs = get_fat(obj, clst);/* 該簇應(yīng)該已經(jīng)分配,空閑簇則錯(cuò)誤非法參數(shù)也要報(bào)錯(cuò) */if(cs < 2) return 1;/* 讀取失敗 */if(cs == 0xFFFFFFFF) return cs;/* 下一個(gè)簇號(hào)必須在FAT表中 */if(cs < fs->n_fatent) return cs;/* 從指定簇開(kāi)始尋找空閑簇 */scl = clst;}/* 尋找空閑簇 */ncl = scl;for(;;) {ncl++;/* 找到了FAT尾部 */if(ncl >= fs->n_fatent) {/* 從頭(2號(hào)簇)開(kāi)始繼續(xù)找 */ncl = 2;/* 整個(gè)FAT表找個(gè)遍,沒(méi)有空閑簇 */if(ncl > scl) return 0;}/* 獲取ncl簇對(duì)應(yīng)FAT表項(xiàng)的內(nèi)容 */cs = get_fat(obj, ncl);/* 找到空閑簇 */if (cs == 0) break;/* 發(fā)生錯(cuò)誤 */if(cs == 1 || cs == 0xFFFFFFFF) return cs;/* 找了一遍沒(méi)有空閑簇 */if(ncl == scl) return 0;}/* 找到空閑簇,將該空閑簇設(shè)置為EOC */res = put_fat(fs, ncl, 0xFFFFFFFF);if(res == FR_OK && clst != 0){/* 將指定簇指向找到的簇(即將新簇鏈接到簇鏈) */res = put_fat(fs, clst, ncl);}/* 更新FSINFO */if(res == FR_OK) {fs->last_clst = ncl; //最后一個(gè)被分配的簇號(hào)if(fs->free_clst <= fs->n_fatent - 2) fs->free_clst--; //空閑簇減一fs->fsi_flag |= 1; //FSINFO數(shù)據(jù)變化,需要更新}else {ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1;}return ncl; }/// /* 設(shè)置目錄讀寫偏移量 */ static FRESULT dir_sdi(DIR *dp, DWORD ofs) {DWORD csz, clst;FATFS *fs = dp->obj.fs;if(ofs >= (DWORD)MAX_DIR || ofs % SZDIRE) {return FR_INT_ERR;}/* 當(dāng)前偏移量 */dp->dptr = ofs;/* 該目錄所在簇(0:root) */clst = dp->obj.sclust;/* FAT32根目錄 */if(clst == 0 && fs->fs_type >= FS_FAT32) {/* 根目錄起始簇 */clst = fs->dirbase;}/* FAT12/16根目錄 */if(clst == 0) {/* 偏移量不能超過(guò)根目錄的目錄項(xiàng)數(shù) */if(ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR;/* 根目錄起始扇區(qū)號(hào) */dp->sect = fs->dirbase;} /* 子目錄或FAT32根目錄 */else{ /* 每簇字節(jié)數(shù) */csz = (DWORD)fs->csize * SS(fs);/* 查找偏移量所在簇 */while(ofs >= csz) { clst = get_fat(&dp->obj, clst);if(clst == 0xFFFFFFFF) return FR_DISK_ERR;if(clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR;ofs -= csz;}/* 偏移量所在簇的起始扇區(qū) */dp->sect = clust2sect(fs, clst);}/* 偏移量所在當(dāng)前簇 */dp->clust = clst;if (!dp->sect) return FR_INT_ERR;/* 偏移量所在當(dāng)前扇區(qū) */dp->sect += ofs / SS(fs);/* 偏移量所對(duì)應(yīng)的緩存窗口指針 */dp->dir = fs->win + (ofs % SS(fs));return FR_OK; }/* 當(dāng)前偏移量轉(zhuǎn)移到下一個(gè)目錄項(xiàng) stretch:0不擴(kuò)展 1:擴(kuò)展 */ static FRESULT dir_next(DIR *dp, int stretch) {DWORD ofs, clst;FATFS *fs = dp->obj.fs;UINT n;/* 將偏移量指向下一個(gè)目錄項(xiàng) */ofs = dp->dptr + SZDIRE;if(!dp->sect || ofs >= (DWORD)MAX_DIR) return FR_NO_FILE;/* 偏移量所在扇區(qū)號(hào)發(fā)生變化 */if(ofs % SS(fs) == 0) {dp->sect++;/* 根目錄 */if(!dp->clust) {/* 超出根目錄范圍 */if(ofs / SZDIRE >= fs->n_rootdir) {dp->sect = 0; return FR_NO_FILE;}}/* 子目錄 */else {/* 偏移量所在簇號(hào)發(fā)生變化 */if((ofs / SS(fs) & (fs->csize - 1)) == 0) {/* 獲取下一個(gè)簇號(hào) */clst = get_fat(&dp->obj, dp->clust);if(clst <= 1) return FR_INT_ERR;if(clst == 0xFFFFFFFF) return FR_DISK_ERR;/* 文件最后最后一個(gè)簇 */if(clst >= fs->n_fatent){/* 不允許擴(kuò)展 */if(!stretch) {dp->sect = 0; return FR_NO_FILE;}/* 擴(kuò)展一個(gè)簇 */clst = create_chain(&dp->obj, dp->clust);if (clst == 0) return FR_DENIED;if (clst == 1) return FR_INT_ERR;if (clst == 0xFFFFFFFF) return FR_DISK_ERR;if (_FS_EXFAT) dp->obj.stat |= 4; /* 將緩存窗口數(shù)據(jù)同步到扇區(qū)中 */if(sync_window(fs) != FR_OK) return FR_DISK_ERR;/* 將新簇清空為0 */mem_set(fs->win, 0, SS(fs));for (n = 0, fs->winsect = clust2sect(fs, clst); n < fs->csize; n++, fs->winsect++) { /* Fill the new cluster with 0 */fs->wflag = 1;if(sync_window(fs) != FR_OK) return FR_DISK_ERR;}/* 重新設(shè)置緩存窗口扇區(qū)號(hào)為當(dāng)前簇起始扇區(qū)(即偏移量所在扇區(qū)) */fs->winsect -= n;}/* 當(dāng)前偏移量所在簇號(hào) */dp->clust = clst;/* 當(dāng)前偏移量所在扇區(qū)號(hào) */dp->sect = clust2sect(fs, clst);}}}/* 當(dāng)前偏移量 */dp->dptr = ofs;/* 當(dāng)前偏移量對(duì)應(yīng)緩存窗口中的指針 */dp->dir = fs->win + ofs % SS(fs);return FR_OK; }/* 在指定目錄中申請(qǐng)連續(xù)nent個(gè)目錄項(xiàng)的空間 */ static FRESULT dir_alloc(DIR *dp, UINT nent) {FRESULT res;UINT n;FATFS *fs = dp->obj.fs;/* 設(shè)置目錄偏移量到目錄起始處 */res = dir_sdi(dp, 0);if(res == FR_OK) {n = 0;do {/* 將緩沖窗口轉(zhuǎn)移到當(dāng)前扇區(qū) */res = move_window(fs, dp->sect);if (res != FR_OK) break;/* 目錄項(xiàng)未被使用 */if(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) {/* 連續(xù)空目錄項(xiàng)的個(gè)數(shù)加一 */if(++n == nent) break;} /* 該處有目錄項(xiàng) */else {/* 連續(xù)空目錄項(xiàng)的個(gè)數(shù)清零 */n = 0;}/* 當(dāng)前偏移量轉(zhuǎn)移到下一個(gè)目錄項(xiàng),簇不夠放了就擴(kuò)展 */res = dir_next(dp, 1);}while(res == FR_OK);}if (res == FR_NO_FILE) res = FR_DENIED;return res; }/* 從目錄項(xiàng)中讀出文件/目錄起始簇號(hào) */ static DWORD ld_clust(FATFS *fs, const BYTE *dir) {DWORD cl;cl = ld_word(dir + DIR_FstClusLO);if(fs->fs_type == FS_FAT32) {cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16;}return cl; }/* 將文件/目錄起始簇號(hào)寫入目錄項(xiàng) */ static void st_clust(FATFS *fs, BYTE *dir, DWORD cl) {st_word(dir + DIR_FstClusLO, (WORD)cl);if(fs->fs_type == FS_FAT32) {st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16));} }/* 指定目錄中查找一個(gè)指定屬性(vol)的目錄項(xiàng) vol(0:文件/目錄 1:卷標(biāo)) */ static FRESULT dir_read(DIR *dp, int vol) {FRESULT res = FR_NO_FILE;FATFS *fs = dp->obj.fs;BYTE a, c;/* 遍歷整個(gè)目錄,查找目錄項(xiàng) 0:文件/目錄項(xiàng) 1:卷標(biāo) */while(dp->sect) {res = move_window(fs, dp->sect);if(res != FR_OK) break;/* 檢查該目錄項(xiàng)是否被使用 */c = dp->dir[DIR_Name];if(c == 0) //未被使用{res = FR_NO_FILE; break;}/* 獲取目錄項(xiàng)屬性 */dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK;/* 檢查是不是合理的目錄項(xiàng) 1表示查找卷標(biāo) 0表示查找文件或目錄 */if(c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) {break;}/* 繼續(xù)查找下一個(gè)目錄項(xiàng) */res = dir_next(dp, 0);if(res != FR_OK) break;}if(res != FR_OK) dp->sect = 0;return res; }/* 指定目錄中通過(guò)文件名查找一個(gè)目錄項(xiàng) */ static FRESULT dir_find(DIR *dp) {FRESULT res;FATFS *fs = dp->obj.fs;BYTE c;/* 設(shè)置偏移量到目錄起始位置 */res = dir_sdi(dp, 0);if(res != FR_OK) return res;/* 循環(huán)查找目錄項(xiàng) */do {res = move_window(fs, dp->sect);if (res != FR_OK) break;/* 直到目錄結(jié)尾處,沒(méi)有查到合適的文件 */c = dp->dir[DIR_Name];if(c == 0) { res = FR_NO_FILE; break; }/* 非卷標(biāo),匹配文件名 */dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK;if(!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) break;res = dir_next(dp, 0);}while(res == FR_OK);return res; }/* 在指定目錄中創(chuàng)建一個(gè)目錄項(xiàng)(指定文件名和擴(kuò)展名) */ static FRESULT dir_register(DIR *dp) {FRESULT res;FATFS *fs = dp->obj.fs;/* 申請(qǐng)連續(xù)1個(gè)目錄項(xiàng)的空間 */res = dir_alloc(dp, 1);if (res == FR_OK) {/* 將緩存窗口移到新的目錄項(xiàng)空間 */res = move_window(fs, dp->sect);if(res == FR_OK) {/* 將文件名寫入目錄項(xiàng),其它都清零 */mem_set(dp->dir, 0, SZDIRE);mem_cpy(dp->dir + DIR_Name, dp->fn, 11);fs->wflag = 1;}}return res; }/* 在指定目錄中移除當(dāng)前偏移量指向的目錄項(xiàng) */ static FRESULT dir_remove(DIR *dp) {FRESULT res;FATFS *fs = dp->obj.fs;/* 將當(dāng)前緩存窗口移到當(dāng)前偏移量所在扇區(qū) */res = move_window(fs, dp->sect);if(res == FR_OK) {/* 將目錄項(xiàng)設(shè)置為未被使用(刪除) */dp->dir[DIR_Name] = DDEM;fs->wflag = 1;}return res; }/* 從指定目錄項(xiàng)中讀出文件信息 */ static void get_fileinfo(DIR *dp, FILINFO *fno) {UINT i, j;TCHAR c;DWORD tm;/* 清空文件信息 */fno->fname[0] = 0;/* 偏移量不允許指向目錄結(jié)尾 */if(!dp->sect) return;/* 獲取短文件名 */i = j = 0;while(i < 11) {/* 從文件名中獲取字符 */c = (TCHAR)dp->dir[i++];/* 跳過(guò)空格 */if(c == ' ') continue;/* 將0x05替換成0xE5 */if(c == RDDEM) c = (TCHAR)DDEM;/* 第9個(gè)字符一定要插入'.' */if(i == 9) fno->fname[j++] = '.';/* 填入字符 */fno->fname[j++] = c;}/* 結(jié)尾用'/0'表示 */fno->fname[j] = 0;/* 文件屬性屬性 */fno->fattrib = dp->dir[DIR_Attr];/* 文件大小 */fno->fsize = ld_dword(dp->dir + DIR_FileSize);/* 修改日期和時(shí)間 */tm = ld_dword(dp->dir + DIR_ModTime);fno->ftime = (WORD)tm; fno->fdate = (WORD)(tm >> 16); }/* 取出最頂級(jí)路徑,返回剩余路徑段 */ static FRESULT create_name(DIR *dp, const TCHAR **path) {BYTE c, d, *sfn;UINT ni, si, i;const char *p;/* 獲取路徑指針 */p = *path; /* 清空文件名緩沖區(qū) */sfn = dp->fn;mem_set(sfn, ' ', 11);si = i = 0; ni = 8;/* "FILENAME.TXT" "FILENAMETXT""FILE.TXT" "FILE TXT""file.txt" "FILE TXT""蜃気樓.TXT" "?気樓 TXT" "蜃"的第一個(gè)字節(jié)為0xE5,用0x05替換"NOEXT" "NOEXT "*/for(;;) {c = (BYTE)p[si++];/* \0到\x1F被識(shí)別為路徑結(jié)尾,在短文件名中空格被識(shí)別為路徑結(jié)尾 */if(c <= ' ') //路徑結(jié)尾break;/* 發(fā)現(xiàn)分隔符 */if(c == '/' || c == '\\') { /* 自動(dòng)跳過(guò)并忽略重復(fù)的分隔符 */while (p[si] == '/' || p[si] == '\\') si++;break;}/* 規(guī)范為8.3存儲(chǔ)格式 */if(c == '.' || i >= ni) {/* 1.2.txt非法 123456789.txt非法 1234567891111非法 */if(ni == 11 || c != '.') return FR_INVALID_NAME;/* 跳到擴(kuò)展名 */i = 8; ni = 11;continue;}/* 擴(kuò)展字符第一字節(jié) */if(IsDBCS1(c)) { /* 擴(kuò)展字符第二字節(jié) */d = (BYTE)p[si++];if(!IsDBCS2(d) || i >= ni - 1) return FR_INVALID_NAME;/* 擴(kuò)展字符占兩字節(jié) */sfn[i++] = c;sfn[i++] = d;} /* 非擴(kuò)展字符 */else {/* 非法字符 */if(chk_chr("\"*+,:;<=>\?[]|\x7F", c)) return FR_INVALID_NAME;/* 全部轉(zhuǎn)成大小 */if(IsLower(c)) c -= 0x20;sfn[i++] = c;}}/* 返回下一段路徑的指針 */*path = p + si;if(i == 0) return FR_INVALID_NAME;/* 第一個(gè)字節(jié)是DDEM轉(zhuǎn)換為RDDEM */if(sfn[0] == DDEM) sfn[0] = RDDEM;/* 如果是最后一段路徑,則添加路徑結(jié)束標(biāo)志 */sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0;return FR_OK; }/* 進(jìn)入文件所在路徑(將偏移量定位到指定路徑) */ static FRESULT follow_path(DIR *dp, const TCHAR *path) {FRESULT res;BYTE ns;_FDID *obj = &dp->obj;FATFS *fs = obj->fs;/* 跳過(guò)分隔符 */while(*path == '/' || *path == '\\') path++;/* 從根目錄開(kāi)始找 */obj->sclust = 0;/* ' '表示已經(jīng)到了路徑結(jié)尾(沒(méi)有路徑),將偏移量設(shè)置為當(dāng)前目錄起始端 */if((UINT)*path < ' ') { dp->fn[NSFLAG] = NS_NONAME;res = dir_sdi(dp, 0);} else {/* 進(jìn)入路徑 */for(;;) {/* 取出最頂級(jí)路徑,返回剩余路徑段 */res = create_name(dp, &path);if(res != FR_OK) break;/* 在目錄中查找取出的最頂級(jí)路徑的目錄項(xiàng) */res = dir_find(dp);ns = dp->fn[NSFLAG];/* 沒(méi)找到該目錄項(xiàng) */if(res != FR_OK) {if(res == FR_NO_FILE) {/* 將錯(cuò)誤返回精確到?jīng)]有最后一段 */if(!(ns & NS_LAST)) res = FR_NO_PATH;}break;}/* 最后一段路徑 */if(ns & NS_LAST) break;/* 如果找到該目錄項(xiàng),并且不是最后一段路徑,則該目錄項(xiàng)必須為子目錄 */if(!(obj->attr & AM_DIR)) {res = FR_NO_PATH; break;}/* 從目錄項(xiàng)中讀出文件/目錄起始簇號(hào) */obj->sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs));}}return res; }/* 從路徑中取出邏輯驅(qū)動(dòng)器號(hào),返回剩余路徑段 */ static int get_ldnumber(const TCHAR **path) {const TCHAR *tp, *tt;UINT i;int vol = -1;/* 路徑不為空 */if(*path) {/* 從路徑中找到':'所在位置 */for(tt = *path; (UINT)*tt >= (_USE_LFN ? ' ' : '!') && *tt != ':'; tt++) ;/* 存在':' */if(*tt == ':') {/* 取出邏輯驅(qū)動(dòng)器號(hào),并返回剩余的路徑 */tp = *path;i = *tp++ - '0';if(i < 10 && tp == tt) {if(i < _VOLUMES) {vol = (int)i;*path = ++tt;}}return vol;}/* 未指明驅(qū)動(dòng)器號(hào),則默認(rèn)為0號(hào) */vol = 0;}return vol; }/// /* 讀指定扇區(qū)內(nèi)容并檢查是不是boot扇區(qū) 0:FAT引導(dǎo)扇區(qū), 1:exFAT引導(dǎo)扇區(qū), 2:有效的引導(dǎo)扇區(qū)(當(dāng)前可能是MBR), 3:無(wú)效引導(dǎo)扇區(qū), 4:Disk error */ static BYTE check_fs(FATFS *fs, DWORD sect) {fs->wflag = 0; fs->winsect = 0xFFFFFFFF;/* 將窗口移到指定扇區(qū) */if(move_window(fs, sect) != FR_OK) return 4;/* 一個(gè)引導(dǎo)簽名,表明這是一個(gè)有效的引導(dǎo)扇區(qū) */if(ld_word(fs->win + BS_55AA) != 0xAA55) return 3;/* x86跳轉(zhuǎn)指令。如果兩種格式之外的任何格式,Windows都將無(wú)法識(shí)別該卷 */if(fs->win[BS_JmpBoot] == 0xE9 || (fs->win[BS_JmpBoot] == 0xEB && fs->win[BS_JmpBoot + 2] == 0x90)) {/* 文件系統(tǒng)類型FAT12/FAT16 */if((ld_dword(fs->win + BS_FilSysType) & 0xFFFFFF) == 0x544146) return 0;/* 文件系統(tǒng)類型FAT32 */if(ld_dword(fs->win + BS_FilSysType32) == 0x33544146) return 0;}return 2; }/* 通過(guò)路徑中的邏輯驅(qū)動(dòng)器號(hào),在邏輯驅(qū)動(dòng)器上查找該卷是否被掛載(同時(shí)檢查磁盤是否寫保護(hù)(mode!=0寫保護(hù)檢查)),如果沒(méi)有則嘗試掛載 返回邏輯驅(qū)動(dòng)器號(hào)后的路徑,返回文件系統(tǒng)指針 */ static FRESULT find_volume(const TCHAR **path, FATFS **rfs, BYTE mode) {BYTE fmt, *pt;int vol;DSTATUS stat;DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4];WORD nrsv;FATFS *fs;UINT i;/* 從路徑中取出邏輯驅(qū)動(dòng)器號(hào),返回剩余路徑段 */*rfs = 0;vol = get_ldnumber(path);if(vol < 0) return FR_INVALID_DRIVE;/* 根據(jù)邏輯驅(qū)動(dòng)器號(hào)獲取文件系統(tǒng)指針 */fs = FatFs[vol];if(!fs) return FR_NOT_ENABLED;ENTER_FF(fs);/* 返回文件系統(tǒng)指針 */*rfs = fs;/* 檢查是否有寫訪問(wèn)權(quán)限 */mode &= (BYTE)~FA_READ;/* 文件系統(tǒng)已經(jīng)掛載 */if(fs->fs_type) {/* 物理設(shè)備已經(jīng)初始化 */stat = disk_status(fs->drv);if(!(stat & STA_NOINIT)) { /* 請(qǐng)求檢測(cè)寫保護(hù)權(quán)限,但物理設(shè)備寫保護(hù) */if(!_FS_READONLY && mode && (stat & STA_PROTECT)) { return FR_WRITE_PROTECTED;}return FR_OK;}}/* 文件系統(tǒng)未掛載或物理設(shè)備未初始化 *//* 清空文件系統(tǒng)掛載標(biāo)志 */fs->fs_type = 0;/* 綁定邏輯驅(qū)動(dòng)器號(hào) */fs->drv = LD2PD(vol);/* 初始化物理設(shè)備 */stat = disk_initialize(fs->drv);if(stat & STA_NOINIT) {return FR_NOT_READY;}/* 請(qǐng)求檢測(cè)寫保護(hù)權(quán)限,但物理設(shè)備寫保護(hù) */if(!_FS_READONLY && mode && (stat & STA_PROTECT)) {return FR_WRITE_PROTECTED;}/* 讀取0號(hào)扇區(qū),檢查是不是FAT的boot扇區(qū) */bsect = 0;fmt = check_fs(fs, bsect);/* 不是FAT的boot扇區(qū),但可能是MBR(分區(qū)表放在MBR中) */if(fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) {/* 遍歷分區(qū)表 */for(i = 0; i < 4; i++) {/* 分區(qū)表指針 */pt = fs->win + (MBR_Table + i * SZ_PTE);/* 從分區(qū)表中獲取分區(qū)的起始扇區(qū) */br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0;}/* 分區(qū)號(hào)0:auto, 1-4:forced */i = LD2PT(vol);if(i) i--;/* 查找分區(qū)的起始扇區(qū),檢查FAT的boot扇區(qū) */do{bsect = br[i];fmt = bsect ? check_fs(fs, bsect) : 3;}while(LD2PT(vol) == 0 && fmt >= 2 && ++i < 4);}if(fmt == 4) return FR_DISK_ERR;if(fmt >= 2) return FR_NO_FILESYSTEM;/* 存在FAT文件系統(tǒng) *//* 檢查扇區(qū)字節(jié)數(shù)和物理設(shè)備相不相同 */if(ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM;/* 每個(gè)FAT占用的扇區(qū)數(shù) */fasize = ld_word(fs->win + BPB_FATSz16);if(fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32);fs->fsize = fasize;/* FAT表個(gè)數(shù) */fs->n_fats = fs->win[BPB_NumFATs];if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM;/* FAT總扇區(qū)數(shù) */fasize *= fs->n_fats;/* 每個(gè)簇的扇區(qū)數(shù) */fs->csize = fs->win[BPB_SecPerClus];if(fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM;/* FAT12/16根目錄中目錄項(xiàng)個(gè)數(shù) */fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt);if(fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM;/* 卷的總扇區(qū)數(shù) */tsect = ld_word(fs->win + BPB_TotSec16);if(tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32);/* 保留區(qū)扇區(qū)數(shù) */nrsv = ld_word(fs->win + BPB_RsvdSecCnt);if(nrsv == 0) return FR_NO_FILESYSTEM;/* RSV + FAT + DIR總扇區(qū)數(shù) */sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */if(tsect < sysect) return FR_NO_FILESYSTEM;/* 簇個(gè)數(shù) */nclst = (tsect - sysect) / fs->csize;if(nclst == 0) return FR_NO_FILESYSTEM;/* 根據(jù)簇?cái)?shù)確定FAT子系統(tǒng)類型 */fmt = FS_FAT32;if(nclst <= MAX_FAT16) fmt = FS_FAT16;if(nclst <= MAX_FAT12) fmt = FS_FAT12;/* FAT表項(xiàng)個(gè)數(shù) 簇?cái)?shù) + 2 */fs->n_fatent = nclst + 2;/* 卷起始扇區(qū) */fs->volbase = bsect;/* FAT表起始扇區(qū) */fs->fatbase = bsect + nrsv;/* 數(shù)據(jù)區(qū)起始扇區(qū) */fs->database = bsect + sysect;/* FAT32 */if(fmt == FS_FAT32) {/* FAT32版本號(hào)必定為0.0 */if(ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM;/* FAT32根目錄中目錄項(xiàng)個(gè)數(shù)字段為0 */if(fs->n_rootdir) return FR_NO_FILESYSTEM;/* 根目錄起始簇號(hào) */fs->dirbase = ld_dword(fs->win + BPB_RootClus32);/* FAT表字節(jié)數(shù) */szbfat = fs->n_fatent * 4;}/* FAT12/16 */else {/* FAT12/16根目錄中目錄項(xiàng)個(gè)數(shù)字段不為0 */if(fs->n_rootdir == 0) return FR_NO_FILESYSTEM;/* 根目錄起始扇區(qū)號(hào) */fs->dirbase = fs->fatbase + fasize;/* FAT表字節(jié)數(shù) */szbfat = (fmt == FS_FAT16) ? fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);}if(fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM;/* 最后一個(gè)被分配的簇和空閑簇?cái)?shù),初始化為未知,0xFFFFFFFF表示未知 */fs->last_clst = fs->free_clst = 0xFFFFFFFF;fs->fsi_flag = 0x80;/* 如果是FAT32則讀出FSINFO,為最后一個(gè)被分配的簇和空閑簇?cái)?shù)賦值 */if(fmt == FS_FAT32 && ld_word(fs->win + BPB_FSInfo32) == 1&& move_window(fs, bsect + 1) == FR_OK){fs->fsi_flag = 0;/* 有效的FSINFO */if(ld_word(fs->win + BS_55AA) == 0xAA55&& ld_dword(fs->win + FSI_LeadSig) == 0x41615252&& ld_dword(fs->win + FSI_StrucSig) == 0x61417272){/* 空閑簇?cái)?shù) */fs->free_clst = ld_dword(fs->win + FSI_Free_Count);/* 驅(qū)動(dòng)程序分配的最后一個(gè)簇編號(hào) */fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free);}}/* FAT子系統(tǒng)類型 */fs->fs_type = fmt;/* 文件系統(tǒng)掛載ID */fs->id = ++Fsid;clear_lock(fs);return FR_OK; }/// /* 檢查該文件/目錄是否有效,并請(qǐng)求互斥鎖,返回文件系統(tǒng)指針 */ static FRESULT validate(_FDID *obj, FATFS **fs) {FRESULT res = FR_INVALID_OBJECT;if(obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) {if(lock_fs(obj->fs)) {if(!(disk_status(obj->fs->drv) & STA_NOINIT)) {res = FR_OK;} else {unlock_fs(obj->fs, FR_OK);}} else {res = FR_TIMEOUT;}}*fs = (res == FR_OK) ? obj->fs : 0;return res; }/// /* 掛載/卸載一個(gè)邏輯驅(qū)動(dòng)器((!fs || opt != 1)卸載原邏輯驅(qū)動(dòng)器;否則掛載新驅(qū)動(dòng)器) */ FRESULT f_mount(FATFS *fs, const TCHAR *path, BYTE opt) {FATFS *cfs;int vol;FRESULT res;const TCHAR *rp = path;/* 從路徑中取出邏輯驅(qū)動(dòng)器號(hào),返回剩余路徑段 */vol = get_ldnumber(&rp);if(vol < 0) return FR_INVALID_DRIVE;/* 文件系統(tǒng)指針 */cfs = FatFs[vol];/* 文件系統(tǒng)指針已經(jīng)存在,將原文件系統(tǒng)取消掛載 */if(cfs){/* 釋放該卷占用的所有文件鎖 */clear_lock(cfs);/* 刪除互斥鎖 */if(!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR;/* 將原文件系統(tǒng)取消掛載 */cfs->fs_type = 0;}/* 新文件系統(tǒng) */if(fs) {/* 清空掛載標(biāo)志位 */fs->fs_type = 0;/* 創(chuàng)建互斥鎖 */if(!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR;}/* 注冊(cè)新的文件系統(tǒng)指針 */FatFs[vol] = fs;if(!fs || opt != 1) return FR_OK;/* 通過(guò)路徑中的邏輯驅(qū)動(dòng)器號(hào),并嘗試掛載 */res = find_volume(&path, &fs, 0);LEAVE_FF(fs, res); }/* 打開(kāi)文件(創(chuàng)建;檢查訪問(wèn)權(quán)限;更新讀寫偏移量) */ FRESULT f_open(FIL *fp, const TCHAR *path, BYTE mode) {FRESULT res;DIR dj;FATFS *fs;DWORD dw, cl, bcs, clst, sc;FSIZE_t ofs;if(!fp) return FR_INVALID_OBJECT;/* 訪問(wèn)模式 */mode &= _FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND | FA_SEEKEND;/* 通過(guò)路徑中的邏輯驅(qū)動(dòng)器號(hào),在邏輯驅(qū)動(dòng)器上查找該卷是否被掛載(同時(shí)檢查磁盤是否寫保護(hù)(mode!=0寫保護(hù)檢查)),如果沒(méi)有則嘗試掛載 返回邏輯驅(qū)動(dòng)器號(hào)后的路徑,返回文件系統(tǒng)指針 */res = find_volume(&path, &fs, mode);if(res == FR_OK) {/* 目錄項(xiàng)所處文件系統(tǒng) */dj.obj.fs = fs;/* 進(jìn)入文件所在路徑(將偏移量定位到指定路徑) */res = follow_path(&dj, path);if(res == FR_OK) {/* 非法路徑名 */if(dj.fn[NSFLAG] & NS_NONAME) {res = FR_INVALID_NAME;}else {/* 檢查文件是否可以采用acc方式進(jìn)行訪問(wèn) */res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);}}/* 打開(kāi)或創(chuàng)建并打開(kāi)一個(gè)文件 */if(mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {/* 沒(méi)有這個(gè)文件,創(chuàng)建一個(gè)新的 */if(res != FR_OK) {/* 在指定目錄中創(chuàng)建一個(gè)目錄項(xiàng)(指定文件名和擴(kuò)展名) */if(res == FR_NO_FILE) {res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;}/* 文件已經(jīng)創(chuàng)建 */mode |= FA_CREATE_ALWAYS;}/* 文件已經(jīng)存在 */else {/* 文件屬性只讀或目錄,不允許創(chuàng)建 */if(dj.obj.attr & (AM_RDO | AM_DIR)) {res = FR_DENIED;}else{/* 已存在不允許創(chuàng)建 */if(mode & FA_CREATE_NEW) res = FR_EXIST;}}/* 覆蓋模式 */if(res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* 獲取時(shí)間戳 */dw = GET_FATTIME();{/* 覆蓋修改日期和時(shí)間 */st_dword(dj.dir + DIR_CrtTime, dw);st_dword(dj.dir + DIR_ModTime, dw);/* 重置屬性 */dj.dir[DIR_Attr] = AM_ARC;/* 獲取文件第一個(gè)簇號(hào) */cl = ld_clust(fs, dj.dir);/* 重置文件第一個(gè)簇號(hào) */st_clust(fs, dj.dir, 0);/* 重置文件大小 */st_dword(dj.dir + DIR_FileSize, 0);fs->wflag = 1;/* 移除FAT中原有簇鏈 */if(cl) {dw = fs->winsect;res = remove_chain(&dj.obj, cl, 0);if(res == FR_OK) {res = move_window(fs, dw);fs->last_clst = cl - 1; }}}}}/* 只允許打開(kāi)已存在的文件 */else {if(res == FR_OK) {/* 目錄不能打開(kāi) */if(dj.obj.attr & AM_DIR) {res = FR_NO_FILE;} else {/* 只讀項(xiàng)不能寫 */if((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) {res = FR_DENIED;}}}}if(res == FR_OK) {/* 覆蓋模式 */if(mode & FA_CREATE_ALWAYS)mode |= FA_MODIFIED; //文件已經(jīng)被修改/* 指針直到該目錄項(xiàng)扇區(qū) */fp->dir_sect = fs->winsect;/* 當(dāng)前目錄項(xiàng)在緩存窗口中的指針 */fp->dir_ptr = dj.dir;/* 文件訪問(wèn)次數(shù)加一 acc(0:Read, 1:Write, 2:Delete/Rename) */fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);if (!fp->obj.lockid) res = FR_INT_ERR;}if(res == FR_OK) {{/* 從目錄項(xiàng)中讀出文件起始簇號(hào) */fp->obj.sclust = ld_clust(fs, dj.dir);/* 從目錄項(xiàng)中讀出文件大小 */fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize);}fp->obj.fs = fs; /* 文件系統(tǒng)指針 */fp->obj.id = fs->id; /* 文件系統(tǒng)掛載ID */fp->flag = mode; /* 文件當(dāng)前狀態(tài) */fp->err = 0; /* 清空錯(cuò)誤 */fp->sect = 0; /* 清空當(dāng)前數(shù)據(jù)扇區(qū) */fp->fptr = 0; /* 文件偏移量指向文件首部 */mem_set(fp->buf, 0, _MAX_SS); /* 清空讀寫數(shù)據(jù)緩存窗口 *//* 指向文件結(jié)尾 */if((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* 當(dāng)前讀寫偏移量指向文件結(jié)尾 */fp->fptr = fp->obj.objsize;/* 調(diào)整讀寫指針?biāo)诖靥?hào) */bcs = (DWORD)fs->csize * SS(fs);clst = fp->obj.sclust;for(ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) {/* 獲取下一簇號(hào) */clst = get_fat(&fp->obj, clst);if (clst <= 1) res = FR_INT_ERR;if (clst == 0xFFFFFFFF) res = FR_DISK_ERR;}fp->clust = clst;if(res == FR_OK && ofs % SS(fs)) { if((sc = clust2sect(fs, clst)) == 0) {res = FR_INT_ERR;} else {/* 調(diào)整讀寫偏移量所在扇區(qū)號(hào) */fp->sect = sc + (DWORD)(ofs / SS(fs));/* 將讀寫偏移量所在扇區(qū)數(shù)據(jù)讀到讀寫數(shù)據(jù)緩存窗口 */if(disk_read(fs->drv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR;}}}}}if(res != FR_OK) fp->obj.fs = 0;LEAVE_FF(fs, res); }/* 讀文件 */ FRESULT f_read(FIL *fp, void *buff, UINT btr, UINT *br) {FRESULT res;FATFS *fs;DWORD clst, sect;FSIZE_t remain;UINT rcnt, cc, csect;BYTE *rbuff = (BYTE *)buff;/* 成功讀取字節(jié)數(shù)清零 */*br = 0;/* 檢查該文件是否有效,返回文件系統(tǒng)指針 */res = validate(&fp->obj, &fs);if(res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);/* 檢查讀權(quán)限 */if(!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED);/* 文件剩余字節(jié)數(shù) */remain = fp->obj.objsize - fp->fptr;if(btr > remain) btr = (UINT)remain;for(; btr; rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {/* 在扇區(qū)邊界 */if(fp->fptr % SS(fs) == 0) { /* 偏移量處于所在簇的第幾個(gè)扇區(qū) */csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1));/* 在簇的邊界 */if(csect == 0) {/* 在文件頂部 */if(fp->fptr == 0) {/* 當(dāng)前偏移量在文件起始簇 */clst = fp->obj.sclust;} /* 不在文件頂部 */else {/* 查找FAT,取出下一簇號(hào) */{clst = get_fat(&fp->obj, fp->clust);}}if(clst < 2) ABORT(fs, FR_INT_ERR);if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);/* 更新當(dāng)前讀寫偏移量所在簇號(hào) */fp->clust = clst;}/* 更新當(dāng)前讀寫偏移量所在扇區(qū)號(hào) */sect = clust2sect(fs, fp->clust);if(!sect) ABORT(fs, FR_INT_ERR);sect += csect;/* 當(dāng)剩余字節(jié)大于等于一個(gè)扇區(qū) */cc = btr / SS(fs);if(cc) {/* 在該簇中剩余扇區(qū)數(shù) */if(csect + cc > fs->csize) {cc = fs->csize - csect;}/* 將該簇中剩余數(shù)據(jù)都讀出來(lái) */if(disk_read(fs->drv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR);/* 還沒(méi)來(lái)得及回寫的數(shù)據(jù),需要從數(shù)據(jù)緩存窗口中讀出來(lái) */if((fp->flag & FA_DIRTY) && fp->sect - sect < cc) {mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs));}rcnt = SS(fs) * cc;continue;}/* 剩余字節(jié)數(shù)不大于一個(gè)扇區(qū) *//* 數(shù)據(jù)緩存窗口扇區(qū)不等于偏移量所在扇區(qū) */if(fp->sect != sect) {/* 先將緩存窗口數(shù)據(jù)回寫到扇區(qū) */if(fp->flag & FA_DIRTY) {if(disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);fp->flag &= (BYTE)~FA_DIRTY;}/* 將偏移量所在扇區(qū)數(shù)據(jù)更新到數(shù)據(jù)緩存窗口 */if(disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);}/* 更新數(shù)據(jù)緩存窗口扇區(qū)號(hào) */fp->sect = sect;}/* 確定該扇區(qū)中需要讀的字節(jié)數(shù) */rcnt = SS(fs) - (UINT)fp->fptr % SS(fs);if(rcnt > btr) rcnt = btr;/* 將數(shù)據(jù)從緩存窗口中讀出來(lái) */mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt);}LEAVE_FF(fs, FR_OK); }/* 寫文件 */ FRESULT f_write(FIL *fp, const void *buff, UINT btw, UINT *bw) {FRESULT res;FATFS *fs;DWORD clst, sect;UINT wcnt, cc, csect;const BYTE *wbuff = (const BYTE*)buff;*bw = 0;/* 檢查該文件/目錄是否有效,返回文件系統(tǒng)指針 */res = validate(&fp->obj, &fs);if(res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);/* 檢查文件是否具備寫權(quán)限 */if(!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED);/* 文件大小不能超過(guò)4GB */if((!_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr);}for(; btw; wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize, *bw += wcnt, btw -= wcnt) {/* 在扇區(qū)邊界 */if(fp->fptr % SS(fs) == 0) {/* 偏移量處于所在簇的第幾個(gè)扇區(qū) */csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster *//* 在簇的邊界 */if(csect == 0) { /* 在文件頂部 */if(fp->fptr == 0) { /* 當(dāng)前偏移量在文件起始簇 */clst = fp->obj.sclust;/* 文件還沒(méi)有寫入過(guò)任何內(nèi)容 */if(clst == 0) {/* 創(chuàng)建新簇鏈 */clst = create_chain(&fp->obj, 0);}} /* 不在文件頂部 */else {/* 查找FAT,取出下一簇號(hào) */{clst = create_chain(&fp->obj, fp->clust);}}if (clst == 0) break;if (clst == 1) ABORT(fs, FR_INT_ERR);if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);/* 更新當(dāng)前讀寫偏移量所在簇號(hào) */fp->clust = clst;/* 第一次寫,設(shè)置文件起始簇 */if(fp->obj.sclust == 0) fp->obj.sclust = clst;}/* 數(shù)據(jù)緩存窗口由數(shù)據(jù)需要回寫,先將數(shù)據(jù)回寫 */if(fp->flag & FA_DIRTY) {if(disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);fp->flag &= (BYTE)~FA_DIRTY;}/* 更新當(dāng)前讀寫偏移量所在扇區(qū)號(hào) */sect = clust2sect(fs, fp->clust);if(!sect) ABORT(fs, FR_INT_ERR);sect += csect;/* 當(dāng)剩余字節(jié)大于等于一個(gè)扇區(qū) */cc = btw / SS(fs);if(cc) {/* 在該簇中剩余扇區(qū)數(shù) */if(csect + cc > fs->csize) {cc = fs->csize - csect;}/* 將屬于該簇的所有數(shù)據(jù)寫入 */if(disk_write(fs->drv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR);/* 同時(shí)更新數(shù)據(jù)緩存窗口中數(shù)據(jù) */if(fp->sect - sect < cc) {mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs));fp->flag &= (BYTE)~FA_DIRTY;}wcnt = SS(fs) * cc;continue;}/* 剩余字節(jié)數(shù)不大于一個(gè)扇區(qū) *//* 數(shù)據(jù)緩存窗口扇區(qū)不等于偏移量所在扇區(qū) *//* 將偏移量所在扇區(qū)數(shù)據(jù)更新到數(shù)據(jù)緩存窗口 */if(fp->sect != sect && fp->fptr < fp->obj.objsize &&disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) {ABORT(fs, FR_DISK_ERR);}/* 更新數(shù)據(jù)緩存窗口扇區(qū)號(hào) */fp->sect = sect;}/* 確定該扇區(qū)中需要寫的字節(jié)數(shù) */wcnt = SS(fs) - (UINT)fp->fptr % SS(fs);if(wcnt > btw) wcnt = btw;/* 將數(shù)據(jù)寫到緩沖區(qū),下次有機(jī)會(huì)更新到存儲(chǔ)設(shè)備 */mem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt);fp->flag |= FA_DIRTY;}/* 文件發(fā)生修改 */fp->flag |= FA_MODIFIED;LEAVE_FF(fs, FR_OK); }/* 將數(shù)據(jù)和文件信息立即同步到存儲(chǔ)設(shè)備 */ FRESULT f_sync(FIL *fp) {FRESULT res;FATFS *fs;DWORD tm;BYTE *dir;/* 檢查該文件/目錄是否有效,返回文件系統(tǒng)指針 */res = validate(&fp->obj, &fs); /* Check validity of the file object */if(res == FR_OK) {/* 文件已經(jīng)被修改 */if(fp->flag & FA_MODIFIED) {/* 有數(shù)據(jù)需要回寫到存儲(chǔ)設(shè)備中 */if(fp->flag & FA_DIRTY) {if(disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR);fp->flag &= (BYTE)~FA_DIRTY;}/* 獲取時(shí)間戳 */tm = GET_FATTIME();{/* 將緩存窗口移動(dòng)到文件對(duì)應(yīng)的目錄項(xiàng)扇區(qū) */res = move_window(fs, fp->dir_sect);if(res == FR_OK) {/* 將文件信息寫入目錄項(xiàng) */dir = fp->dir_ptr;dir[DIR_Attr] |= AM_ARC; //歸檔st_clust(fp->obj.fs, dir, fp->obj.sclust); //文件起始簇st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); //文件大小st_dword(dir + DIR_ModTime, tm); //修改時(shí)間st_word(dir + DIR_LstAccDate, 0); //最后訪問(wèn)日期/* 文件信息立即寫入 */fs->wflag = 1;res = sync_fs(fs);fp->flag &= (BYTE)~FA_MODIFIED;}}}}LEAVE_FF(fs, res); }/* 關(guān)閉文件 */ FRESULT f_close(FIL *fp) {FRESULT res;FATFS *fs;/* 將數(shù)據(jù)和文件信息立即同步到存儲(chǔ)設(shè)備 */res = f_sync(fp);if(res == FR_OK){/* 檢查該文件/目錄是否有效,返回文件系統(tǒng)指針 */res = validate(&fp->obj, &fs); /* Lock volume */if (res == FR_OK) {/* 文件訪問(wèn)次數(shù)減一 */res = dec_lock(fp->obj.lockid);if (res == FR_OK){/* 文件指針?biāo)幬募到y(tǒng)請(qǐng)空 */fp->obj.fs = 0;}unlock_fs(fs, FR_OK);}}return res; }/* 將讀寫偏移量查找到指定位置 */ FRESULT f_lseek(FIL *fp, FSIZE_t ofs) {FRESULT res;FATFS *fs;DWORD clst, bcs, nsect;FSIZE_t ifptr;/* 檢查該文件/目錄是否有效,返回文件系統(tǒng)指針 */res = validate(&fp->obj, &fs);if (res == FR_OK) res = (FRESULT)fp->err;if(res != FR_OK) LEAVE_FF(fs, res);/* 不允許快速查找 */{/* 偏移量超過(guò)文件大小,并且當(dāng)前不在寫操作過(guò)程,則將偏移量調(diào)整為文件大小 */if(ofs > fp->obj.objsize && (_FS_READONLY || !(fp->flag & FA_WRITE))) {ofs = fp->obj.objsize;}/* 文件當(dāng)前讀寫偏移量 */ifptr = fp->fptr;fp->fptr = nsect = 0;if(ofs) {/* 每個(gè)簇字節(jié)數(shù) */bcs = (DWORD)fs->csize * SS(fs);/* 請(qǐng)求偏移量在當(dāng)前偏移量所在簇或后面簇 */if(ifptr > 0 && (ofs - 1) / bcs >= (ifptr - 1) / bcs) {/* 當(dāng)前簇起始偏移量 */fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1);/* 剩余偏移量 */ofs -= fp->fptr;/* 從當(dāng)前偏移量所在簇開(kāi)始往后找 */clst = fp->clust;} /* 請(qǐng)求偏移量在當(dāng)前偏移量所在簇的前年簇 */else { /* 文件起始簇 */clst = fp->obj.sclust;/* 沒(méi)有寫過(guò)任何數(shù)據(jù),沒(méi)有創(chuàng)建簇鏈,則創(chuàng)建簇鏈 */if(clst == 0) {clst = create_chain(&fp->obj, 0);if (clst == 1) ABORT(fs, FR_INT_ERR);if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);fp->obj.sclust = clst;}/* 從文件起始簇開(kāi)始找 */fp->clust = clst;}/* 向后找,更新當(dāng)前偏移量、所在簇和扇區(qū) */if(clst != 0) {while(ofs > bcs) {ofs -= bcs; fp->fptr += bcs;/* 寫請(qǐng)求,文件大小不夠需要擴(kuò)展 */if(fp->flag & FA_WRITE) {if(_FS_EXFAT && fp->fptr > fp->obj.objsize) {fp->obj.objsize = fp->fptr;fp->flag |= FA_MODIFIED;}clst = create_chain(&fp->obj, clst);if(clst == 0) {ofs = 0; break;}} else{clst = get_fat(&fp->obj, clst);}if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR);fp->clust = clst;}fp->fptr += ofs;if(ofs % SS(fs)) {nsect = clust2sect(fs, clst); /* Current sector */if(!nsect) ABORT(fs, FR_INT_ERR);nsect += (DWORD)(ofs / SS(fs));}}}/* 擴(kuò)展了簇鏈 */if(!_FS_READONLY && fp->fptr > fp->obj.objsize) {fp->obj.objsize = fp->fptr;fp->flag |= FA_MODIFIED;}/* 請(qǐng)求偏移量所在扇區(qū)和當(dāng)前數(shù)據(jù)緩沖窗口所在扇區(qū)不同 */if(fp->fptr % SS(fs) && nsect != fp->sect) {/* 將原窗口數(shù)據(jù)寫入扇區(qū) */if(fp->flag & FA_DIRTY) {if(disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);fp->flag &= (BYTE)~FA_DIRTY;}/* 將請(qǐng)求偏移量所在扇區(qū)數(shù)據(jù)讀到窗口中 */if(disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);/* 更新偏移量所在扇區(qū)號(hào) */fp->sect = nsect;}}LEAVE_FF(fs, res); }/* 打開(kāi)一個(gè)目錄項(xiàng) */ FRESULT f_opendir(DIR *dp, const TCHAR *path) {FRESULT res;FATFS *fs;_FDID *obj;if(!dp) return FR_INVALID_OBJECT;/* 通過(guò)路徑中的邏輯驅(qū)動(dòng)器號(hào),在邏輯驅(qū)動(dòng)器上查找該卷是否被掛載,如果沒(méi)有則嘗試掛載 返回邏輯驅(qū)動(dòng)器號(hào)后的路徑,返回文件系統(tǒng)指針 */obj = &dp->obj;res = find_volume(&path, &fs, 0);if(res == FR_OK) {/* 設(shè)置文件系統(tǒng)指針 */obj->fs = fs;/* 進(jìn)入文件所在路徑(將偏移量定位到指定路徑) */res = follow_path(dp, path);if(res == FR_OK) {/* 不是原目錄本身 */if(!(dp->fn[NSFLAG] & NS_NONAME)) { /* 該對(duì)象是一個(gè)子目錄 */if(obj->attr & AM_DIR) {/* 從目錄項(xiàng)中讀出文件/目錄起始簇號(hào) */obj->sclust = ld_clust(fs, dp->dir);}/* 該對(duì)象是一個(gè)文件 */ else {res = FR_NO_PATH;}}if(res == FR_OK) {obj->id = fs->id;/* 設(shè)置目錄偏移量到當(dāng)前目錄起始位置 */res = dir_sdi(dp, 0);if(res == FR_OK) {if(obj->sclust) {/* 文件訪問(wèn)次數(shù)加一 0:Read */obj->lockid = inc_lock(dp, 0);if(!obj->lockid) res = FR_TOO_MANY_OPEN_FILES;} /* 根目錄不需要鎖定 */else {obj->lockid = 0;}}}}if(res == FR_NO_FILE) res = FR_NO_PATH;}if(res != FR_OK) obj->fs = 0;LEAVE_FF(fs, res); }/* 關(guān)閉一個(gè)目錄項(xiàng) */ FRESULT f_closedir(DIR *dp) {FRESULT res;FATFS *fs;/* 檢查該文件/目錄是否有效,返回文件系統(tǒng)指針 */res = validate(&dp->obj, &fs);if (res == FR_OK) {/* 文件訪問(wèn)次數(shù)減一 */if(dp->obj.lockid) {res = dec_lock(dp->obj.lockid);}/* 清除所處文件系統(tǒng)指針,表示關(guān)閉 */if(res == FR_OK){dp->obj.fs = 0;}unlock_fs(fs, FR_OK);}return res; }/* 在指定目錄中讀出一個(gè)目錄項(xiàng) */ FRESULT f_readdir(DIR *dp, FILINFO *fno) {FRESULT res;FATFS *fs;/* 檢查該文件/目錄是否有效,返回文件系統(tǒng)指針 */res = validate(&dp->obj, &fs);if(res == FR_OK) {if(!fno) {/* 設(shè)置目錄偏移量到目錄起始處 */res = dir_sdi(dp, 0);} else{/* 指定目錄中查找一個(gè)目錄項(xiàng) */res = dir_read(dp, 0);if(res == FR_NO_FILE) res = FR_OK;if(res == FR_OK) {/* 獲取文件信息 */get_fileinfo(dp, fno);/* 當(dāng)前偏移量轉(zhuǎn)移到下一個(gè)目錄項(xiàng) */res = dir_next(dp, 0);if(res == FR_NO_FILE) res = FR_OK;}}}LEAVE_FF(fs, res); }/* 讀取指定文件信息 */ FRESULT f_stat(const TCHAR *path, FILINFO *fno) {FRESULT res;DIR dj;/* 通過(guò)路徑中的邏輯驅(qū)動(dòng)器號(hào),在邏輯驅(qū)動(dòng)器上查找該卷是否被掛載,如果沒(méi)有則嘗試掛載 返回邏輯驅(qū)動(dòng)器號(hào)后的路徑,返回文件系統(tǒng)指針 */res = find_volume(&path, &dj.obj.fs, 0);if (res == FR_OK) {/* 進(jìn)入文件所在路徑(將偏移量定位到指定路徑) */res = follow_path(&dj, path);if(res == FR_OK) { if(dj.fn[NSFLAG] & NS_NONAME) {res = FR_INVALID_NAME;} else { /* 獲取文件信息 */if(fno) get_fileinfo(&dj, fno);}}}LEAVE_FF(dj.obj.fs, res); }/* 獲取指定卷中的空閑簇個(gè)數(shù),并返回文件系統(tǒng)指針 */ FRESULT f_getfree(const TCHAR *path, DWORD *nclst, FATFS **fatfs) {FRESULT res;FATFS *fs;DWORD nfree, clst, sect, stat;UINT i;BYTE *p;_FDID obj;/* 通過(guò)路徑中的邏輯驅(qū)動(dòng)器號(hào),在邏輯驅(qū)動(dòng)器上查找該卷是否被掛載,如果沒(méi)有則嘗試掛載 返回邏輯驅(qū)動(dòng)器號(hào)后的路徑,返回文件系統(tǒng)指針 */res = find_volume(&path, &fs, 0);if(res == FR_OK) {/* 返回文件系統(tǒng)指針 */*fatfs = fs;/* 空閑簇個(gè)數(shù)值合理,返回空閑簇個(gè)數(shù) */if(fs->free_clst <= fs->n_fatent - 2) {*nclst = fs->free_clst;} else {/* 通過(guò)FAT表計(jì)算空閑簇個(gè)數(shù) */nfree = 0;if(fs->fs_type == FS_FAT12) {clst = 2; obj.fs = fs;do {stat = get_fat(&obj, clst);if(stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }if(stat == 1) { res = FR_INT_ERR; break; }if(stat == 0) nfree++;}while (++clst < fs->n_fatent);} else {{ /* FAT16/32: Sector alighed FAT entries */clst = fs->n_fatent; sect = fs->fatbase;i = 0; p = 0;do {if (i == 0) {res = move_window(fs, sect++);if (res != FR_OK) break;p = fs->win;i = SS(fs);}if (fs->fs_type == FS_FAT16) {if (ld_word(p) == 0) nfree++;p += 2; i -= 2;} else {if ((ld_dword(p) & 0x0FFFFFFF) == 0) nfree++;p += 4; i -= 4;}} while (--clst);}}*nclst = nfree;/* 更新一個(gè)合理的空閑簇個(gè)數(shù)到FSInfo中 */fs->free_clst = nfree; fs->fsi_flag |= 1;}}LEAVE_FF(fs, res); }/* 將文件大小縮減到當(dāng)前文件讀寫偏移量的位置 */ FRESULT f_truncate(FIL *fp) {FRESULT res;FATFS *fs;DWORD ncl;/* 檢查該文件/目錄是否有效,返回文件系統(tǒng)指針 */res = validate(&fp->obj, &fs);if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);/* 文件必須可寫 */if(!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED);/* 文件讀寫偏移量不在尾部 */if(fp->fptr < fp->obj.objsize) {/* 文件讀寫偏移量在文件首部 */if(fp->fptr == 0) {/* 將文件對(duì)應(yīng)的簇鏈所有簇移除 */res = remove_chain(&fp->obj, fp->obj.sclust, 0);fp->obj.sclust = 0;} /* 讀寫偏移量在中間 */else { /* 獲取讀寫偏移量所在簇對(duì)應(yīng)下一個(gè)簇號(hào) */ncl = get_fat(&fp->obj, fp->clust);res = FR_OK;if(ncl == 0xFFFFFFFF) res = FR_DISK_ERR;if(ncl == 1) res = FR_INT_ERR;/* 將讀寫偏移量所在簇后面的簇從簇鏈中全部移除 */if(res == FR_OK && ncl < fs->n_fatent) {res = remove_chain(&fp->obj, ncl, fp->clust);}}/* 將文件大小縮減到當(dāng)前讀寫偏移量 */fp->obj.objsize = fp->fptr;fp->flag |= FA_MODIFIED;/* 需要回寫數(shù)據(jù)緩存窗口內(nèi)容 */if(res == FR_OK && (fp->flag & FA_DIRTY)) {if(disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) {res = FR_DISK_ERR;} else {fp->flag &= (BYTE)~FA_DIRTY;}}if (res != FR_OK) ABORT(fs, res);}LEAVE_FF(fs, res); }/* 刪除路徑所指文件/目錄 */ FRESULT f_unlink(const TCHAR *path) {FRESULT res;DIR dj, sdj;DWORD dclst = 0;FATFS *fs;/* 通過(guò)路徑中的邏輯驅(qū)動(dòng)器號(hào),在邏輯驅(qū)動(dòng)器上查找該卷是否被掛載,如果沒(méi)有則嘗試掛載 返回邏輯驅(qū)動(dòng)器號(hào)后的路徑,返回文件系統(tǒng)指針 */res = find_volume(&path, &fs, FA_WRITE);dj.obj.fs = fs;if(res == FR_OK) {/* 進(jìn)入文件所在路徑(將偏移量定位到指定路徑) */res = follow_path(&dj, path);if(_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) {res = FR_INVALID_NAME;}if(res == FR_OK) res = chk_lock(&dj, 2);if(res == FR_OK) {if(dj.fn[NSFLAG] & NS_NONAME) {res = FR_INVALID_NAME;} else {if(dj.obj.attr & AM_RDO) {res = FR_DENIED;}}if(res == FR_OK) {{/* 從目錄項(xiàng)中讀出文件/目錄起始簇號(hào) */dclst = ld_clust(fs, dj.dir);}/* 這是一個(gè)目錄 */if(dj.obj.attr & AM_DIR) {{/* 設(shè)置目錄偏移量到該目錄起始處 */sdj.obj.fs = fs;sdj.obj.sclust = dclst;res = dir_sdi(&sdj, 0);if(res == FR_OK) {/* 指定目錄中查找一個(gè)文件/目錄 */res = dir_read(&sdj, 0);if(res == FR_OK) res = FR_DENIED; //該目錄不是空的if(res == FR_NO_FILE) res = FR_OK;}}}}/* 該目錄或文件可以刪除 */if(res == FR_OK) {/* 在指定目錄中移除當(dāng)前偏移量指向的目錄項(xiàng) */res = dir_remove(&dj);if(res == FR_OK && dclst) {/* 將該目錄/文件對(duì)應(yīng)簇鏈移除 */res = remove_chain(&dj.obj, dclst, 0);}/* 將數(shù)據(jù)同步到文件系統(tǒng) 包括緩存窗口數(shù)據(jù)和FSInfo數(shù)據(jù) */if(res == FR_OK) res = sync_fs(fs);}}}LEAVE_FF(fs, res); }/* 創(chuàng)建一個(gè)目錄項(xiàng) */ FRESULT f_mkdir(const TCHAR *path) {FRESULT res;DIR dj;FATFS *fs;BYTE *dir;UINT n;DWORD dsc, dcl, pcl, tm;/* 通過(guò)路徑中的邏輯驅(qū)動(dòng)器號(hào),在邏輯驅(qū)動(dòng)器上查找該卷是否被掛載,如果沒(méi)有則嘗試掛載 返回邏輯驅(qū)動(dòng)器號(hào)后的路徑,返回文件系統(tǒng)指針 */res = find_volume(&path, &fs, FA_WRITE);dj.obj.fs = fs;if(res == FR_OK) {/* 進(jìn)入文件所在路徑(將偏移量定位到指定路徑) */res = follow_path(&dj, path);if (res == FR_OK) res = FR_EXIST;if(_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) {res = FR_INVALID_NAME;}/* 可以創(chuàng)建該新目錄 */if(res == FR_NO_FILE) {/* 創(chuàng)建新簇鏈 */dcl = create_chain(&dj.obj, 0);/* 目錄項(xiàng)大小為一簇 */dj.obj.objsize = (DWORD)fs->csize * SS(fs);res = FR_OK;if(dcl == 0) res = FR_DENIED; if(dcl == 1) res = FR_INT_ERR;if(dcl == 0xFFFFFFFF) res = FR_DISK_ERR;/* 將緩存窗口數(shù)據(jù)同步到扇區(qū)中(更新FAT表) */if(res == FR_OK) res = sync_window(fs);/* 獲取時(shí)間戳 */tm = GET_FATTIME();if (res == FR_OK) { /* 將目錄起始簇號(hào)轉(zhuǎn)換為扇區(qū)號(hào) */dsc = clust2sect(fs, dcl);/* 初始化目錄中的兩個(gè)目錄項(xiàng) .和.. */dir = fs->win;mem_set(dir, 0, SS(fs));if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) {/* 第一個(gè)目錄項(xiàng). */mem_set(dir + DIR_Name, ' ', 11); /* 清空文件名 */dir[DIR_Name] = '.'; //目錄項(xiàng)名.dir[DIR_Attr] = AM_DIR; //屬性為目錄st_dword(dir + DIR_ModTime, tm); //修改時(shí)間st_clust(fs, dir, dcl); /* 將目錄.起始簇號(hào)寫入目錄項(xiàng) *//* 第二個(gè)目錄項(xiàng).. */mem_cpy(dir + SZDIRE, dir, SZDIRE); dir[SZDIRE + 1] = '.'; //目錄項(xiàng)名..pcl = dj.obj.sclust;if(fs->fs_type == FS_FAT32 && pcl == fs->dirbase) pcl = 0;st_clust(fs, dir + SZDIRE, pcl); //目錄項(xiàng)..起始簇號(hào)寫入目錄項(xiàng)}/* 將目錄當(dāng)前簇的數(shù)據(jù)寫進(jìn)去(第一扇區(qū)包含.和..,其它空間清零) */for(n = fs->csize; n; n--) {fs->winsect = dsc++;fs->wflag = 1;res = sync_window(fs);if(res != FR_OK) break;mem_set(dir, 0, SS(fs));}}if(res == FR_OK) {/* 將創(chuàng)建號(hào)的目錄項(xiàng)加入目錄 */res = dir_register(&dj);}/* 設(shè)置新創(chuàng)建的目錄項(xiàng)的文件信息 */if(res == FR_OK) {{dir = dj.dir;st_dword(dir + DIR_ModTime, tm); /* Created time */st_clust(fs, dir, dcl); /* Table start cluster */dir[DIR_Attr] = AM_DIR; /* Attribute */fs->wflag = 1;}if(res == FR_OK) {res = sync_fs(fs);}}/* 沒(méi)注冊(cè)成功,刪除創(chuàng)建好的目錄項(xiàng)簇鏈 */ else {remove_chain(&dj.obj, dcl, 0);}}}LEAVE_FF(fs, res); }/* 重命名目錄/文件 */ FRESULT f_rename(const TCHAR *path_old, const TCHAR *path_new) {FRESULT res;DIR djo, djn;FATFS *fs;BYTE buf[_FS_EXFAT ? SZDIRE * 2 : 24], *dir;DWORD dw;/* 從路徑中取出邏輯驅(qū)動(dòng)器號(hào),返回剩余路徑段 */get_ldnumber(&path_new);/* 通過(guò)路徑中的邏輯驅(qū)動(dòng)器號(hào),在邏輯驅(qū)動(dòng)器上查找該卷是否被掛載同時(shí)檢查磁盤是否寫保護(hù),如果沒(méi)有則嘗試掛載 返回邏輯驅(qū)動(dòng)器號(hào)后的路徑,返回文件系統(tǒng)指針 */res = find_volume(&path_old, &fs, FA_WRITE);if(res == FR_OK) {djo.obj.fs = fs;/* 進(jìn)入文件所在路徑(將偏移量定位到指定路徑) */res = follow_path(&djo, path_old);if(res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME;if(res == FR_OK) {res = chk_lock(&djo, 2);}/* 重命名的對(duì)象被找到 */if(res == FR_OK) {{ /* 保存名稱以外的文件信息 */mem_cpy(buf, djo.dir + DIR_Attr, 21);/* 復(fù)制目錄項(xiàng) */mem_cpy(&djn, &djo, sizeof(DIR));/* 進(jìn)入新文件所在路徑(將偏移量定位到指定路徑) */res = follow_path(&djn, path_new);if(res == FR_OK) {res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST;}/* 新文件名不沖突 */if(res == FR_NO_FILE) {/* 在指定目錄中創(chuàng)建新文件名的目錄項(xiàng) */res = dir_register(&djn); /* Register the new entry */if (res == FR_OK) {/* 將老文件名的目錄項(xiàng)信息拷貝到新目錄項(xiàng) */dir = djn.dir;mem_cpy(dir + 13, buf + 2, 19);dir[DIR_Attr] = buf[0] | AM_ARC;fs->wflag = 1;/* 新老目錄項(xiàng)不在同一個(gè)簇中 */if((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) {/* 將新目錄中的..目錄項(xiàng)的起始簇更新過(guò)來(lái) */dw = clust2sect(fs, ld_clust(fs, dir));if(!dw) {res = FR_INT_ERR;} else {res = move_window(fs, dw);dir = fs->win + SZDIRE * 1;if (res == FR_OK && dir[1] == '.') {st_clust(fs, dir, djn.obj.sclust);fs->wflag = 1;}}}}}}/* 移除老的目錄項(xiàng) */if(res == FR_OK) {res = dir_remove(&djo);if(res == FR_OK) {res = sync_fs(fs);}}}}LEAVE_FF(fs, res); }/* 創(chuàng)建一個(gè)FAT卷 opt指定文件系統(tǒng)類型 au指定簇字節(jié)數(shù) work和len工作緩沖區(qū)指針和長(zhǎng)度(最好是一個(gè)扇區(qū)) */ FRESULT f_mkfs(const TCHAR *path, BYTE opt, DWORD au, void *work, UINT len) {const UINT n_fats = 1;const UINT n_rootdir = 512;static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0};static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0};BYTE fmt, sys, *buf, *pte, pdrv;WORD ss;DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n;DWORD b_vol, b_fat, b_data;DWORD sz_vol, sz_rsv, sz_fat, sz_dir;UINT i;int vol;DSTATUS stat;/* 從路徑中取出邏輯驅(qū)動(dòng)器號(hào),返回剩余路徑段 */vol = get_ldnumber(&path);if (vol < 0) return FR_INVALID_DRIVE;/* 清除原來(lái)的卷 */if(FatFs[vol])FatFs[vol]->fs_type = 0;/* 物理設(shè)備號(hào) */pdrv = LD2PD(vol);/* 檢查物理設(shè)備狀態(tài) */stat = disk_initialize(pdrv);if(stat & STA_NOINIT) return FR_NOT_READY;if(stat & STA_PROTECT) return FR_WRITE_PROTECTED;/* 塊扇區(qū)個(gè)數(shù) */if(disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1;/* 扇區(qū)字節(jié)數(shù) */ss = _MAX_SS;if((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER;/* 每個(gè)簇多少扇區(qū) */au /= ss;/* 工作緩沖區(qū)指針、扇區(qū)數(shù)、字節(jié)數(shù)(扇區(qū)對(duì)齊) */buf = (BYTE *)work;sz_buf = len / ss;szb_buf = sz_buf * ss;if(!szb_buf) return FR_MKFS_ABORTED;/* 創(chuàng)建一個(gè)單分區(qū) *//* 獲取扇區(qū)個(gè)數(shù) */if(disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) return FR_DISK_ERR;/* 卷起始扇區(qū) */b_vol = (opt & FM_SFD) ? 0 : 63;if(sz_vol < b_vol) return FR_MKFS_ABORTED;/* 卷扇區(qū)個(gè)數(shù) */sz_vol -= b_vol;if(sz_vol < 128) return FR_MKFS_ABORTED;/* 指定FAT類型 */do { if(au > 128) return FR_INVALID_PARAMETER;/* FAT32 */if(opt & FM_FAT32) {if((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) {fmt = FS_FAT32; break;}}if(!(opt & FM_FAT)) return FR_INVALID_PARAMETER;/* FAT12/16 */fmt = FS_FAT16;}while(0);/* 創(chuàng)建FAT12/16/32卷 */do{pau = au;/* 預(yù)先確定了FAT32類型 */if(fmt == FS_FAT32) {/* 沒(méi)指定簇大小 */if(!pau) {/* 一個(gè)卷有多少128K扇區(qū)單元 */n = sz_vol / 0x20000;/* 計(jì)算一個(gè)簇占多少扇區(qū) */for(i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ;}/* 計(jì)算簇個(gè)數(shù) */n_clst = sz_vol / pau;/* FAT表的扇區(qū)數(shù) */sz_fat = (n_clst * 4 + 8 + ss - 1) / ss;/* 保留扇區(qū)個(gè)數(shù) */sz_rsv = 32;/* 無(wú)靜態(tài)目錄 */sz_dir = 0;/* 簇個(gè)數(shù)不符合FAT32要求 */if(n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) return FR_MKFS_ABORTED;}/* FAT12/16類型 */else {/* 沒(méi)指定簇大小 */if(!pau) {/* 一個(gè)卷有多少4KS扇區(qū)單元 */n = sz_vol / 0x1000;/* 計(jì)算一個(gè)簇占多少扇區(qū) */for(i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ;}/* 計(jì)算簇個(gè)數(shù) */n_clst = sz_vol / pau;/* FAT16 */if(n_clst > MAX_FAT12) {n = n_clst * 2 + 4;} /* FAT12 */else {fmt = FS_FAT12;n = (n_clst * 3 + 1) / 2 + 3;}/* FAT表的扇區(qū)數(shù) */sz_fat = (n + ss - 1) / ss;/* 保留區(qū)域扇區(qū)數(shù) */sz_rsv = 1;/* 根目錄扇區(qū)數(shù) */sz_dir = (DWORD)n_rootdir * SZDIRE / ss;}/* FAT起始扇區(qū) */b_fat = b_vol + sz_rsv;/* 數(shù)據(jù)起始扇區(qū) */b_data = b_fat + sz_fat * n_fats + sz_dir;/* 向后n扇區(qū)可進(jìn)行擦除塊對(duì)齊 */n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data;if(fmt == FS_FAT32) {/* 移動(dòng)保留區(qū)和FAT表起始扇區(qū) */sz_rsv += n; b_fat += n;} else { /* 擴(kuò)展FAT大小 */sz_fat += n / n_fats;}if(sz_vol < b_data + pau * 16 - b_vol) return FR_MKFS_ABORTED;/* 計(jì)算簇個(gè)數(shù) */n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau;if(fmt == FS_FAT32) {if(n_clst <= MAX_FAT16) {if(!au && (au = pau / 2) != 0) continue;return FR_MKFS_ABORTED;}}/* 對(duì)于FAT16 */if(fmt == FS_FAT16) {/* 簇太多了 */if(n_clst > MAX_FAT16) {/* 簇扇區(qū)個(gè)數(shù)很少,可以調(diào)整,但不能大于64 */if(!au && (pau * 2) <= 64) {au = pau * 2; continue;}/* 換成FAT32 */if((opt & FM_FAT32)) {fmt = FS_FAT32; continue;}/* 簇扇區(qū)個(gè)數(shù)很少,可以調(diào)整,但不能大于128 */if(!au && (au = pau * 2) <= 128) continue;return FR_MKFS_ABORTED;}/* 簇太少了 */if (n_clst <= MAX_FAT12) { /* 簇扇區(qū)個(gè)數(shù)很少,可以調(diào)整,但不能大于128 */if(!au && (au = pau * 2) <= 128) continue;return FR_MKFS_ABORTED;}}/* 對(duì)于FAT12來(lái)說(shuō)簇太多了 */if(fmt == FS_FAT12 && n_clst > MAX_FAT12) return FR_MKFS_ABORTED;/* 計(jì)算出了合理的簇扇區(qū)數(shù)和簇?cái)?shù) */break;}while(1);/* 創(chuàng)建FAT的boot扇區(qū) */mem_set(buf, 0, ss);/* x86跳轉(zhuǎn)指令 */mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11); /* FAT12/16:扇區(qū)大小 FAT32:0 */st_word(buf + BPB_BytsPerSec, ss); /* 簇的扇區(qū)數(shù) */ buf[BPB_SecPerClus] = (BYTE)pau; /* 保留區(qū)的扇區(qū)數(shù) */st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* FAT表個(gè)數(shù) */buf[BPB_NumFATs] = (BYTE)n_fats; /* FAT12/16:根目錄中目錄項(xiàng)個(gè)數(shù) FAT32:0 */st_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir));/* FAT卷的總扇區(qū)數(shù) */if(sz_vol < 0x10000) {st_word(buf + BPB_TotSec16, (WORD)sz_vol);} else {st_dword(buf + BPB_TotSec32, sz_vol);}/* 媒體確定,不再用于任何目的 */buf[BPB_Media] = 0xF8;/* 每個(gè)軌道的扇區(qū)數(shù) */st_word(buf + BPB_SecPerTrk, 63);/* 磁頭數(shù) */st_word(buf + BPB_NumHeads, 255);/* FAT卷之前隱藏的物理扇區(qū)數(shù) */st_dword(buf + BPB_HiddSec, b_vol);/* FAT32 */if(fmt == FS_FAT32) {/* 卷序列號(hào) */st_dword(buf + BS_VolID32, GET_FATTIME());/* FAT占用的扇區(qū)數(shù) */st_dword(buf + BPB_FATSz32, sz_fat);/* 根目錄起始簇號(hào) */st_dword(buf + BPB_RootClus32, 2);/* FSInfo的扇區(qū)相對(duì)于FAT32卷的頂部的偏移 */st_word(buf + BPB_FSInfo32, 1);/* 備份引導(dǎo)扇區(qū)相對(duì)于FAT32卷頂部的偏移扇區(qū) */st_word(buf + BPB_BkBootSec32, 6);/* 驅(qū)動(dòng)器號(hào) */buf[BS_DrvNum32] = 0x80;/* 擴(kuò)展引導(dǎo)簽名 */buf[BS_BootSig32] = 0x29;/* 卷標(biāo) */mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); }/* FAT12/16 */else {/* 卷序列號(hào) */st_dword(buf + BS_VolID, GET_FATTIME());/* FAT占用的扇區(qū)數(shù) */st_word(buf + BPB_FATSz16, (WORD)sz_fat);/* 驅(qū)動(dòng)器號(hào) */buf[BS_DrvNum] = 0x80;/* 擴(kuò)展引導(dǎo)簽名 */buf[BS_BootSig] = 0x29;/* 卷標(biāo) */mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19);}/* 引導(dǎo)簽名 */st_word(buf + BS_55AA, 0xAA55);if(disk_write(pdrv, buf, b_vol, 1) != RES_OK) return FR_DISK_ERR;/* FAT32還要?jiǎng)?chuàng)建FSINFO */if(fmt == FS_FAT32) {/* boot扇區(qū)備份 */disk_write(pdrv, buf, b_vol + 6, 1);mem_set(buf, 0, ss);/* FSInfo的主要簽名 */st_dword(buf + FSI_LeadSig, 0x41615252);st_dword(buf + FSI_StrucSig, 0x61417272);/* 空閑簇?cái)?shù) */st_dword(buf + FSI_Free_Count, n_clst - 1);/* 最后一個(gè)被分配的簇號(hào),程序應(yīng)該從此開(kāi)始尋找空閑簇 */st_dword(buf + FSI_Nxt_Free, 2);/* 引導(dǎo)簽名 */st_word(buf + BS_55AA, 0xAA55);/* FSINFO扇區(qū)備份 */disk_write(pdrv, buf, b_vol + 7, 1);/* FSINFO扇區(qū) */disk_write(pdrv, buf, b_vol + 1, 1);}/* 初始化FAT區(qū)域 */mem_set(buf, 0, (UINT)szb_buf);sect = b_fat;for(i = 0; i < n_fats; i++) {/* 設(shè)置FAT表項(xiàng)簇0和簇1 */if(fmt == FS_FAT32) {st_dword(buf + 0, 0xFFFFFFF8); /* 簇0 */st_dword(buf + 4, 0xFFFFFFFF); /* 簇1 */st_dword(buf + 8, 0x0FFFFFFF); /* 簇2(根目錄) */}else {st_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8);}/* 其余FAT表項(xiàng)清空 */nsect = sz_fat;do {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);}/* 初始化根目錄 */nsect = (fmt == FS_FAT32) ? pau : sz_dir;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);/* 文件系統(tǒng)類型ID */if(fmt == FS_FAT32) {sys = 0x0C;} else {if(sz_vol >= 0x10000) {sys = 0x06; /* FAT12/16 (>=64KS) */} else{sys = (fmt == FS_FAT16) ? 0x04 : 0x01; /* FAT16 (<64KS) : FAT12 (<64KS) */}}/* 創(chuàng)建MBR區(qū)域 */if(!(opt & FM_SFD)) {mem_set(buf, 0, ss);st_word(buf + BS_55AA, 0xAA55); /* MBR簽名 */pte = buf + MBR_Table; /* 分區(qū)表指針 */pte[PTE_Boot] = 0; /* 引導(dǎo)標(biāo)志 0x00:非活動(dòng)分區(qū) */pte[PTE_StHead] = 1; /* 起始磁頭號(hào) */pte[PTE_StSec] = 1; /* 起始扇區(qū)號(hào) */pte[PTE_StCyl] = 0; /* 起始柱面號(hào) */pte[PTE_System] = sys; /* 分區(qū)類型 0x06:FAT16 0x0B:FAT32 */n = (b_vol + sz_vol) / (63 * 255); /* (End CHS may be invalid) */pte[PTE_EdHead] = 254; /* 結(jié)束磁頭號(hào) */pte[PTE_EdSec] = (BYTE)(n >> 2 | 63); /* 結(jié)束扇區(qū)號(hào)*/pte[PTE_EdCyl] = (BYTE)n; /* 結(jié)束柱面號(hào) */st_dword(pte + PTE_StLba, b_vol); /* 邏輯起始扇區(qū)號(hào) */st_dword(pte + PTE_SizLba, sz_vol); /* 總扇區(qū)數(shù) */if(disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR;}if(disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) return FR_DISK_ERR;return FR_OK; }

?

總結(jié)

以上是生活随笔為你收集整理的FatFs源码分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。