⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fat16.cpp

📁 我自己实现的fat16文件系统驱动
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// 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 + -