📄 cf_fat.c
字号:
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "CF_FAT.h"
#include "CF_IO.h"
uint8_t FS_Initialize(void)
{
uint16_t w;
uint32_t l;
if(!(FS_BPB = (FS_TBPB *)malloc(sizeof(FS_TBPB))))
return FS_ERR_NORAM;
if(!(FS_FAT = (FS_TFAT *)malloc(sizeof(FS_TFAT))))
return FS_ERR_NORAM;
if(!(FS_RootDir = (FS_TFile *)malloc(sizeof(FS_TFile))))
return FS_ERR_NORAM;
if(!(FS_CurrentDir = (FS_TFile *)malloc(sizeof(FS_TFile))))
return FS_ERR_NORAM;
if(CF_Initialize())
return FS_ERR_MEDIAERR;
if(CF_LBAOpen(0))
return FS_ERR_MEDIAERR;
if(CF_LBAReadb() == 0xeb) //If first byte is a instruction of JMP, it has no DPT.
FS_BPB->StartLBA = 0;
else
{
CF_LBASeek(0x1be);
if(CF_LBAReadb() != 0x80)
{
CF_LBAClose();
return FS_ERR_UNFORMAT;
}
CF_LBASeek(0x1c6);
FS_BPB->StartLBA = CF_LBAReadl();
}
CF_LBAClose();
CF_LBAOpen(FS_BPB->StartLBA);
CF_LBASeek(0x00b);
if(CF_LBAReadw() != 0x0200)
{
CF_LBAClose();
return FS_ERR_UNKNOWNFAT;
}
FS_BPB->SectorsPerCluster = CF_LBAReadb();
switch(FS_BPB->SectorsPerCluster)
{
case 1:
FS_BPB->LShift = 0;
break;
case 2:
FS_BPB->LShift = 1;
break;
case 4:
FS_BPB->LShift = 2;
break;
case 8:
FS_BPB->LShift = 3;
break;
case 16:
FS_BPB->LShift = 4;
break;
case 32:
FS_BPB->LShift = 5;
break;
case 64:
FS_BPB->LShift = 6;
break;
case 128:
FS_BPB->LShift = 7;
break;
default:
CF_LBAClose();
return FS_ERR_UNKNOWNFAT;
}
FS_BPB->Type = FS_TYPE_OTHER;
FS_BPB->SectorsBeforeFAT = CF_LBAReadw();
FS_BPB->FATs = CF_LBAReadb();
FS_BPB->FAT16RootEntries = CF_LBAReadw();
if(FS_BPB->FAT16RootEntries == 0)
FS_BPB->Type = FS_TYPE_FAT32;
w = CF_LBAReadw();
if(w)
FS_BPB->TotalSectors = w;
CF_LBASeek(0x16);
w = CF_LBAReadw();
if(FS_BPB->Type != FS_TYPE_FAT32)
FS_BPB->SectorsPerFAT = w;
CF_LBASeek(0x20);
l = CF_LBAReadl();
if(l)
FS_BPB->TotalSectors = l;
if(FS_BPB->Type != FS_TYPE_FAT32)
{
if((FS_BPB->TotalSectors >> FS_BPB->LShift) < 4085)
FS_BPB->Type = FS_TYPE_FAT12;
else
FS_BPB->Type = FS_TYPE_FAT16;
}
l = CF_LBAReadl();
if(FS_BPB->Type == FS_TYPE_FAT32)
FS_BPB->SectorsPerFAT = l;
CF_LBASeek(0x2c);
l = CF_LBAReadl();
if(FS_BPB->Type == FS_TYPE_FAT32)
FS_BPB->FAT32RootStartCluster = l;
else
FS_BPB->FAT32RootStartCluster = 0;
FS_FAT->StartLBA = FS_BPB->StartLBA + FS_BPB->SectorsBeforeFAT;
if(FS_BPB->Type == FS_TYPE_FAT32)
FS_FAT->LShift = 2;
else if(FS_BPB->Type == FS_TYPE_FAT16)
FS_FAT->LShift = 1;
else
FS_FAT->LShift = 0;
FS_CurrentDir->Attrib = FS_RootDir->Attrib = 0x10;
FS_CurrentDir->StartCluster = FS_RootDir->StartCluster = FS_BPB->FAT32RootStartCluster;
if(FS_BPB->Type == FS_TYPE_FAT32)
{
FS_FAT->DataStartLBA = FS_FAT->StartLBA + FS_BPB->FATs * FS_BPB->SectorsPerFAT;
FS_CurrentDir->StartLBA = FS_RootDir->StartLBA = FS_FAT->DataStartLBA + ((FS_BPB->FAT32RootStartCluster - 2) << FS_BPB->LShift);
}
else
{
FS_CurrentDir->StartLBA = FS_RootDir->StartLBA = FS_FAT->StartLBA + FS_BPB->FATs * FS_BPB->SectorsPerFAT;
FS_FAT->DataStartLBA = FS_RootDir->StartLBA + (FS_BPB->FAT16RootEntries >> 4);
}
FS_CurrentDir->Length = FS_RootDir->Length = 0;
FS_CurrentDir->Offset = FS_RootDir->Offset = 0;
CF_LBAClose();
return FS_ERR_NOERR;
}
void FS_Destory(void)
{
free(FS_BPB);
free(FS_FAT);
free(FS_RootDir);
free(FS_CurrentDir);
}
uint32_t FS_GetNextCluster(uint32_t Cluster)
{
uint8_t f1, f2;
uint16_t cc;
uint32_t c;
if((FS_BPB->Type == FS_TYPE_FAT32) || (FS_BPB->Type == FS_TYPE_FAT16)) //FAT16 or FAT32
{
CF_LBAOpen(FS_FAT->StartLBA + (Cluster >> (9 - FS_FAT->LShift)));
CF_LBASeek((Cluster & ((1 << (9 - FS_FAT->LShift)) - 1)) << FS_FAT->LShift); // locate a FAT entry
if(FS_BPB->Type == FS_TYPE_FAT32) //FAT32
c = CF_LBAReadl();
else //FAT16
c = CF_LBAReadw();
}
else //FAT12. It's more complicated. Because there are 1.5 bytes (12-bits) per FAT entry.
{
CF_LBAOpen(FS_FAT->StartLBA + ((Cluster + (Cluster << 1)) >> 10)); //multiply by 3, then divide by 1024
cc = Cluster & 0b1111111111;
if(cc < 342)
CF_LBASeek(cc + (cc >> 1)); //multiply by 1.5 without using floating point
else if(cc < 683)
CF_LBASeek((cc - 342) + ((cc - 342) >> 1) + 1);
else
CF_LBASeek((cc - 682) + ((cc - 682) >> 1) - 1);
if(((cc >> 1) << 1) == cc)
{
f1 = CF_LBAReadb();
if(cc == 682)
CF_LBAOpen(CF_CurrentLBA + 1);
f2 = (CF_LBAReadb() & 0b00001111) << 4;
}
else
{
f1 = CF_LBAReadb() >> 4;
if(cc == 341)
CF_LBAOpen(CF_CurrentLBA + 1);
f2 = CF_LBAReadb();
}
c = (((uint16_t)f2) << 4) + f1;
}
CF_LBAClose();
return c;
}
uint8_t FS_SearchFile(char *FName, FS_TFile *R, uint8_t dir)
{
uint8_t i = 0, j = 0, attr, s;
uint16_t c, o;
uint32_t LBA, Cluster;
char Name[9], Ext[4];
char dName[9], dExt[4];
memset(Name, 0x20, 8);
memset(Ext, 0x20, 3);
while(FName[i])
if(FName[i] == '.')
{
i ++;
while(FName[i])
Ext[j ++] = toupper(FName[i ++]);
}
else
{
Name[i] = toupper(FName[i]);
i ++;
}
Name[8] = Ext[3] = 0;
Cluster = FS_CurrentDir->StartCluster;
LBA = FS_CurrentDir->StartLBA;
while(1)
{
for(s = 0; s < FS_BPB->SectorsPerCluster; s ++, LBA ++) //for each sector in a cluster
{
CF_LBAOpen(LBA); //Open a sector of current directory
for(o = 0; o < 512; o += 0x20)
{
CF_LBASeek(o);
for(i = 0; i < 8; i ++)
dName[i] = toupper(CF_LBAReadb());
for(i = 0; i < 3; i ++)
dExt[i] = toupper(CF_LBAReadb());
attr = CF_LBAReadb();
dName[8] = dExt[3] = 0;
if(dName[0] == 0)
{
CF_LBAClose();
return FS_ERR_NOTFOUND;
}
else if(dName[0] != 0xe5)
{
if((strcmp(Name, dName) == 0) && (strcmp(Ext, dExt) == 0) && ((attr & 0b00001000) == 0) && ((attr & 0b00010000) || (dir == 0)) ) //if bingo
{
R->Attrib = attr;
CF_LBASeek(o + 0x14);
c = CF_LBAReadw();
CF_LBASeek(o + 0x1a);
R->StartCluster = CF_LBAReadw();
R->Length = CF_LBAReadl();
if(FS_BPB->Type == FS_TYPE_FAT32)
R->StartCluster += (uint32_t)c << 16;
R->CurrentLBA = R->StartLBA = FS_FAT->DataStartLBA + ((R->StartCluster - 2) << FS_BPB->LShift);
R->CurrentCluster = R->StartCluster;
R->Offset = 0;
CF_LBAClose();
return FS_ERR_NOERR;
}
}
}
}
if(Cluster != 0) //Cluster==0 is for FAT16/FAT12, where the root directory is stored consecutively.
{
Cluster = FS_GetNextCluster(Cluster);
if( ((FS_BPB->Type == FS_TYPE_FAT32) && (Cluster >= FS_FAT32_EOF)) ||
((FS_BPB->Type == FS_TYPE_FAT16) && (Cluster >= FS_FAT16_EOF)) ||
((FS_BPB->Type == FS_TYPE_FAT12) && (Cluster >= FS_FAT12_EOF))) //if it is the last cluster
return FS_ERR_NOTFOUND;
LBA = FS_FAT->DataStartLBA + ((Cluster - 2) << FS_BPB->LShift);
}
}
}
uint8_t FS_ChangeDir(char *DirName)
{
FS_TFile *D;
if(strcmp(DirName, "\\") == 0)
{
FS_CurrentDir->Attrib = FS_RootDir->Attrib;
FS_CurrentDir->StartCluster = FS_RootDir->StartCluster;
FS_CurrentDir->StartLBA = FS_RootDir->StartLBA;
FS_CurrentDir->Offset = FS_RootDir->Offset;
FS_CurrentDir->Length = FS_RootDir->Length;
return FS_ERR_NOERR;
}
D = (FS_TFile *)malloc(sizeof(FS_TFile));
if(D == NULL)
return FS_ERR_NORAM;
if(FS_SearchFile(DirName, D, 1))
{
free(D);
return FS_ERR_NOTFOUND;
}
else
{
FS_CurrentDir->Attrib = D->Attrib;
FS_CurrentDir->StartCluster = D->StartCluster;
FS_CurrentDir->StartLBA = D->StartLBA;
FS_CurrentDir->Offset = D->Offset;
FS_CurrentDir->Length = D->Length;
free(D);
return FS_ERR_NOERR;
}
}
FS_TFile *FS_Open(char *FileName)
{
FS_TFile *F;
F = (FS_TFile *)malloc(sizeof(FS_TFile));
if(F == NULL)
return NULL;
if(FS_SearchFile(FileName, F, 0))
{
free(F);
return NULL;
}
else
return F;
}
void FS_Close(FS_TFile *F)
{
free(F);
}
uint8_t FS_Seek(FS_TFile *F, uint32_t off)
{
uint32_t i;
if(off >= F->Length)
return FS_ERR_SEEKERR;
else
{
if(off < F->Offset)
{
F->CurrentCluster = F->StartCluster;
F->CurrentLBA = F->StartLBA;
F->Offset = 0;
}
for(i = (F->Offset >> 9); i < (off >> 9); i ++)
{
F->CurrentLBA ++;
if(((F->CurrentLBA - FS_FAT->DataStartLBA) & ((1 << FS_BPB->LShift) - 1)) == 0)
{
F->CurrentCluster = FS_GetNextCluster(F->CurrentCluster);
F->CurrentLBA = FS_FAT->DataStartLBA + ((F->CurrentCluster - 2) << FS_BPB->LShift);
}
}
F->Offset = off;
return FS_ERR_NOERR;
}
}
uint32_t FS_Read(FS_TFile *F, char *buf, uint32_t count)
{
uint32_t i = 0;
CF_LBAOpen(F->CurrentLBA);
CF_LBASeek(F->Offset & 511);
while(i < count)
{
*(buf ++) = CF_LBAReadb();
i ++;
if(FS_Seek(F, F->Offset + 1))
{
CF_LBAClose();
return i;
}
if((F->Offset & 511) == 0)
CF_LBAOpen(F->CurrentLBA);
}
CF_LBAClose();
return i;
}
void FS_FastBlockRead(FS_TFile *F, char *buf, uint8_t sectors)
{
F->Offset = ((F->Offset >> 9) << 9);
while(sectors)
{
CF_LBAReadSector(F->CurrentLBA, 1, buf);
buf += 512;
FS_Seek(F, F->Offset + 512);
sectors --;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -