#include "precomp.h"

#include "pdriveposix.h"
#include "unistd.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "sys/types.h"


#define USE_SPECIFIC_DEVICE -2

extern char* g_szUseSpecificDevice;

PPosixPhysicalDrive::PPosixPhysicalDrive()
{
    m_iDriveHandle = 0;
}

PPosixPhysicalDrive::~PPosixPhysicalDrive()
{
    if( m_iDriveHandle )
    {
        close( m_iDriveHandle );
        m_iDriveHandle = 0;
    }
}

BOOL PPosixPhysicalDrive::ReadPartitionInfoRecursive(DWORD dwSector,INT64 TotalOffset )
{
	BYTE mbr[512];
	INT64 OffsetInBytes = dwSector;
	OffsetInBytes *= 512;


	if( ReadAbsolute(mbr,sizeof(mbr),OffsetInBytes) )
	{
		MBR* pMBR = (MBR*) &(mbr[446]);
		if( pMBR->wSignature != 0xaa55 )
			return FALSE;

		INT64 ScheissOffset = 0;

		for( int i = 0; i < 4; i++ )
		{
			PARTITIONINFO* source = &(pMBR->pi[i]);

			if( !source->SIZE && !source->LBA )
				continue;

			PARTITION_INFORMATION pi;
			memset(&pi,0,sizeof(pi));

			pi.PartitionLength.QuadPart = source->SIZE;
			pi.PartitionLength.QuadPart *= 512L;
			pi.PartitionType = source->Type;

			if( i == 0 )
			{
				pi.StartingOffset.QuadPart = source->LBA;
				pi.StartingOffset.QuadPart *= 512L;
				pi.StartingOffset.QuadPart += TotalOffset;
				ScheissOffset = pi.StartingOffset.QuadPart;
			}
			else
			{
				pi.StartingOffset.QuadPart = ScheissOffset;
			}
			ScheissOffset += pi.PartitionLength.QuadPart;

			P9xPartitionInfo* p9pi = new P9xPartitionInfo(&pi);
			m_PartitionInfo.AddTail( p9pi );
			if( pi.PartitionType == PARTITION_TYPE_EXTENDED )
			{
				if( !ReadPartitionInfoRecursive(dwSector + source->LBA,pi.StartingOffset.QuadPart) )
				{
					p9pi->m_pi.StartingOffset.QuadPart += 63*512;
				}
			}
			
		}
	}
	return TRUE;
}

BOOL PPosixPhysicalDrive::Open( int iDrive )
{
    Close();
	m_iDriveNumber = iDrive;

    CHAR szFilenameBuffer[] = "/dev/hda";
	char* szFilename;
	if( iDrive == USE_SPECIFIC_DEVICE )
	{
		szFilename = g_szUseSpecificDevice;
	}
	else
	{
		szFilenameBuffer[7] += (char) iDrive;
		szFilename = szFilenameBuffer;
	}
    
    printf("Using device '%s'\n", szFilename );
    
    m_iDriveHandle = open(szFilename,0);
    if( m_iDriveHandle )
    {
		m_PartitionInfo.DeleteContents();
		ReadPartitionInfoRecursive(0,0);
		return TRUE;
	}
	return FALSE;
}

void PPosixPhysicalDrive::Close()
{
    if( m_iDriveHandle )
    {
        close(m_iDriveHandle);
        m_iDriveHandle = 0;
    }
}

BOOL PPosixPhysicalDrive::GetDriveGeometry( DISK_GEOMETRY* lpDG )
{
    memset(lpDG,0,sizeof(DISK_GEOMETRY));  
	lpDG->BytesPerSector = 512;
    return TRUE;
}

BOOL PPosixPhysicalDrive::ReadAbsolute( LPBYTE lpbMemory, DWORD dwSize, INT64 OffsetInBytes )
{
	lseek(m_iDriveHandle,OffsetInBytes,SEEK_SET);
    read( m_iDriveHandle, lpbMemory, dwSize );
    return TRUE;
}

BOOL PPosixPhysicalDrive::GetDriveLayout( LPBYTE lpbMemory, DWORD dwSize )
{
	if( m_iDriveNumber == USE_SPECIFIC_DEVICE )
	{
		DWORD dwBytesRequired = sizeof(DRIVE_LAYOUT_INFORMATION) + sizeof(PARTITION_INFORMATION);
		
		if( dwSize < dwBytesRequired )
			return FALSE;

		PDRIVE_LAYOUT_INFORMATION pli = (PDRIVE_LAYOUT_INFORMATION) lpbMemory;
		memset(lpbMemory, 0, dwSize);
		pli->PartitionCount = 1;
		pli->Signature = 0;
		return TRUE;
	}

	DWORD dwBytesRequired = sizeof(DRIVE_LAYOUT_INFORMATION) + sizeof(PARTITION_INFORMATION)*(m_PartitionInfo.m_lCount-1);
	
	if( dwSize < dwBytesRequired )
		return FALSE;

	PDRIVE_LAYOUT_INFORMATION pli = (PDRIVE_LAYOUT_INFORMATION) lpbMemory;
	pli->PartitionCount = m_PartitionInfo.m_lCount;
	pli->Signature = 0;
	int index = 0;
	ENUMERATE( &m_PartitionInfo, P9xPartitionInfo, pI )
	{
		pli->PartitionEntry[index++] = pI->m_pi;
	}
	return TRUE;
}




syntax highlighted by Code2HTML, v. 0.9.1