www.pudn.com > SmartFDISK.zip > part.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.
*
****************************************************************************/
/*
* part.cpp : Source file for Class TPartition
*/
#define Uses_KernelObject
#define Uses_DataType
#define Uses_HardDrive
#define Uses_Partition
#define Uses_FAT16
#define Uses_FAT32
#include "Kernel.H"
//Declare the partition type data
TPartitionType PartitionTypes[MAXPTTYPENUMBER]=
{
{0x00,"Free "}, //0
{0x01,"FAT-12 "}, //1
{0x02,"XENIX Root "}, //2
{0x03,"XENIX Usr "}, //3
{0x04,"FAT-16 Small"}, //4
{0x05,"Extended "}, //5
{0x06,"FAT-16 "}, //6
{0x07,"HPFS/NTFS "}, //7
{0x08,"AIX "}, //8
{0X09,"AIX Boot "}, //9
{0x0A,"Boot Manager"}, //10
{0x0B,"FAT-32 "}, //11
{0x0C,"FAT-32 LBA "}, //12
{0x0E,"FAT-16 LBA "}, //13
{0x0F,"Extended LBA"}, //14
{0x11,"Hidden FAT12"}, //15
{0x14,"Hidden FAT16"}, //16
{0x16,"Hidden FAT16"}, //17
{0x40,"Venix 80286 "}, //18
{0x50,"DM "}, //19
{0x51,"Novell? "}, //20
{0x52,"Microport "}, //21
{0x56,"GB "}, //22
{0x61,"Speed "}, //23
{0x63,"GNU HURD "}, //24
{0x64,"Novell 286 "}, //25
{0x65,"Novell 386 "}, //26
{0x75,"PC / IX "}, //27
{0x80,"Old MINIX "}, //28
{0x81,"Linux/MINIX "}, //29
{0x82,"Linux Swap "}, //30
{0x83,"Linux "}, //31
{0x85,"Linux Extend"}, //32
{0x93,"Amoeba "}, //33
{0x94,"Amoeba BBT "}, //34
{0xA0,"Hidden "}, //35
{0xA5,"BSD / 386 "}, //36
{0xB7,"BSDI fs "}, //37
{0xB8,"BSDI swap "}, //38
{0xC7,"Syrinx "}, //39
{0xDB,"CP/M "}, //40
{0xE1,"DOS Access "}, //41
{0xE3,"DOS R/O "}, //42
{0xF2,"DOS Second "}, //43
{0xFF,"BBT "}, //44
};
/****************************************************************************/
/* Member Function of class TPartition */
/****************************************************************************/
TPartition::TPartition()
{
PreInit();
}
TPartition::TPartition
( THardDrive *hd, TPartition * father, TPartitionRecord & record )
{
Initialize(hd,father,record);
}
TPartition::TPartition
( THardDrive *hd, TPartition * father, BYTE type, DWORD relative, DWORD sect )
{
Initialize( hd, father, type, True, relative, sect );
}
void TPartition::ShutDown()
{
DeleteAllSon();
if( FileSystem != NULL ) destroy(FileSystem);
PreInit();
}
int32 TPartition::Initialize( THardDrive *hd, TPartition * father,
TPartitionRecord & record )
{
QWORD absSect, sectors, relative;
WORD sector, head, cylinder;
TDiskGeometry geometry;
int32 errno;
if( hd == NULL || hd->IsUseable() == False )
{
Useable = False;
return 0x102;
}
/*
hd->GetGeometry( geometry );
if( geometry.Cylinders > MAXINT13CYLINDER ||
record.StartSC == 0xFFFF || record.EndSC == 0xFFFF ||
record.Type == 0x0C || record.Type == 0x0E || record.Type == 0x0F )
{
errno = Initialize(hd, father, record.Type, False,
record.RelativeSector, record.Sectors);
State = record.State;
return errno;
}
*/
errno = Initialize(hd, father, record.Type, False,
record.RelativeSector, record.Sectors);
State = record.State;
return errno;
/*
sector = record.StartSC & 0x3f;
head = record.StartHead;
cylinder = (record.StartSC >> 8) | (( record.StartSC << 2 ) & 0x300);
hd->CHStoLBA( cylinder, head, sector, absSect );
if( father!=NULL && father->IsUseable() )
relative = absSect - father->GetAbsSector();
else relative = absSect;
sector = record.EndSC & 0x3f;
head = record.EndHead;
cylinder = (record.EndSC >> 8) | (( record.EndSC << 2 ) & 0x300);
hd->CHStoLBA( cylinder, head, sector, sectors );
sectors = sectors - absSect + 1;
errno = Initialize(hd, father, record.Type, False, relative, sectors );
State = record.State;
return errno;
*/
}
int32 TPartition::Initialize( THardDrive *hd, TPartition * father,
BYTE type, Boolean IsNew, DWORD relative, DWORD sect )
{
DWORD temp;
PreInit();
if( (HardDrive = hd) == NULL ||
HardDrive->IsUseable() == False)
{
Useable=False;
return 0x102;
}
Father = father;
if( Father!=NULL && Father->IsUseable()==False )
{
Useable=False;
return 0x200;
}
Useable = True;
MarkNewPartition( IsNew );
if( IsNew )
{
RelativeSector = CalcValidRelativeSector( relative );
Sectors = CalcValidSectors( sect );
}
else
{
RelativeSector = relative;
Sectors = sect;
}
AbsSector = CalcAbsSector( 0 );
Type = type;
temp = 1048576uL / HardDrive->GetSectorSize();
SizeInMega = Sectors / temp;
if( (Sectors % temp) >= temp / 2 ) SizeInMega++;
AttachFileSystem();
return 0;
}
int32 TPartition::Read( DWORD BlockNum, WORD BlockCount, void * Buffer )
{
if( !Useable ) return 0x200;
if( Father == NULL )
return HardDrive->Read( (QWORD)(BlockNum + RelativeSector), BlockCount, Buffer );
else
return Father->Read( BlockNum + RelativeSector, BlockCount, Buffer );
}
int32 TPartition::Write( DWORD BlockNum, WORD BlockCount, void * Buffer )
{
if( !Useable ) return 0x200;
if( Father == NULL )
return HardDrive->Write( (QWORD)(BlockNum + RelativeSector), BlockCount, Buffer );
else
return Father->Write( BlockNum + RelativeSector, BlockCount, Buffer );
}
int32 TPartition::Verify( DWORD BlockNum, WORD BlockCount )
{
if( !Useable ) return 0x200;
if( Father == NULL )
return HardDrive->Verify( (QWORD)(BlockNum + RelativeSector), BlockCount );
else
return Father->Verify( BlockNum + RelativeSector, BlockCount );
}
int32 TPartition::Seek ( DWORD BlockNum )
{
if( !Useable ) return 0x200;
if( Father == NULL )
return HardDrive->Seek( (QWORD)(BlockNum + RelativeSector) );
else
return Father->Seek( BlockNum + RelativeSector );
}
DWORD TPartition::CalcValidRelativeSector( DWORD relative )
{
QWORD temp, abs;
WORD cylinder,head,sector;
TDiskGeometry geometry;
HardDrive->GetGeometry( geometry );
abs = 0;
if( Father!=NULL )
{
if( relative==0 ) relative++;
abs = Father->GetAbsSector();
if( Prev!=NULL && Prev->IsUseable() &&
Prev->Father==Father && Prev->Next==this )
{
if( relative < Prev->GetSectors() + Prev->GetRelativeSector() )
relative = Prev->GetSectors() + Prev->GetRelativeSector();
}
if( Next!=NULL && Next->IsUseable() &&
Next->Father==Father && Next->Prev==this )
{
if( relative >= Next->GetRelativeSector() )
relative = Next->GetRelativeSector() - 1;
}
}
HardDrive->LBAtoCHS( relative + abs, cylinder, head, sector );
if( sector > 1 )
{
sector = 1;
head ++;
}
if( head >= geometry.Heads )
{
head -= geometry.Heads;
cylinder ++;
}
HardDrive->CHStoLBA( cylinder, head, sector, temp );
temp -= abs;
if( Father != NULL && temp >Father->GetSectors() )
temp = Father->GetSectors();
return temp;
}
DWORD TPartition::CalcValidSectors( DWORD sectors )
{
QWORD temp, abs;
WORD cylinder, head, sector;
TDiskGeometry geometry;
abs = CalcAbsSector(0);
if( sectors==0 ) sectors++;
if( Father!=NULL )
{
if( Next!=NULL && Next->IsUseable() &&
Next->Father==Father && Next->Prev==this )
{
if( sectors + RelativeSector > Next->GetRelativeSector() )
sectors = Next->GetRelativeSector() - RelativeSector;
}
else if( sectors + RelativeSector > Father->GetSectors() )
sectors = Father->GetSectors() - RelativeSector;
}
HardDrive->LBAtoCHS( sectors + abs - 1, cylinder, head, sector );
HardDrive->GetGeometry( geometry );
sector = geometry.SectorsPerTrack;
head = geometry.Heads - 1;
HardDrive->CHStoLBA( cylinder, head, sector, temp );
temp = temp - abs + 1;
if( Father != NULL && temp + RelativeSector > Father->GetSectors() )
temp = Father->GetSectors() - RelativeSector;
return temp;
}
DWORD TPartition::CalcAbsSector(DWORD relative)
{
if( !Useable ) return 0;
if( Father == NULL ) return RelativeSector + relative;
return RelativeSector + Father->GetAbsSector() + relative;
}
int32 TPartition::GetRecord(TPartitionRecord & record)
{
WORD stCyl, edCyl, head, stSect, edSect;
// TDiskGeometry geometry;
memset( &record, 0, sizeof(record) );
if( !Useable ) return 0x200;
// HardDrive->GetGeometry(geometry);
record.State = State;
record.Type = Type;
record.RelativeSector = RelativeSector;
record.Sectors = Sectors;
HardDrive->LBAtoCHS( CalcAbsSector(0), stCyl, head, stSect );
record.StartHead = (BYTE) head;
HardDrive->LBAtoCHS( CalcAbsSector(0) + Sectors - 1, edCyl, head, edSect );
record.EndHead = (BYTE) head;
if( stCyl > MAXINT13CYLINDER )
record.StartSC = 0xFFFF;
else
{
record.StartSC |= (stSect & 0x003F);
record.StartSC |= ((stCyl << 8) & 0xFF00);
record.StartSC |= ((stCyl & 0x0300) >> 2);
}
if( edCyl > MAXINT13CYLINDER )
record.EndSC = 0xFFFF;
else
{
record.EndSC |= (edSect & 0x003F);
record.EndSC |= ((edCyl << 8) & 0xFF00);
record.EndSC |= ((edCyl & 0x0300) >> 2);
}
if( stCyl >MAXINT13CYLINDER || edCyl >MAXINT13CYLINDER )
{
switch( Type )
{
case 0x06:
record.Type = 0x0E;
break;
case 0x0B:
record.Type = 0x0C;
break;
}
}
return 0;
}
const char * TPartition::GetTypeName()
{
static char *Unknown="Unknown ";
for( int i=0; i< MAXPTTYPENUMBER; i++ )
if( Type == PartitionTypes[i].Type )
return PartitionTypes[i].Name;
return Unknown;
}
Boolean TPartition::IsChanged()
{
TPartition *part;
if( !IsUseable() ) return False;
for( part=Son; part!=NULL; part=part->Next )
if( part->GetType()!=0 && part->IsChanged() )
return True;
if( FileSystem!=NULL && FileSystem->IsUseable() && FileSystem->IsChanged() )
return True;
return (Boolean) (((ExtState & PARTCHANGED) != 0) || IsNewPartition());
}
int32 TPartition::WriteChange()
{
char *byte;
TPartition *part;
int32 errno=0;
if( !Useable ) return 0x200;
if( !IsChanged() ) return 0;
if( IsNewPartition() && GetValidSonNumber() == 0 )
{
byte = new char[HardDrive->GetSectorSize()];
if( byte == NULL ) return 0x400;
memset( byte, 0, HardDrive->GetSectorSize() );
errno = Write( 0, 1, byte );
delete byte;
if( errno!= 0 ) return errno;
}
for( part=Son; part!=NULL; part=part->Next )
{
if( part->GetType() != 0 && part->IsChanged() )
{
errno=part->WriteChange();
if( errno!=0 ) return errno;
}
}
MarkChanged( False );
MarkNewPartition( False );
if( FileSystem!=NULL && FileSystem->IsUseable() && FileSystem->IsChanged() )
errno = FileSystem->WriteChange();
return errno;
}
int32 TPartition::Resize( DWORD size )
{
DWORD temp;
TPartition *last;
if( !IsUseable() ) return 0x200;
if( Son!=NULL )
{
last = GetLastSon();
if( last->GetRelativeSector() + last->GetSectors() > size )
size = last->GetRelativeSector() + last->GetSectors();
}
size = CalcValidSectors( size );
if( Father!=NULL )
{
if( Next!=NULL && Next->IsUseable() &&
Next->Father==Father && Next->Prev==this )
{
if( size > Next->GetRelativeSector() + Next->GetSectors() )
size = Next->GetRelativeSector() + Next->GetSectors();
}
else if( size + RelativeSector > Father->GetSectors() )
size = Father->GetSectors() - RelativeSector;
}
Sectors = size;
temp = 1048576uL / HardDrive->GetSectorSize();
SizeInMega = Sectors / temp;
if( (Sectors % temp) >= temp / 2 ) SizeInMega++;
if( IsNewPartition() ) MarkChanged(True);
return 0;
}
void TPartition::MarkBootable( Boolean bootable )
{
if( bootable ) ExtState |= BOOTABLE;
else ExtState &= ~BOOTABLE;
}
void TPartition::MarkActive( Boolean active )
{
if( active ) State = HardDrive->GetDriveNumber();
else State = 0;
}
void TPartition::MarkChanged( Boolean changed )
{
if( changed ) ExtState |= PARTCHANGED;
else ExtState &= ~PARTCHANGED;
}
void TPartition::MarkNewPartition( Boolean newPart )
{
if( newPart ) ExtState |= NEWPARTITION;
else ExtState &= ~NEWPARTITION;
}
void TPartition::MarkRootPartition( Boolean root )
{
if( root ) ExtState |= ROOTPARTITION;
else ExtState &= ~ROOTPARTITION;
}
void TPartition::SetName( const char * name )
{
if( name==NULL ) return;
strncpy(Name, name, MAXPTNAMELENGTH);
Name[MAXPTNAMELENGTH]=0;
}
void TPartition::PreInit()
{
Useable = False;
HardDrive = NULL;
SizeInMega = 0;
State = 0;
Type = 0;
ExtState = 0;
RelativeSector = 0;
Sectors = 0;
Name[0] = 0;
FileSystem = NULL;
Father = NULL;
Prev = NULL;
Next = NULL;
Son = NULL;
}
int32 TPartition::GetValidSonNumber()
{
TPartition *part;
int32 num;
if( !IsUseable() ) return 0;
for( part=Son, num=0; part!=NULL; part=part->Next )
{
if( part->GetType()!=0 && part->IsUseable() ) num++;
}
return num;
}
int32 TPartition::InsertSon( TPartition * part )
{
TPartition *temp;
if( FindSon(part)!=NULL ) return 0x201;
if( part->Father!=this ) return 0x202;
if( Son==NULL )
{
Son = part;
Son->Prev=NULL;
Son->Next=NULL;
return 0;
}
if( part->GetRelativeSector() + part->GetSectors() <=
Son->GetRelativeSector() )
{
temp = Son;
Son = part;
Son->Next = temp;
Son->Prev = NULL;
temp->Prev = Son;
return 0;
}
for( temp=Son; temp!=NULL; temp=temp->Next )
{
if( part->GetRelativeSector() >= temp->GetRelativeSector() )
{
if( temp->Next==NULL || (temp->Next!=NULL &&
part->GetRelativeSector() + part->GetSectors() <=
temp->Next->GetRelativeSector() ) )
{
part->Prev=temp;
part->Next=temp->Next;
temp->Next=part;
if( part->Next!=NULL ) part->Next->Prev=part;
return 0;
}
}
}
return 1;
}
int32 TPartition::DeleteSon( TPartition * part )
{
int32 errno;
if( (errno=RemoveSon(part))!=0 ) return errno;
destroy(part);
return 0;
}
int32 TPartition::RemoveSon( TPartition * part )
{
if( FindSon(part)==NULL ) return 0x203;
if( part->Prev!=NULL ) part->Prev->Next = part->Next;
else Son = part->Next;
if( part->Next!=NULL ) part->Next->Prev = part->Prev;
return 0;
}
void TPartition::DeleteAllSon()
{
if( Son==NULL ) return;
while( Son!=NULL ) DeleteSon( Son );
}
TPartition * TPartition::GetFirstValidSon()
{
TPartition *valid;
for( valid = Son; valid!=NULL && valid->GetType() == 0; valid=valid->Next )
NULL;
return valid;
}
TPartition * TPartition::GetLastSon()
{
TPartition *part;
for( part=Son; part!=NULL && part->Next!=NULL; part=part->Next ) NULL;
return part;
}
TPartition * TPartition::FindSon(TPartition * part)
{
TPartition *temp;
for( temp=Son; temp!=NULL; temp=temp->Next )
if( temp==part )
return part;
return NULL;
}
int32 TPartition::ChangeFather( TPartition * newFather )
{
if( !IsUseable() ) return 0x200;
if( newFather==NULL )
{
RelativeSector = AbsSector;
Father=NULL;
return 0;
}
else if( newFather->IsUseable()==False ||
newFather->GetAbsSector() >= AbsSector )
return 0x200;
else
{
RelativeSector = AbsSector - newFather->GetAbsSector();
Father=newFather;
return 0;
}
}
WORD TPartition::GetSectorSize()
{
if( !IsUseable() ) return 0;
return HardDrive->GetSectorSize();
}
int32 TPartition::AttachFileSystem()
{
if( !IsUseable() || IsRootPartition() )
return 0x200;
if( FileSystem!=NULL ) destroy(FileSystem);
FileSystem = NULL;
switch( GetType() )
{
case 0x01:
case 0x04:
case 0x06:
case 0x0E:
case 0x11:
case 0x14:
case 0x16:
FileSystem = new TFAT16( this );
break;
case 0x0B:
case 0x0C:
FileSystem = new TFAT32( this );
break;
case 0:
FileSystem = new TRawFileSystem( this );
}
if( FileSystem != NULL )
{
if( FileSystem->IsUseable() == False )
{
destroy(FileSystem);
FileSystem = NULL;
}
else if( FileSystem->GetFileSysType() !=0 )
Type = FileSystem->GetFileSysType();
}
return 0;
}
int32 TPartition::GetSonIndex( TPartition *part )
{
int32 index, ok, test;
TPartition *temp, *ext;
if( !IsUseable() || part == NULL ) return -1;
index=ok=0;
for( temp = Son; temp != NULL; temp = temp->Next )
{
if( temp == part ){ ok=1; break; }
else if( temp->GetType() == 0x05 || temp->GetType() == 0x0F )
{
test = temp->GetSonIndex( part );
if( test >= 0 )
{
index += test;
ok = 1;
break;
}
else index += temp->GetTotalSonNumber();
}
else index ++;
}
if( ok ) return index;
return -1;
}
TPartition * TPartition::FindSonByIndex( int32 index )
{
int32 count;
TPartition *part, *result;
if( !IsUseable() || index < 0 ) return NULL;
result=NULL;
for( count = 0, part = Son; part != NULL; part=part->Next )
{
if( part->GetType() == 0x05 || part->GetType() == 0x0F )
if( (result=part->FindSonByIndex( index - count )) != NULL )
break;
if( count == index )
{
result = part;
break;
}
if( (++ count) > index ) break;
}
return result;
}
int32 TPartition::GetTotalSonNumber()
{
int32 total,test;
TPartition *part;
total=0;
for( part=Son; part != NULL; part=part->Next )
{
if( part->GetType() == 0x05 || part->GetType() == 0x0F )
{
test = part->GetTotalSonNumber();
if( test != 0 ) total += test;
else total ++;
}
else total ++;
}
return total;
}
void TPartition::SetType(BYTE type)
{
Type = type;
AttachFileSystem();
}
/*
TBadBlockList *TPartition::SurfaceScan( CallBackFunc CallBack )
{
if( FileSystem != NULL && FileSystem->IsUseable() )
return FileSystem->SurfaceScan( CallBack );
return NULL;
}
*/
DWORD TPartition::GetBlockSize()
{
if( FileSystem!=NULL && FileSystem->IsFormated() )
return FileSystem->GetBlockSize();
else return (DWORD)GetSectorSize();
}
int32 TPartition::GetLevel()
{
int32 level;
TPartition *temp;
if( !IsUseable() || Father == NULL )
return -1;
level=0;
for( temp = Father; temp!=NULL && temp->Father != NULL ; temp = temp->Father )
level++;
return level;
}