www.pudn.com > SmartFDISK.zip > fatbase.cpp


/**************************************************************************** 
 * 
 * Smart FDISK 
 * 
 * This program is a powerful Harddisk Partitioning Tool including a 
 * easy-to-use Boot Manager. 
 * 
 * 
 *     Copyright (C) 1999 Suzhe (suzhe@263.net) 
 * 
 * This program is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version. 
 * 
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 * General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with this program; if not, write to the Free Software Foundation, 
 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 * 
 ****************************************************************************/ 
/* 
 * fatbase.cpp : Source file for Class TFATBase 
 */ 
 
#define Uses_FATBase 
#define Uses_DataType 
#define Uses_Partition 
#define Uses_HardDrive 
#define Uses_FileSystem 
#define Uses_KernelMessage 
#include "Kernel.H" 
#include "FATMacro.h" 
 
/****************************************************************************/ 
/* Functions for class TFATBase                                             */ 
/****************************************************************************/ 
void TFATBase::PreInit() 
{ 
	FATBufStartSector = 0; 
	FATBufSectors = 0; 
	FATBuf		  = NULL; 
	BadBlockList  = NULL; 
	FATType		  = 0; 
	FATBufChanged = False; 
	memset( &ParamBlock, 0, sizeof( ParamBlock )); 
} 
 
void TFATBase::ShutDown() 
{ 
	TFileSystem::ShutDown(); 
	if( FATBuf != NULL ) 
		delete FATBuf; 
	PreInit(); 
} 
 
int32 TFATBase::Initialize( TPartition *partition ) 
{ 
	int32 errno; 
	TDiskGeometry geometry; 
	BYTE *DriveNumber; 
 
	PreInit(); 
 
	if( (errno = TFileSystem::Initialize( partition )) != 0 ) 
		return errno; 
 
	FATBuf =new BYTE[ Partition->GetSectorSize() * FATBUFSECTORS ]; 
	if( FATBuf == NULL ) 
	{ 
		Useable = False; 
		return 0x400; 
	} 
	FATBufSectors = FATBUFSECTORS; 
	FATBufStartSector = -1; 
 
	if( !Partition->IsNewPartition() && 
		(errno = ReadBootRecord()) != 0 ) 
		return errno; 
 
	if( IsFormated()==False ) 
		errno = CreateBootRecord(ValidBlockSize[0]); 
 
	Partition->GetHardDrive()->GetGeometry( geometry ); 
 
	if( FATType == 32 ) 
		DriveNumber =  & ParamBlock.bpb32.DriveNumber; 
	else DriveNumber = & ParamBlock.bpb16.DriveNumber; 
 
	if( IsFormated() && 
		(( *DriveNumber != Partition->GetHardDrive()->GetDriveNumber()) || 
		(ParamBlock.com.SectorsPerTrack != geometry.SectorsPerTrack) || 
		(ParamBlock.com.Heads != geometry.Heads)) ) 
    { 
    	Changed = True; 
		*DriveNumber = Partition->GetHardDrive()->GetDriveNumber(); 
		ParamBlock.com.SectorsPerTrack = geometry.SectorsPerTrack; 
		ParamBlock.com.Heads = geometry.Heads; 
    } 
 
	if( FATType == 16 || FATType == 12 ) 
		strncpy( FileSysName, (char*)ParamBlock.bpb16.SystemType, 16 ); 
	else if( FATType == 32 ) 
		strncpy( FileSysName, (char*)ParamBlock.bpb32.SystemType, 16 ); 
	FileSysName[15] = 0; 
 
	return errno; 
} 
 
int32 TFATBase::ReadCluster( DWORD start, WORD num, void * buf ) 
{ 
	DWORD LBAStart, LBANum; 
	if( !IsUseable() ) return 0x300; 
	if( buf==NULL ) return 0x401; 
	LBAStart = GetClusterLBA( start ); 
	LBANum = num * GetSectorsPerCluster(); 
	if( LBAStart == 0 || LBANum == 0 ) return 0x401; 
	return Partition->Read( LBAStart, LBANum, buf ); 
} 
 
int32 TFATBase::WriteCluster( DWORD start, WORD num, void * buf ) 
{ 
	DWORD LBAStart, LBANum; 
	if( !IsUseable() ) return 0x300; 
	if( buf==NULL ) return 0x401; 
	LBAStart = GetClusterLBA( start ); 
	LBANum = num * GetSectorsPerCluster(); 
	if( LBAStart == 0 || LBANum == 0 ) return 0x401; 
	return Partition->Write( LBAStart, LBANum, buf ); 
} 
 
int32 TFATBase::VerifyCluster( DWORD start, WORD num ) 
{ 
	DWORD LBAStart, LBANum; 
	if( !IsUseable() ) return 0x300; 
	LBAStart = GetClusterLBA( start ); 
	LBANum = num * GetSectorsPerCluster(); 
	if( LBAStart == 0 || LBANum == 0 ) return 0x401; 
	return Partition->Verify( LBAStart, LBANum ); 
} 
 
int32 TFATBase::Format( CallBackFunc CallBack, int32 method, DWORD MinBlockSize ) 
{ 
	int32 errno; 
	DWORD delta, amount, percent; 
	DWORD cluster, temp, TotalClusters; 
	int32 FirstFmt; 
 
	char *buf=NULL; 
	char *StatusMsg    = KernelMsg[2]; 
	char *RecordBadMsg = KernelMsg[3]; 
	char *CreateFATMsg = KernelMsg[4]; 
	char *WriteBadMsg  = KernelMsg[5]; 
	char *CreateRootMsg= KernelMsg[6]; 
	char *CreateBootMsg= KernelMsg[7]; 
	char *EndMsg       = KernelMsg[8]; 
	char MsgBuf[80]; 
 
	if( !IsUseable() ) return 0x300; 
	if( !CanFormat() ) return 0x301; 
 
	if( IsFormated() && method == QUICKFORMAT ) 
		MinBlockSize = GetBlockSize(); 
 
	errno=CreateBootRecord(MinBlockSize); 
	if( errno!=0 ) return errno; 
 
	if( IsFormated() && 
		method == QUICKFORMAT && MinBlockSize == GetBlockSize() ) 
	{ 
 
		if( CallBack!=NULL ) CallBack( RecordBadMsg ); 
		ReadBadBlockRecord(); 
		FirstFmt=0; 
	} 
	else FirstFmt=1; 
 
	if( CallBack!=NULL ) CallBack( CreateBootMsg ); 
	errno=WriteBootRecord(); 
	if( errno!=0 ) return errno; 
 
	if( CallBack!=NULL ) CallBack( CreateFATMsg ); 
	errno = ClearFATTable(); 
	if( errno!=0 ) return errno; 
 
	if( method == SAFEFORMAT || method == FULLFORMAT) 
	{ 
		TotalClusters=GetTotalClusters(); 
 
		if( method == SAFEFORMAT ) 
		{ 
			buf=new char[ 32768uL ]; 
			if( buf==NULL ) return 0x400; 
			memset( buf, 0xF6, sizeof(char)*GetBlockSize() ); 
		} 
 
		delta = 32768ul / GetBlockSize(); 
		percent = (TotalClusters + FIRSTCLUSTER) / 100uL; 
		if( (TotalClusters + FIRSTCLUSTER) % 100uL > 50 ) 
			percent ++; 
 
		for( cluster=FIRSTCLUSTER;clusterGetSizeInMega(), cluster / percent ); 
				if( CallBack( MsgBuf )!=0 ) break; 
			} 
 
			amount = delta; 
			if( amount > TotalClusters + FIRSTCLUSTER - cluster ) 
				amount = TotalClusters + FIRSTCLUSTER - cluster; 
 
			if( method == SAFEFORMAT ) 
				 errno = WriteCluster( cluster, amount, buf ); 
			else errno = 0; 
 
			if( errno == 0 ) errno = VerifyCluster( cluster, amount ); 
 
			if( errno!=0 ) 
			{ 
				for( temp = cluster; temp < cluster + amount; temp ++ ) 
				{ 
					if( method == SAFEFORMAT ) 
						 errno = WriteCluster( temp, 1, buf ); 
					else errno = 0; 
 
					if( errno == 0 ) errno = VerifyCluster( temp, 1 ); 
 
					if( errno != 0 ) 
						WriteFATEntry( temp, GetBadClusterID() ); 
				} 
			} 
		} 
 
		FlushFATBuf(); 
	} 
 
	if( method == SAFEFORMAT ) delete buf; 
 
	if( CallBack!=NULL ) CallBack( CreateRootMsg ); 
	errno = ClearRootDir(); 
	if( errno!=0 ) return errno; 
 
	if( !FirstFmt ) 
	{ 
		if( CallBack!=NULL ) CallBack( WriteBadMsg ); 
		WriteBadBlockRecord(); 
	} 
	Formated = True; 
 
	if( CallBack!=NULL ) 
		CallBack( EndMsg ); 
 
	return 0; 
} 
 
TBadBlockList *TFATBase::SurfaceScan( CallBackFunc CallBack ) 
{ 
	int32 errno,lastErr; 
	DWORD cluster, temp, TotalClusters; 
	DWORD delta, amount, percent; 
	TBadBlockList *point; 
 
	char *StatusMsg= KernelMsg[0]; 
	char *EndMsg   = KernelMsg[1]; 
	char MsgBuf[80]; 
 
	if( !IsUseable() || !IsFormated() ) return NULL; 
 
	DeleteBadBlockList(); 
 
	BadBlockList=NULL; 
	point=NULL; 
	errno=0; 
	lastErr=0; 
 
	TotalClusters=GetTotalClusters(); 
 
	delta = 65535ul / GetBlockSize(); 
	percent = (TotalClusters + FIRSTCLUSTER) / 100uL; 
	if( (TotalClusters + FIRSTCLUSTER) % 100uL > 50 ) 
		percent ++; 
 
	for( cluster = FIRSTCLUSTER; 
		cluster < TotalClusters + FIRSTCLUSTER; 
		cluster+=delta ) 
	{ 
		if( CallBack!=NULL ) 
		{ 
			sprintf( MsgBuf, StatusMsg, Partition->GetSizeInMega(), cluster / percent ); 
			if( CallBack( MsgBuf )!=0 ) break; 
		} 
 
		amount = delta; 
		if( amount > TotalClusters + FIRSTCLUSTER - cluster ) 
			amount = TotalClusters + FIRSTCLUSTER - cluster; 
 
		errno = VerifyCluster( cluster, amount ); 
		if( errno!=0 ) 
		{ 
			for( temp = cluster; temp < cluster + amount; temp ++ ) 
			{ 
				errno = VerifyCluster( temp, 1 ); 
				if( errno!=0 ) 
				{ 
					if( lastErr==0 ) 
					{ 
						if( BadBlockList==NULL ) 
						{ 
							BadBlockList = point = new TBadBlockList; 
							BadBlockList->Next=NULL; 
						} 
						else 
						{ 
							point->Next = new TBadBlockList; 
							point=point->Next; 
							point->Next = NULL; 
						} 
						point->Start = temp; 
						point->End = temp; 
					} 
					else point->End = temp; 
				} 
				lastErr = errno; 
			} 
		} 
		else lastErr = errno; 
	} 
	if( CallBack!=NULL ) 
		CallBack( EndMsg ); 
	return BadBlockList; 
} 
 
int32 TFATBase::GetFileSysInfo( TFileSysInfo &info ) 
{ 
	DWORD total, free, bad; 
 
	memset( &info, 0, sizeof( TFileSysInfo ) ); 
	if( !IsUseable() ) return 0x300; 
 
	info.InfoSize = sizeof( TFileSysInfo ); 
	info.Formated = IsFormated(); 
	info.TotalKBytes = Partition->GetSectors() / 1024uL * Partition->GetSectorSize(); 
	info.TotalKBytes += ( (Partition->GetSectors() % 1024uL) * 
						Partition->GetSectorSize() ) / 1024uL; 
 
	strncpy( (char*)info.FileSysName, GetFileSysName(), 16); 
	info.FileSysName[15]=0; 
 
	if( IsFormated() ) 
	{ 
		info.BytesPerBlock = GetBlockSize(); 
		info.TotalBlocks = GetTotalClusters(); 
		info.ReservedKBytes = info.TotalKBytes - info.TotalBlocks * 
							  ( GetBlockSize() / 1024uL); 
 
		info.FreeBlocks = info.TotalBlocks; 
 
		if( ReadFATTable( info.FreeBlocks, info.BadBlocks )!=0 ) 
			return 0x302; 
 
		info.FreeKBytes = info.FreeBlocks * ( info.BytesPerBlock / 1024uL ); 
	} 
	return 0; 
} 
 
int32 TFATBase::ReadFATTable( DWORD &FreeClusters, DWORD &BadClusters ) 
{ 
	DWORD entry, TotalClusters; 
 
	if( !IsUseable() ) return 0x300; 
	if( !IsFormated() ) return 0x303; 
	BadClusters = 0; 
	FreeClusters = 0; 
	TotalClusters=GetTotalClusters(); 
 
	for( DWORD i = FIRSTCLUSTER; i< TotalClusters + FIRSTCLUSTER; i++ ) 
	{ 
		entry = ReadFATEntry( i ); 
		if( entry == 0uL ) FreeClusters++; 
		else if( entry == GetBadClusterID() ) 
			BadClusters++; 
	} 
	return 0; 
} 
 
int32 TFATBase::ReadBadBlockRecord() 
{ 
	DWORD i; 
	DWORD lastEntry; 
	DWORD entry; 
	DWORD BadID; 
	DWORD TotalClusters; 
 
	TBadBlockList *point; 
	if( !IsUseable() ) return 0x300; 
	if( !IsFormated() ) return 0x303; 
 
	DeleteBadBlockList(); 
 
	BadBlockList = NULL; 
	point = NULL; 
	lastEntry = 0; 
	BadID = GetBadClusterID(); 
 
	TotalClusters=GetTotalClusters(); 
 
	for( i=FIRSTCLUSTER; i< TotalClusters+FIRSTCLUSTER; i++ ) 
	{ 
		entry=ReadFATEntry( i ); 
		if( entry==BadID ) 
		{ 
			if( lastEntry!=BadID ) 
			{ 
				if( BadBlockList==NULL ) 
				{ 
					BadBlockList = point = new TBadBlockList; 
					BadBlockList->Next=NULL; 
				} 
				else 
				{ 
					point->Next = new TBadBlockList; 
					point=point->Next; 
					point->Next = NULL; 
				} 
				point->Start = i; 
				point->End = i; 
			} 
			else point->End = i; 
		} 
	} 
	return 0; 
} 
 
int32 TFATBase::WriteBadBlockRecord() 
{ 
	TBadBlockList *point; 
	DWORD i; 
	DWORD BadID; 
 
	if( !IsUseable() ) return 0x300; 
	if( !IsFormated() ) return 0x303; 
 
	BadID = GetBadClusterID(); 
 
	for( point = BadBlockList; point!=NULL; point=point->Next ) 
		for( i=point->Start; i<=point->End; i++ ) 
			WriteFATEntry( i,BadID ); 
	FlushFATBuf(); 
	return 0; 
} 
 
 
BYTE TFATBase::GetFileSysType() 
{ 
	if( !IsUseable() || ( FATType != 16 && FATType != 12 && FATType != 32 ) ) 
		return 0; 
    if( FATType == 16 ) 
    	return 0x06; 
    else if( FATType == 12 ) 
    	return 0x01; 
	else return	0x0B; 
} 
 
int32 TFATBase::WriteChange() 
{ 
	BYTE *buf; 
	int32 errno=0; 
 
	if( !IsUseable() || ( FATType != 16 && FATType != 12 && FATType != 32 ) ) 
		return 0x300; 
    if( !IsChanged() || !IsFormated() ) 
    	return 0; 
 
	buf = new BYTE[ Partition->GetSectorSize() ]; 
	if( buf==NULL ) return 0x400; 
 
	if( (errno=Partition->Read( 0, 1, buf )) == 0 && 
		*((DWORD*)(buf+BOOTIDOFFSET)) == GOODBOOTID ) 
	{ 
		if( FATType == 16 || FATType == 12 ) 
			memcpy( buf+BPBOFFSET, &ParamBlock, SIZEOFBPB16 ); 
		else 
			memcpy( buf+BPBOFFSET, &ParamBlock, SIZEOFBPB32 ); 
 
		if( (errno=Partition->Write( 0, 1, buf )) ==0 ) 
			errno=Partition->Verify( 0, 1 ); 
    } 
 
    delete buf; 
    if( errno==0 ) Changed=False; 
 
	FlushFATBuf(); 
 
	return errno; 
} 
 
DWORD TFATBase::GetBadClusterID() 
{ 
	if( FATType == 16 ) return 0x0FFF7uL; 
	else if( FATType == 12 ) return 0x0FF7uL; 
	else return 0x0FFFFFF7uL; 
} 
 
Boolean TFATBase::CanFormat() 
{ 
	if( TFileSystem::CanFormat() == False ) 
		return False; 
	if( ( FATType == 16 || FATType == 12 ) && Partition->GetSizeInMega() >= 2048uL ) 
		return False; 
	if( FATType == 32 && 
		( Partition->GetSizeInMega() < 256uL || 
		Partition->GetSizeInMega() >= 2097152uL ) 
	  ) 
		return False; 
	return True; 
} 
 
int32 TFATBase::GetBlkSizeInfo( WORD & minIndex, WORD & maxIndex , WORD & defIndex) 
{ 
	WORD SPC; 
	DWORD MaxCluster, sectors; 
	int index; 
 
	minIndex = 0; 
	maxIndex = 0; 
 
	if( !IsUseable() || FATType==0 ) 
		return 0x300; 
 
 
	if( FATType == 32 ) MaxCluster = 0x10000000uL; 
	else MaxCluster = (1uL)<GetSectors(); 
 
	for(SPC=2; sectors / (DWORD)SPC >= MaxCluster; SPC<<=1) 
		minIndex++; 
 
	maxIndex = 5; 
	if( FATType != 32 ) defIndex = minIndex; 
	else if( minIndex < 2 ) defIndex = 2; 
	else defIndex = minIndex; 
 
	return 0; 
}