📄 cf_fat.c
字号:
#include <ctype.h>
#include <string.h>
#include "CF_FAT.h"
#include "CF_IO.h"
uint8_t FS_Initialize(void)
{
uint16_t w;
uint32_t l;
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;
}
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;
}
if(FS_SearchFile(DirName, &D, 1))
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;
return FS_ERR_NOERR;
}
}
uint8_t FS_Open(FS_TFile *F, char *FileName)
{
if(FS_SearchFile(FileName, F, 0))
return FS_ERR_NOTFOUND;
else
{
F->ClusterChain = NULL;
return FS_ERR_NOERR;
}
}
void FS_Close(FS_TFile *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;
}
if(F->ClusterChain == NULL)
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);
}
}
else
{
F->CurrentCluster = F->ClusterChain[off >> (9 + FS_BPB.LShift)];
F->CurrentLBA = FS_FAT.DataStartLBA + ((F->CurrentCluster - 2) << FS_BPB.LShift) + ((off >> 9) & ((1 << FS_BPB.LShift) - 1));
}
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 --;
}
}
void FS_GetClusterChain(FS_TFile *F, uint32_t *chain)
{
uint32_t c;
*chain = F->StartCluster;
do
{
c = FS_GetNextCluster(*chain);
chain ++;
*chain = c;
if( ((FS_BPB.Type == FS_TYPE_FAT32) && (c >= FS_FAT32_EOF)) ||
((FS_BPB.Type == FS_TYPE_FAT16) && (c >= FS_FAT16_EOF)) ||
((FS_BPB.Type == FS_TYPE_FAT12) && (c >= FS_FAT12_EOF))) //if it is the last cluster
break;
} while(1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -