📄 fat16.cpp
字号:
// fat16.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "fat16.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <windows.h>
extern void* MemDisk;
struct _BPB Bpb;
DWORD RootDirSectors; // Numbers of sectors occupied by Root Directory.
DWORD FirstDataSector; //The first sector of cluster 2 (the data region of the disk).
DWORD FirstFatSecNum; //Start sector of the first fat data structure.
DWORD FirstRootDirSecNum; //Start sector of root directory.
WORD* FatCache;
///////////////////////////////////////////////////////////////////
// disk cache management
///////////////////////////////////////////////////////////////////
BYTE SectorCache[512];
DWORD CurrentCacheSector;
//Read a special sector into disk cache.
//NULL indicate failed.
BYTE* GetSectorData(DWORD StartSector)
{
//return &((BYTE*)MemDisk)[StartSector * Bpb.BytsPerSec];
if(CurrentCacheSector == StartSector && StartSector != 0)
return SectorCache;
memcpy(SectorCache, &((BYTE*)MemDisk)[StartSector * Bpb.BytsPerSec], 512);
CurrentCacheSector = StartSector;
return SectorCache;
}
//Flush cache data onto disk.
void Flush()
{
memcpy(&((BYTE*)MemDisk)[CurrentCacheSector * Bpb.BytsPerSec], SectorCache, 512);
}
//Write data into special sector. Size can more than bytes per sector.
int SetSectorData(DWORD StartSector, BYTE* Buffer, DWORD Size)
{
memcpy(&((BYTE*)MemDisk)[StartSector * Bpb.BytsPerSec], Buffer, Size);
return 0;
}
///////////////////////////////////////////////////////////////////
//fat16 low interface
///////////////////////////////////////////////////////////////////
// 0 indicate success.
int fat_init()
{
BYTE* bootsec;
DWORD DataSec;
DWORD CountofClusters;
BYTE* Cache;
WORD* pFat;
DWORD Sector;
// Initialize BPB.
bootsec = GetSectorData(0);
Bpb.BytsPerSec = *((WORD*)&bootsec[11]);
Bpb.SecPerClus = bootsec[13];
Bpb.RsvdSecCnt = *((WORD*)&bootsec[14]);
Bpb.NumFATs = bootsec[16];
Bpb.RootEntCnt = *((WORD*)&bootsec[17]);
if((Bpb.TotSec = *((WORD*)&bootsec[19])) == 0)
Bpb.TotSec = *((DWORD*)&bootsec[32]);
if((Bpb.FATSz = *((WORD*)&bootsec[22])) == 0)
Bpb.FATSz = *((DWORD*)&bootsec[36]);
RootDirSectors = ((Bpb.RootEntCnt * 32) + (Bpb.BytsPerSec - 1)) / Bpb.BytsPerSec;
DataSec = Bpb.TotSec - (Bpb.RsvdSecCnt + (Bpb.NumFATs * Bpb.FATSz) + RootDirSectors);
CountofClusters = DataSec / Bpb.SecPerClus;
/*FAT12 < 4085, FAT32 >= 65525*/
if(CountofClusters < 4085 || CountofClusters >= 65525)
return 1;
FirstFatSecNum = Bpb.RsvdSecCnt;
FirstRootDirSecNum = Bpb.RsvdSecCnt + (Bpb.NumFATs * Bpb.FATSz);
FirstDataSector = Bpb.RsvdSecCnt + (Bpb.NumFATs * Bpb.FATSz) + RootDirSectors;
FatCache = (WORD*)malloc(Bpb.BytsPerSec * Bpb.FATSz);
if(FatCache == NULL)
return 2;
for(Sector = FirstFatSecNum, pFat = FatCache; Sector <= Bpb.FATSz; Sector++, pFat+=Bpb.BytsPerSec/sizeof(WORD))
{
Cache = GetSectorData(Sector);
if(Cache == NULL)
{
free(FatCache);
return 3;
}
memcpy(pFat, Cache, Bpb.BytsPerSec);
}
memset(&fat_get, 0, sizeof(fat_get));
memset(&handles, 0, sizeof(handles));
return 0;
}
void fat_deinit()
{
DWORD i;
// close all opened files
for(i=0; i<16; i++)
{
if(handles[i].valid)
{
fat_close(i);
}
}
// flush the fat cache to disk.
for(i = 0; i < Bpb.NumFATs; i++)
{
SetSectorData(FirstFatSecNum + i * Bpb.FATSz, (BYTE*)FatCache, Bpb.BytsPerSec * Bpb.FATSz);
}
}
WORD SectorNum2ClusterNum(DWORD SectorNum)
{
return (WORD)((SectorNum - FirstDataSector) / Bpb.SecPerClus + 2);
}
DWORD ClusterNum2SectorNum(WORD ClusterNum)
{
return FirstDataSector + (ClusterNum - 2) * Bpb.SecPerClus;
}
//return next cluster num,
//0xffff indicate no next cluster.
//Note! : this function will dirty cache!
WORD GetNextClusterNum(WORD ClusterNum)
{
return FatCache[ClusterNum];
}
// alloc a free cluster. policy is searching from prev cluster number, if no free cluster till end of fat, then search from head of fat.
// return a cluster number. 0xffff indicate faild, disk overflow.
// argument 0 : no prev cluster.
WORD AllocCluster(WORD PrevClusterNum)
{
static WORD LastAllocClusterNum=0;
WORD i;
if(LastAllocClusterNum == 0)
LastAllocClusterNum = PrevClusterNum;
for(i = LastAllocClusterNum; i < Bpb.BytsPerSec * Bpb.FATSz / sizeof(WORD); i++)
{
if(FatCache[i] == 0)
{
FatCache[i] = 0xffff; // flag with 0xffff, this is the last cluster.
LastAllocClusterNum = i;
//chain this cluster to prev one.
if(PrevClusterNum != 0)
FatCache[PrevClusterNum] = LastAllocClusterNum;
return LastAllocClusterNum;
}
}
// we have to search from head of fat
for(i = 2; i < Bpb.BytsPerSec * Bpb.FATSz / sizeof(WORD); i++)
{
if(FatCache[i] == 0)
{
FatCache[i] = 0xffff; // flag with 0xffff, this is the last cluster.
LastAllocClusterNum = i;
//chain this cluster to prev one.
if(PrevClusterNum != 0)
FatCache[PrevClusterNum] = LastAllocClusterNum;
return LastAllocClusterNum;
}
}
return 0xffff;
}
// free cluster chain.
// argument 0 : no prev cluster.
void FreeCluster(WORD StartClusterNum)
{
WORD Cluster;
WORD NextCluster;
Cluster = StartClusterNum;
while(Cluster != 0xffff)
{
NextCluster = FatCache[Cluster];
FatCache[Cluster] = 0x0000;
Cluster = NextCluster;
}
}
// return the first sector number of dir content .
// 0xffffffff indicate failed.
int AllocDir(DWORD ParentDirSectorNum, struct _DIR* new_dir, struct _file * fp)
{
BYTE* Cache;
struct _DIR *dir;
DWORD i;
WORD PrevCluster;
WORD Cluster;
DWORD DirSectorNum = ParentDirSectorNum;
//if(dirname == NULL)
//return 1;
if(ParentDirSectorNum == FirstRootDirSecNum)
{
for(i=0; i<Bpb.RootEntCnt * sizeof(struct _DIR) / Bpb.BytsPerSec; i++)
{
Cache = GetSectorData(DirSectorNum);
if(Cache == NULL)
return 2;
for(dir = (struct _DIR *)Cache; (BYTE*)dir < Cache + Bpb.BytsPerSec; dir++)
{
if(dir->Name[0] == '\0' || dir->Name[0] == ERCHAR)
{
memcpy(dir, new_dir, sizeof(struct _DIR));
Flush();
if(fp)
{
fp->DirSectorNum = DirSectorNum;
fp->DirIndex = ((BYTE*)dir - Cache) / sizeof(struct _DIR);
memcpy(&fp->dir, new_dir, sizeof(struct _DIR));
}
return 0;
}
}
DirSectorNum++;
}
// root dir have no room.
return 3;
}
else
{
Cluster = SectorNum2ClusterNum(DirSectorNum);
while(Cluster != 0xffff)
{
for(i=0; i< Bpb.SecPerClus; i++)
{
Cache = GetSectorData(DirSectorNum);
if(Cache == NULL)
return 2;
for(dir = (struct _DIR *)Cache; (BYTE*)dir < Cache + Bpb.BytsPerSec; dir++)
{
if(dir->Name[0] == '\0' || dir->Name[0] == ERCHAR)
{
memcpy(dir, new_dir, sizeof(struct _DIR));
Flush();
if(fp)
{
fp->DirSectorNum = DirSectorNum;
fp->DirIndex = ((BYTE*)dir - Cache) / sizeof(struct _DIR);
memcpy(&fp->dir, new_dir, sizeof(struct _DIR));
}
return 0;
}
}
DirSectorNum++;
}
PrevCluster = Cluster;
Cluster = GetNextClusterNum(Cluster);
DirSectorNum = ClusterNum2SectorNum(Cluster);
}
//
// we have to extend this parent dir room.
//
Cluster = AllocCluster(PrevCluster);
if(Cluster == 0xffff)
return 4;
DirSectorNum = ClusterNum2SectorNum(Cluster);
Cache = GetSectorData(DirSectorNum);
if(Cache == NULL)
return 2;
dir = (struct _DIR *)Cache;
memcpy(dir, new_dir, sizeof(struct _DIR));
Flush();
if(fp)
{
fp->DirSectorNum = DirSectorNum;
fp->DirIndex = ((BYTE*)dir - Cache) / sizeof(struct _DIR);
memcpy(&fp->dir, new_dir, sizeof(struct _DIR));
}
return 0;
}
return 5;
}
int DeleteDir(struct _file *file)
{
BYTE* Cache;
struct _DIR *dir;
Cache = GetSectorData(file->DirSectorNum);
if(Cache == NULL)
return 1;
dir = (struct _DIR *)Cache;
dir += file->DirIndex;
dir->Name[0] = ERCHAR;
Flush();
return 0;
}
// helper functions
// NULL indicate failed.
//Valid format is full path: \[8.3\]*DIR_Name
//limits:
// length < 80 && !(special char)
char* get_valid_format(const char *fullpath)
{
static char static_path[512];
char* p=static_path;
char path[80];
char* ppath = path;
int dir_len_count; //count dir len.
int i;
if(fullpath == NULL || strlen(fullpath) >=80 || *fullpath != '\\')
return NULL;
if(strlen(fullpath) > 1 && fullpath[strlen(fullpath)-1] =='\\')
return NULL;
strcpy(path, fullpath);
strupr(path);
memset(p, 0, 512);
for(;;)
{
switch(*ppath)
{
case 0x00:
{
if(dir_len_count != 0) // prev is not '\\'
{
for(i=0; i<(11 - dir_len_count); i++)
{
*p = 0x20;
p++;
}
}
}
return static_path;
case '\\':
{
if(p != static_path) // this is not the first '\\'
{
if(dir_len_count == 0)// more than one '\\'
return NULL;
for(i=0; i<(11 - dir_len_count); i++)
{
*p = 0x20;
p++;
}
}
*p = '\\';
p++;
ppath++;
dir_len_count =0;
continue;
}
break;
case '.':
{
if(dir_len_count > 8 || dir_len_count ==0) // '\\.' check
return NULL;
if(ppath[1] == '.' || ppath[1] == '\\') // more than one '.' or '.\\' check
return NULL;
for(i=0; i<(8 - dir_len_count); i++)
{
*p = 0x20;
p++;
}
dir_len_count =8;
ppath++;
continue;
}
break;
case 0x22:
case 0x2A:
case 0x2B:
case 0x2C:
case 0x2F:
case 0x3A:
case 0x3B:
case 0x3C:
case 0x3D:
case 0x3E:
case 0x3F:
case 0x5B:
case 0x5D:
case 0x7C:
return NULL;
default:
{
if(*ppath < 0x20)
return NULL;
}
break;
}
*p = *ppath;
dir_len_count ++;
if(dir_len_count > 11)
return NULL;
p++;
ppath++;
}
return static_path;
}
void unformat_name(char * filename, const unsigned char dirname[11])
{
int i;
int j;
memset(filename, 0, 13);
for(i=0; i<8; i++)
{
if(dirname[i] != 0x20)
filename[i] = dirname[i];
else
break;
}
if(dirname[8] != 0x20)
{
filename[i] = '.';
j = i + 1;
for(i=8; i<11; i++,j++)
{
if(dirname[i] != 0x20)
filename[j] = dirname[i];
else
break;
}
}
}
DWORD SectorSearch(DWORD Sector, const char dirname[11], struct _file *file)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -