www.pudn.com > SmartFDISK.zip > rootpart.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.
*
****************************************************************************/
/*
* rootpart.cpp : Source file for Class TRootPartition
*/
#define Uses_DataType
#define Uses_HardDrive
#define Uses_Partition
#define Uses_RootPartition
#define Uses_FileSystem
#define Uses_BootManager
#include "Kernel.H"
/****************************************************************************/
/* Member Function of class TRootPartition */
/****************************************************************************/
TRootPartition::TRootPartition( THardDrive *hd ) :
TPartition()
{
Initialize( hd );
}
TRootPartition::TRootPartition() :
TPartition()
{
}
int32 TRootPartition::Initialize( THardDrive *hd )
{
if( hd->IsUseable()==False ) return 0x102;
TPartition::Initialize( hd, NULL, 0, False, 0, hd->GetSectors() );
MarkRootPartition( True );
if( ReadPartitionTable()!=0 )
{
Useable = False;
return 0x102;
}
return 0;
}
int32 TRootPartition::ReadPartitionTable()
{
int32 errno,extCount;
TPartition * son;
TPartitionRecord PartitionTable[MAXPTNUMBER];
char * BootRecord=NULL;
if( !IsUseable() ) return 0x200;
memset( PartitionTable, 0, sizeof(TPartitionRecord) * MAXPTNUMBER );
BootRecord = new char[HardDrive->GetSectorSize()];
if( BootRecord == NULL ) return 0x400;
DeleteAllSon();
errno=Read(0, 1, BootRecord);
if( errno!=0 )
{
delete BootRecord;
return errno;
}
if( ((WORD *)BootRecord)[255]==GOODPTID)
{
memcpy( PartitionTable, BootRecord + PTTABOFFSET,
sizeof(TPartitionRecord) * MAXPTNUMBER );
for( int i=0; i< MAXPTNUMBER; i++ )
{
if( PartitionTable[i].Type != 0 )
{
son = new TPartition( HardDrive, this, PartitionTable[i] );
InsertSon( son );
}
}
for( son=Son, extCount=0; son!=NULL; son=son->Next )
{
if( (son->GetType()==0x05 || son->GetType()==0x0F) && extCount<1 )
{
extCount ++;
ReadExtPartTable( son, son );
}
}
TransExtPartLink();
}
delete BootRecord;
CheckFree();
return 0;
}
int32 TRootPartition::WritePartitionTable()
{
int32 count;
int32 errno=0;
TPartition *part;
TPartitionRecord PartitionTable[MAXPTNUMBER];
char * BootRecord=NULL;
if( !IsUseable() ) return 0x200;
AntiTransExtPartLink();
for( part=Son; part!=NULL; part=part->Next )
if( part->GetType()==0x05 || part->GetType()==0x0F )
break;
if( part!=NULL )
errno = WriteExtPartTable( part, part );
if( errno==0 )
errno = CreatePartitionTable( PartitionTable );
TransExtPartLink();
if( errno!=0 ) return errno;
BootRecord = new char[HardDrive->GetSectorSize()];
if( BootRecord == NULL ) return 0x400;
errno=Read(0, 1, BootRecord);
if( errno!=0 )
{
delete BootRecord;
return errno;
}
memcpy( BootRecord + PTTABOFFSET, PartitionTable,
sizeof( TPartitionRecord ) * MAXPTNUMBER );
((WORD *)BootRecord)[255]=GOODPTID;
errno=Write( 0, 1, BootRecord );
delete BootRecord;
return errno;
}
int32 TRootPartition::CreatePartitionTable(TPartitionRecord *PartitionTable)
{
int32 partCount=0;
TPartition *part;
WORD edCyl, head, edSect;
if( !IsUseable() ) return 0x200;
memset( PartitionTable, 0, sizeof( TPartitionRecord ) * MAXPTNUMBER );
for( part = Son, partCount=0;
part != NULL && partCount < MAXPTNUMBER;
part = part->Next )
{
if( part->GetType() != 0 && part->IsUseable() )
{
part->GetRecord(PartitionTable[partCount]);
if( part->GetType() == 0x05 )
{
HardDrive->LBAtoCHS( part->GetAbsSector() + part->GetSectors() - 1
, edCyl, head, edSect );
if( edCyl > MAXINT13CYLINDER )
PartitionTable[partCount].Type = 0x0F;
}
partCount ++;
}
}
return 0;
}
int32 TRootPartition::WriteChange()
{
int32 errno;
if( !IsChanged() ) return 0;
errno=WritePartitionTable();
if( errno!=0 ) return errno;
errno=TPartition::WriteChange();
if( errno!=0 ) return errno;
return 0;
}
int32 TRootPartition::CheckFree()
{
TPartition *part, *free, *temp;
TDiskGeometry geometry;
int32 errno;
DWORD sect;
if( !IsUseable() ) return 0x200;
HardDrive->GetGeometry( geometry );
for( part=Son; part!=NULL; part=part->Next )
{
if( part->GetType() == 0x05 || part->GetType() == 0x0F )
{
temp=part->GetLastSon();
while( temp!=NULL && temp->GetType()==0 )
{
part->DeleteSon(temp);
temp = part->GetLastSon();
}
if( temp!=NULL )
{
part->Resize( temp->GetRelativeSector() + temp->GetSectors() );
}
else
{
temp=part->Prev;
DeleteSon(part);
if( temp!=NULL ) part=temp;
else part=Son;
}
}
}
if( Son == NULL )
{
free = new TPartition( HardDrive, this, 0, geometry.SectorsPerTrack,
GetSectors() - geometry.SectorsPerTrack );
InsertSon( free );
return 0;
}
if( Son->GetRelativeSector() > geometry.SectorsPerTrack )
{
free = new TPartition( HardDrive, this, 0, geometry.SectorsPerTrack,
Son->GetRelativeSector() - geometry.SectorsPerTrack );
if( free->GetRelativeSector() + free->GetSectors() <=
Son->GetRelativeSector() )
InsertSon( free );
else destroy(free);
}
for( part=Son; part->Next!=NULL; part=part->Next )
{
sect = part->GetRelativeSector() + part->GetSectors();
if( sect < part->Next->GetRelativeSector() )
{
free = new TPartition( HardDrive, this, 0, sect,
part->Next->GetRelativeSector() - sect );
if( free->GetRelativeSector() >= sect &&
free->GetRelativeSector() + free->GetSectors() <=
part->Next->GetRelativeSector() )
{
InsertSon( free );
part=part->Next;
}
else destroy(free);
}
}
sect = part->GetRelativeSector() + part->GetSectors();
if( sect < GetSectors() )
{
free = new TPartition( HardDrive, this, 0, sect, GetSectors() - sect );
if( free->GetRelativeSector() >= sect &&
free->GetRelativeSector() + free->GetSectors() <= GetSectors() )
InsertSon( free );
else destroy(free);
}
for( part=Son; part->Next!=NULL; )
{
if( part->GetType() == 0 && part->Next->GetType() == 0 )
{
free = new TPartition( HardDrive, this, 0, part->GetRelativeSector(),
part->Next->GetRelativeSector() + part->Next->GetSectors() -
part->GetRelativeSector() );
DeleteSon( part->Next );
DeleteSon( part );
InsertSon( free );
part = free;
}
else part=part->Next;
}
return 0;
}
Boolean TRootPartition::IsChanged()
{
if( TPartition::IsChanged() ) return True;
return False;
}
int32 TRootPartition::ReadExtPartTable( TPartition *ext, TPartition *part )
{
TPartition *temp;
TPartitionRecord PartitionTable[MAXPTNUMBER];
char *BootRecord;
int32 errno,extCount;
if( !IsUseable() ) return 0x200;
if( ext==NULL || part==NULL || !ext->IsUseable() || !part->IsUseable() )
return 0x401;
BootRecord = new char[HardDrive->GetSectorSize()];
if( BootRecord == NULL ) return 0x400;
errno = part->Read( 0, 1, BootRecord );
if( errno!=0 )
{
delete BootRecord;
return errno;
}
if( ((WORD *)BootRecord)[255]!=GOODPTID)
{
delete BootRecord;
return 0x204;
}
memcpy( PartitionTable, BootRecord + PTTABOFFSET,
sizeof(TPartitionRecord) * MAXPTNUMBER );
delete BootRecord;
extCount=0;
for( int i=0; iInsertSon( temp );
}
else if( extCount<1 )
{
temp = new TPartition( HardDrive, ext, PartitionTable[i] );
ext->InsertSon( temp );
ReadExtPartTable( ext, temp );
extCount++;
}
}
}
return 0;
}
int32 TRootPartition::WriteExtPartTable( TPartition *ext, TPartition *part )
{
int32 count,errno;
TPartition *temp;
TPartitionRecord PartitionTable[MAXPTNUMBER];
char *BootRecord;
if( !IsUseable() ) return 0x200;
if( ext==NULL || part==NULL || !ext->IsUseable() || !part->IsUseable() )
return 0x401;
if( ext == part )
{
for( temp=ext->Son; temp!=NULL; temp=temp->Next )
{
if( temp->GetType()==0x05 || temp->GetType()==0x0F )
WriteExtPartTable( ext, temp );
}
}
BootRecord = new char[HardDrive->GetSectorSize()];
if( BootRecord == NULL ) return 0x400;
errno=part->Read(0, 1, BootRecord);
if( errno!=0 )
{
delete BootRecord;
return errno;
}
CreateExtPartTable( ext, part, PartitionTable );
memcpy( BootRecord + PTTABOFFSET, PartitionTable,
sizeof( TPartitionRecord ) * MAXPTNUMBER );
((WORD *)BootRecord)[255]=GOODPTID;
errno=part->Write( 0, 1, BootRecord );
delete BootRecord;
return errno;
}
int32 TRootPartition::TransExtPartLink()
{
TPartition *ext, *extSon, *part, *temp;
if( !IsUseable() ) return 0x200;
for( ext=Son; ext!=NULL; ext=ext->Next )
if( ext->GetType()==0x05 || ext->GetType()==0x0F )
break;
if( ext==NULL ) return 0;
for( extSon=ext->Son; extSon!=NULL; extSon=extSon->Next )
if( extSon->GetType()==0x05 || extSon->GetType()==0x0F )
break;
if( extSon==NULL ) return 0;
for( part=extSon; part!=NULL; )
{
temp=part->Next;
part->ChangeFather( this );
ext->RemoveSon( part );
InsertSon( part );
part=temp;
}
extSon = ext->GetLastSon();
if( extSon!=NULL )
ext->Resize( extSon->GetRelativeSector() + extSon->GetSectors() );
return 0;
}
int32 TRootPartition::AntiTransExtPartLink()
{
TPartition *firstExt, *lastExt, *part, *temp, *ext;
if( !IsUseable() ) return 0x200;
for( firstExt=Son; firstExt!=NULL; firstExt=firstExt->Next )
if( firstExt->GetType()==0x05 || firstExt->GetType()==0x0F )
break;
if( firstExt==NULL ) return 0;
for( lastExt=GetLastSon(); lastExt!=NULL; lastExt=lastExt->Prev )
if( lastExt->GetType()==0x05 || lastExt->GetType()==0x0F )
break;
if( lastExt==firstExt ) return 0;
ext=firstExt->Next;
while( ext!=lastExt )
{
part=ext->Next;
ext->ChangeFather( firstExt );
RemoveSon( ext );
firstExt->InsertSon( ext );
ext=part;
}
ext->ChangeFather( firstExt );
RemoveSon( ext );
firstExt->InsertSon( ext );
firstExt->Resize( lastExt->GetRelativeSector() + lastExt->GetSectors() );
return 0;
}
int32 TRootPartition::CreateExtPartTable
( TPartition *ext, TPartition *part, TPartitionRecord * table )
{
TPartition *son;
int32 count,extCount;
if( !IsUseable() ) return 0x200;
if( ext==NULL || part==NULL || table==NULL ||
!ext->IsUseable() || !part->IsUseable() )
return 0x401;
memset( table, 0, sizeof(TPartitionRecord) * MAXPTNUMBER );
if( ext == part )
{
for( son=ext->Son, count=0, extCount=0;
son!=NULL && countNext )
if( son->GetType()!=0 )
{
if(son->GetType()!=0x05 && son->GetType()!=0x0F )
{
son->GetRecord(table[count]);
count ++;
}
else if( extCount<1 )
{
son->GetRecord(table[count]);
count ++;
extCount ++;
}
}
}
else
{
count=0;
extCount=0;
for( son=part->Son; son!=NULL && countNext )
if( son->GetType()!=0 && son->GetType()!=0x05 && son->GetType()!=0x0F )
{
son->GetRecord( table[count] );
count++;
}
for( son=part->Next; son!=NULL && countNext )
if( (son->GetType()==0x05 || son->GetType()==0x0F) && extCount<1 )
{
son->GetRecord( table[count] );
count++;
extCount++;
}
}
return 0;
}
Boolean TRootPartition::CanCreatePrimary( TPartition *part )
{
TPartition *temp;
int32 extCount1, extCount2;
TDiskGeometry geometry;
if( !IsUseable() || part==NULL || part->GetType() != 0 ||
FindSon(part) == NULL || GetPrimaryNumber() >= MAXPTNUMBER )
return False;
extCount1=extCount2=0;
for( temp = Son; temp != part; temp=temp->Next )
if( temp->GetType() == 0x05 || temp->GetType() == 0x0F )
extCount1++;
for( temp = part->Next; temp != NULL; temp=temp->Next )
if( temp->GetType() == 0x05 || temp->GetType() == 0x0F )
extCount2++;
if( extCount1 != 0 && extCount2 != 0 )
return False;
GetHardDrive()->GetGeometry( geometry );
if( part->GetSectors() <
geometry.SectorsPerCylinder - geometry.SectorsPerTrack )
return False;
return True;
}
Boolean TRootPartition::CanCreateLogical( TPartition *part )
{
TPartition *temp;
int32 extCount1, extCount2;
TDiskGeometry geometry;
if( !IsUseable() || part==NULL || part->GetType() != 0 || FindSon(part)==NULL ||
( GetPrimaryNumber() >= MAXPTNUMBER && GetLogicalNumber() ==0 ) )
return False;
if( GetLogicalNumber() != 0 )
{
extCount1=extCount2=0;
for( temp=part->Prev; temp != NULL && temp->GetType()==0; temp=temp->Prev )
NULL;
if( temp != NULL && ( temp->GetType() == 0x05 || temp->GetType() == 0x0F ) )
extCount1 ++;
for( temp=part->Next; temp != NULL && temp->GetType()==0; temp=temp->Next )
NULL;
if( temp != NULL && ( temp->GetType() == 0x05 || temp->GetType() == 0x0F ) )
extCount2 ++;
if( extCount1 == 0 && extCount2 == 0 )
return False;
}
GetHardDrive()->GetGeometry( geometry );
if( part->GetSectors() < geometry.SectorsPerCylinder )
return False;
return True;
}
Boolean TRootPartition::CanDelete( TPartition *part )
{
if( !IsUseable() || part == NULL || part->GetType() == 0 || GetSonIndex(part) < 0 )
return False;
return True;
}
Boolean TRootPartition::CanBoot( TPartition *part )
{
if( !IsUseable() || part == NULL || part->GetType() == 0 ||
part->GetType() == 0x05 || part->GetType() == 0x0F ||
part->GetTotalSonNumber()!=0 || GetSonIndex(part) < 0)
return False;
return True;
}
Boolean TRootPartition::CanActive( TPartition *part )
{
if( !IsUseable() || part == NULL || part->GetType() == 0 ||
part->GetType() == 0x05 || part->GetType() == 0x0F ||
part->GetTotalSonNumber()!=0 || FindSon(part) == NULL ||
GetSonLevel(part) != 0 )
return False;
return True;
}
Boolean TRootPartition::CanFormat( TPartition *part )
{
if( !IsUseable() || part == NULL || part->GetType() == 0 ||
part->GetType() == 0x05 || part->GetType() == 0x0F ||
GetSonIndex(part) < 0 || part->GetFileSystem() == NULL )
return False;
return part->GetFileSystem()->CanFormat();
}
Boolean TRootPartition::CanSurfaceScan( TPartition *part )
{
if( !IsUseable() || part == NULL || !part->IsUseable() ||
GetSonIndex(part) < 0 || part->GetFileSystem()==NULL ||
!part->GetFileSystem()->IsUseable() ||
(part->GetType()!=0 && !part->GetFileSystem()->IsFormated()) )
return False;
return True;
}
int32 TRootPartition::GetSonLevel( TPartition *part )
{
int32 level;
TPartition *temp;
if( !IsUseable() || part == NULL || GetSonIndex( part ) < 0 )
return -1;
level=0;
for( temp = part->Father; temp != this && temp != NULL; temp = temp->Father )
level++;
return level;
}
int32 TRootPartition::GetPrimaryNumber()
{
int32 count, extCount;
TPartition *part;
if( !IsUseable() ) return 0;
count = extCount = 0;
for( part = Son; part != NULL; part = part->Next )
{
if( (part->GetType() == 0x05 || part->GetType() == 0x0F) )
{
if( extCount == 0 ) count ++;
extCount ++;
}
else if( part->GetType() != 0 )
count ++;
}
return count;
}
int32 TRootPartition::GetLogicalNumber()
{
int32 count;
TPartition *part;
count =0;
for( part = Son; part != NULL; part = part->Next )
if( (part->GetType() == 0x05 || part->GetType() == 0x0F) )
count ++;
return count;
}
int32 TRootPartition::CreatePrimary
( TPartition *free, BYTE type, DWORD mega, int32 pos, char * name )
{
TPartition *part;
DWORD relative, sectors, oldSect;
if( !CanCreatePrimary( free ) ) return 0x205;
if( mega > free->GetSizeInMega() || mega <= 0) return 0x401;
if( type == 0 ) return 0x401;
if( mega == free->GetSizeInMega() )
{
free->MarkNewPartition( True );
free->SetType( type );
free->SetName( name );
}
else if( pos == 0 )
{
relative = free->GetRelativeSector();
sectors = ( mega - 1 ) * 2048uL;
if( sectors > free->GetSectors() ) sectors = free->GetSectors();
part = new TPartition( HardDrive, this, type, relative, sectors );
if( part==NULL || part->IsUseable()==False )
return 0x400;
part->SetName( name );
DeleteSon( free );
InsertSon( part );
}
else
{
oldSect = free->GetSectors();
sectors = ( free->GetSizeInMega() - mega - 1uL) * 2048uL;
free->Resize( sectors );
relative = free->GetRelativeSector() + free->GetSectors();
sectors = oldSect - free->GetSectors();
part = new TPartition( HardDrive, this, type, relative, sectors );
if( part==NULL || part->IsUseable()==False )
return 0x400;
part->SetName( name );
InsertSon( part );
}
CheckFree();
MarkChanged(True);
return 0;
}
int32 TRootPartition::CreateLogical
( TPartition *free, BYTE type, DWORD mega, int32 pos, char * name )
{
TPartition *part, *logical;
QWORD relative, sectors, freeSize;
QWORD extRelative, extSectors;
WORD cyl, sect, head;
if( !CanCreateLogical( free ) ) return 0x206;
if( mega <= 0 || type == 0 ) return 0x401;
relative = free->GetRelativeSector();
sectors = free->GetSectors();
HardDrive->LBAtoCHS( relative, cyl, head, sect );
if( head > 0 )
{
head = 0;
cyl ++;
}
HardDrive->CHStoLBA( cyl, head, sect, extRelative );
extSectors = sectors - ( extRelative - relative );
if( extSectors == 0 ) return 0x206;
DeleteSon( free );
free = new TPartition( HardDrive, this, 0, extRelative, extSectors );
InsertSon( free );
if( mega >= free->GetSizeInMega() )
{
free->MarkNewPartition( True );
free->SetType( 0x05 );
part = free;
}
else if( pos == 0 )
{
sectors = ( mega - 1 ) * ( 1048576uL / HardDrive->GetSectorSize() );
if( sectors > free->GetSectors() ) sectors = free->GetSectors();
free->Resize( sectors );
free->MarkNewPartition( True );
free->SetType( 0x05 );
part = free;
}
else
{
freeSize = free->GetSectors();
sectors = ( free->GetSizeInMega() - mega - 1uL ) *
(1048576uL / free->GetSectorSize());
free->Resize( sectors );
relative = free->GetRelativeSector() + free->GetSectors();
sectors = freeSize - free->GetSectors();
part = new TPartition( HardDrive, this, 0x05, relative, sectors );
if( part==NULL || part->IsUseable()==False )
{
CheckFree();
return 0x400;
}
InsertSon( part );
}
relative = 1;
sectors = part->GetSectors() - relative;
logical = new TPartition( HardDrive, part, type, relative, sectors );
if( logical==NULL || logical->IsUseable()==False )
{
CheckFree();
return 0x400;
}
logical->SetName( name );
part->InsertSon( logical );
CheckFree();
MarkChanged(True);
return 0;
}
int32 TRootPartition::Delete( TPartition *part )
{
if( !CanDelete( part ) ) return 0x207;
if( part->Father !=0 ) part->Father->DeleteSon( part );
CheckFree();
MarkChanged(True);
return 0;
}
int32 TRootPartition::MarkAsActive( TPartition *part )
{
TPartition *temp;
if( !CanActive( part ) ) return 0x208;
for( int i=0; iGetType()!=0 && temp->IsActive() )
{
temp->MarkActive( False );
temp->Father->MarkChanged(True);
}
}
part->MarkActive( True );
part->Father->MarkChanged(True);
return 0;
}
int32 TRootPartition::ToggleBootable( TPartition *part )
{
TPartition *son;
int32 sonNum;
int32 bootNum;
if( !CanBoot( part ) ) return 0x209;
if( !part->IsBootable() )
{
sonNum = GetTotalSonNumber();
bootNum=0;
for( int i=0; iIsUseable() &&
son->GetType()!=0 && son->IsBootable() )
bootNum++;
}
if( bootNum >= BOOTMENUENTRYNUM )
return 0x504;
}
part->MarkBootable( (Boolean) (!part->IsBootable()) );
part->Father->MarkChanged(True);
return 0;
}