📄 fat.c
字号:
/*----------------------------------------------------------------------
*
* Filename: fat.cpp
*
* Contents:
*
* Contributors: Lee Yoonsu, Kang sungtae
*
* Copyright (c) 2006 SAMSUNG Electronics.
*
*----------------------------------------------------------------------
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "library.h"
#include "system.h"
#include "fat.h"
/*------------------------
* FAT Data Structure
*------------------------
*
* Boot Sector and BPB Structure (p.9)
*------------------------------------
*
* m_usBpbBytsPerSec;
*
* Count of bytes per sector.
* This value may take on only the following values: 512, 1024, 2048 or 4096.
* If maximum compatibility with old implementations is desired,
* only the value 512 should be used.
* There is a lot of FAT code in the world that is basically "hard wired" to 512 bytes per sector
* and doesn't bother to check this field to make sure it is 512.
* Microsoft operating systems will properly support 1024, 2048, and 4096.
* Note: Do not misinterpret these statements about maximum compatibility.
* If the media being recorded has a physical sector size N,
* you must use N and this must still be less than or equal to 4096.
* Maximum compatibility is achieved by only using media with specific sector sizes.
*
* m_ucBpbSecPerClus;
*
* Number of sectors per allocation unit.
* This value must be a power of 2 that is greater than 0.
* The legal values are 1, 2, 4, 8, 16, 32, 64, and 128.
* Note however, that a value should never be used that results in
* a "bytes per cluster" value (m_usBpbBytsPerSec * m_ucBpbSecPerClus) greater than 32K (32 * 1024).
* There is a misconception that values greater than this are OK.
* Values that cause a cluster size greater than 32K bytes do not work properly; do not try to define one.
* Some versions of some systems allow 64K bytes per cluster value.
*
* m_usBpbRsvdSecCnt;
*
* Number of reserved sectors in the Reserved region of the volume
* starting at the first sector of the volume.
* This field must not be 0.
* For FAT12 and FAT16 volumes, this value should never be anything
* other than 1. For FAT32 volumes, this value is typically 32.
* There is a lot of FAT code in the world "hard wired"
* to 1 reserved sector for FAT12 and FAT16 volumes and
* that doesn't bother to check this field to make sure it is 1.
* Microsoft operating systems will properly support any non-zero value in this field.
* Many application setup programs will not work correctly on such a FAT volume.
*
* m_usBpbRootEntCnt;
*
* For FAT12 and FAT16 volumes,
* this field contains the count of 32-byte directory entries in the root directory.
* For FAT32 volumes, this field must be set to 0.
* For FAT12 and FAT16 volumes,
* this value should always specify a count that
* when multiplied by 32 results in an even multiple of m_usBpbBytsPerSec.
* For maximum compatibility, FAT16 volumes should use the value 512.
*
* USHORT BpbTotSec16;
*
* This field is the old 16-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions of the volume.
* This field can be 0; if it is 0, then BPB_TotSec32 must be non-zero.
* For FAT32 volumes, this field must be 0.
* For FAT12 and FAT16 volumes, this field contains the sector count,
* and BPB_TotSec32 is 0 if the total sector count "fits" (is less than 0x10000).
*
* m_ucBpbMedia;
*
* non-removable(fixed) media - 0xF8
* removable media - 0xF0
* legal values - 0xF0, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF.
*
* m_uBpbHiddSec;
*
* Count of hidden sectors preceding the partition
* that contains this FAT volume.
* This field is generally only relevant for media visible on interrupt 0x13.
* This field should always be zero on media that are not partitioned.
* Exactly what value is appropriate is operating system specific.
*
* DWORD BPB_TotSec32;
*
* new 32-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions of the volume.
* This field can be 0; if it is 0, then BpbTotSec16 must be non-zero.
* For FAT32 volumes, this field must be non-zero.
* For FAT12/FAT16 volumes, this field contains the sector count
* if BpbTotSec16 is 0 (count is greater than or equal to 0x10000).
*
* m_uBpbTotSectors;
*
* Integration of BpbTotSec16 and BPB_TotSec32
*
* m_uBpbRootClus;
*
* FAT32 only.
* This is set to the cluster number of the first cluster of the root directory,
* usually 2 but not required to be 2.
*
* m_nEOC;
*
* End of Cluster Mark
*
* FAT32 FSInfo Sector Structure and Backup Boot Sector (pp.21-22)
*-----------------------------------------------------------------
*
* m_uFsiFreeCount;
*
* the last known free cluster count on the volume.
* 0xFFFFFFFF --> free count: unknown, so must be computed.
* range check: field value <= volume cluster count
*
* m_uFsiNxtFree;
*
* This is a hint for the FAT driver.
* It indicates the cluster number at which the driver should start looking for free clusters.
* Because a FAT32 FAT is large, it can be rather time consuming
* if there are a lot of allocated clusters at the start of the FAT
* and the driver starts looking for a free cluster starting at cluster 2.
* Typically this value is set to the last cluster number that the driver allocated.
* 0xFFFFFFFF --> there is no hint and the driver should start looking at cluster 2.
* Any other value can be used, but should be checked first
* to make sure it is a valid cluster number for the volume.
*
* m_uFsiLeadSig;
*
* Value 0x41615252.
* This lead signature is used to validate that this is in fact an FSInfo sector.
*
* m_ucFileEntryHead replace the below data structure..
*
* char DIR_Name[11]; // p.23 refer to algorithm (DIR_Name[0])
* BYTE DIR_CrtTimeTenth; // file creation time millisecond stamp, valid: 0~199
* USHORT DIR_CrtTime; // Time file was created.
* USHORT DIR_CrtDate; // Date file was created.
* USHORT DIR_LstAccDate; // Last access date (read or write)
* USHORT DIR_WrtTime; // Time of last write. file creation is included in this case.
* USHORT DIR_WrtDate; // Date of last write. file creation is included in this case.
*
* FAT Long Directory Entry Structure (p.26~27)
*---------------------------------------------
*
* m_ucLDirOrd;
*
* The nOrder of this entry in the sequence of long dir entries
* associated with the short dir entry at the end of the long dir set.
* If masked with 0x40 (LAST_LONG_ENTRY),
* this indicates the entry is the last long dir entry in a set of long dir entries.
* All valid sets of long dir entries must begin with an entry having this mask.
*
* m_ucLDirAttr;
*
* Attributes - must be ATTR_LONG_NAME
*/
typedef enum
{
IS_FAT12 = 3,
IS_FAT16 = 4,
IS_FAT32 = 8
} FATTYPE_T;
#if 0
typedef enum
{
BUFF_READ,
BUFF_WRITE
} BUFF_STATE;
#endif
typedef enum
{
CLUSTER_CHAIN,
CLUSTER_BPLUS,
CLUSTER_BMINUS
} COPY_MODE;
#define UNICODE2CHAR 0
#define CHAR2UNICODE 1
#define FAT_FREE_CLUSTER 0x0
#define LAST_CLUSTER(x) (((x&oFat.m_nEOC)==oFat.m_nEOC)?1:0)
#define PATH_NAME_CHAR_SEPARATOR '.'
#define PATH_NAME_CHAR_DELIMITER '/'
#define PATH_NAME_CHAR_END '\0'
#define PATH_NAME_CHAR_VALID(c) (((c>='A')&&(c<='Z'))|| \
((c>='0')&&(c<='9'))||(c=='-')||(c=='_')||(c=='.')||(c=='/')||(c=='\0')||(c==' '))
#define FREE_ENTRY_TAG0 0xe5
#define TERM_ENTRY_TAG0 0x00
#define DOT_ENTRY_TAG0 0x2e
#define FREE_ENTRY_TAG 0x20e5
#define TERM_ENTRY_TAG 0x0000
#define DOT_ENTRY_TAG 0x202e
#define DOTDOT_ENTRY_TAG 0x2e2e
///#define ENTRY_COPY(p, x) memncpy(p, HD_dir_entry(x, 0), DIR_ENTRY_SIZE)
// Little Endian value caculation
#define LSB_GET_4BYTES(x) ((*((x)+3)) << 24) | ((*((x)+2)) << 16) | \
((*((x)+1)) << 8) | ((*((x))))
#define LSB_GET_3BYTES(x) ((*((x)+2)) << 16) | \
((*((x)+1)) << 8) | ((*((x))))
#define LSB_GET_2BYTES(x) ((*((x)+1)) << 8 ) | ((*((x))))
#define UNICODEtOCHAR(x) ((*((x)+1)) << 16) | ((*((x))))
#define LSB_SET_4BYTES(p, x) { *((p)+3)= 0x0ff&(x>>24) ; \
*((p)+2) = 0x0ff&(x>>16); \
*((p)+1) = 0x0ff&(x>>8); \
*(p) = 0x00ff&x; }
#define LSB_SET_3BYTES(p, x) { *((p)+2) = 0xff&(x>>16); \
*((p)+1) = 0xff&(x>>8); \
*(p) = 0xff&x; }
#define LSB_SET_2BYTES(p, x) { *((p)+1) = 0xff&(x>>8); \
*(p) = 0xff&x; }
// FAT Volume Initialization (p.20)
// This is the table for FAT16 drives. NOTE that this table includes
// entries for disk sizes larger than 512 MB even though typically
// only the entries for disks < 512 MB in size are used.
// The way this table is accessed is to look for the first entry
// in the table for which the disk size is less than or equal
// to the DiskSize field in that table entry. For this table to
// work properly m_usBpbRsvdSecCnt must be 1
// must be 2, and m_usBpbRootEntCnt must be 512. Any of these values
// being different may require the first table entries DiskSize value
// to be changed otherwise the cluster count may be to low for FAT16.
DSKSZTOSECPERCLUS DskTableFAT16 [] = {
{ 8400, 0}, // disks up to 4.1 MB, the 0 value for SecPerClusVal trips an ucNerror
{ 32680, 2}, // disks up to 16 MB, 1k cluster
{ 262144, 4}, // disks up to 128 MB, 2k cluster
{ 524288, 8}, // disks up to 256 MB, 4k cluster
{ 1048576, 16}, // disks up to 512 MB, 8k cluster
// The entries after this point are not used unless FAT16 is forced
{ 2097152, 32}, // disks up to 1 GB, 16k cluster
{ 4194304, 64}, // disks up to 2 GB, 32k cluster
{ 0xFFFFFFFF, 0} // any disk greater than 2GB, 0 value for SecPerClusVal trips an ucNerror
};
// This is the table for FAT32 drives. NOTE that this table includes
// entries for disk sizes smaller than 512 MB even though typically
// only the entries for disks >= 512 MB in size are used.
// The way this table is accessed is to look for the first entry
// in the table for which the disk size is less than or equal
// to the DiskSize field in that table entry. For this table to
// work properly m_usBpbRsvdSecCnt must be 32
// must be 2. Any of these values being different may require the first
// table entries DiskSize value to be changed otherwise the cluster count
// may be to low for FAT32.
DSKSZTOSECPERCLUS DskTableFAT32 [] = {
{ 66600, 0}, // disks up to 32.5 MB, the 0 value for SecPerClusVal trips an ucNerror
{ 532480, 1}, // disks up to 260 MB, .5k cluster
{ 16777216, 8}, // disks up to 8 GB, 4k cluster
{ 33554432, 16}, // disks up to 16 GB, 8k cluster
{ 67108864, 32}, // disks up to 32 GB, 16k cluster
{ 0xFFFFFFFF, 64} // disks greater than 32GB, 32k cluster
};
// in DIR_Attr,
#define ATTR_READ_ONLY 0x01
#define ATTR_HIDDEN 0x02
#define ATTR_SYSTEM 0x04
#define ATTR_VOLUME_ID 0x08
#define ATTR_DIRECTORY 0x10
#define ATTR_ARCHIVE 0x20
#define ATTR_LONG_NAME 0x0f //ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID
#define ATTR_LONG_NAME_MASK 0x3f //ATTR_READ_ONLY|ATTR_HIDDEN|ATTR_SYSTEM|ATTR_VOLUME_ID|ATTR_DIRECTORY|ATTR_ARCHIVE
#define ATTR_FILES_ONLY 0x2f // (ATTR_READ_ONLY|ATTR_HIDDEN|ATTR_SYSTEM|ATTR_ARCHIVE|ATTR_VOLUME_ID)
#define ATTR_DIR_FILES 0x3f //(ATTR_FILES_ONLY|ATTR_DIRECTORY)
#define WRITE_CLUSTER
#define MAX_FILE_HANDLES 2
#define HDF_APPEND 0x0000
#define HDF_INSERT 0x0100
FATTYPE_T FATType; // FAT Type determination
//static HDFHANDLE *HDp, HDFhandle[MAX_FILE_HANDLES]; // each handle data for each file
FAT oFat;
//////////
// File Name : FAT_ReadFile1
// File Description : File Read function
// Input : file index, destination address, HSMMC_descriptor
// Output : NONE.
bool FAT_ReadFile1(s32 nIdx, u32 uDestAddr, SDHC* sCh)
{
return (FAT_ReadFile(nIdx, (u8 *)uDestAddr, sCh) == 0) ? false : true;
}
//////////
// File Name : FAT_ReadFile2
// File Description : File Read function with file size.
// Input : file index, destination address, file size pointer, HSMMC_descriptor
// Output : NONE.
bool FAT_ReadFile2(s32 nIdx, u32 uDstAddr, u32* uFileSize, SDHC* sCh)
{
*uFileSize = FAT_ReadFile(nIdx, (u8 *)uDstAddr, sCh);
return (*uFileSize == 0) ? false : true;
}
//////////
// File Name : FAT_ReadFile3
// File Description : File Read function
// Input : file name, destination address, file size pointer, HSMMC_descriptor
// Output : NONE.
bool FAT_ReadFile3(const char* pFileName, u32 uDstAddr, u32* uFileSize, SDHC* sCh)
{
int index;
FAT_GetFileIndex(pFileName, (s32*)&index, sCh);
*uFileSize = FAT_ReadFile(index, (u8 *)uDstAddr, sCh);
return (*uFileSize == 0) ? false : true;
}
//////////
// File Name : FAT_ReadFile5
// File Description : File Read function
// Input : file name, block position, block count
// Output : NONE.
bool FAT_ReadFile5(const char* pFileName, u32 nBlockPos, u32 nBlocks, u32 uDestAddr, SDHC* sCh)
{
int index;
FAT_GetFileIndex(pFileName, (s32*)&index, sCh);
return FAT_ReadFile4(index, nBlockPos, nBlocks, uDestAddr, sCh);
}
void FAT_GetNumOfFilesAndDirs(u32* uCount, SDHC* sCh)
{
*uCount = oFat.m_nFileIndex;
}
///////////////////////////////
// Array Manipulation //
///////////////////////////////
bool FAT_CopyArray(u8* a, const u8* b, u32 n, SDHC* sCh)
{
u32 i;
for(i=0; i<n; i++)
{
*(a+i) = *(b+i);
}
return true;
}
void FAT_CompareArray(u8* a, const u8* b, u32 n, int* nComArray, SDHC* sCh)
{
u32 i;
for(i=0; i<n; i++)
{
if (*(a+i) < *(b+i))
{
*nComArray = -1;
}
else if (*(a+i) > *(b+i))
{
*nComArray = 1;
}
}
// a is equal to b..
*nComArray = 0;
}
//-----------------------------------------------------------------------
// In FAT32,
// byte Directory Entry Structure (p.23~25)
// DIR_Name, DIR_Attr, DIR_CrtTimeTenth, DIR_CrtTime, DIR_CrtDate,
// DIR_LstAccDate, DIR_WrtTime, DIR_WrtDate
// In DIR_Attr,
// FAT Long Directory Entry Structure (p.26~27)
// Organization and Association of Short & Long Directory Entries (p.27)
//-----------------------------------------------------------------------
// Sequence of Long Directory Entries (p.27)
//-----------------------------------------------------------------------
// ChkSum()
// Returns an unsigned byte checksum computed on an unsigned byte
// array. The array must be 11 bytes long and is assumed to contain
// a name stored in the format of a MS-DOS directory entry.
// Passed: pFcbName Pointer to an unsigned byte array assumed to be
// 11 bytes long.
// Returns: ucSum An 8-bit unsigned checksum of the array pointed
// to by pFcbName.
//-----------------------------------------------------------------------
void FAT_ComputeChkSum (u8 *pFcbName, u8* uSum, SDHC* sCh)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -