📄 fat16.c
字号:
hour=rBCDHOUR;
min=rBCDMIN;
sec=rBCDSEC;
fatdatetime->Date = ((day << DD_DAY_SHIFT)&DD_DAY_MASK)+((month <<DD_MONTH_SHIFT)&DD_MONTH_MASK)
+(((year-1980) <<DD_YEAR_SHIFT)&DD_YEAR_MASK);
fatdatetime->Time = ((hour<<DT_HOURS_SHIFT)&DT_HOURS_MASK)+((min<<DT_MINUTES_SHIFT)&DT_MINUTES_MASK)
+(((sec/2)<<DT_2SECONDS_SHIFT)&DT_2SECONDS_MASK);
fatdatetime->TimeTenth = (sec % 2) * 100; //+ systm.wMilliseconds / 10;
}
///////////////////////////////////////////////////////////////////
// fat apis
///////////////////////////////////////////////////////////////////
//创建目录
int fat_mkdir( const char *dirname)//仅1级目录: 父目录\新目录
{
DIRENTRY dir;
DWORD SectorNum;
char path[512];
char name[11];
char *p;
FatDateTime tm;
_FILE file;
BYTE* Cache;
DIRENTRY *pdir;
WORD NewCluster;
char dot[11] = {'.', 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
char dotdot[11] = {'.', '.', 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
// is path format correct ?
p = get_valid_format(dirname);
if(p == NULL)
return 1;
//if exist this dir ?寻找是否有相同名字的文件夹/文件
//若没有,返回0xffffffff。若有,返回扇区数
if(fat_locate(dirname, NULL) != 0xffffffff)
return 4;
//separate path into parent and name(directory name)
strncpy(name, &p[strlen(p)-11], 11);//拷贝新的目录名->name
//获得了文件的第一级目录(parent path)名称
strcpy(path, dirname);
p = strrchr(path, '\\');//返回path中‘\’第一次出现的指针
if(p == path) // it is root dir.
*(p+1) = '\0';
else
*p = '\0';
//locate parent path
SectorNum = fat_locate(path, NULL);//获取第一级目录指向第一个扇区的地址
if(SectorNum == 0xffffffff)
return 2;
//fill dir attributes
memset((BYTE *)&dir, 0, sizeof(dir));//dir指向的结构体清0
memcpy((BYTE *)(dir.deName), name, 11);
dir.deAttributes = ATTR_DIRECTORY;//目录属性0x10:子目录文件
fat_datetime(&tm);
dir.CrtDate = dir.LstAccDate = dir.WrtDate = tm.Date;//填写结构体日期
dir.CrtTime = dir.WrtTime = tm.Time;//填写结构体时间
dir.CrtTimeTenth = tm.TimeTenth;
//dir.CrtDate = dir.LstAccDate = dir.WrtDate = 0x398b;//填写结构体日期
//dir.CrtTime = 0x49bd;//填写结构体时间
//dir.WrtTime = 0x49c0;
//dir.CrtTimeTenth = 0x8f;
//dir.deLowerCase = 0x08;
//alloc one dir在父目录所指的扇区下获得一个新的目录项
////从根目录区中取得一个目录项,并将信息写进该目录项,并更新根目录区对应地方数据
if(AllocDir(SectorNum, &dir, &file) != 0)
return 3;
//alloc a cluster 查找空簇,找到后填写0xFFFF,后重写FAT表,返回没用到的空簇
NewCluster = AllocCluster(0);
if(NewCluster == 0xffff)
return 4;
//flush to disk
Cache = GetSectorData(file.DirSectorNum);//将新的目录项所在扇区读入
if(Cache == NULL) //用于填写根目录表中的起始簇终止簇
return 6;
pdir = (DIRENTRY *)Cache;
pdir += file.DirIndex;
pdir->deStartCluster = NewCluster;//填写根目录表中的起始簇终止簇
Flush();//烧写,内容在SectorBuffer中
//create . and .. dir items.
Cache = GetSectorData(ClusterNum2SectorNum(NewCluster));//将新簇的第一个扇区读入
if(Cache == NULL) //新簇对应于文件夹对应的数据区
return 6;
//填写并烧写文件夹对应数据区的内容
pdir = (DIRENTRY *)Cache;//获得一个目录项本地目录:.?
memset((BYTE *)pdir, 0, sizeof(DIRENTRY));
memcpy((BYTE *)(pdir->deName), dot, 11);
pdir->deAttributes = ATTR_DIRECTORY;
fat_datetime(&tm);//获得当前系统的时间,填写当前目录项的属性
pdir->CrtDate = pdir->LstAccDate = pdir->WrtDate = tm.Date;
pdir->CrtTime = pdir->WrtTime = tm.Time;
pdir->CrtTimeTenth = tm.TimeTenth;
pdir->deStartCluster = NewCluster;//指向本地
pdir++;//获得一个目录项父目录:..
memset((BYTE *)pdir, 0, sizeof(DIRENTRY));
memcpy((BYTE *)(pdir->deName), dotdot, 11);
pdir->deAttributes = ATTR_DIRECTORY;
fat_datetime(&tm);
pdir->CrtDate = pdir->LstAccDate = pdir->WrtDate = tm.Date;
pdir->CrtTime = pdir->WrtTime = tm.Time;
pdir->CrtTimeTenth = tm.TimeTenth;
pdir->deStartCluster = SectorNum2ClusterNum(SectorNum);
Flush();//烧写,内容在SectorBuffer中
return 0;
}
//删除目录
int fat_rmdir( const char *dirname)
{
DWORD SectorNum;
_FILE file;
char filename[13];
//is dir have no sub dir or file ?
if(fat_getfirst(dirname, filename) == 0)
return 3;
//locate
SectorNum = fat_locate(dirname, &file);
if(SectorNum == 0xffffffff)
return 4;
// is it a dir ?
if(!(file.dir.deAttributes & ATTR_DIRECTORY))
return 6;
if(DeleteDir(&file) != 0)
return 5;
FreeCluster(file.dir.deStartCluster);
return 0;
}
FatGet fat_get;
//path所指目录下是否有子目录或文件,获得第一个子目录/文件名
int fat_getfirst(const char *path, char* filename)
{
DWORD Sector;
unsigned int i;
WORD Cluster;
//if exist this dir ?
Sector = fat_locate(path, NULL);
if(Sector == 0xffffffff)
return 1;
if(Sector ==FirstDirSector)
{
fat_get.IsRootDir = 1;
fat_get.DirIndex = 2;
for(i=0; i<RootDirCount * sizeof(DIRENTRY) / BytesPerSector; i++)
{
if(SectorGet(Sector++, &fat_get) == 0)
{
strcpy(filename, fat_get.filename);
return 0;
}
}
}
else
{
fat_get.IsRootDir = 0;
fat_get.DirIndex = 2;
Cluster = SectorNum2ClusterNum(Sector);
// because the sector is the first sector of parent dir,
// so it is the first sector of cluster.
/*
i = (Sector - FirstDataSector) % Bpb.SecPerClus;
if(i != 0)
{
for(; i< Bpb.SecPerClus; i++)
{
if(SectorGet(Sector++, &fat_get) == 0)
{
strcpy(filename, fat_get.filename);
return 0;
}
}
Cluster = GetNextClusterNum(Cluster);
Sector = ClusterNum2SectorNum(Cluster);
}*/
while(Cluster != 0xffff)
{
for(i=0; i< SectorsPerCluster; i++)
{
if(SectorGet(Sector++, &fat_get) == 0)
{
strcpy(filename, fat_get.filename);
return 0;
}
}
Cluster = GetNextClusterNum(Cluster);
Sector = ClusterNum2SectorNum(Cluster);
}
}
return 2;
}
int fat_getnext(char* filename)
{
DWORD Sector;
unsigned int i;
WORD Cluster;
Sector = fat_get.DirSectorNum;
if(fat_get.IsRootDir)
{
i=(Sector - RootDirSectors) * BytesPerSector/ sizeof(DIRENTRY) + fat_get.DirIndex +1;
for(; i<RootDirCount * sizeof(DIRENTRY) / BytesPerSector; i++)
{
if(SectorGet(Sector++, &fat_get) == 0)
{
strcpy(filename, fat_get.filename);
return 0;
}
}
}
else
{
Cluster = SectorNum2ClusterNum(Sector);
i = (Sector - FirstDataSector) % SectorsPerCluster;
if(i != 0)
{
for(; i< SectorsPerCluster; i++)
{
if(SectorGet(Sector++, &fat_get) == 0)
{
strcpy(filename, fat_get.filename);
return 0;
}
}
Cluster = GetNextClusterNum(Cluster);
Sector = ClusterNum2SectorNum(Cluster);
}
while(Cluster != 0xffff)
{
for(i=0; i< SectorsPerCluster; i++)
{
if(SectorGet(Sector++, &fat_get) == 0)
{
strcpy(filename, fat_get.filename);
return 0;
}
}
Cluster = GetNextClusterNum(Cluster);
Sector = ClusterNum2SectorNum(Cluster);
}
}
return 2;
}
_FILE handles[16];
int fat_close(int handle)
{
_FILE *fp;
FatDateTime tm;
BYTE* Cache;
DIRENTRY *dir;
if(handle <0 || handle >= sizeof(handles)/sizeof(_FILE))
return -1;
fp = &handles[handle];
fat_datetime(&tm);
fp->dir.LstAccDate = fp->dir.WrtDate = tm.Date;
fp->dir.WrtTime = tm.Time;
Cache = GetSectorData(fp->DirSectorNum);
if(Cache == NULL)
return -2;
dir = (DIRENTRY *)Cache;
dir += fp->DirIndex;
memcpy((BYTE *)dir, (BYTE *)&fp->dir, sizeof(DIRENTRY));
Flush();
FlushFAT();
handles[handle].valid = 0;
return 0;
}
//创建文件 文件名包括路径 文件属性
int fat_creat(const char* filename, BYTE attribute)
{
DIRENTRY dir;
char path[512];
char name[11];
char *p;
DWORD ParentDirSectorNum;
FatDateTime tm;
_FILE file;
DIRENTRY *pdir;
WORD NewCluster;
BYTE* Cache;
//判断文件名包括路径是否有效, is path format correct ?
p = get_valid_format(filename);
if(p == NULL)
return -2;
//if exist this file ? 寻找是否有相同名字的文件
//若没有,返回0xffffffff。若有,返回扇区数
if(fat_locate(filename, NULL) != 0xffffffff)
return -3;
//将文件名拷贝到name,不包括路径 separate path into parent and name
strncpy(name, &p[strlen(p)-11], 11);
strcpy(path, filename); //将文件名和路径拷贝到path
p = strrchr(path, '\\'); //找出path中最后一个\并在该处写0,
*p = '\0'; //用于将文件夹和文件名分开
//locate parent path
ParentDirSectorNum = fat_locate(path, NULL); //在根目录区寻找是否有与path同名的文件夹
if(ParentDirSectorNum == 0xffffffff) //返回文件夹的第一簇
return -4;
//fill dir attributes
memset((BYTE *)&dir, 0, sizeof(dir)); //dir清0
memcpy((BYTE *)(dir.deName), name, 11); //将文件名拷贝到dir.deName,不包括路径
dir.deAttributes = attribute; //填写属性,0x20代表txt文件
dir.deLowerCase = 0x00; //系统保留
fat_datetime(&tm); //获取时间,填写时间
dir.CrtDate = dir.LstAccDate = dir.WrtDate = tm.Date;
dir.CrtTime = dir.WrtTime = tm.Time;
dir.CrtTimeTenth = tm.TimeTenth;
dir.deFileSize = 100; //文件长度为0
//alloc one dir 在父目录所指的扇区下获得一个新的目录项
//从目录区中取得一个目录项,并将信息写进该目录项,并更新根目录区对应地方数据
//只写了文件名,属性,时间等信息,没有把起始簇信息写入
if(AllocDir(ParentDirSectorNum, &dir, &file) != 0)
return -5;
//alloc a cluster 查找空簇,找到后填写0xFFFF,后重写FAT表,返回没用到的空簇
NewCluster = AllocCluster(0);
if(NewCluster == 0xffff)
return -6;
//flush to disk
Cache = GetSectorData(file.DirSectorNum);//取得文件目录区登记该文件信息的扇区的内容
if(Cache == NULL)
return -7;
pdir = (DIRENTRY *)Cache;
pdir += file.DirIndex; //加上目录索引,即加上该扇区中第几个目录项
pdir->deStartCluster= NewCluster;//填写起始簇号
Flush();//烧写,内容在SectorBuffer中
return fat_open(filename);
}
long fat_lseek(int handle, long offset, int origin)
{
_FILE *fp;
WORD Cluster;
unsigned int len;
int i;
if(handle <0 || handle >= sizeof(handles)/sizeof(_FILE))
return 0;
fp = &handles[handle]; //handles为指向_FILE的数组
switch(origin)
{
case SEEK_SET:
{
if(offset < 0)
return (-1);
fp->offset = offset;
}
break;
case SEEK_CUR:
{
if((fp->offset + offset) <0 )
return (-1);
fp->offset += offset;
}
break;
case SEEK_END:
{
if((fp->offset + offset) <0 )
return (-1);
fp->offset = fp->dir.deFileSize + offset;
}
break;
default:
return (-2);
}
// re-locate CurrentSectorNum, SectorOffset
Cluster = fp->dir.deStartCluster;
fp->CurrentSectorNum = ClusterNum2SectorNum(Cluster);
len = 0;
while(Cluster != 0xffff)
{
for(i=0; i< SectorsPerCluster; i++)
{
len += BytesPerSector;
if(len >= fp->offset)
{
fp->SectorOffset = fp->offset % BytesPerSector;
return fp->offset;
}
fp->CurrentSectorNum ++;
}
Cluster = GetNextClusterNum(Cluster);
fp->CurrentSectorNum = ClusterNum2SectorNum(Cluster);
}
return handles[handle].offset;
}
int fat_open(const char* filename)
{
int i;
_FILE * fp = NULL;
DWORD FirstSectorNum;
for(i=0; i<16; i++)
{
if(!handles[i].valid) //handles为指向_FILE的数组
{
fp = &handles[i];
break;
}
}
if(fp == NULL)
return -1;
//寻找是否有相同名字的文件
//若没有,返回0xffffffff。若有,返回扇区数
FirstSectorNum = fat_locate(filename, fp);
if(FirstSectorNum == 0xffffffff)
return -2;
fp->StartSectorNum = FirstSectorNum;
fp->CurrentSectorNum = fp->StartSectorNum;
fp->SectorOffset = 0;
fp->offset = 0;
fp->valid = 1;
return i;
}
unsigned int fat_read(int handle, void* buffer, unsigned int bytes)
{
BYTE* Cache;
unsigned long int read_bytes =0;
unsigned int max_copy_bytes_in_sector;
_FILE *fp;
WORD Cluster;
int i,j=0;
if(handle <0 || handle >= sizeof(handles)/sizeof(_FILE))
return 0;
fp = &handles[handle]; //装入文件句柄(由之前fat_open带回的x),handles为指向_FILE的数组
//计算要读取的字节数,如果 文件大小 > bytes bytes就等于它本身
// 如果 文件大小 < bytes bytes就等于文件大小 bytes由实参带入
bytes = (fp->dir.deFileSize - fp->offset) > bytes ? bytes : (fp->dir.deFileSize - fp->offset);
Cluster = SectorNum2ClusterNum(fp->CurrentSectorNum);//根据当前扇区算出数据起始簇
i = (fp->CurrentSectorNum - FirstDataSector) % SectorsPerCluster;//计算是否有不是一整簇的扇区
if(i != 0) //读取不满一簇的数据扇区
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -