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;
}