kerneltest/f32test/tools/mbrutil.cpp
changeset 0 a41df078684a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/f32test/tools/mbrutil.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,549 @@
+/*
+* 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;
+	}
\ No newline at end of file