文件系统分析了两天,自己都不知道入没入门,现在就把这两天分析的结果总结一下吧!
一、res = f_mount(0,&fs);
首先是挂接根文件系统,为什么要挂接根文件系统内容?因为根文件系统里面会对我们的SD卡进行初始化,除此之外
f_mount函数可以实现在FatFs模块上注册/ 注销一个工作区。 在使用任何其他文件函数之前,必须使用该函数为每个
卷注册一个工作区。要注销一个工作区,只要指定FileSystemObject 为NULL即可,然后该工作区可以被丢
弃。 该函数只初始化给定的工作区,以及将该工作区的地址注册到内部表中,不访问磁盘I/O 层。卷装入过程是在
f_mount函数后或存储介质改变后的第一次文件访问时完成的。
接着分析这个函数是怎么定义的:
/******************************************************************************** * 函数名称: f_mount * 函数说明: 用于挂载/卸载磁盘驱动器 * 输入参数: vol:Logical drive number to be mounted/unmounted * fs:Pointer to new file system object (NULL for unmount) * 返回参数: 挂载标识FR_OK表示成功! * 注意事项: 无 *********************************************************************************/ FRESULT f_mount ( BYTE vol, /* Logical drive number to be mounted/unmounted */ FATFS *fs /* */ ) { FATFS *rfs; if (vol >= _VOLUMES) /* Check if the drive number is valid */ //如果 return FR_INVALID_DRIVE; rfs = FatFs[vol]; /* Get current fs object */ if (rfs) { #if _FS_LOCK clear_lock(rfs); #endif #if _FS_REENTRANT /* Discard sync object of the current volume */ if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR; #endif rfs->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(vol, &fs->sobj)) return FR_INT_ERR; #endif } FatFs[vol] = fs; /* Register new fs object */ return FR_OK; }1、vol = 0,fs = &fs 首先看这个rfs = FatFs[vol]; /* Get current fs object */
typedef struct { BYTE fs_type; /* FAT sub-type (0:Not mounted) */ BYTE drv; /* Physical drive number */ BYTE csize; /* Sectors per cluster (1,2,4...128) */ BYTE n_fats; /* Number of FAT copies (1,2) */ BYTE wflag; /* win[] dirty flag (1:must be written back) */ BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */ WORD id; /* File system mount ID */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ DWORD last_clust; /* Last allocated cluster */ DWORD free_clust; /* Number of free clusters */ DWORD fsi_sector; /* fsinfo sector (FAT32) */ DWORD n_fatent; /* Number of FAT entries (= number of clusters + 2) */ DWORD fsize; /* Sectors per FAT */ DWORD fatbase; /* FAT start sector */ DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */ DWORD database; /* Data start sector */ DWORD winsect; /* Current sector appearing in the win[] */ BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and Data on tiny cfg) */ //存放的就是我们读SD卡第一扇区的内容 } FATFS;
if (rfs) { rfs->fs_type = 0; /* Clear old fs object */ } if (fs) { fs->fs_type = 0; /* Clear new fs object */ } FatFs[vol] = fs; /* Register new fs object */ return FR_OK;
FRESULT f_open ( FIL *fp, /* Pointer to the blank file object */ const TCHAR *path, /* Pointer to the file name */ BYTE mode /* Access mode and file open mode flags */ ) { FRESULT res; DIR dj; BYTE *dir; DEF_NAMEBUF; if (!fp) return FR_INVALID_OBJECT; fp->fs = 0; /* Clear file object */ mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW; res = chk_mounted(&path, &dj.fs, (BYTE)(mode & ~FA_READ)); if (res == FR_OK) { INIT_BUF(dj); res = follow_path(&dj, path); /* Follow the file path */ dir = dj.dir; } /* Create or Open a file */ if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { DWORD dw, cl; if (res != FR_OK) { /* No file, create new */ if (res == FR_NO_FILE) /* There is no file to open, create a new entry */ res = dir_register(&dj); mode |= FA_CREATE_ALWAYS; /* File is created */ dir = dj.dir; /* New entry */ } else { /* Any object is already existing */ if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ res = FR_DENIED; } else { if (mode & FA_CREATE_NEW) /* Cannot create as new file */ res = FR_EXIST; } } if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ dw = get_fattime(); /* Created time */ ST_DWORD(dir+DIR_CrtTime, dw); dir[DIR_Attr] = 0; /* Reset attribute */ ST_DWORD(dir+DIR_FileSize, 0); /* size = 0 */ cl = ld_clust(dj.fs, dir); /* Get start cluster */ st_clust(dir, 0); /* cluster = 0 */ dj.fs->wflag = 1; if (cl) { /* Remove the cluster chain if exist */ dw = dj.fs->winsect; res = remove_chain(dj.fs, cl); if (res == FR_OK) { dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */ res = move_window(dj.fs, dw); } } } } else { /* Open an existing file */ if (res == FR_OK) { /* Follow succeeded */ if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */ res = FR_NO_FILE; } else { if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */ res = FR_DENIED; } } } if (res == FR_OK) { if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */ mode |= FA__WRITTEN; fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dir; if (res == FR_OK) { /* Follow succeeded */ dir = dj.dir; if (!dir) { /* Current dir itself */ res = FR_INVALID_NAME; } else { if (dir[DIR_Attr] & AM_DIR) /* It is a directory */ res = FR_NO_FILE; } } FREE_BUF(); if (res == FR_OK) { fp->flag = mode; /* File access mode */ fp->sclust = ld_clust(dj.fs, dir); /* File start cluster */ fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */ fp->fptr = 0; /* File pointer */ fp->dsect = 0; fp->fs = dj.fs; fp->id = dj.fs->id; /* Validate file object */ } } LEAVE_FF(dj.fs, res); }
typedef struct { FATFS* fs; /* Pointer to the related file system object */ WORD id; /* File system mount ID of the related file system object */ BYTE flag; /* File status flags */ BYTE pad1; DWORD fptr; /* File read/write pointer (0ed on file open) */ DWORD fsize; /* File size */ DWORD sclust; /* File data start cluster (0:no data cluster, always 0 when fsize is 0) */ DWORD clust; /* Current cluster of fpter */ DWORD dsect; /* Current data sector of fpter */ } FIL; fp->fs = 0; /* Clear file object */这里就把fs清零了。
static FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occurred */ const TCHAR **path, /* Pointer to pointer to the path name (drive number) */ FATFS **rfs, /* Pointer to pointer to the found file system object */ BYTE wmode /* !=0: Check write protection for write access */ )
typedef struct { FATFS* fs; /* Pointer to the owner file system object */ WORD id; /* Owner file system mount ID */ WORD index; /* Current read/write index number */ DWORD sclust; /* Table start cluster (0:Root dir) */ DWORD clust; /* Current cluster */ DWORD sect; /* Current sector */ BYTE* dir; /* Pointer to the current SFN entry in the win[] */ BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ #if _USE_LFN WCHAR* lfn; /* Pointer to the LFN working buffer */ WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */ #endif } DIR;
/* Get logical drive number from the path name */ vol = p[0] - '0'; /* Is there a drive number? */ if (vol <= 9 && p[1] == ':') { /* Found a drive number, get and strip it */ p += 2; *path = p; /* Return pointer to the path name */ } else { /* No drive number is given */ vol = 0; /* Use drive 0 */ }
*rfs = 0; if (vol >= _VOLUMES) /* Is the drive number valid? */ return FR_INVALID_DRIVE; fs = FatFs[vol]; /* Get corresponding file system object */ if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */ ENTER_FF(fs); /* Lock file system */ *rfs = fs; /* Return pointer to the corresponding file system object */ if (fs->fs_type) { /* If the volume has been mounted */ stat = disk_status(fs->drv); if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized (has not been changed), */ if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check write protection if needed */ return FR_WRITE_PROTECTED; return FR_OK; /* The file system object is valid */ } }
fs->fs_type = 0; /* Clear the file system object */ fs->drv = LD2PD(vol); /* Bind the logical drive and a physical drive */ stat = disk_initialize(fs->drv); /* Initialize the physical drive */ if (stat & STA_NOINIT) /* Check if the initialization succeeded */ return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */
tatic BYTE check_fs ( /* 0:FAT-VBR, 1:Any BR but not FAT, 2:Not a BR, 3:Disk error */ FATFS *fs, /* File system object */ DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */ ) { if (disk_read(fs->drv, fs->win, sect, 1) != RES_OK) /* Load boot record */ return 3; if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check record signature (always placed at offset 510 even if the sector size is >512) */ return 2; if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */ return 0; if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146) return 0; return 1; }
if (LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */ return FR_NO_FILESYSTEM;
fasize = LD_WORD(fs->win+BPB_FATSz16); if (!fasize) fasize = LD_DWORD(fs->win+BPB_FATSz32); fs->fsize = fasize; fs->n_fats = b = fs->win[BPB_NumFATs]; /* Number of FAT copies */ if (b != 1 && b != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ fasize *= b; /* Number of sectors for FAT area */ fs->csize = b = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ if (!b || (b & (b - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ tsect = LD_WORD(fs->win+BPB_TotSec16); /* Number of sectors on the volume */ if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32); nrsv = LD_WORD(fs->win+BPB_RsvdSecCnt); /* Number of reserved sectors */ if (!nrsv) return FR_NO_FILESYSTEM; /* (BPB_RsvdSecCnt must not be 0) */
/* Determine the FAT sub type */ sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIR); /* RSV+FAT+DIR */ if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ fmt = FS_FAT12; if (nclst >= MIN_FAT16) fmt = FS_FAT16; if (nclst >= MIN_FAT32) fmt = FS_FAT32;
/* Boundaries and Limits */ fs->n_fatent = nclst + 2; /* Number of FAT entries */ fs->database = bsect + sysect; /* Data start sector */ fs->fatbase = bsect + nrsv; /* FAT start sector */
fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ szbfat = (fmt == FS_FAT16) ? /* (Required FAT size) */
/* Initialize cluster allocation information */ fs->free_clust = 0xFFFFFFFF; fs->last_clust = 0;
INIT_BUF(dj); //初始化了 res = follow_path(&dj, path); /* Follow the file path */ dir = dj.dir;
static WCHAR LfnBuf[_MAX_LFN+1]; #define DEF_NAMEBUF BYTE sfn[12] #define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; }
if (*path == '/' || *path == '\\') /* Strip heading separator if exist */ path++; dj->sclust = 0; /* Start from the root dir */
if ((UINT)*path < ' ') { /* Nul path means the start directory itself */ res = dir_sdi(dj, 0); dj->dir = 0;
for (;;) { w = p[si++]; /* Get a character */ if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */ if (di >= _MAX_LFN) /* Reject too long name */ return FR_INVALID_NAME; #if !_LFN_UNICODE w &= 0xFF; if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ b = (BYTE)p[si++]; /* Get 2nd byte */ if (!IsDBCS2(b)) return FR_INVALID_NAME; /* Reject invalid sequence */ w = (w << 8) + b; /* Create a DBC */ } w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */ if (!w) return FR_INVALID_NAME; /* Reject invalid code */ #endif if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal chars for LFN */ return FR_INVALID_NAME; lfn[di++] = w; /* Store the Unicode char */ }
*path = &p[si]; /* Return pointer to the next segment */ cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
res = dir_sdi(dj, 0); /* Rewind directory object */ static FRESULT dir_sdi ( DIR *dj, /* Pointer to directory object */ WORD idx /* Index of directory table */ ) { DWORD clst; WORD ic; dj->index = idx; clst = dj->sclust; if (clst == 1 || clst >= dj->fs->n_fatent) /* Check start cluster range */ return FR_INT_ERR; if (!clst && dj->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */ clst = dj->fs->dirbase; if (clst == 0) { /* Static table (root-dir in FAT12/16) */ dj->clust = clst; if (idx >= dj->fs->n_rootdir) /* Index is out of range */ return FR_INT_ERR; dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / SZ_DIR); /* Sector# */ } dj->dir = dj->fs->win + (idx % (SS(dj->fs) / SZ_DIR)) * SZ_DIR; /* Ptr to the entry in the sector */ return FR_OK; /* Seek succeeded */ }
if (sector) { if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK) return FR_DISK_ERR; fs->winsect = sector;
static FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not stretch */ DIR *dj, /* Pointer to directory object */ int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ ) { DWORD clst; WORD i; stretch = stretch; /* To suppress warning on read-only cfg. */ i = dj->index + 1; if (!i || !dj->sect) /* Report EOT when index has reached 65535 */ return FR_NO_FILE; dj->index = i; dj->dir = dj->fs->win + (i % (SS(dj->fs) / SZ_DIR)) * SZ_DIR; return FR_OK; }
if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ dw = get_fattime(); /* Created time */ ST_DWORD(dir+DIR_CrtTime, dw); dir[DIR_Attr] = 0; /* Reset attribute */ ST_DWORD(dir+DIR_FileSize, 0); /* size = 0 */ cl = ld_clust(dj.fs, dir); /* Get start cluster */ st_clust(dir, 0); /* cluster = 0 */ dj.fs->wflag = 1; if (cl) { /* Remove the cluster chain if exist */ dw = dj.fs->winsect; res = remove_chain(dj.fs, cl); if (res == FR_OK) { dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */ res = move_window(dj.fs, dw); } } } }
if (res == FR_OK) { if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */ mode |= FA__WRITTEN; fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dir; #if _FS_LOCK fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); if (!fp->lockid) res = FR_INT_ERR; #endif } #else /* R/O configuration */ if (res == FR_OK) { /* Follow succeeded */ dir = dj.dir; if (!dir) { /* Current dir itself */ res = FR_INVALID_NAME; } else { if (dir[DIR_Attr] & AM_DIR) /* It is a directory */ res = FR_NO_FILE; } } #endif FREE_BUF(); if (res == FR_OK) { fp->flag = mode; /* File access mode */ fp->sclust = ld_clust(dj.fs, dir); /* File start cluster */ fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */ fp->fptr = 0; /* File pointer */ fp->dsect = 0; #if _USE_FASTSEEK fp->cltbl = 0; /* Normal seek mode */ #endif fp->fs = dj.fs; fp->id = dj.fs->id; /* Validate file object */
FRESULT f_close ( FIL *fp /* Pointer to the file object to be closed */ ) { FRESULT res; res = f_sync(fp); /* Flush cached data */ if (res == FR_OK) fp->fs = 0; /* Discard file object */ return res; }
if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) /* Fill sector cache */