📄 sdfat.c
字号:
return dwEntries;
}
static DWORD ConvertFATEntriesToBytes(DWORD dwPartNo, DWORD dwEntries){
DWORD dwBytes = FAT_ERROR;
switch(Partition[dwPartNo].FileSystem){
case PART_FAT12:
dwBytes = FAT12_ENTRIES2BYTES(dwEntries);
break;
case PART_FAT16:
dwBytes = FAT16_ENTRIES2BYTES(dwEntries);
break;
case PART_FAT32:
dwBytes = FAT32_ENTRIES2BYTES(dwEntries);
break;
}
return dwBytes;
}
static BOOL IsFreeFATEntry(DWORD dwPartNo, DWORD dwCluster){
BOOL isFree = FALSE;
switch(Partition[dwPartNo].FileSystem){
case PART_FAT12:
isFree = FAT12_ISFREE(dwCluster);
break;
case PART_FAT16:
isFree = FAT16_ISFREE(dwCluster);
break;
case PART_FAT32:
isFree = FAT32_ISFREE(dwCluster);
break;
}
return isFree;
}
static BOOL IsAllocFATEntry(DWORD dwPartNo, DWORD dwCluster){
BOOL isAlloc = FALSE;
switch(Partition[dwPartNo].FileSystem){
case PART_FAT12:
isAlloc = FAT12_ISALLOC(dwCluster, Partition[dwPartNo].FATEntryNumber);
break;
case PART_FAT16:
isAlloc = FAT16_ISALLOC(dwCluster, Partition[dwPartNo].FATEntryNumber);
break;
case PART_FAT32:
isAlloc = FAT32_ISALLOC(dwCluster, Partition[dwPartNo].FATEntryNumber);
break;
}
return isAlloc;
}
static BOOL IsDefectFATEntry(DWORD dwPartNo, DWORD dwCluster){
BOOL isDefect = FALSE;
switch(Partition[dwPartNo].FileSystem){
case PART_FAT12:
isDefect = FAT12_ISDEFECT(dwCluster);
break;
case PART_FAT16:
isDefect = FAT16_ISDEFECT(dwCluster);
break;
case PART_FAT32:
isDefect = FAT32_ISDEFECT(dwCluster);
break;
}
return isDefect;
}
static BOOL IsEndFATEntry(DWORD dwPartNo, DWORD dwCluster){
BOOL isEnd = FALSE;
switch(Partition[dwPartNo].FileSystem){
case PART_FAT12:
isEnd = FAT12_ISEND(dwCluster);
break;
case PART_FAT16:
isEnd = FAT16_ISEND(dwCluster);
break;
case PART_FAT32:
isEnd = FAT32_ISEND(dwCluster);
break;
}
return isEnd;
}
static BOOL FillCacheFATEntries(DWORD dwPartNo, DWORD dwCluster){
DWORD dwByteOffset, dwReadBytes;
// 1.invalidate CacheFATEntryBegin&CacheFATEntryEnd
Partition[dwPartNo].CacheFATEntryBegin = FAT_ERROR;
Partition[dwPartNo].CacheFATEntryEnd = FAT_ERROR;
// 2.convert dwCluster to dwByteOffset
dwByteOffset = ConvertFATEntriesToBytes(dwPartNo, dwCluster);
// 3.read FAT entry from partition
dwReadBytes = FATReadPartition(dwPartNo, Partition[dwPartNo].CacheFATEntry,
sizeof(Partition[dwPartNo].CacheFATEntry), Partition[dwPartNo].StartingFATEntry+dwByteOffset);
// 4.check result
if(dwReadBytes==FAT_ERROR || dwReadBytes<GetFATEntryBytes(dwPartNo)){
return FALSE;
}
// 5.update cache variable
Partition[dwPartNo].CacheFATEntryBegin = dwCluster;
Partition[dwPartNo].CacheFATEntryEnd = dwCluster+ConvertBytesToFATEntries(dwPartNo, dwReadBytes);
return TRUE;
}
static DWORD GetFATEntry(DWORD dwPartNo, DWORD dwCluster){
// check parameter
if(dwCluster >= Partition[dwPartNo].FATEntryNumber){
return FAT_ERROR;
}
// check cache miss and fill new entries, if need
if(dwCluster<Partition[dwPartNo].CacheFATEntryBegin || dwCluster>=Partition[dwPartNo].CacheFATEntryEnd){
if(!FillCacheFATEntries(dwPartNo, dwCluster)){ // fill cache
return FAT_ERROR;
}
}
// dispatch according file system type
switch(Partition[dwPartNo].FileSystem){
case PART_FAT12:
return FAT12_GETENTRY(Partition[dwPartNo].CacheFATEntry, Partition[dwPartNo].CacheFATEntryBegin, dwCluster);
case PART_FAT16:
return FAT16_GETENTRY(Partition[dwPartNo].CacheFATEntry, Partition[dwPartNo].CacheFATEntryBegin, dwCluster);
case PART_FAT32:
return FAT32_GETENTRY(Partition[dwPartNo].CacheFATEntry, Partition[dwPartNo].CacheFATEntryBegin, dwCluster);
default:
return FAT_ERROR;
}
}
static DWORD CalculateFATEntries(DWORD dwPartNo, DWORD dwStart){
DWORD dwCount = 0;
while(IsAllocFATEntry(dwPartNo, dwStart)){
++dwCount;
dwStart = GetFATEntry(dwPartNo, dwStart);
}
if(!IsEndFATEntry(dwPartNo, dwStart)){
dwCount = FAT_ERROR;
}
return dwCount;
}
// help routine for file
static VOID ClearFileInfo(PFILEINFO pFileInfo){
pFileInfo->PartitionNumber = FAT_ERROR;
pFileInfo->StartingCluster = FAT_ERROR;
pFileInfo->FileLength = FAT_ERROR;
pFileInfo->FileAttribute = FAT_ERROR;
pFileInfo->CurrentCluster = FAT_ERROR;
pFileInfo->CurrentPostion = FAT_ERROR;
}
static VOID InitFileInfo(PFILEINFO pFileInfo, DWORD dwPartNo, DWORD dwStartingCluster, DWORD dwFileLength, DWORD dwAttribute){
if(dwFileLength == 0){
// assume length align on cluster length
DWORD dwCount = CalculateFATEntries(dwPartNo, dwStartingCluster);
if(dwCount != FAT_ERROR){
dwFileLength = Partition[dwPartNo].LengthPerCluster*dwCount;
}
}
pFileInfo->PartitionNumber = dwPartNo;
pFileInfo->StartingCluster = dwStartingCluster;
pFileInfo->FileLength = dwFileLength;
pFileInfo->FileAttribute = dwAttribute;
pFileInfo->CurrentCluster = dwStartingCluster;
pFileInfo->CurrentPostion = 0;
}
// help routine for directory
static UINT8 ComputeCheckSum(PUINT8 pName){
int i;
UINT8 Sum = 0;
for(i = 0; i < DIRENTRY_NAMELEN+DIRENTRY_EXTENSIONLEN; ++i){
// NOTE: The operation is an unsigned char rotate right
Sum = ((Sum&1)?0x80:0) + (Sum>>1) + *pName++;
}
return Sum;
}
static DWORD GetDirEntryNumber(PFILEINFO pFileInfo){
return FATGetFileSize(pFileInfo)/sizeof(RAWDIRENTRY);
}
static BOOL GetDirEntry(PFILEINFO pFileInfo, PDIRENTRY pDirEntry, DWORD dwPos){
RAWDIRENTRY drEntry;
// set all field to zero
memset(pDirEntry, 0, sizeof(*pDirEntry));
// seek to right position
if(dwPos != 0){
if(!FATSetFilePos(pFileInfo, dwPos*sizeof(drEntry))){
return FALSE;
}
}
// read raw entry
if(FATReadFile(pFileInfo, &drEntry, sizeof(drEntry)) != sizeof(drEntry)){
return FALSE;
}
// according entry type, fill in
pDirEntry->Attribute = drEntry.Attribute;
if(drEntry.Attribute == DIRENTRY_LONGNAME){ // long format
// filename
int i, j = 0;
for(i = 0; i<DIRENTRY_NAMELEN1 && drEntry.Name1[i]!=DIRENTRY_PADDING; ++i){
pDirEntry->FileName[j++] = (CHAR)drEntry.Name1[i];
}
for(i = 0; i<DIRENTRY_NAMELEN2 && drEntry.Name2[i]!=DIRENTRY_PADDING; ++i){
pDirEntry->FileName[j++] = (CHAR)drEntry.Name2[i];
}
for(i = 0; i<DIRENTRY_NAMELEN3 && drEntry.Name3[i]!=DIRENTRY_PADDING; ++i){
pDirEntry->FileName[j++] = (CHAR)drEntry.Name3[i];
}
// checksum&ordinal
pDirEntry->CheckSum = drEntry.CheckSum;
pDirEntry->Ordinal = drEntry.Ordinal;
}
else{ // short format
// filename
int i, j = 0;
for(i = 0; i<DIRENTRY_NAMELEN && drEntry.Name[i]!=DIRENTRY_ENDCHAR; ++i){
pDirEntry->FileName[j++] = drEntry.Name[i];
}
for(i = 0; i<DIRENTRY_EXTENSIONLEN && drEntry.Extension[i]!=DIRENTRY_ENDCHAR; ++i){
if(i == 0){ // add '.'
pDirEntry->FileName[j++] = '.';
}
pDirEntry->FileName[j++] = drEntry.Extension[i];
}
// checksum
pDirEntry->CheckSum = ComputeCheckSum(drEntry.Name);
// create time
pDirEntry->Created.wYear = DIRENTRY_YEAR(drEntry.CreatedDate);
pDirEntry->Created.wMonth = DIRENTRY_MONTH(drEntry.CreatedDate);
pDirEntry->Created.wDay = DIRENTRY_DAY(drEntry.CreatedDate);
pDirEntry->Created.wHour = DIRENTRY_HOUR(drEntry.CreatedTime);
pDirEntry->Created.wMinute = DIRENTRY_MINUTE(drEntry.CreatedTime);
pDirEntry->Created.wSecond = DIRENTRY_SECONDEX(drEntry.CreatedTime, drEntry.CreatedTimeTenth);
pDirEntry->Created.wMilliseconds = DIRENTRY_MILLISECOND(drEntry.CreatedTimeTenth);
// access time
pDirEntry->Accessed.wYear = DIRENTRY_YEAR(drEntry.AccessedDate);
pDirEntry->Accessed.wMonth = DIRENTRY_MONTH(drEntry.AccessedDate);
pDirEntry->Accessed.wDay = DIRENTRY_DAY(drEntry.AccessedDate);
// modify time
pDirEntry->Modified.wYear = DIRENTRY_YEAR(drEntry.ModifiedDate);
pDirEntry->Modified.wMonth = DIRENTRY_MONTH(drEntry.ModifiedDate);
pDirEntry->Modified.wDay = DIRENTRY_DAY(drEntry.ModifiedDate);
pDirEntry->Modified.wHour = DIRENTRY_HOUR(drEntry.ModifiedTime);
pDirEntry->Modified.wMinute = DIRENTRY_MINUTE(drEntry.ModifiedTime);
pDirEntry->Modified.wSecond = DIRENTRY_SECOND(drEntry.ModifiedTime);
// cluster&length
pDirEntry->StartingCluster = (drEntry.StartingClusterHi<<16)+drEntry.StartingCluster;
pDirEntry->FileLength = drEntry.FileLength;
}
return TRUE;
}
static BOOL GetDirEntryEx(PFILEINFO pFileInfo, PDIRENTRY pDirEntry){
int i, j = 0;
DWORD dwPrevPos;
DIRENTRY drEntry[DIRENTRY_MAXCOMP];
while(1){
// 1.save current position
dwPrevPos = FATGetFilePos(pFileInfo);
// 2.try to get one entry
if(!GetDirEntry(pFileInfo, pDirEntry, 0)){
return FALSE;
}
// 3.short format? break loop
if(pDirEntry->Attribute != DIRENTRY_LONGNAME){
break;
}
// 4.otherwise, copy to DirEntry
if(j < DIRENTRY_MAXCOMP){
memcpy(&drEntry[j++], pDirEntry, sizeof(*pDirEntry));
}
}
if(j != 0){ // long format
CHAR FileName[MAX_PATH+1];
FileName[0] = 0;
// 1.verify last component flag
if(!(drEntry[0].Ordinal&DIRENTRY_LASTCOMP)){
return TRUE; // no flag
}
// 2.form long file name
for(i = j-1; i >= 0; --i){
// verify ordinal
if((drEntry[i].Ordinal&DIRENTRY_COMPMASK) != j-i){
return TRUE; // wrong ordinal
}
// verify checksum
if(drEntry[i].CheckSum != pDirEntry->CheckSum){
return TRUE; // wrong checksum
}
strcat(FileName, drEntry[i].FileName);
}
// 3.change to long file name
strcpy(pDirEntry->FileName, FileName);
// 4.restore file position for next operation
FATSetFilePos(pFileInfo, dwPrevPos);
}
return TRUE;
}
// if match, it will update *ppCurItem to next item
static BOOL CompareFileName(PCSTR pFileName, PCSTR* ppCurItem){
PCSTR pCurItem;
for(pCurItem = *ppCurItem; *pFileName != 0; ++pCurItem, ++pFileName){
if(*pCurItem == 0){ // pCurItem finish, but pFileName not
return FALSE;
}
if(toupper(*pCurItem) != toupper(*pFileName)){ // no match
return FALSE;
}
}
// check endpoint
switch(*pCurItem){
case '/':
case '\\':
++pCurItem; // skip separator
// go through
case '\0':
*ppCurItem = pCurItem; // update to next
return TRUE;
}
return FALSE;
}
static BOOL FindRootDirEntry(PFILEINFO pFileInfo, PCSTR* ppCurItem){
DWORD dwPartNo = FAT_ERROR, dwLoop;
// find partition No.
if((*ppCurItem)[0]!=0 && (*ppCurItem)[1]==':'){ // specify disk no.
CHAR DiskName[] = "A:"; // search from A:
for(dwLoop = 0; dwLoop < PartitionNumber; ++dwLoop, ++DiskName[0]){
// compare root, if match update ppCurItem to next
if(CompareFileName(DiskName, ppCurItem)){
dwPartNo = dwLoop;
break;
}
}
}
else if(PartitionNumber > 0){
dwPartNo = 0; // default partition is zero
// search active partition
for(dwLoop = 0; dwLoop < PartitionNumber; ++dwLoop){
if(Partition[dwLoop].Bootable){
dwPartNo = dwLoop; // active partition is high priority
break;
}
}
CompareFileName("", ppCurItem); // skip optional first '/'
}
// init pFileInfo
if(dwPartNo != FAT_ERROR){
if(Partition[dwPartNo].FileSystem == PART_FAT32){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -