📄 fs_fat.c
字号:
/*----------------------------------------------------------------------------
* R T L - F l a s h F i l e S y s t e m
*----------------------------------------------------------------------------
* Name: FS_FAT.C
* Purpose: FAT File System Class Implementation
* Rev.: V3.22
*----------------------------------------------------------------------------
* This code is part of the RealView Run-Time Library.
* Copyright (c) 2004-2008 KEIL - An ARM Company. All rights reserved.
*---------------------------------------------------------------------------*/
#include "File_Config.h"
#include <string.h>
#define INVAL_SECT 0xFFFFFFFF
/* Possible "search_for_name" function actions definitions */
#define ACT_NONE 0x00
#define ACT_KEEPFCB 0x01
/* Local Constants */
static const DEVPAR IniDevCfg[10] = {
/* FatType SecClus SecClus32 NumHeads BootRecSec */
{ FS_FAT12, 16, 0, 2, 65 }, /* Size 8 MB */
{ FS_FAT12, 16, 0, 2, 65 }, /* Size 16 MB */
{ FS_FAT12, 32, 0, 2, 65 }, /* Size 32 MB */
{ FS_FAT12, 32, 0, 4, 65 }, /* Size 64 MB */
{ FS_FAT16, 16, 0, 8, 65 }, /* Size 128 MB */
{ FS_FAT16, 16, 4, 16, 129 }, /* Size 256 MB */
{ FS_FAT16, 32, 8, 32, 129 }, /* Size 512 MB */
{ FS_FAT16, 32, 16, 64, 257 }, /* Size 1 GB */
{ FS_FAT16, 64, 32, 128, 257 }, /* Size 2 GB */
{ FS_FAT32, 64, 64, 128, 257 }}; /* Size 4 GB */
/* Parameters in this table are optimized for SD/MMC memory cards. */
/* Optimal file system is FAT12/FAT16 with Cluster sizes 8k, 16k, 32k. */
/* Cluster 2 shall be block aligned (32K aligned) */
static const U8 ChIndex[13] = { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
/* Local Variables */
static FCACHE fat;
static DCACHE ca;
static FATINFO mmc;
static U32 free_clus;
static U32 top_clus;
static U32 startDirClus;
static U32 firstEntClus;
static U16 firstEntOffs;
static U8 numOfEntries;
static BIT in_root_1x;
static BIT warm_restart;
static char name_buf[260]; /* Name buffer */
/* Local Function Prototypes */
static int init_dev (void);
static BOOL write_mbr (U32 iSz);
static BOOL write_br (U32 sernum);
static void wipe_disk (U32 dsize);
static BOOL fat_find_dir (const char *fn, IOB *fcb, U8 create);
static BOOL write_label (const char *label);
static BOOL set_next_clus (U32 *ptr_clus);
static BOOL get_free_clus (U32 *ptr_clus);
static BOOL clus_in_use (U32 clus);
static BOOL clear_clus (U32 clus);
static BOOL write_fat_link (U32 clus, U32 next_clus);
static BOOL unlink_clus_chain (U32 clus);
static BOOL alloc_new_clus (U32 *ptr_clus, U8 wr_fat_link);
static U32 count_free_clus (void);
static U32 clus_to_sect (U32 clus);
static U32 get_fat_sect (U32 clus);
static BOOL read_sector (U32 sect);
static BOOL write_sector (U32 sect);
static BOOL read_cache (U32 sect, U32 cnt);
static void write_cache (U32 sect);
static BOOL cache_fat (U32 sect);
static BOOL is_EOC (U32 clus);
static U32 get_EOC (void);
static BOOL get_mbrec (void);
static BOOL get_bootrec (void);
static BOOL is_fat_valid (void);
static U16 get_time (void);
static U16 get_date (void);
static void set_time_date (FINFO *info, FILEREC *frec);
static BOOL cvt_fatname (const char *fn, char *en);
static BOOL check_lfn (const char *fn);
static U8 val_char (U8 ch);
static BOOL val_char_sn (U8 ch);
//static BOOL val_char_ln (U8 ch);
static U8 val_char_lab (U8 ch);
static U16 get_u16 (U8 *nr);
static void set_u16 (U8 *nr, U16 val);
static U32 get_u32 (U8 *nr);
static void set_u32 (U8 *nr, U32 val);
static BOOL get_dir_name (const char *fn, char *dn, unsigned int *sz);
static BOOL get_nt_name (const char *fn, char *sn, int num);
static U32 get_dir_sect (U32 clus);
static BOOL search_for_name (const char *name, IOB *fcb, U8 type, U8 keep_fcb);
static BOOL find_name (const char *name, IOB *fcb, U8 type);
static BOOL check_name (const char *name, IOB *fcb, U8 type);
static BOOL alloc_name (const char *name, IOB *fcb);
static BOOL get_next_info (FINFO *info, IOB *fcb);
static BOOL chk_dir_empty (IOB *fcb);
static BOOL read_last_entry (IOB *fcb, FILEREC *filerec);
static BOOL write_last_entry (IOB *fcb, FILEREC *filerec);
static BOOL write_entries (const char *name, IOB *fcb, U8 type, FILEREC *last_entry);
static BOOL delete_entries (IOB *fcb, U8 action);
static BOOL rename_entries (const char *new_name, IOB *fcb, U8 type);
static BOOL write_dot_entries (IOB *fcb);
static U8 lfn_calc_chksum (U8 *fn);
static void lfn_copy_name (U8 *lfn, char *fn);
static BOOL lfn_cmp_name (U8 *lfn, char *fn);
static BOOL sfn_cmp_name (U8 *sfn, char *fn);
static void lfn_copy_info (S8 *fn, U8 *lfn);
static BOOL chk_param (const char *par, const char *sp);
/*--------------------------- fat_init --------------------------------------*/
int fat_init (void) {
/* Initialize FAT File System driver. */
/* Initialize Flash Card interface. */
if (mmc_init () == __FALSE) {
/* Failed to Initialize or No Card error. */
return (1);
}
/* Initialize FAT file system. */
return (init_dev ());
}
/*--------------------------- init_dev --------------------------------------*/
static int init_dev (void) {
U32 root_scnt;
/* Invalidate Cached Sectors. */
fat.sect = INVAL_SECT;
fat.buf = (U8 *)&mc_cache[0];
fat.dirty= __FALSE;
ca.sect = INVAL_SECT;
ca.buf = (U8 *)&mc_cache[128];
ca.cbuf = (U8 *)&mc_cache[256];
ca.nwr = 0;
ca.nrd = 0;
/* First 2 clusters are always reserved. */
top_clus = 2;
/* Clear MMC info record. */
memset (&mmc, 0, sizeof (mmc));
if (get_mbrec () == __FALSE) {
/* Failed to read or invalid MBR. */
warm_restart = __FALSE;
return (2);
}
/* Read Boot Record Info. */
if (get_bootrec () == __FALSE) {
/* Failed to read or Invalid Boot Record. */
warm_restart = __FALSE;
return (3);
}
if (is_fat_valid () == __FALSE) {
/* Invalid FAT table. */
warm_restart = __FALSE;
return (4);
}
/* Calculate Root Sector Count. */
root_scnt = (mmc.RootEntCnt * 32 + mmc.BytesPerSec - 1) / mmc.BytesPerSec;
/* Count Data Sectors/Clusters */
mmc.DataSecCnt = mmc.DskSize - (mmc.RsvdSecCnt +
mmc.NumOfFat * mmc.FatSize + root_scnt);
mmc.DataClusCnt = mmc.DataSecCnt / mmc.SecPerClus;
mmc.RootDirAddr = mmc.RsvdSecCnt + mmc.NumOfFat * mmc.FatSize;
mmc.RootSecCnt = root_scnt;
mmc.ClusSize = mmc.SecPerClus * mmc.BytesPerSec;
mmc.EntsPerClus = mmc.ClusSize / 32;
/* Determine Fat Type. */
if (mmc.DataClusCnt < 4085) {
mmc.FatType = FS_FAT12;
warm_restart = __FALSE;
}
else if (mmc.DataClusCnt < 65525) {
mmc.FatType = FS_FAT16;
warm_restart = __FALSE;
}
else {
mmc.FatType = FS_FAT32;
/* Calculate number of free cluster the first time. */
if (warm_restart == __FALSE) {
warm_restart = __TRUE;
free_clus = count_free_clus ();
}
}
return (0);
}
/*--------------------------- fat_format ------------------------------------*/
BOOL fat_format (const char *label) {
/* Format a Flash Card for FAT12 or FAT16. */
U32 datSect,volSz,iSz,secClus,i,sec;
MMCFG mcfg;
/* Read MMC/SD Card configuration. */
if (mmc_read_config (&mcfg) == __FALSE) {
/* Failed to read Card configuration. */
return (__FALSE);
}
/* Check Read and Write Block sizes. */
if (mcfg.read_blen != mcfg.write_blen) {
return (__FALSE);
}
switch (mcfg.read_blen) {
case 512:
/* Up to 1GB cards. */
break;
case 1024:
/* 2 GB cards. */
mcfg.blocknr *= 2;
break;
case 2048:
/* 4 GB cards. */
mcfg.blocknr *= 4;
break;
default:
/* Block Size not supported. */
return (__FALSE);
}
volSz = mcfg.blocknr >> 11;
for (iSz = 0, i = 8; iSz < 10; i <<= 1, iSz++) {
if (volSz < i) break;
}
if (iSz == 10) {
/* Only Flash Card up to 4GB supported. */
return (__FALSE);
}
/* Check for parameter: /WIPE */
if (chk_param ("WIPE", label) == __TRUE) {
/* Clear the whole disk. */
wipe_disk (mcfg.blocknr);
}
/* Format with Partition Table and BPB. */
mmc.BootRecSec = IniDevCfg[iSz].BootRecSec;
mmc.DskSize = mcfg.blocknr - mmc.BootRecSec;
mmc.RsvdSecCnt = 1;
mmc.BytesPerSec= 512;
mmc.NumOfFat = 2;
/* Set Volume Parameter Info. */
mmc.FatType = IniDevCfg[iSz].FatType;
secClus = IniDevCfg[iSz].SecClus;
/* Check for parameter: /FAT32 */
if (chk_param ("FAT32", label) == __TRUE) {
/* Force FAT32 */
mmc.FatType = FS_FAT32;
secClus = IniDevCfg[iSz].SecClus32;
if (secClus == 0) {
/* Not possible to use FAT32, size is too small. */
return (__FALSE);
}
}
mmc.SecPerClus = secClus;
mmc.ClusSize = secClus * 512;
datSect = mmc.DskSize - mmc.RsvdSecCnt;
/* Calculate Data Space and FAT Table Size. */
switch (mmc.FatType) {
case FS_FAT12:
datSect -= 32;
mmc.RootEntCnt = 512;
mmc.RootSecCnt = 32;
mmc.DataClusCnt = (datSect * 512 - 1022) / (secClus * 512 + 3);
mmc.FatSize = (mmc.DataClusCnt * 3 + 1022) / 1024;
break;
case FS_FAT16:
datSect -= 32;
mmc.RootEntCnt = 512;
mmc.RootSecCnt = 32;
mmc.DataClusCnt = (datSect * 128 - 255) / (secClus * 128 + 1);
mmc.FatSize = (mmc.DataClusCnt + 255) / 256;
break;
case FS_FAT32:
mmc.RootSecCnt = 0;
mmc.DataClusCnt = (datSect * 64 - 127) / (secClus * 64 + 1);
mmc.FatSize = (mmc.DataClusCnt + 127) / 128;
break;
}
/* Count Data Sectors/Clusters */
mmc.DataSecCnt = mmc.DskSize - (mmc.RsvdSecCnt + mmc.RootSecCnt +
mmc.NumOfFat * mmc.FatSize);
mmc.RootDirAddr = mmc.RsvdSecCnt + mmc.NumOfFat * mmc.FatSize;
/* 2nd Cluster should be 32K aligned for optimal Card performance. */
sec = mmc.RootDirAddr + mmc.RootSecCnt;
mmc.BootRecSec = ((mmc.BootRecSec + sec + 32) & ~0x3F) - sec;
warm_restart = __FALSE;
/* Write MBR, create Partition Table. */
if (write_mbr (iSz) == __FALSE) {
return (__FALSE);
}
/* Generate Boot Record */
if (write_br (mcfg.sernum) == __FALSE) {
return (__FALSE);
}
/* Clear FAT Table and Root Directory. */
memset (ca.buf, 0, 512);
/* Write Reserved Clusters 0,1 to FAT table. */
switch (mmc.FatType) {
case FS_FAT12:
set_u32 (&ca.buf[0], 0xFFFFF8);
break;
case FS_FAT16:
set_u32 (&ca.buf[0], 0xFFFFFFF8);
break;
case FS_FAT32:
/* Write also Root Dir Cluster to FAT table. */
set_u32 (&ca.buf[0], 0x0FFFFFF8);
set_u32 (&ca.buf[4], 0xFFFFFFFF);
set_u32 (&ca.buf[8], 0x0FFFFFFF);
break;
}
sec = mmc.BootRecSec + mmc.RsvdSecCnt;
/* Use cache for faster write. */
write_cache (sec);
memset (ca.buf, 0, 12);
datSect = mmc.RootSecCnt;
if (mmc.FatType == FS_FAT32) {
/* Clear first Data Cluster (Root Dir) for FAT32. */
datSect = mmc.SecPerClus;
}
datSect += mmc.FatSize * 2;
for (i = 1; i < datSect; i++) {
write_cache (sec + i);
}
/* Flush the cache when done. */
write_cache (0);
if (*label != 0) {
/* If provided, write also a Volume Label. */
return (write_label (label));
}
return (__TRUE);
}
/*--------------------------- write_mbr -------------------------------------*/
static BOOL write_mbr (U32 iSz) {
/* Construct and write a Master Boot Record to sector 0. */
U8 NumHeads;
U32 val;
memset (ca.buf, 0, 512);
NumHeads = IniDevCfg[iSz].NumHeads;
/* Boot Descriptor: Non Bootable Device. */
ca.buf[446] = 0;
/* Beginning of Partition - Head */
ca.buf[447] = mmc.BootRecSec / 32;
/* First Partition Cylinder/Sector */
val = mmc.BootRecSec % 32;
set_u16 (&ca.buf[448], val + 1);
/* File System Descriptor. */
switch (mmc.FatType) {
case FS_FAT12:
/* Type 12-bit FAT */
ca.buf[450] = 0x01;
break;
case FS_FAT16:
if (iSz < 3) {
/* Type 16-bit FAT, Partition < 32 MB */
ca.buf[450] = 0x04;
}
else {
/* Type 16-bit FAT, Partition > 32MB */
ca.buf[450] = 0x06;
}
break;
case FS_FAT32:
/* Type 32-bit FAT, Partition < 2047GB */
ca.buf[450] = 0x0b;
break;
}
/* End of Partition - Head */
ca.buf[451] = NumHeads;
/* End of Partition Cylinder/Sector. */
val = (mmc.DskSize + mmc.BootRecSec) / (2 * NumHeads);
set_u16 (&ca.buf[452], val | 32);
/* First Sector Position Relative to Beginning of Device. */
set_u32 (&ca.buf[454], mmc.BootRecSec);
/* Number of Sectors in Partition */
set_u32 (&ca.buf[458], mmc.DskSize);
/* Executable Marker */
set_u16 (&ca.buf[510], 0xAA55);
return (write_sector (0));
}
/*--------------------------- write_br --------------------------------------*/
static BOOL write_br (U32 sernum) {
/* Construct and write a Boot Rrecord. */
memset (ca.buf, 0, 512);
/* Boot Code: E9 00 90 */
ca.buf[0] = 0xE9;
ca.buf[1] = 0x00;
ca.buf[2] = 0x90;
/* OEM name */
memcpy (&ca.buf[3], "MSWIN4.1", 8);
/* Bytes per Sector */
set_u16 (&ca.buf[11], 512);
/* Sectors per Cluster */
ca.buf[13] = mmc.SecPerClus;
/* Reserved Sectors */
ca.buf[14] = mmc.RsvdSecCnt;
/* Number of FAT Tables */
ca.buf[16] = 2;
/* Root Entry Count */
if (mmc.FatType != FS_FAT32) {
/* Must be 0 for FAT32. */
set_u16 (&ca.buf[17], 512);
}
/* Total Sector Count */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -