kerneltest/f32test/ext/t_rawext.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:26:05 +0100
branchRCL_3
changeset 29 743008598095
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:
*
*/
//
// RAWEXT.CPP
//
// This file system extension provides a way to access a drive on the local windows system in "raw format".
// It can be used to test large files / drives
// 
// NB This should be used WITH CARE to avoid unintentionally overwriting or formatting a windows disk
// 

#include <f32fsys.h>

#include <emulator.h>

#include <windows.h>

#define WIN32_LEAN_AND_MEAN
#pragma warning (disable:4201) // warning C4201: nonstandard extension used : nameless struct/union

#include <winioctl.h>

// Enable this macro to find the last REMOVABLE drive (e.g. a card reader drive) 
// (to minimise the chance of doing any damage !
// Doesn't even try any drive letters below E (again for safety):
#define __LOOK_FOR_DRIVE__

// Otherwise the windows drive letter can be hard-coded here:
#ifndef __LOOK_FOR_DRIVE__
	char diskName[] = "\\\\.\\Y:";
#endif


const TInt KSectorSize = 512;

class CRawWinDiskExtProxyDrive : public CBaseExtProxyDrive
	{
public:
	static CRawWinDiskExtProxyDrive* NewL(CProxyDrive* aProxyDrive, CMountCB* aMount);
	~CRawWinDiskExtProxyDrive();
public:
	virtual TInt Initialise();
	virtual TInt Dismounted();
	virtual TInt Enlarge(TInt aLength);
	virtual TInt ReduceSize(TInt aPos, TInt aLength);
	virtual TInt Read(TInt64 aPos,TInt aLength,const TAny* aTrg,TInt aThreadHandle,TInt anOffset);
	virtual TInt Read(TInt64 aPos,TInt aLength,TDes8& aTrg);
	virtual TInt Write(TInt64 aPos,TInt aLength,const TAny* aSrc,TInt aThreadHandle,TInt anOffset);
	virtual TInt Write(TInt64 aPos,const TDesC8& aSrc);
	virtual TInt Caps(TDes8& anInfo);
	virtual TInt Format(TFormatInfo& anInfo);
private:
	CRawWinDiskExtProxyDrive(CProxyDrive* aProxyDrive, CMountCB* aMount);
private:
	HANDLE iDeviceHandle; 
	};

class CRawWinDiskProxyDriveFactory : public CProxyDriveFactory
	{
public:
	CRawWinDiskProxyDriveFactory();
	virtual TInt Install();			
	virtual CProxyDrive* NewProxyDriveL(CProxyDrive* aProxy,CMountCB* aMount);
	};



CRawWinDiskExtProxyDrive* CRawWinDiskExtProxyDrive::NewL(CProxyDrive* aProxyDrive, CMountCB* aMount)
//
//
//
	{
	CRawWinDiskExtProxyDrive* temp=new(ELeave) CRawWinDiskExtProxyDrive(aProxyDrive,aMount);
	return(temp);
	}


CRawWinDiskExtProxyDrive::CRawWinDiskExtProxyDrive(CProxyDrive* aProxyDrive, CMountCB* aMount):CBaseExtProxyDrive(aProxyDrive,aMount)
	{
	RDebug::Print(_L("CRawWinDiskExtProxyDrive::CRawWinDiskExtProxyDrive"));
	}

CRawWinDiskExtProxyDrive::~CRawWinDiskExtProxyDrive()
//
//
//
	{
	CloseHandle(iDeviceHandle);
	}

TInt CRawWinDiskExtProxyDrive::Initialise()
//
//
//
	{
	RDebug::Print(_L("CRawWinDiskExtProxyDrive::Initialise()"));


#ifdef __LOOK_FOR_DRIVE__
	// Find the last REMOVABLE drive (to minimise the chance of doing any damage !
	// Don't even try any drive letters below E (agai for safety):
	char diskName[] = "\\\\.\\?:";
	char driveLetter;
	for (driveLetter = 'Z'; driveLetter > 'D'; driveLetter--)
		{
		diskName[4] = driveLetter;

		DISK_GEOMETRY geometry;
		DWORD dummy;

		iDeviceHandle = CreateFileA(diskName, 
			GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 
			NULL, OPEN_EXISTING, 0, NULL); 
 
		if (iDeviceHandle == INVALID_HANDLE_VALUE) 
			{
			continue;
			}

		if(DeviceIoControl(iDeviceHandle, 
							IOCTL_DISK_GET_DRIVE_GEOMETRY, 
							NULL, 
							0, 
							&geometry, 
							sizeof(geometry), 
							&dummy, 
							(LPOVERLAPPED)NULL))
			{
			RDebug::Print(_L("Drive %c MediaType %d removable %s"), 
				driveLetter, 
				geometry.MediaType,
				geometry.MediaType==RemovableMedia ? _S16("True") : _S16("False"));

			}

		CloseHandle(iDeviceHandle);
		if (geometry.MediaType==RemovableMedia)
			break;
		}
	if (driveLetter == 'D')
		return KErrNotFound;
#endif

	// Creating a handle to drive a: using CreateFile () function ..
	TPtrC8 diskName8((const TUint8*) diskName);
	TBuf16<16> diskName16;
	diskName16.Copy(diskName8);
	RDebug::Print(_L("RAWEXT: Opening drive %S"), &diskName16);

	iDeviceHandle = CreateFileA(
//		"\\\\.\\H:",
		diskName,
        GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 
        NULL, OPEN_EXISTING, 0, NULL); 
 
    if (iDeviceHandle == INVALID_HANDLE_VALUE) 
		{
		return Emulator::LastError();
		}

	return KErrNone;
	}

TInt CRawWinDiskExtProxyDrive::Dismounted()
//
//
//
	{
	RDebug::Print(_L("CRawWinDiskExtProxyDrive::Dismounted()"));
	return(KErrNone);
	}

TInt CRawWinDiskExtProxyDrive::Enlarge(TInt /*aLength*/)
//
//
//
	{
	return(KErrNotSupported);
	}


TInt CRawWinDiskExtProxyDrive::ReduceSize(TInt /*aPos*/, TInt /*aLength*/)
//
//
//
	{
	return(KErrNotSupported);
	}

LOCAL_C TInt ParameterNum(const TInt aMessageHandle, const TAny* aAddress)
	{
	RMessage2 tmpMessage(*(RMessagePtr2 *) &aMessageHandle);
		
	if (tmpMessage.Ptr0() == aAddress)
		{
		return 0;
		}
	if (tmpMessage.Ptr1() == aAddress)
		{
		return 1;
		}
	if (tmpMessage.Ptr2() == aAddress)
		{
		return 2;
		}
	if (tmpMessage.Ptr3() == aAddress)
		{
		return 3;
		}
	User::Panic(_L("RAWEXT"),KErrBadHandle);
	return -1;
	}



TInt CRawWinDiskExtProxyDrive::Read(TInt64 aPos,TInt aLength,const TAny* aTrg,TInt aThreadHandle,TInt aOffset)
//
//
//
	{

	//
	// Set file position to where we want to read...
	//
	LARGE_INTEGER li;
	li.QuadPart = aPos;

	long posH = I64HIGH(aPos);
	long posL = I64LOW(aPos);

	TInt off = posL & 0x1FF;
	posL &= ~0x1FF;

	if(SetFilePointer (iDeviceHandle, posL, &posH, FILE_BEGIN) == 0xFFFFFFFF)
		{
		return Emulator::LastError();
		}

	const TInt KLocalBufferSize = 256*1024;
	char buffer[KLocalBufferSize];

	const TInt param = ParameterNum(aThreadHandle, aTrg);

	TInt totalBytesRead = 0;

	//
	// Read first sector if start of data is offset from 512 bytes...
	//
	if(off)
		{
		// read 1st sector if offset
		DWORD bytesRead;    
		if (!ReadFile (iDeviceHandle, buffer, KSectorSize, &bytesRead, NULL) )
			{
			return Emulator::LastError();
			}

		if(bytesRead != KSectorSize)
			{
			return KErrNotReady;
			}

		bytesRead-= off;
		TInt copyLen = Min(aLength, bytesRead);;

		totalBytesRead += copyLen;
		aLength -= copyLen;

		TPtrC8 des((TUint8*) buffer+off, copyLen);
		((RMessagePtr2 *) &aThreadHandle)->Write(param, des, aOffset);
		}

	//
	// Read the remainder of the data, accounting for partial last sector...
	//
	while(aLength > 0)
		{
		TUint32 bytesThisTime = min(KLocalBufferSize, (TUint32)aLength);
		
		bytesThisTime = (bytesThisTime + KSectorSize-1) & ~(KSectorSize-1);

		DWORD bytesread;    
		if (!ReadFile (iDeviceHandle, buffer, bytesThisTime, &bytesread, NULL) )
			{
			return Emulator::LastError();
			}

		if(bytesread != (TUint32)bytesThisTime)
			{
			return KErrNotReady;
			}
    
		TPtrC8 des((TUint8*)buffer, min((TUint32)aLength, bytesThisTime));
		((RMessagePtr2 *) &aThreadHandle)->Write(param, des, aOffset + totalBytesRead);
		totalBytesRead += bytesThisTime;
		aLength -= bytesThisTime;
		}

	return KErrNone;
	}

//////

GLDEF_C void DumpBuffer( const TDesC8& aBuffer )
	/**
	 * Dump the content of aBuffer in hex
	 */
	{
	static const TText hextab[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
										'A', 'B', 'C', 'D', 'E', 'F' };
	const TInt KBytesPerLine = 32;
	const TInt KCharsPerLine = KBytesPerLine * 2;

	TInt remaining = aBuffer.Length();
	TUint8* pSrc = const_cast<TUint8*>(aBuffer.Ptr());

	TBuf<KCharsPerLine> line;
	line.SetLength( KCharsPerLine );	// don't need to print trailing space
	TInt bytesPerLine = KBytesPerLine;
	TInt lineOffs = 0;
	while( remaining )
		{
		if( remaining < KBytesPerLine )
			{
			bytesPerLine = remaining;
			line.SetLength( (bytesPerLine*2) );
			}
		TUint16* pDest = const_cast<TUint16*>(line.Ptr());
		remaining -= bytesPerLine;
		for( TInt i = bytesPerLine; i > 0; --i )
			{
			TUint8 c = *pSrc++;
			*pDest++ = hextab[c >> 4];
			*pDest++ = hextab[c & 0xF];
			}
		_LIT( KFmt, "%06x: %S\n\r" );
		RDebug::Print( KFmt, lineOffs, &line );
		lineOffs += bytesPerLine;
		}
	}



TInt CRawWinDiskExtProxyDrive::Read(TInt64 aPos,TInt aLength,TDes8& aTrg)
//
//
//
	{

	//
	// Set file position to where we want to read...
	//
	LARGE_INTEGER li;
	li.QuadPart = aPos;

	long posH = I64HIGH(aPos);
	long posL = I64LOW(aPos);

	TInt off = posL & 0x1FF;
	posL &= ~0x1FF;

	if(SetFilePointer (iDeviceHandle, posL, &posH, FILE_BEGIN) == 0xFFFFFFFF)
		{
		return Emulator::LastError();
		}

	const TInt KLocalBufferSize = 256*1024;
	char buffer[KLocalBufferSize];

	TInt totalBytesRead = 0;

	aTrg.SetLength(aLength);
	
	//
	// Read first sector if start of data is offset from 512 bytes...
	//
	if(off)
		{
		// read 1st sector if offset
		DWORD bytesRead;    
		if (!ReadFile (iDeviceHandle, buffer, KSectorSize, &bytesRead, NULL) )
			{
			return Emulator::LastError();
			}

		if(bytesRead != KSectorSize)
			{
			return KErrNotReady;
			}

		bytesRead-= off;
		TInt copyLen = Min(aLength, bytesRead);;

		totalBytesRead += copyLen;
		aLength -= copyLen;

		memcpy(&aTrg[0], &buffer[off], copyLen);
		}

	//
	// Read the remainder of the data, accounting for partial last sector...
	//
	while(aLength > 0)
		{
		TInt bytesThisTime = (aLength > KLocalBufferSize) ? KLocalBufferSize : aLength;

		bytesThisTime = (bytesThisTime + KSectorSize-1) & ~(KSectorSize-1);

		DWORD bytesread;    
		if (!ReadFile (iDeviceHandle, buffer, bytesThisTime, &bytesread, NULL) )
			{
			return Emulator::LastError();
			}

		if(bytesread != (TUint32)bytesThisTime)
			 return KErrNotReady;
		
		TInt copyLen = aLength < bytesThisTime ? aLength : bytesThisTime;

		memcpy(&aTrg[totalBytesRead], buffer, copyLen);

		totalBytesRead += bytesThisTime;
		aLength -= bytesThisTime;
		}

//	DumpBuffer(aTrg);
	
	return KErrNone;
	}

TInt CRawWinDiskExtProxyDrive::Write(TInt64 aPos,TInt aLength,const TAny* aSrc,TInt aThreadHandle,TInt aOffset)
//
//
//
	{
	//
	// Set file position to where we want to write...
	//
	long posStartH = I64HIGH(aPos);
	long posStartL = I64LOW(aPos);

	TInt offStart = posStartL & 0x1FF;
	posStartL &= ~0x1FF;

	if(SetFilePointer (iDeviceHandle, posStartL, &posStartH, FILE_BEGIN) == 0xFFFFFFFF)
		{
		return Emulator::LastError();
		}

	const TInt KLocalBufferSize = 256*1024;
	char buffer[KLocalBufferSize];

	const TInt param = ParameterNum(aThreadHandle, aSrc);

	TInt totalBytesRead = 0;

	//
	// Read-Modify-Write on first sector if start of data is offset from 512 bytes
	// or if this is a partial write...
	//
	if(offStart || aLength < KSectorSize)
		{
		DWORD bytesread;    
		if (!ReadFile (iDeviceHandle, buffer, KSectorSize, &bytesread, NULL) )
			{
			return Emulator::LastError();
			}

		if(bytesread != KSectorSize)
			{
			return KErrNotReady;
			}

		totalBytesRead = min(KSectorSize-offStart, aLength);
		aLength -= totalBytesRead;

		TPtr8 des((TUint8*)&buffer[offStart], totalBytesRead);
		((RMessagePtr2 *) &aThreadHandle)->Read(param, des, aOffset);

		if(SetFilePointer (iDeviceHandle, posStartL, &posStartH, FILE_BEGIN) == 0xFFFFFFFF)
			{
			return Emulator::LastError();
			}

		if (!WriteFile (iDeviceHandle, buffer, KSectorSize, &bytesread, NULL) )
			{
			return Emulator::LastError();
			}
		}

	//
	// Write the remainder of the aligned data
	//
	while(aLength >= KSectorSize)
		{
		TInt alignedLength = aLength & ~0x1FF;

		TInt bytesThisTime = (alignedLength > KLocalBufferSize) ? KLocalBufferSize : alignedLength;

		TPtr8 des((TUint8*)buffer, bytesThisTime);
		((RMessagePtr2 *) &aThreadHandle)->Read(param, des, aOffset + totalBytesRead);
	
		DWORD bytesWritten;    
		if (!WriteFile (iDeviceHandle, buffer, bytesThisTime, &bytesWritten, NULL) )
			{
			return Emulator::LastError();
			}

		if(bytesWritten != (TUint32)bytesThisTime)
			{
			return KErrNotReady;
			}
		
		totalBytesRead += bytesThisTime;
		aLength -= bytesThisTime;
		}

	//
	// Read-Modify-Write on the last block if a partial write...
	//
	if(aLength > 0)
		{
		DWORD curPos = SetFilePointer(iDeviceHandle, 0, NULL, FILE_CURRENT);

		// RMW last sector if offset
		DWORD bytesread;    
		if (!ReadFile (iDeviceHandle, buffer, KSectorSize, &bytesread, NULL) )
			{
			return Emulator::LastError();
			}

		if(bytesread != KSectorSize)
			 return KErrNotReady;

		TPtr8 des((TUint8*)buffer, aLength);
		((RMessagePtr2 *) &aThreadHandle)->Read(param, des, aOffset + totalBytesRead);

		if(SetFilePointer (iDeviceHandle, curPos, &posStartH, FILE_BEGIN) == 0xFFFFFFFF)
			{
			return Emulator::LastError();
			}

		if (!WriteFile (iDeviceHandle, buffer, KSectorSize, &bytesread, NULL) )
			{
			return Emulator::LastError();
			}
		}

	return KErrNone;
	}

TInt CRawWinDiskExtProxyDrive::Write(TInt64 aPos,const TDesC8& aSrc)
//
//
//
	{
	//
	// Set file position to where we want to write...
	//
	TInt length = aSrc.Length();

	long posStartH = I64HIGH(aPos);
	long posStartL = I64LOW(aPos);

	TInt offStart = posStartL & 0x1FF;
	posStartL &= ~0x1FF;

	if(SetFilePointer (iDeviceHandle, posStartL, &posStartH, FILE_BEGIN) == 0xFFFFFFFF)
		{
		return Emulator::LastError();
		}

	const TInt KLocalBufferSize = 256*1024;
	char buffer[KLocalBufferSize];

	TInt totalBytesRead = 0;

	//
	// Read-Modify-Write on first sector if start of data is offset from 512 bytes
	// or if this is a partial write...
	//
	if(offStart || length < KSectorSize)
		{
		DWORD bytesread;    
		if (!ReadFile (iDeviceHandle, buffer, KSectorSize, &bytesread, NULL) )
			{
			return Emulator::LastError();
			}

		if(bytesread != KSectorSize)
			{
			return KErrNotReady;
			}

		totalBytesRead = min(KSectorSize-offStart, length);
		length -= totalBytesRead;

		memcpy(&buffer[offStart], &aSrc[0], totalBytesRead);

		if(SetFilePointer (iDeviceHandle, posStartL, &posStartH, FILE_BEGIN) == 0xFFFFFFFF)
			{
			return Emulator::LastError();
			}

		if (!WriteFile (iDeviceHandle, buffer, KSectorSize, &bytesread, NULL) )
			{
			return Emulator::LastError();
			}
		}

	//
	// Write the remainder of the aligned data
	//
	while(length >= KSectorSize)
		{
		TInt alignedLength = length & ~0x1FF;

		TInt bytesThisTime = (alignedLength > KLocalBufferSize) ? KLocalBufferSize : alignedLength;

		memcpy(buffer, &aSrc[totalBytesRead], bytesThisTime);
	
		DWORD bytesWritten;    
		if (!WriteFile (iDeviceHandle, buffer, bytesThisTime, &bytesWritten, NULL) )
			{
			return Emulator::LastError();
			}

		if(bytesWritten != (TUint32)bytesThisTime)
			{
			return KErrNotReady;
			}
		
		totalBytesRead += bytesThisTime;
		length -= bytesThisTime;
		}

	//
	// Read-Modify-Write on the last block if a partial write...
	//
	if(length > 0)
		{
		DWORD curPos = SetFilePointer(iDeviceHandle, 0, NULL, FILE_CURRENT);

		// RMW last sector if offset
		DWORD bytesread;    
		if (!ReadFile (iDeviceHandle, buffer, KSectorSize, &bytesread, NULL) )
			{
			return Emulator::LastError();
			}

		if(bytesread != KSectorSize)
			 return KErrNotReady;

		memcpy(&buffer[0], &aSrc[totalBytesRead], length);

		if(SetFilePointer (iDeviceHandle, curPos, &posStartH, FILE_BEGIN) == 0xFFFFFFFF)
			{
			return Emulator::LastError();
			}

		if (!WriteFile (iDeviceHandle, buffer, KSectorSize, &bytesread, NULL) )
			{
			return Emulator::LastError();
			}
		}


	return KErrNone;
	}

TInt CRawWinDiskExtProxyDrive::Caps(TDes8& anInfo)
//
//
//
	{
	TLocalDriveCapsV3Buf caps;
	TInt err = CBaseExtProxyDrive::Caps(caps);
	if(err == KErrNone)
		{
		DISK_GEOMETRY geometry;
		DWORD dummy;

		if(!DeviceIoControl(iDeviceHandle, 
							IOCTL_DISK_GET_DRIVE_GEOMETRY, 
							NULL, 
							0, 
							&geometry, 
							sizeof(geometry), 
							&dummy, 
							(LPOVERLAPPED)NULL))
			{
			return KErrNotReady;
			}

		caps().iExtraInfo = EFalse;

		// NB This seems to be incorrect:If the disk is formatted by Windows, then the 
		// number of sectors reported in the Boot Sector is slightly greater than
		// the number of sectors calculated here ... resulting in CheckDisk failures.
		// One solution is to ensure the disk is formatted by the emulator.
		caps().iSize =	MAKE_TINT64(geometry.Cylinders.HighPart, geometry.Cylinders.LowPart) * 
									geometry.TracksPerCylinder * 
									geometry.SectorsPerTrack * 
									geometry.BytesPerSector;

		anInfo = caps.Left(Min(caps.Length(),anInfo.MaxLength()));
		}

	return(err);
	}

TInt CRawWinDiskExtProxyDrive::Format(TFormatInfo& /*anInfo*/)
//
//
//
	{
	return(KErrEof);
	}


CRawWinDiskProxyDriveFactory::CRawWinDiskProxyDriveFactory()
//
//
//
	{
	RDebug::Print(_L("CRawWinDiskProxyDriveFactory::CRawWinDiskProxyDriveFactory"));
	}

TInt CRawWinDiskProxyDriveFactory::Install()
//
//
//
	{
	_LIT(KLoggerName,"RAWEXT");
	return(SetName(&KLoggerName));
	}


CProxyDrive* CRawWinDiskProxyDriveFactory::NewProxyDriveL(CProxyDrive* aProxy,CMountCB* aMount)
//
//
//
	{
	return(CRawWinDiskExtProxyDrive::NewL(aProxy,aMount));
	}

extern "C" {

EXPORT_C CProxyDriveFactory* CreateFileSystem()
//
// Create a new file system
//
	{
	return(new CRawWinDiskProxyDriveFactory());
	}
}