www.pudn.com > SmartFDISK.zip > fat16.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. 
 * 
 ****************************************************************************/ 
/* 
 * fat16.cpp : Source file for Class TFAT16 
 */ 
 
#define Uses_FATBase 
#define Uses_FAT16 
 
#include "Kernel.H" 
#include "FATMacro.h" 
#include  
 
#define MAXBLOCKSIZE 32768uL 
 
/****************************************************************************/ 
/* Functions for class TFAT16                                               */ 
/****************************************************************************/ 
BYTE TFAT16::FAT16BootRecord[]= 
{ 
#include "FAT16BR.h" 
}; 
 
TFAT16::TFAT16() : TFATBase() 
{ 
} 
 
TFAT16::TFAT16( TPartition * part ) 
{ 
	Initialize( part ); 
} 
 
int32 TFAT16::ReadBootRecord() 
{ 
	BYTE *buf; 
	int32 errno=0; 
 
	if( !IsUseable() ) return 0x300; 
 
	Formated = False; 
 
	buf = new BYTE[ Partition->GetSectorSize() ]; 
	if( buf==NULL ) return 0x400; 
 
	if( (errno=Partition->Read( 0, 1, buf )) == 0 && 
		*((DWORD*)(buf+BOOTIDOFFSET)) == GOODBOOTID ) 
	{ 
		memcpy( &ParamBlock, buf + BPBOFFSET, SIZEOFBPB16 ); 
 
		if( ParamBlock.com.BytesPerSector == Partition->GetSectorSize() && 
			ParamBlock.bpb16.ExtBootRecordID == EXTBRID ) 
		{ 
			if( strncmp( (char*) ParamBlock.bpb16.SystemType, FAT16FSNAME, 
				strlen(FAT16FSNAME) ) ==0 ) 
			{ 
				FATType = 16; 
				Formated = True; 
			} 
			else if( strncmp( (char*) ParamBlock.bpb16.SystemType, FAT12FSNAME, 
					 strlen(FAT16FSNAME) ) ==0 ) 
			{ 
				FATType = 12; 
				Formated = True; 
			} 
		} 
    } 
	delete buf; 
	return errno; 
} 
 
int32 TFAT16::WriteBootRecord() 
{ 
	BYTE *buf; 
	int32 errno; 
 
	if( !IsUseable() || ( FATType != 16 && FATType != 12 ) ) 
		return 0x300; 
 
	buf = new BYTE[ Partition->GetSectorSize() ]; 
	if( buf==NULL ) return 0x400; 
 
	memcpy( buf, FAT16BootRecord, Partition->GetSectorSize() ); 
	memcpy( buf+BPBOFFSET, &ParamBlock, SIZEOFBPB16 ); 
 
	if( (errno=Partition->Write( 0, 1, buf )) ==0 ) 
		errno=Partition->Verify( 0, 1 ); 
 
	delete buf; 
    if( errno==0 ) Changed=False; 
	return errno; 
} 
 
int32 TFAT16::CreateBootRecord(DWORD MinBlockSize) 
{ 
	DWORD SPF, sectors, MaxCluster; 
	WORD SPC,BPC2; 
	TDiskGeometry geometry; 
 
	srand(time(0)); 
	if( !IsUseable() ) return 0x300; 
 
	if( MinBlockSize > MAXBLOCKSIZE ) MinBlockSize=MAXBLOCKSIZE; 
	MinBlockSize /= Partition->GetSectorSize(); 
 
	sectors = Partition->GetSectors(); 
	Partition->GetHardDrive()->GetGeometry( geometry ); 
 
	strncpy( (char*) ParamBlock.com.OemID, OEMID, 8 ); 
	ParamBlock.com.BytesPerSector	= Partition->GetSectorSize(); 
	ParamBlock.com.ReservedSectors	= 1; 
	ParamBlock.com.NumberOfFAT		= 2; 
	ParamBlock.com.RootEntries		= 512; 
	ParamBlock.com.TotalSectors		= ( sectors > 65535uL ) ? 0 : ((WORD)sectors); 
	ParamBlock.com.MediaDescriptor	= 0xF8; 
	ParamBlock.com.SectorsPerTrack	= geometry.SectorsPerTrack; 
	ParamBlock.com.Heads			= geometry.Heads; 
	ParamBlock.com.HiddenSectors	= Partition->GetRelativeSector(); 
	ParamBlock.com.BigTotalSectors	= sectors; 
	ParamBlock.bpb16.DriveNumber	= Partition->GetHardDrive()->GetDriveNumber(); 
	ParamBlock.bpb16.BootReserved	= 0; 
	ParamBlock.bpb16.ExtBootRecordID= EXTBRID; 
	ParamBlock.bpb16.SerialNumber	= (DWORD)random(); 
 
	memset( ParamBlock.bpb16.VolumeLabel, 0, sizeof(BYTE) * 11 ); 
 
	if( Partition->GetSectors() < 32768uL ) FATType = 12; 
	else FATType = 16; 
 
	MaxCluster = (1uL)<= MaxCluster || SPC= FIRSTCLUSTER + GetTotalClusters() ) 
		return 0; 
 
	SectorSize = Partition->GetSectorSize(); 
 
	if( FATType == 16 ) 
	{ 
		Sector = cluster * 2uL / SectorSize; 
		Offset = ((cluster * 2uL) % SectorSize) / 2uL; 
 
		if( FATBufStartSector < 0 || 
			Sector < FATBufStartSector || 
			Sector >= FATBufStartSector + FATBufSectors ) 
		{ 
			FlushFATBuf(); 
			FATBufStartSector = Sector; 
			if( FATBufStartSector + FATBufSectors >	ParamBlock.com.SectorsPerFAT ) 
				FATBufStartSector = ParamBlock.com.SectorsPerFAT - FATBufSectors; 
 
			if( ReadFATtoBuf() !=0 ) return 0; 
		} 
		Result = (DWORD) ((WORD*)(FATBuf+(Sector - FATBufStartSector)*SectorSize))[Offset]; 
	} 
	else if( FATType == 12 ) 
	{ 
		Sector = cluster * 3uL / ( SectorSize * 2uL ); 
		Offset = ((cluster * 3uL) % ( SectorSize * 2uL )) / 2uL; 
		FAT12Index = ((cluster * 3uL) % ( SectorSize * 2uL )) % 2uL; 
 
		if( FATBufStartSector < 0 || 
 			Sector = FATBufStartSector + FATBufSectors - 1 && 
 			  SectorSize - Offset < 2 ) || 
 			Sector >= FATBufStartSector + FATBufSectors ) 
		{ 
			FlushFATBuf(); 
			FATBufStartSector = Sector; 
			if( FATBufStartSector + FATBufSectors >	ParamBlock.com.SectorsPerFAT ) 
				FATBufStartSector = ParamBlock.com.SectorsPerFAT - FATBufSectors; 
 
			if( ReadFATtoBuf() !=0 ) return 0; 
		} 
		if( FAT12Index == 0 ) 
			Result= ((DWORD)(FATBuf+(Sector - FATBufStartSector)*SectorSize)[Offset]) | 
					( (((DWORD)(FATBuf+(Sector - FATBufStartSector)*SectorSize)[Offset+1])<<8) & 0x0F00 ); 
		else if( FAT12Index == 1 ) 
			Result= ( ((DWORD)(FATBuf+(Sector - FATBufStartSector)*SectorSize)[Offset]) >> 4 ) | 
					( ((DWORD)(FATBuf+(Sector - FATBufStartSector)*SectorSize)[Offset+1]) << 4 ); 
	} 
	return Result; 
} 
 
int32 TFAT16::WriteFATEntry( DWORD cluster, DWORD entry ) 
{ 
	int32 Sector=0, Offset=0; 
	BYTE FAT12Index=0; 
	WORD SectorSize; 
	int i; 
 
	if( !IsUseable() || ( FATType != 16 && FATType != 12 ) ) 
		return 0x300; 
 
	if( cluster >= FIRSTCLUSTER + GetTotalClusters() ) 
		return 0x401; 
 
	SectorSize = Partition->GetSectorSize(); 
 
	if( FATType == 16 ) 
	{ 
		Sector = cluster * 2uL / SectorSize; 
		Offset = ((cluster * 2uL) % SectorSize) / 2uL; 
 
		if( FATBufStartSector < 0 || 
			Sector < FATBufStartSector || 
			Sector >= FATBufStartSector + FATBufSectors ) 
		{ 
			FlushFATBuf(); 
			FATBufStartSector = Sector; 
			if( FATBufStartSector + FATBufSectors >	ParamBlock.com.SectorsPerFAT ) 
				FATBufStartSector = ParamBlock.com.SectorsPerFAT - FATBufSectors; 
 
			if( ReadFATtoBuf() != 0 ) return 0x302; 
		} 
		((WORD*)(FATBuf+(Sector - FATBufStartSector)*SectorSize))[Offset]= (WORD)entry; 
		FATBufChanged = True; 
	} 
	else if( FATType == 12 ) 
	{ 
		Sector = cluster * 3uL / ( SectorSize * 2uL ); 
		Offset = ((cluster * 3uL) % ( SectorSize * 2uL )) / 2uL; 
		FAT12Index = ((cluster * 3uL) % ( SectorSize * 2uL )) % 2uL; 
 
		if( FATBufStartSector < 0 || 
 			Sector = FATBufStartSector + FATBufSectors - 1 && 
 			  SectorSize - Offset < 2 ) || 
 			Sector >= FATBufStartSector + FATBufSectors ) 
		{ 
			FlushFATBuf(); 
			FATBufStartSector = Sector; 
			if( FATBufStartSector + FATBufSectors >	ParamBlock.com.SectorsPerFAT ) 
				FATBufStartSector = ParamBlock.com.SectorsPerFAT - FATBufSectors; 
 
			if( ReadFATtoBuf() != 0 ) return 0x302; 
		} 
		if( FAT12Index == 0 ) 
		{ 
			(FATBuf+(Sector - FATBufStartSector)*SectorSize)[Offset] = (BYTE) (entry & 0x00FF); 
			(FATBuf+(Sector - FATBufStartSector)*SectorSize)[Offset+1] &= 0xF0; 
			(FATBuf+(Sector - FATBufStartSector)*SectorSize)[Offset+1] |= (BYTE)( (entry>>8) & 0x0F); 
		} 
		else if( FAT12Index == 1 ) 
		{ 
			(FATBuf+(Sector - FATBufStartSector)*SectorSize)[Offset] &= 0x0F; 
			(FATBuf+(Sector - FATBufStartSector)*SectorSize)[Offset] |= (BYTE) ((entry << 4) & 0x00F0); 
			(FATBuf+(Sector - FATBufStartSector)*SectorSize)[Offset+1] = (BYTE) ((entry >> 4) & 0x00FF); 
		} 
		FATBufChanged = True; 
	} 
	return 0; 
} 
 
int32 TFAT16::ClearFATTable() 
{ 
	BYTE *buf; 
	DWORD start, sect; 
	int32 errno; 
 
	if( !IsUseable() || ( FATType != 16 && FATType != 12 ) ) 
		return 0x300; 
 
	start = ParamBlock.com.ReservedSectors; 
	buf =new BYTE[ Partition->GetSectorSize() ]; 
	if( buf==NULL ) return 0x400; 
	memset( buf,0,Partition->GetSectorSize() ); 
 
	for( int i=0; i< ParamBlock.com.NumberOfFAT; i++ ) 
	{ 
		for( sect = 0; sect < ParamBlock.com.SectorsPerFAT; sect ++ ) 
			if( (errno= Partition-> 
					Write(start + sect + ParamBlock.com.SectorsPerFAT * (DWORD)i,1, buf)) 
					!= 0 ) 
				return errno; 
	} 
	WriteFATEntry( 0, 0xFFF8 ); 
	WriteFATEntry( 1, 0xFFFF ); 
	FlushFATBuf(); 
	delete buf; 
	return 0; 
} 
 
int32 TFAT16::ClearRootDir() 
{ 
	BYTE *buf; 
	DWORD start, sect, total; 
 
	if( !IsUseable() || ( FATType != 16 && FATType != 12 ) ) 
		return 0x300; 
 
	start = ParamBlock.com.ReservedSectors; 
	start += (DWORD)ParamBlock.com.NumberOfFAT * (DWORD)ParamBlock.com.SectorsPerFAT; 
	total = (DWORD)ParamBlock.com.RootEntries * DIRENTRYSIZE / ParamBlock.com.BytesPerSector; 
	if( ((DWORD)ParamBlock.com.RootEntries * DIRENTRYSIZE) % ParamBlock.com.BytesPerSector != 0 ) 
		total ++; 
 
	buf = new BYTE[ Partition->GetSectorSize() ]; 
	if( buf==NULL ) return 0x400; 
	memset( buf,0,Partition->GetSectorSize() ); 
 
	for( sect = 0; sect< total; sect++ ) 
		Partition->Write( sect + start, 1, buf ); 
	delete buf; 
	return 0; 
} 
 
DWORD TFAT16::GetClusterLBA( DWORD cluster ) 
{ 
	DWORD Start, Offset; 
 
	if( !IsUseable() || ( FATType != 16 && FATType != 12 ) ) 
		return 0; 
 
	if( cluster < FIRSTCLUSTER || cluster >= FIRSTCLUSTER + GetTotalClusters() ) 
		return 0; 
 
	Start = ParamBlock.com.ReservedSectors; 
	Start += (DWORD)ParamBlock.com.NumberOfFAT * (DWORD)ParamBlock.com.SectorsPerFAT; 
	Start += (DWORD)ParamBlock.com.RootEntries * DIRENTRYSIZE / ParamBlock.com.BytesPerSector; 
	if( ((DWORD)ParamBlock.com.RootEntries * DIRENTRYSIZE) % ParamBlock.com.BytesPerSector != 0 ) 
		Start ++; 
	Offset = (cluster - FIRSTCLUSTER) * ParamBlock.com.SectorsPerCluster; 
	return Start + Offset; 
} 
 
DWORD TFAT16::GetTotalClusters() 
{ 
	DWORD TotalSect; 
 
	if( !IsUseable() ) return 0; 
 
	TotalSect = ParamBlock.com.BigTotalSectors; 
	if( TotalSect == 0 ) TotalSect = Partition->GetSectors(); 
 
	TotalSect -= ParamBlock.com.ReservedSectors; 
	TotalSect -= (DWORD)ParamBlock.com.SectorsPerFAT * ParamBlock.com.NumberOfFAT; 
	TotalSect -= (DWORD)ParamBlock.com.RootEntries * DIRENTRYSIZE / ParamBlock.com.BytesPerSector; 
	if( ((DWORD)ParamBlock.com.RootEntries * DIRENTRYSIZE) % ParamBlock.com.BytesPerSector != 0 ) 
		TotalSect --; 
 
	return TotalSect / ParamBlock.com.SectorsPerCluster; 
} 
 
int32 TFAT16::ReadFATtoBuf() 
{ 
	short i; 
	for( i=0; i< ParamBlock.com.NumberOfFAT; i++ ) 
		if( Partition->Read( 
				ParamBlock.com.ReservedSectors + 
				ParamBlock.com.SectorsPerFAT*i + 
				FATBufStartSector,FATBufSectors,FATBuf ) 
			== 0 ) 
			return 0; 
	if( i >= ParamBlock.com.NumberOfFAT ) return 1; 
} 
 
int32 TFAT16::FlushFATBuf() 
{ 
	if( FATBufChanged == False ) return 0; 
 
	for( int i=0; i< ParamBlock.com.NumberOfFAT; i++ ) 
		Partition->Write( ParamBlock.com.ReservedSectors + 
						ParamBlock.com.SectorsPerFAT*i + 
						FATBufStartSector,FATBufSectors,FATBuf ); 
	FATBufChanged = False; 
 
	return 0; 
}