kerneltest/f32test/tools/mbrutil.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
//
// MbrUtil.cpp
//


#define _WIN32_WINNT 0x0400
#include <windows.h>

#pragma warning (disable:4201) // warning C4201: nonstandard extension used : nameless struct/union
#include <winioctl.h>

#include <stdio.h>


const int KSectorSize = 512;
BYTE TheBuffer[KSectorSize];

template <class T>
T Min(T aLeft,T aRight)
	{return(aLeft<aRight ? aLeft : aRight);}



const unsigned char KPartitionTypeEmpty=0x00;
const unsigned char KPartitionTypeFAT12=0x01;
const unsigned char KPartitionTypeFAT16small=0x04;
const unsigned char KPartitionTypeFAT16=0x06;
const unsigned char KPartitionTypeNTFS=0x07;
const unsigned char KPartitionTypeWin95FAT32=0x0b;
const unsigned char KPartitionTypeWin95FAT32LBA=0x0c;
const unsigned char KPartitionTypeWin95FAT16LBA=0x0e;
const unsigned char KPartitionTypeWin95ExtdLBA=0x0f;
const unsigned char KPartitionTypeHiddenFAT12=0x11;
const unsigned char KPartitionTypeHiddenFAT16small=0x14;
const unsigned char KPartitionTypeHiddenFAT16=0x16;
const unsigned char KPartitionTypeHiddenNTFS=0x17;
const unsigned char KPartitionTypeHiddenWin95FAT32=0x1b;
const unsigned char KPartitionTypeHiddenWin95FAT32LBA=0x1c;
const unsigned char KPartitionTypeHiddenWin95FAT16LBA=0x1e;

const unsigned char KBootIndicatorBootable=0x80;

const int KDiskSectorSize = 512;
const int KDiskSectorSizeLog2 = 9;

const int KMegaByte = 0x100000;
const int KMegaByteLog2 = 20;
const int KMegaByteToSectorSizeShift = KMegaByteLog2 - KDiskSectorSizeLog2;
const int KMegaByteInSectors = KMegaByte >> KMegaByteToSectorSizeShift;

const int KMaxPartitionEntries=0x4;
const int KMBRFirstPartitionOffset=0x1BE;
const int KMBRSignatureOffset=0x1FE;

inline BOOL PartitionIsFAT(unsigned char a)
	{
	return (
		a==KPartitionTypeFAT12						||
		a==KPartitionTypeFAT16small					||
		a==KPartitionTypeFAT16						||
		a==KPartitionTypeFAT16						||
		a==KPartitionTypeWin95FAT16LBA				||
		a==KPartitionTypeHiddenFAT12				||
		a==KPartitionTypeHiddenFAT16small			||
		a==KPartitionTypeHiddenFAT16				||
		a==KPartitionTypeHiddenWin95FAT16LBA
		);
	}

inline BOOL PartitionIsFAT32(unsigned char a)
	{
	return (
		a==KPartitionTypeWin95FAT32					||
		a==KPartitionTypeWin95FAT32LBA				||
		a==KPartitionTypeHiddenWin95FAT32			||
		a==KPartitionTypeHiddenWin95FAT32LBA
		);
	}

inline BOOL PartitionIsNTFS(unsigned char a)
	{
	return (
		a==KPartitionTypeNTFS						||
		a==KPartitionTypeHiddenNTFS
		);
	}

class TMBRPartitionEntry
	{
public:
	BOOL IsValidPartition()
		{ return (iNumSectors>0 && iPartitionType!=KPartitionTypeEmpty); }
	BOOL IsValidDosPartition()
		{ return (iNumSectors>0 && PartitionIsFAT(iPartitionType)); }
	BOOL IsDefaultBootPartition()
		{ return(iX86BootIndicator==KBootIndicatorBootable && (IsValidDosPartition() || IsValidFAT32Partition())); }
	BOOL IsValidFAT32Partition()
		{ return (iNumSectors>0 && PartitionIsFAT32(iPartitionType)); }
public:
	unsigned char iX86BootIndicator;
	unsigned char iStartHead;
	unsigned char iStartSector;
	unsigned char iStartCylinder;
	unsigned char iPartitionType;
	unsigned char iEndHead;
	unsigned char iEndSector;
	unsigned char iEndCylinder;
	DWORD iFirstSector;
	DWORD iNumSectors;
	};


char* GetPartitionType(unsigned char aType)
	{
	switch (aType)
		{
		case KPartitionTypeFAT12: return "FAT12";
		case KPartitionTypeFAT16: return "FAT16";
		case KPartitionTypeFAT16small: return "FAT16";
		case KPartitionTypeWin95FAT32: return "FAT32";
		default:
			return "????";

		}
	}

void ReadMbr(unsigned char* aMbrBuf, int aDiskSizeInSectors, BOOL aHexDump)
	{
//	printf("Reading MBR...\n");
	if (aHexDump)
		{
		int n;
		for (n=0; n<KDiskSectorSize; n+=16)
			{
			printf("%08X : %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
				n,
				aMbrBuf[n+0x00],aMbrBuf[n+0x01],aMbrBuf[n+0x02],aMbrBuf[n+0x03],aMbrBuf[n+0x04],aMbrBuf[n+0x05],aMbrBuf[n+0x06],aMbrBuf[n+0x07],
				aMbrBuf[n+0x08],aMbrBuf[n+0x09],aMbrBuf[n+0x0A],aMbrBuf[n+0x0B],aMbrBuf[n+0x0C],aMbrBuf[n+0x0D],aMbrBuf[n+0x0E],aMbrBuf[n+0x0F]);
			}
		}



	if ((aMbrBuf[KMBRSignatureOffset+0] != 0x55) ||
		(aMbrBuf[KMBRSignatureOffset+1] != 0xAA))
		{
		printf("No valid MBR\n");
		return;
		}

	int i;
	TMBRPartitionEntry *pe;
	for (i=0, pe = (TMBRPartitionEntry*)(&aMbrBuf[KMBRFirstPartitionOffset]); i < KMaxPartitionEntries && pe->iPartitionType != 0; i++, pe++)
		{
		if (pe->iFirstSector + pe->iNumSectors > (DWORD) aDiskSizeInSectors)
			{
			printf("No valid MBR\n");
			return;
			}
		}
		
	printf("Partitions: \n");
	printf("  #  Name  Type Fat BtI Hed Sct Cyl Hed Sct Cyl  FirstSect NumSectors\n");
	
	for (i=0, pe = (TMBRPartitionEntry*)(&aMbrBuf[KMBRFirstPartitionOffset]); i < KMaxPartitionEntries && pe->iPartitionType != 0; i++, pe++)
		{
		char* partitionName = GetPartitionType(pe->iPartitionType);
		printf("%3d: %-6s %3u %3u %3u %3u %3u %3u %3u %3u %3u %10u %10u (%u MB)\n", 
			i,
			partitionName,
			pe->iPartitionType,
			pe->IsValidDosPartition() || pe->IsValidFAT32Partition() ? 1 : 0,
			pe->iX86BootIndicator,
			pe->iStartHead,
			pe->iStartSector,
			pe->iStartCylinder,
			pe->iEndHead,
			pe->iEndSector,
			pe->iEndCylinder,
			pe->iFirstSector,
			pe->iNumSectors,
			pe->iNumSectors >> KMegaByteToSectorSizeShift);

		if (pe->iPartitionType == KPartitionTypeHiddenNTFS)
			{
			printf("Drive contains an NTFS partition, aborting for safety\n");
			return;
			}
		}
	}


BOOL WriteMbr(unsigned char* aMbrBuf, int aFatSectorCount)
	{
	TMBRPartitionEntry *pe=(TMBRPartitionEntry*)(&aMbrBuf[KMBRFirstPartitionOffset]);

	// first partition starts at one MB
	int sectorStart = KMegaByteInSectors;

	// Create FAT partition
	pe->iFirstSector = sectorStart;


	pe->iNumSectors  = aFatSectorCount;
	pe->iX86BootIndicator = 0x00;
	if (pe->iNumSectors < 32680)
		pe->iPartitionType = KPartitionTypeFAT12;
	else if(pe->iNumSectors < 65536)
		pe->iPartitionType = KPartitionTypeFAT16small;
	else if (pe->iNumSectors < 1048576)
		pe->iPartitionType = KPartitionTypeFAT16;
	else
		pe->iPartitionType = KPartitionTypeWin95FAT32;
	sectorStart+= pe->iNumSectors;

	aMbrBuf[KMBRSignatureOffset+0] = 0x55;
	aMbrBuf[KMBRSignatureOffset+1] = 0xAA;

	return true;
	}


int main(int argc,char *argv[])
	{

	if (argc < 2)
		{
		printf("MbrUtil - Decodes and optionally writes or erases the Master Boot Record on a removable drive\n");
		printf("Syntax : MbrUtil <drive letter> [-e] [-w <FatSizeInMegabytes>] [FAT] [FAT32]\n");
		printf("Where  :\n");
		printf("-e     : erase Master Boot Record:\n");
		printf("-w     : create FAT partition of size <FatSizeInMegabytes>:\n");
		printf("E.g.   : MbrUtil f:\n");
		printf("       : MbrUtil f: -w 16 FAT\n");
		exit(0);
		}

	bool writeMbr = false;
	bool eraseMbr = false;
	int fatSectorCount = 0;
	char* fatType = "FAT";

	char driveLetter = (char) toupper(argv[1][0]);
	if ((strlen(argv[1]) > 2) ||
		(strlen(argv[1]) == 2 && argv[1][1] != ':') ||
		(driveLetter < 'A' || driveLetter > 'Z'))
		{
		printf("invalid drive letter");
		exit(4);
		}

	for (int i=2; i<argc; i++)
		{
		if (strcmpi(argv[i], "-e") == 0)
			{
			eraseMbr = true;
			}
		else if (strcmpi(argv[i], "-w") == 0)
			{
			writeMbr = true;
			i++;
			if (i >= argc)
				{
				printf("no drive size specified");
				exit(4);
				}
			int fatSizeInMegabytes = atoi(argv[i]);
			fatSectorCount = fatSizeInMegabytes << KMegaByteToSectorSizeShift;
//			printf("fatSizeInMegabytes %d, fatSectorCount %d\n", fatSizeInMegabytes, fatSectorCount);
			}
		else if (strcmpi(argv[i], "FAT") == 0)
			{
			}
		else if (strcmpi(argv[i], "FAT32") == 0)
			{
			fatType = argv[i];
			}
		else
			{
			printf("invalid option");
			exit(4);
			}
		}


	char diskName[10] = "\\\\.\\?:";
	diskName[4] = driveLetter;
	char physDiskName[20] = "\\\\.\\PHYSICALDRIVE?";



	DISK_GEOMETRY geometry;
	DWORD dummy;
	HANDLE logDeviceHandle;
	HANDLE physDeviceHandle;
	BOOL b;
	DWORD bytesRead;    
	DWORD bytesWritten;
	DWORD dwRet;

	//*****************************************************************************************
	// open logical drive...
	//*****************************************************************************************
	printf("Opening %s...\n", diskName);
	logDeviceHandle = CreateFileA(
		diskName, 
		GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE , 
		NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH, NULL); 
	if (logDeviceHandle == INVALID_HANDLE_VALUE) 
		{
		printf("CreateFileA() returned INVALID_HANDLE_VALUE\n");
		exit(4);
		}

	// query geometry
	b = DeviceIoControl(
			logDeviceHandle, 
			IOCTL_DISK_GET_DRIVE_GEOMETRY, 
			NULL, 
			0, 
			&geometry, 
			sizeof(geometry), 
			&dummy, 
			(LPOVERLAPPED)NULL);
	if (!b)
		{
		printf("IOCTL_DISK_GET_DRIVE_GEOMETRY failed error %x", GetLastError());
		CloseHandle(logDeviceHandle);
		exit(4);
		}
	
	LONGLONG diskSizeInBytes = geometry.Cylinders.QuadPart * geometry.TracksPerCylinder * geometry.SectorsPerTrack * KDiskSectorSize;
	int diskSizeInMegaBytes = (int) (diskSizeInBytes / KMegaByte);
	int diskSizeInSectors = (int) (diskSizeInBytes / KDiskSectorSize);


	printf("Drive %c MediaType: %d (%s). Size: %ld MBytes, %lu sectors\n", 
		driveLetter, 
		geometry.MediaType,
		geometry.MediaType==RemovableMedia ? "RemovableMedia" :
			geometry.MediaType==FixedMedia ? "FixedMedia" : "?",
		diskSizeInMegaBytes,
		diskSizeInSectors
		);
//	printf("Size: %llu sectors\n", diskSizeInSectors);

	if (geometry.MediaType != RemovableMedia)
		{
		printf("Drive is not removable, exiting");
		CloseHandle(logDeviceHandle);
		exit(4);
		}

	if (fatSectorCount + KMegaByteInSectors > diskSizeInSectors)
		{
		printf("Specified size is too big");
		CloseHandle(logDeviceHandle);
		exit(4);
		}

	//*****************************************************************************************
	// Get physical device number
	//*****************************************************************************************
	STORAGE_DEVICE_NUMBER storageDeviceNumber;
	b = IOCTL_STORAGE_GET_DEVICE_NUMBER;
	b = DeviceIoControl(
		  logDeviceHandle,
		  IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &storageDeviceNumber, sizeof(storageDeviceNumber), &bytesRead, 0);
//	printf("IOCTL_STORAGE_GET_DEVICE_NUMBER b %d DeviceNumber %d\n", b, storageDeviceNumber.DeviceNumber);
	if (!b)
		{
		printf("IOCTL_STORAGE_GET_DEVICE_NUMBER failed error %x", GetLastError());
		CloseHandle(logDeviceHandle);
		exit(4);
		}



	//*****************************************************************************************
	// open physical drive...
	//*****************************************************************************************
	physDiskName[strlen(physDiskName)-1] = (char) ('0' + storageDeviceNumber.DeviceNumber);

	printf("Opening %s...\n", physDiskName);
	physDeviceHandle = CreateFileA(
		physDiskName, 
		GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE , 
		NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH, NULL); 
	if (physDeviceHandle == INVALID_HANDLE_VALUE) 
		{
		printf("CreateFileA() returned INVALID_HANDLE_VALUE\n");
		exit(4);
		}




	//*******************************************************
	// Read first sector
	//*******************************************************
	dwRet = SetFilePointer(
		physDeviceHandle, 0, 0, FILE_BEGIN);
	if (dwRet != 0)
		{
		printf("Unable to set file pointer, exiting");
		CloseHandle(physDeviceHandle);
		CloseHandle(logDeviceHandle);
		exit(4);
		}
	if (!ReadFile (physDeviceHandle, TheBuffer, KSectorSize, &bytesRead, NULL) )
		{
		printf("ReadFile failed with %d", GetLastError());
		CloseHandle(physDeviceHandle);
		CloseHandle(logDeviceHandle);
		exit(4);
		}
	if(bytesRead != KSectorSize)
		{
		printf("ReadFile length too small: %d", bytesRead);
		CloseHandle(physDeviceHandle);
		CloseHandle(logDeviceHandle);
		exit(4);
		}

	//*******************************************************
	// Interpret MBR
	//*******************************************************
	ReadMbr(TheBuffer, diskSizeInSectors, false);
	
	//*******************************************************
	// Write new MBR
	//*******************************************************
	if (writeMbr)
		{
		printf("Writing MBR...\n");
		memset(TheBuffer, 0, sizeof(TheBuffer));
		b = WriteMbr(TheBuffer, fatSectorCount);
		if (!b)
			writeMbr = eraseMbr = false;
		}
	if (eraseMbr)
		{
		printf("Erasing MBR...\n");
		memset(TheBuffer, 0, sizeof(TheBuffer));
		}
	if (writeMbr || eraseMbr)
		{
		// Write first sector
		dwRet = SetFilePointer(
			physDeviceHandle, 0, 0, FILE_BEGIN);
		if (dwRet != 0)
			{
			printf("Unable to set file pointer, exiting");
			CloseHandle(physDeviceHandle);
			CloseHandle(logDeviceHandle);
			exit(4);
			}
		if (!WriteFile (physDeviceHandle, TheBuffer, KSectorSize, &bytesWritten, NULL) )
			{
			printf("WriteFile failed with %d", GetLastError());
			CloseHandle(physDeviceHandle);
			CloseHandle(logDeviceHandle);
			exit(4);
			}
		if(bytesWritten != KSectorSize)
			{
			printf("WriteFile length too small: %d", bytesWritten);
			CloseHandle(physDeviceHandle);
			CloseHandle(logDeviceHandle);
			exit(4);
			}
		if (writeMbr)
			ReadMbr(TheBuffer, diskSizeInSectors, false);
		}

	
	CloseHandle(physDeviceHandle);


	if (writeMbr || eraseMbr)
		{
		printf("Dismounting %s...\n", diskName);
		b = DeviceIoControl(
		  logDeviceHandle,
		  FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &bytesRead, 0);
		if (!b)
			printf("FSCTL_DISMOUNT_VOLUME b %d err %d\n", b, GetLastError());
		}

	CloseHandle(logDeviceHandle);
	
	//*******************************************************
	// Format the disk
	//*******************************************************
	if (writeMbr || eraseMbr)
		{
		printf("\n");
		char prompt[80];
		sprintf(prompt, "Eject card from drive %C: and press ENTER when ready...\n", driveLetter);
		printf(prompt);
		getchar();

		char winCmd[1024];
		char cmdArgs[1024];
		STARTUPINFO si = {0,};
		PROCESS_INFORMATION pi;

		GetWindowsDirectory(winCmd, sizeof(winCmd));
		strncat(winCmd, "\\system32\\cmd.exe", sizeof(winCmd));
		sprintf(cmdArgs, "/C format %c: /FS:%s /Q /X", driveLetter, fatType);
		printf("Executing : %s %s\n", winCmd, cmdArgs);
		b = CreateProcessA(
			winCmd,				//__in_opt     LPCTSTR lpApplicationName,
			cmdArgs,			//__inout_opt  LPTSTR lpCommandLine,
			NULL,				//__in_opt     LPSECURITY_ATTRIBUTES lpProcessAttributes,
			NULL,				//__in_opt     LPSECURITY_ATTRIBUTES lpThreadAttributes,
			FALSE,				//__in         BOOL bInheritHandles,
			0,					//__in         DWORD dwCreationFlags,
			NULL,				//__in_opt     LPVOID lpEnvironment,
			NULL,				//__in_opt     LPCTSTR lpCurrentDirectory,
			&si,				//__in         LPSTARTUPINFO lpStartupInfo,
			&pi);				//__out        LPPROCESS_INFORMATION lpProcessInformation
		if (!b)
			printf("CreateProcess failed with %d", GetLastError());

		dwRet = WaitForSingleObject(pi.hProcess, INFINITE);
		CloseHandle(pi.hThread);
		CloseHandle(pi.hProcess);

		}

	return 0;
	}