userlibandfileserver/fileserver/swins/elocal.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 8 538db54a451d
child 42 a179b74831c9
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) 1995-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:
//

#include "elocal.h"
#include <emulator.h>
#include <TCHAR.h>

const TInt KMajorVersionNumber=1;
const TInt KMinorVersionNumber=0;

const TUint KInvalidSetFilePointer = 0xffffffff;	// INVALID_SET_FILE_POINTER

#pragma data_seg(".data2")
#ifdef __VC32__
#pragma bss_seg(".data2")
#endif
static TInt ReadSpeed;
static TInt WriteSpeed;
#pragma data_seg()
#ifdef __VC32__
#pragma bss_seg()
#endif

static void Panic(TPanic aPanic)
	{
	User::Panic(_L("LocalFSys"),aPanic);
	}


//
// Map aDrive to a path given by environment variables
//
TBool MapDrive(TDes& aFileName, TInt aDrive)
	{

	TDriveName root(TDriveUnit(aDrive).Name());
	TFileName path;
	TBuf<3> rootWithSlash(root);
	rootWithSlash.Append('\\');

	if (MapEmulatedFileName(path, rootWithSlash) == KErrNone)
		{
		aFileName=path.Left(3);	// drive letter, colon and backslash
		return(ETrue);
		}
	aFileName=root;  // no trailing backslash
	return(EFalse);
	}
	
TInt MapFileName(TDes& aFileName, TInt aDrive, const TDesC& aName)
	{
	TFileName n(TDriveUnit(aDrive).Name());
	n.Append(aName);
	return MapEmulatedFileName(aFileName,n);
	}

void MapFileNameL(TDes& aFileName, TInt aDrive, const TDesC& aName)
	{
	User::LeaveIfError(MapFileName(aFileName,aDrive,aName));
	}


/**
Check whether a descriptor has enough space for null-terminating and append a zero terminator if it does.
Supposed to be used for Win32 file operations, taking C-like strings as parameters.
The main purpose is to avoid panics caused by descriptors overflow.

@param  aDes descriptor to be null-terminated; a file(directory) name presumably.
@return cast to LPCTSTR value of the descriptor, supposed to be the unicode string
@leave  KErrBadName if there is no room for trailing zero 
*/
LPCTSTR StrPtrZL(TDes16& aDes)
    {
    if(aDes.MaxLength() - aDes.Length() < 1)
        User::Leave(KErrBadName);  //-- no room for terminating zero
    
    return (LPCTSTR)aDes.PtrZ();
    }



//
// Converts a TTime structure to a Windows/NT filetime.  Assumes that aTime is a
// UTC (system) time
//
static void timeToFileTimeL(const TTime& aTime,FILETIME* f)
	{

	TDateTime dateTime=aTime.DateTime();
	SYSTEMTIME t;
	#pragma warning( disable : 4244 ) // conversion from 'const int' to 'unsigned short', possible loss of data
	t.wYear=dateTime.Year();
	t.wMonth=dateTime.Month()+1;
	t.wDay=dateTime.Day()+1;
	t.wDayOfWeek=(aTime.DayNoInWeek()+1)%7;
	t.wHour=dateTime.Hour();
	t.wMinute=dateTime.Minute();
	t.wSecond=dateTime.Second();
	t.wMilliseconds=dateTime.MicroSecond()/1000;
	#pragma warning( default : 4244 ) // conversion from 'const int' to 'unsigned short', possible loss of data
	__ASSERT_ALWAYS(SystemTimeToFileTime(&t,f)==TRUE,User::Leave(KErrArgument));
	}

//
//	Convert Windows/NT file time to TTime
//	Assumes the NT file time is UTC
//
static void fileTimeToTime(FILETIME* f,TTime& aTime)
	{
	SYSTEMTIME t;
	__ASSERT_ALWAYS(FileTimeToSystemTime(f,&t)==TRUE,Panic(EFileTimeToSystemTime));
	aTime=TDateTime(t.wYear,TMonth(t.wMonth-1),t.wDay-1,t.wHour,t.wMinute,t.wSecond,t.wMilliseconds*1000);
	}

//
// Return the size and free space on a drive.
//
static TInt GetMediaSize(TInt aDriveNumber,TInt64& aSize,TInt64& aFree)
	{

	TBuf<4> driveName;
	MapDrive(driveName,aDriveNumber);
	DWORD sectorsPerCluster;
	DWORD bytesPerSector;
	DWORD freeClusters;
	DWORD sizeClusters;
	// this function should be upgraded to GetDiskFreeSpaceEx
	BOOL b=Emulator::GetDiskFreeSpace((LPCTSTR)driveName.PtrZ(),&sectorsPerCluster,&bytesPerSector,&freeClusters,&sizeClusters);
	if (!b)
		return Emulator::LastError();

	TInt64 bytesPerCluster=(TInt)(sectorsPerCluster*bytesPerSector);
	aSize=TInt64((TInt)sizeClusters)*bytesPerCluster;
	aFree=TInt64((TInt)freeClusters)*bytesPerCluster;
	return(KErrNone);
	}

//
// Return the volume name and uniqueID.
//
static TInt GetVolumeId(TInt aDriveNumber,TUint& aUniqueID)
	{

	TBuf<4> driveName;
	MapDrive(driveName,aDriveNumber);
	DWORD uniqueID,componentLength,flags;
	BOOL b=Emulator::GetVolumeInformation((LPCTSTR)driveName.PtrZ(),NULL,0,&uniqueID,&componentLength,&flags,NULL,0);
	if (!b)
		return Emulator::LastError();

	aUniqueID=uniqueID;
	return(KErrNone);
	}

//#########################################################################################################################
//##        CLocalMountCB class implementation
//#########################################################################################################################


CLocalMountCB::CLocalMountCB()
	{
	}

CLocalMountCB::~CLocalMountCB()
	{
	}


//
// Returns ETrue if the drive == EDriveZ
//
TBool CLocalMountCB::IsRomDrive() const
	{
	// WINS emulated rom drive is Z:
	return(Drive().DriveNumber()==EDriveZ);
	}

//-------------------------------------------------------------------------------------------------------------------

/**
Mount a volume. 

@param aForceMount Flag to indicate whether mount should be forced to succeed if an error occurs
@leave KErrNoMemory,KErrNotReady,KErrCorrupt,KErrUnknown.
*/
void CLocalMountCB::MountL(TBool /*aForceMount*/)
	{
	TInt64 s,f;
	const TInt driveNum=Drive().DriveNumber();
	User::LeaveIfError(GetMediaSize(driveNum,s,f));
	
    iSize=s;
    if (driveNum==EDriveZ)
		iSize=4*1048576;
	
    User::LeaveIfError(GetVolumeId(driveNum,iUniqueID));
	SetVolumeName(HBufC::NewL(0));	// all Win32 volumes are unnamed
	
    //-- assign default value, 4G-1
    iMaxFileSizeSupported = ((TUint64)4 << 30)-1;

        {
        //-- find out the maximal supported file size. For this we need to query the name of the windows filesystem that is
        //-- used for the emulated drive
        TBuf<20> bufWinDrive;
        MapDrive(bufWinDrive, Drive().DriveNumber());
        ASSERT(bufWinDrive.Length() >= 3);

        TCHAR rootName[10];
        TCHAR volName[30];
        TCHAR volFSFileName[30];
        DWORD volSerNum;
        DWORD volMaxCompLen;
        DWORD volFsFlags;
        
        memset(rootName, 0, sizeof(rootName));
        wcsncpy(rootName, bufWinDrive.Ptr(), 3); //- something like "k:\\"

        BOOL b = GetVolumeInformation(rootName, volName, sizeof(volName)/sizeof(TCHAR), &volSerNum, &volMaxCompLen, &volFsFlags, volFSFileName, sizeof(volFSFileName)/sizeof(TCHAR));
        if(b)
            {
            if(_wcsicmp(volFSFileName, _TEXT("NTFS")) == 0)
                {//-- this is NTFS
                iMaxFileSizeSupported = 0xFFFFFFF0000; //-- max. file size for NTFS
                }
             else
                {//-- theoretically other than FAT & NTFS filesystem are possible.. Figure yourself.
            }   }
        }


    }

//-------------------------------------------------------------------------------------------------------------------
/**
    Try remount this volume. Checks if the volume parameters remained the same as on original MountL() call, and
    if they are, re-initialises the mount. 
    @return KErrNone if the remount was OK
            system-wide error code otherwise
*/
TInt CLocalMountCB::ReMount()
	{

	TInt d=Drive().DriveNumber();
	TUint uniqueID;
	TInt r=GetVolumeId(d,uniqueID);
	if (r==KErrNone && uniqueID!=iUniqueID)
		r=KErrGeneral;
	return(r);
	}

//-------------------------------------------------------------------------------------------------------------------
void CLocalMountCB::Dismounted()
	{
    }

//-------------------------------------------------------------------------------------------------------------------
//
// Return the volume info.
//
void CLocalMountCB::VolumeL(TVolumeInfo& aVolume) const
	{

	TInt64 s,f;
	TInt driveNum=Drive().DriveNumber();
	User::LeaveIfError(GetMediaSize(driveNum,s,f));
	if (driveNum==EDriveZ)
		aVolume.iFree=0;
	else
		aVolume.iFree=f;
	}

//-------------------------------------------------------------------------------------------------------------------
//
// Set the volume label. Not supported on Win32 volumes
//
void CLocalMountCB::SetVolumeL(TDes&)
	{

	User::Leave(IsRomDrive() ? KErrAccessDenied : KErrNotSupported);
	}

//-------------------------------------------------------------------------------------------------------------------
//
// Return the address of the file if it is in rom
//
void CLocalMountCB::IsFileInRom(const TDesC& aName,TUint8*& aFileStart)
	{

	aFileStart=NULL;
	if (!IsRomDrive())
		return;

	TFileName n;
	if (MapFileName(n,Drive().DriveNumber(),aName)!=KErrNone)
		return;
	
	DWORD access=GENERIC_READ;
	DWORD share=FILE_SHARE_WRITE|FILE_SHARE_READ;
	DWORD create=OPEN_EXISTING;
	HANDLE h=Emulator::CreateFile((LPCTSTR)n.PtrZ(),access,share,NULL,create,FILE_FLAG_RANDOM_ACCESS,NULL);
	if (h==INVALID_HANDLE_VALUE)
		return;

	CLocalFileCB::RomAddress(aName, h, aFileStart);
	CloseHandle(h);
	}

//-------------------------------------------------------------------------------------------------------------------
/**
    Make a directory.
    @param aName full path to the directory to create. Name validity is checked by file server.
*/
void CLocalMountCB::MkDirL(const TDesC& aName)
	{

	if (IsRomDrive())
		User::Leave(KErrAccessDenied);
	TFileName n;
	MapFileNameL(n,Drive().DriveNumber(),aName);
	BOOL b=Emulator::CreateDirectory(StrPtrZL(n),NULL);
	
	if (b)
		return;
	TInt r=Emulator::LastError();
	if (r!=KErrAlreadyExists)
		User::Leave(r);
	TEntry e;
	EntryL(aName,e);

	if (e.IsDir())
		User::Leave(KErrAlreadyExists);
	else
		User::Leave(KErrAccessDenied);
	}

//-------------------------------------------------------------------------------------------------------------------
/**
    Remove a directory.
    @param aName directory name
*/
void CLocalMountCB::RmDirL(const TDesC& aName)
	{

	if (IsRomDrive())
		User::Leave(KErrAccessDenied);
	
    TFileName n;
	MapFileNameL(n,Drive().DriveNumber(),aName);
	BOOL b=Emulator::RemoveDirectory(StrPtrZL(n));
	
	if (!b)
		User::Leave(Emulator::LastError());
	}

//-------------------------------------------------------------------------------------------------------------------
//
// Delete a file.
//
void CLocalMountCB::DeleteL(const TDesC& aName)
	{

	if (IsRomDrive())
		User::Leave(KErrAccessDenied);
	
    //-- check entry attributes
    TEntry entry;
    EntryL(aName, entry);
	if (entry.IsDir() ||  entry.IsReadOnly())
	    User::Leave(KErrAccessDenied);

    TFileName n;
	MapFileNameL(n,Drive().DriveNumber(),aName);
	BOOL b=Emulator::DeleteFile(StrPtrZL(n));
	
	if (!b)
		User::Leave(Emulator::LastError());
	}

//-------------------------------------------------------------------------------------------------------------------
//
// Rename a file or directory.
//
void CLocalMountCB::RenameL(const TDesC& aOldName,const TDesC& aNewName)
	{

	if (IsRomDrive())
		User::Leave(KErrAccessDenied);
	TEntry entry;
	TRAPD(r,EntryL(aNewName,entry));
	if (r!=KErrNone && r!=KErrNotFound)
		User::Leave(r);
	TFileName old;
	MapFileNameL(old,Drive().DriveNumber(),aOldName);
	TFileName n;
	MapFileNameL(n,Drive().DriveNumber(),aNewName);
	BOOL b=Emulator::MoveFile(StrPtrZL(old),StrPtrZL(n));
	
	if (!b)
		User::Leave(Emulator::LastError());
	}

//-------------------------------------------------------------------------------------------------------------------
void CLocalMountCB::ReplaceL(const TDesC& aOldName,const TDesC& aNewName)
//
// Delete aNewName if it exists and rename anOldName.
//
	{

	if (IsRomDrive())
		User::Leave(KErrAccessDenied);
	TEntry entry;
	if(FileNamesIdentical(aOldName,aNewName))
		{
		return;
		}
	TRAPD(r,DeleteL(aNewName));
	if (r!=KErrNotFound && r!=KErrNone)
		User::Leave(r);
	TFileName old;
	MapFileNameL(old,Drive().DriveNumber(),aOldName);
	TFileName n;
	MapFileNameL(n,Drive().DriveNumber(),aNewName);
	BOOL b=Emulator::MoveFile(StrPtrZL(old),StrPtrZL(n));
	if (!b)
		User::Leave(Emulator::LastError());
	}
	
//-------------------------------------------------------------------------------------------------------------------
//
//	Set and get file pointer for windows files
//	
static DWORD SetFilePointerL(HANDLE hFile,LONG lDistanceToMove,DWORD dwMoveMethod)
	
	{
	DWORD dwRet;
	
	dwRet=SetFilePointer(hFile,lDistanceToMove,0,dwMoveMethod);
	if (dwRet==KInvalidSetFilePointer)	//	INVALID_HANDLE_VALUE
		User::Leave(Emulator::LastError());

	return (dwRet);	
	}

//-------------------------------------------------------------------------------------------------------------------
//
//	Set and get file pointer for windows files
//	
static DWORD SetFilePointer64L(HANDLE hFile, LARGE_INTEGER * lpDistanceToMove, DWORD dwMoveMethod)
	{

	DWORD dwRet;
	
	dwRet=SetFilePointer(hFile, lpDistanceToMove->LowPart, &(lpDistanceToMove->HighPart), dwMoveMethod);
	
    TInt r = Emulator::LastError();
	if ((KInvalidSetFilePointer==dwRet) && (r != NO_ERROR))	
		User::Leave(r);

	return (dwRet);	
	}

//-------------------------------------------------------------------------------------------------------------------
/**
    Read file section without opening this file on a file server side.
    
    @param  aName       file name; all trailing dots from the name will be removed
    @param  aFilePos    start read position within a file
    @param  aLength     how many bytes to read; on return will be how many bytes actually read
    @param  aDes        local buffer desctriptor
    @param  aMessage    from file server, used to write data to the buffer in different address space.

    @leave on media read error
*/
void CLocalMountCB::ReadSectionL(const TDesC& aName,TInt aPos,TAny* aTrg,TInt aLength,const RMessagePtr2& aMessage)
	{
	
	TFileName n;
	MapFileNameL(n,Drive().DriveNumber(),aName);
	
	WIN32_FIND_DATA d;
	HANDLE hFile=Emulator::FindFirstFile(StrPtrZL(n),&d);
	if (hFile==INVALID_HANDLE_VALUE)
		User::Leave(Emulator::LastError());
	FOREVER
		{
		TPtrC fileName((TText*)(&d.cFileName[0]));
		if (fileName!=_L(".") && fileName!=_L(".."))
			break;
		if (!Emulator::FindNextFile(hFile,&d))
			{
			TInt r = Emulator::LastError();
			User::Leave(r == KErrEof ? KErrNotFound : r);
			}
		}
	
	FindClose(hFile);
		
	hFile=Emulator::CreateFile(StrPtrZL(n),GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
	if (hFile==INVALID_HANDLE_VALUE)
		return;

	DWORD dwSizeLow, dwSizeHigh;
	dwSizeLow=GetFileSize(hFile,&dwSizeHigh);
	TInt r = Emulator::LastError();
	if((NO_ERROR != r) && (INVALID_FILE_SIZE == dwSizeLow))
		User::Leave(r);
	
	// ReadSectionL can support only upto 2G as aPos is TInt!
	const TInt64 fileSize = MAKE_TINT64(dwSizeHigh, dwSizeHigh);
	if(fileSize > KMaxTInt)
		{
		if (!CloseHandle(hFile))
			User::Leave(Emulator::LastError());

		User::Leave(KErrTooBig);
		}
	
//	Check that reading from aPos for aLength lies within the file
//	if aPos is within the file, and aLength is too long, read up to EOF
//	If aPos is beyond the file, return a zero length descriptor

	if ((TInt)dwSizeLow>=(aPos+aLength))	//	Can read entire length requested from aPos	
		SetFilePointerL(hFile,aPos,FILE_BEGIN);			
	
	else if ((TInt)dwSizeLow>aPos)		//	Can read from aPos but not entire length requested
		{
		SetFilePointerL(hFile,aPos,FILE_BEGIN);
		aLength=dwSizeLow-aPos;
		}	
	else						//	Cannot read from aPos because it lies outside file
		{						//	Close file and leave with KErrEof
		if (!CloseHandle(hFile))
			User::Leave(Emulator::LastError());

		User::Leave(KErrEof);
		}

	TBuf8<0x1000> buf;
	TInt pos=0;

	if (aMessage.Handle() == KLocalMessageHandle)
		((TPtr8* )aTrg)->SetLength(0);
	
	while (aLength)
		{
		TInt readTotal=Min(aLength,buf.MaxLength());
		DWORD ret;
		BOOL b=ReadFile(hFile,(TAny*)buf.Ptr(),readTotal,&ret,NULL);
		if (!b || ((TInt)ret!=readTotal))	
			User::Leave(Emulator::LastError());
		buf.SetLength(ret);
		
		if(aMessage.Handle() == KLocalMessageHandle)
			((TPtr8* )aTrg)->Append(buf);
		else
			aMessage.WriteL(0,buf,pos);
	
		pos+=ret;
		if (((TInt)ret)<readTotal)
			break;
		aLength-=readTotal;
		}
			
	if (!CloseHandle(hFile))
		User::Leave(Emulator::LastError());
	}


//-------------------------------------------------------------------------------------------------------------------
//
// Read the entry uid if present
//
void CLocalMountCB::ReadUidL(const TDesC& aName,TEntry& anEntry) const
	{

//  First check to see if the first sixteen bytes form a valid UID
	TBuf<KMaxFileName + 1> fileName=aName;
	HANDLE hFile=Emulator::CreateFile(StrPtrZL(fileName),GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
	if (hFile==INVALID_HANDLE_VALUE)
		return;
	DWORD ret;
	TBuf8<sizeof(TCheckedUid)> checkedUidBuf;
	checkedUidBuf.SetLength(sizeof(TCheckedUid));
	ReadFile(hFile,&checkedUidBuf[0],sizeof(TCheckedUid),&ret,NULL);
	if (ret!=sizeof(TCheckedUid))
		goto close;
	{
	TCheckedUid checkedUid(checkedUidBuf);
	if(checkedUid.UidType()!=TUidType(TUid::Null(),TUid::Null(),TUid::Null()))
		{
		anEntry.iType=checkedUid.UidType();
		goto close;
		}
	}

//Look at PE file for UID section
		{
		const TInt KPeHeaderAddrAddr=0x3c;
		const TInt KPeHeaderAddrSize=0x01;
		const TInt KNumberOfSectionsOffset=0x06;
		const TInt KNumberOfSectionsSize=0x02;
		const TInt KSectionTableOffset=0xf8;
		const TInt KSectionHeaderSize=0x28;
		const TInt KSectionNameLength=0x08;
		const TInt KPtrToRawDataOffset=0x14;
		const TInt KPtrToRawDataSize=0x04;
		const TText8 peText[4]={'P','E',0,0};
		const TText8 uidText[8]={'.','S','Y','M','B','I','A','N'};
		
	//Read address of start of PE header
		if (SetFilePointer(hFile,KPeHeaderAddrAddr,0,FILE_BEGIN)==KInvalidSetFilePointer)
			goto close;
		TInt peAddr=0;
		ReadFile(hFile,&peAddr,KPeHeaderAddrSize,&ret,NULL);
		if (ret!=KPeHeaderAddrSize)
			goto close;
		
	//Check it really is the start of PE header
		if (SetFilePointer(hFile,peAddr,0,FILE_BEGIN)==KInvalidSetFilePointer)
			goto close;
		TText8 text[4];
		ReadFile(hFile,text,4,&ret,NULL);
		if (*(TInt32*)text!=*(TInt32*)peText)
			goto close;
		
	//Read number of sections
		if (SetFilePointer(hFile,peAddr+KNumberOfSectionsOffset,0,FILE_BEGIN)==KInvalidSetFilePointer)
			goto close;
		TInt sections=0;
		ReadFile(hFile,&sections,KNumberOfSectionsSize,&ret,NULL);
		if (ret!=KNumberOfSectionsSize)
			goto close;

	//Go through section headers looking for UID section
		if (SetFilePointer(hFile,peAddr+KSectionTableOffset,0,FILE_BEGIN)==KInvalidSetFilePointer)
			goto close;
		TInt i=0;
		for(;i<sections;i++)
			{
			TText8 name[KSectionNameLength];
			ReadFile(hFile,name,KSectionNameLength,&ret,NULL);
			if (ret!=KSectionNameLength)
				goto close;
			if (*(TInt64*)name==*(TInt64*)uidText)
				break;
			if (SetFilePointer(hFile,KSectionHeaderSize-KSectionNameLength,0,FILE_CURRENT)==KInvalidSetFilePointer)
				goto close;
			}
		if (i==sections)
			goto close;

	//Read RVA/Offset
		if (SetFilePointer(hFile,KPtrToRawDataOffset-KSectionNameLength,0,FILE_CURRENT)==KInvalidSetFilePointer)
			goto close;
		TInt uidOffset;
		ReadFile(hFile,&uidOffset,KPtrToRawDataSize,&ret,NULL);
		if (ret!=KPtrToRawDataSize)
			goto close;

	//Read UIDs!
		if (SetFilePointer(hFile,uidOffset,0,FILE_BEGIN)==KInvalidSetFilePointer)
			User::Leave(KErrGeneral);

		TEmulatorImageHeader header;
		ReadFile(hFile,&header,sizeof(header),&ret,NULL);
		if (ret==sizeof(header))
			anEntry.iType=*(TUidType*)&header;
		}
//Close file
close:
	if (!CloseHandle(hFile))
		User::Leave(Emulator::LastError());
	}

//-------------------------------------------------------------------------------------------------------------------
/**
    Try to find a directory entry by the given name and path. 
    This method _must_ leave if the entry is not found. See the caller.

    @param  aName   path to the directory object. all trailing dots from the name will be removed.
    @param  anEntry on return will contain the entry data
    
    @leave  KErrPathNotFound if there is no path to the aName
            KErrNotFound     if the entry corresponding to the aName is not found
            system-wide erorr code of media read failure.
*/
void CLocalMountCB::EntryL(const TDesC& aName,TEntry& anEntry) const
	{

	TFileName n;
	MapFileNameL(n,Drive().DriveNumber(),aName);
	WIN32_FIND_DATA d;
	HANDLE h=Emulator::FindFirstFile(StrPtrZL(n),&d);
	if (h==INVALID_HANDLE_VALUE)
		User::Leave(Emulator::LastError());
	FOREVER
		{
		TPtrC fileName((TText*)(&d.cFileName[0]));
		if (fileName!=_L(".") && fileName!=_L(".."))
			break;
		if (!Emulator::FindNextFile(h,&d))
			{
			TInt r = Emulator::LastError();
			User::Leave(r == KErrEof ? KErrNotFound : r);
			}
		}
	FindClose(h);
	anEntry.iName.Des()=(TText*)(&d.cFileName[0]);
	anEntry.iAtt=d.dwFileAttributes&KEntryAttMaskSupported;
	if (IsRomDrive())
		anEntry.iAtt|=KEntryAttReadOnly;

	anEntry.SetFileSize(MAKE_TINT64(d.nFileSizeHigh,d.nFileSizeLow));

	fileTimeToTime(&d.ftLastWriteTime,anEntry.iModified);
	ReadUidL(n,anEntry);
	}

//-------------------------------------------------------------------------------------------------------------------
/**
    Set directory entry details.
    @param  aName           entry name; all trailing dots from the name will be removed
    @param  aTime           entry modification time (and last access as well)
    @param  aSetAttMask     entry attributes OR mask
    @param  aClearAttMask   entry attributes AND mask

*/
void CLocalMountCB::SetEntryL(const TDesC& aName,const TTime& aTime,TUint aSetAttMask,TUint aClearAttMask)
	{

	if (IsRomDrive())
		User::Leave(KErrAccessDenied);
	TFileName n;
	MapFileNameL(n,Drive().DriveNumber(),aName);
	TUint setAttMask=aSetAttMask&KEntryAttMaskSupported;
	DWORD att=Emulator::GetFileAttributes(StrPtrZL(n));
	if (att==0xffffffffu)
		User::Leave(Emulator::LastError());
	
    if (setAttMask|aClearAttMask)
		{
		att|=setAttMask;
		att&=(~aClearAttMask);
		if (!Emulator::SetFileAttributes((LPCTSTR)n.Ptr(),att))
			User::Leave(Emulator::LastError());
		}
	
    if (aSetAttMask&KEntryAttModified)
		{
		FILETIME f;
		timeToFileTimeL(aTime,&f);

		if (att&KEntryAttReadOnly)
			{
			DWORD writeableAtt=att&(~KEntryAttReadOnly);
			if (!Emulator::SetFileAttributes((LPCTSTR)n.Ptr(),writeableAtt))
				User::Leave(Emulator::LastError());
			}

		HANDLE h;
		if (att&KEntryAttDir)
			{
			h=Emulator::CreateFile((LPCTSTR)n.Ptr(),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_DIRECTORY|FILE_FLAG_BACKUP_SEMANTICS, NULL);
			if (h==INVALID_HANDLE_VALUE)
				User::Leave(Emulator::LastError());
			}
		else
			{
			h=Emulator::CreateFile((LPCTSTR)n.Ptr(),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
			if (h==INVALID_HANDLE_VALUE)
				User::Leave(Emulator::LastError());
			}

		if (!SetFileTime(h,NULL,&f,&f))
			{
			TInt error = Emulator::LastError(); 
			CloseHandle(h);
			User::Leave(error);
			}
		
        if (!CloseHandle(h))
			User::Leave(Emulator::LastError());
		
        if ((att&KEntryAttReadOnly) && !Emulator::SetFileAttributes((LPCTSTR)n.Ptr(),att))
			User::Leave(Emulator::LastError());
		}
	}

//-------------------------------------------------------------------------------------------------------------------
/**
    Open/Create/Replace a file on the current mount.
    
    @param  aName   file name; all trailing dots from the name will be removed
    @param  aMode   File open mode, See TFileMode
    @param  anOpen  specifies action: open, create or replace the file
    @param  aFile   pointer to the CFileCB object to populate

*/
void CLocalMountCB::FileOpenL(const TDesC& aName,TUint aMode,TFileOpen anOpen,CFileCB* aFile)
	{

	if (IsRomDrive() && (anOpen!=EFileOpen || (aMode&EFileWrite)))
		User::Leave(KErrAccessDenied);
	TFileName n;
	MapFileNameL(n,Drive().DriveNumber(),aName);
	
	DWORD access=GENERIC_READ|GENERIC_WRITE;
	DWORD share=FILE_SHARE_WRITE|FILE_SHARE_READ;
	DWORD create=0;
	switch (anOpen)
		{
	    case EFileOpen: create=OPEN_EXISTING; break;
	    case EFileCreate: create=CREATE_NEW; break;
	    case EFileReplace: create=CREATE_ALWAYS; break;
		}

	HANDLE h=Emulator::CreateFile(StrPtrZL(n),access,share,NULL,create,FILE_FLAG_RANDOM_ACCESS,NULL);
	
	if((h==INVALID_HANDLE_VALUE) && !(aMode&EFileWrite))
	{
	// If windows will not allow write access and it was not requested then open for read only
	access=GENERIC_READ;
	h=Emulator::CreateFile(StrPtrZL(n),access,share,NULL,create,FILE_FLAG_RANDOM_ACCESS,NULL);
	}

	if (h==INVALID_HANDLE_VALUE)
		User::Leave(Emulator::LastError());
	CLocalFileCB& file=(*((CLocalFileCB*)aFile));
	file.SetHandle(h);
	
    BY_HANDLE_FILE_INFORMATION info;
	if (!GetFileInformationByHandle(h,&info))
		User::Leave(Emulator::LastError());
	
    const TUint64 fileSize = MAKE_TUINT64(info.nFileSizeHigh, info.nFileSizeLow);
	
    // Check on file size
	if(MaxFileSizeSupported() < fileSize)
		User::Leave(KErrTooBig);
	
    file.SetMaxSupportedSize(MaxFileSizeSupported());
    file.SetSize64(fileSize, EFalse);
	file.SetAtt(info.dwFileAttributes&KEntryAttMaskSupported);

//	if (IsRomDrive())
//		file.iAtt|=KEntryAttReadOnly;
	TTime tempTime=file.Modified();
	fileTimeToTime(&info.ftLastWriteTime,tempTime);
	file.SetModified(tempTime);
	}

void AppendAsteriskL(TDes& aDes)
	{
	if (aDes.Length()==aDes.MaxLength())
		User::Leave(KErrBadName);
	aDes.Append('*');
	}

//-------------------------------------------------------------------------------------------------------------------	
/**
    Open a directory on the current mount.
    
    @param  aName   path to the object in the directory we want to open; all trailing dots from the name will be removed
    @param  aDir    dir. CB to be filled in.
    
    If there is no such a path, this method must leave with KErrPathNotFound

    @leave  KErrPathNotFound if thereis no such path
    @leave  error code on media read fault
*/
void CLocalMountCB::DirOpenL(const TDesC& aName,CDirCB* aDir)
	{

	TFileName n;
	TParse parse;
	MapFileNameL(n,Drive().DriveNumber(),aName);
	parse.Set(n,NULL,NULL);
	n=parse.DriveAndPath();
	AppendAsteriskL(n);
	WIN32_FIND_DATA info;
	HANDLE h=Emulator::FindFirstFile(StrPtrZL(n),&info);
	if (h==INVALID_HANDLE_VALUE)
		{
		TInt error=Emulator::LastError();
		TParse parser;
		TInt r=parser.Set(n,NULL,NULL);
		if (r!=KErrNone)
			User::Leave(r);
		if (!parser.IsRoot() || Drive().DriveNumber()!=0 || error!=KErrNotFound)
			User::Leave(error);
		h=NULL;
		}
	CLocalDirCB& dir=(*((CLocalDirCB*)aDir));
	dir.SetHandle(h);
	dir.SetPending(ETrue);
	dir.iEntry.iName.Des()=(TText*)(&info.cFileName[0]);
	dir.iEntry.iAtt=info.dwFileAttributes&KEntryAttMaskSupported;

	const TInt64 fileSize = MAKE_TINT64(info.nFileSizeHigh,info.nFileSizeLow);
	dir.iEntry.SetFileSize(fileSize);

	n=parse.FullName();
	if (parse.NameAndExt().Length()==0)
		AppendAsteriskL(n);
	dir.SetFullName(n);
	fileTimeToTime(&info.ftLastWriteTime,dir.iEntry.iModified);
	}

//-------------------------------------------------------------------------------------------------------------------	
//
// Read directly from disk
//
void CLocalMountCB::RawReadL(TInt64 /*aPos*/,TInt /*aLength*/,const TAny* /*aDes*/,TInt /*anOffset*/,const RMessagePtr2& /*aMessage*/) const
	{
	User::Leave(KErrNotSupported);
	}

//-------------------------------------------------------------------------------------------------------------------	
//
// Write directly to disk
//
void CLocalMountCB::RawWriteL(TInt64 /*aPos*/,TInt /*aLength*/,const TAny* /*aDes*/ ,TInt /*anOffset*/,const RMessagePtr2& /*aMessage*/)
	{
	User::Leave(KErrNotSupported);
	}

//-------------------------------------------------------------------------------------------------------------------	
//
// Get the short name associated with aLongName
//
void CLocalMountCB::GetShortNameL(const TDesC& aLongName,TDes& aShortName)
	{

	if (IsRomDrive())
		User::Leave(KErrNotSupported);

	TFileName n;
	MapFileNameL(n,Drive().DriveNumber(),aLongName);
	WIN32_FIND_DATA d;
	HANDLE h=Emulator::FindFirstFile(StrPtrZL(n),&d);
	if (h==INVALID_HANDLE_VALUE)
		User::Leave(Emulator::LastError());
	FindClose(h);
    if (d.cAlternateFileName[0])	// we have a dos name too
        aShortName=(TText*)(&d.cAlternateFileName[0]);
	else
		aShortName=(TText*)(&d.cFileName[0]);
	}

//-------------------------------------------------------------------------------------------------------------------	
//
// Get the short name associated with aLongName
//
void CLocalMountCB::GetLongNameL(const TDesC& aShortName,TDes& aLongName)
	{

	if (IsRomDrive())
		User::Leave(KErrNotSupported);

	TFileName n;
	MapFileNameL(n,Drive().DriveNumber(),aShortName);
	WIN32_FIND_DATA d;
	HANDLE h=Emulator::FindFirstFile(StrPtrZL(n),&d);
	if (h==INVALID_HANDLE_VALUE)
		User::Leave(Emulator::LastError());
	FindClose(h);
	aLongName=(TText*)(&d.cFileName[0]);
	}

//-------------------------------------------------------------------------------------------------------------------	
/**
Reports whether the specified interface is supported - if it is,
the supplied interface object is modified to it

@param aInterfaceId     The interface of interest
@param aInterface       The interface object
@return                 KErrNone if the interface is supported, otherwise KErrNotFound 

@see CMountCB::GetInterface()
*/
TInt CLocalMountCB::GetInterface(TInt aInterfaceId,TAny*& aInterface,TAny* aInput)
    {
	switch(aInterfaceId)
		{
		case EFileExtendedInterface:
			((CMountCB::MFileExtendedInterface*&) aInterface) = this;
			return KErrNone;

    	case ELocalBufferSupport:
    		// CLocalMountCB doesn't ever use any extensions?
	    	// 	- seems to not have any iProxyDrive or LocalDrive() or similar, 
    		// so we'll just return KErrNone here.
   			return KErrNone;

		default:
		    return CMountCB::GetInterface(aInterfaceId,aInterface,aInput);
		}
    }

//-------------------------------------------------------------------------------------------------------------------	
TInt CLocalMountCB::LocalBufferSupport()
	{
	TAny* dummyInterface = NULL;
	TAny* dummyInput = NULL;
	return GetInterface(ELocalBufferSupport,dummyInterface,dummyInput);
	}

//-------------------------------------------------------------------------------------------------------------------	
/**
    Read file section without opening this file on a file server side.
    
    @param  aName       file name; all trailing dots from the name will be removed
    @param  aFilePos    start read position within a file
    @param  aLength     how many bytes to read; on return will be how many bytes actually read
    @param  aDes        local buffer desctriptor
    @param  aMessage    from file server, used to write data to the buffer in different address space.

    @leave on media read error
*/
void CLocalMountCB::ReadSection64L(const TDesC& aName, TInt64 aPos, TAny* aTrg, TInt aLength, const RMessagePtr2& aMessage)
	{
	TFileName n;
	MapFileNameL(n,Drive().DriveNumber(),aName);
	
	WIN32_FIND_DATA d;
	HANDLE hFile=Emulator::FindFirstFile(StrPtrZL(n),&d);
	if (hFile==INVALID_HANDLE_VALUE)
		User::Leave(Emulator::LastError());
	
	FOREVER
		{
		TPtrC fileName((TText*)(&d.cFileName[0]));
		if (fileName!=_L(".") && fileName!=_L(".."))
			break;
		if (!Emulator::FindNextFile(hFile,&d))
			{
			TInt r = Emulator::LastError();
			User::Leave(r == KErrEof ? KErrNotFound : r);
			}
		}
	
	FindClose(hFile);
	
	hFile=Emulator::CreateFile(StrPtrZL(n),GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
	if (hFile==INVALID_HANDLE_VALUE)
		return;

	DWORD dwSizeLow, dwSizeHigh;
	dwSizeLow=GetFileSize(hFile,&dwSizeHigh);
	TInt r = Emulator::LastError();
	if((NO_ERROR != r) && (INVALID_FILE_SIZE == dwSizeLow))
		User::Leave(r);
	
	// Check on file size 
	const TInt64 fileSize = MAKE_TINT64(dwSizeHigh, dwSizeLow);
	if(MaxFileSizeSupported() < (TUint64)fileSize)
		{
		if (!CloseHandle(hFile))
			User::Leave(Emulator::LastError());
		
        User::Leave(KErrTooBig);
		}
	
//	Check that reading from aPos for aLength lies within the file
//	if aPos is within the file, and aLength is too long, read up to EOF
//	If aPos is beyond the file, return a zero length descriptor

	if (fileSize>=aPos+aLength)	//	Can read entire length requested from aPos	
		SetFilePointer64L(hFile,(LARGE_INTEGER *)&aPos,FILE_BEGIN);
	
	else if (fileSize>aPos)		//	Can read from aPos but not entire length requested
		{
		SetFilePointer64L(hFile,(LARGE_INTEGER *)&aPos,FILE_BEGIN);
		aLength=(TInt)(fileSize-aPos);
		}	
	else						//	Cannot read from aPos because it lies outside file
		{						//	Close file and leave with KErrEof
		if (!CloseHandle(hFile))
			User::Leave(Emulator::LastError());

		User::Leave(KErrEof);
		}

	TBuf8<0x1000> buf;
	TInt pos=0;

	if (aMessage.Handle() == KLocalMessageHandle)
		((TPtr8* )aTrg)->SetLength(0);
	
	while (aLength)
		{
		TInt readTotal=Min(aLength,buf.MaxLength());
		DWORD ret;
		BOOL b=ReadFile(hFile,(TAny*)buf.Ptr(),readTotal,&ret,NULL);
		if (!b || ((TInt)ret!=readTotal))	
			User::Leave(Emulator::LastError());
		buf.SetLength(ret);
		
		if(aMessage.Handle() == KLocalMessageHandle)
			((TPtr8* )aTrg)->Append(buf);
		else
			aMessage.WriteL(0,buf,pos);
		
		pos+=ret;
		if (((TInt)ret)<readTotal)
			break;
		aLength-=readTotal;
		}
	
	if (!CloseHandle(hFile))
		User::Leave(Emulator::LastError());
	}

//-------------------------------------------------------------------------------------------------------------------

/**
    CLocalMountCB control method.
    @param  aLevel  specifies the operation to perfrom on the mount
    @param  aOption specific option for the given operation
    @param  aParam  pointer to generic parameter, its meaning depends on aLevel and aOption

    @return standard error code.
*/

TInt CLocalMountCB::MountControl(TInt aLevel, TInt aOption, TAny* aParam)
    {
    //-- File System - specific queries 
    if(aLevel == EMountFsParamQuery && aOption == ESQ_GetMaxSupportedFileSize)
        {//-- this is a query to provide the max. supported file size; aParam is a pointer to TUint64 to return the value
        *(TUint64*)aParam = MaxFileSizeSupported();    
        return KErrNone;
        }

    return KErrNotSupported; 
    }

//#########################################################################################################################
//##        CLocalFileCB class implementation
//#########################################################################################################################


CLocalFileCB::CLocalFileCB()
	{
	}

CLocalFileCB::~CLocalFileCB()
	{

	if (iAtt&KEntryAttModified)
		{
		TRAPD(ret,FlushDataL());
//		if (ret!=KErrNone) // Can fail if floppy disk is removed
//			Panic(EFileClose); // Ignore error
		}
	if (iWinHandle!=NULL && !CloseHandle(iWinHandle))
		Panic(EFileClose);
	}

//-------------------------------------------------------------------------------------------------------------------	
//
// Returns ETrue if the drive number == EDriveZ
//
TBool CLocalFileCB::IsRomDrive() const
	{

	// WINS emulated rom drive is Z:
	return(((CLocalFileCB*)this)->Mount().Drive().DriveNumber()==EDriveZ);
	}

//-------------------------------------------------------------------------------------------------------------------	
//
//	Check that the file pointer iCurrentPos is positioned correctly
//	in relation to the Win32 file pointer
//
void CLocalFileCB::CheckPosL(TInt64 aPos)
	{
//	Get the current Win32 file pointer position	
	LARGE_INTEGER pos;
	pos.QuadPart = 0;
	DWORD position=SetFilePointer(iWinHandle,pos.LowPart,&pos.HighPart,FILE_CURRENT);
	TInt r = Emulator::LastError();
	if ((KInvalidSetFilePointer == position) && (r != NO_ERROR))
		User::Leave(r);
//	Set iCurrentPos and Win32 file pointers to aPos if they are different to each
//	other or different to aPos
	if ((pos.QuadPart!=iCurrentPos) || (iCurrentPos!=aPos))
		{
		iCurrentPos=(-1);
		pos.QuadPart = aPos;
		position = SetFilePointer(iWinHandle,pos.LowPart,&pos.HighPart,FILE_BEGIN);
		r = Emulator::LastError();
		if ((KInvalidSetFilePointer == position) && (r != NO_ERROR))
			User::Leave(r);
		iCurrentPos=aPos;
		}
	}

//-------------------------------------------------------------------------------------------------------------------	
void CLocalFileCB::ReadL(TInt aPos,TInt& aLength,const TAny* aDes,const RMessagePtr2& aMessage)
	{
	ReadL((TInt64)aPos, aLength, (TDes8*)aDes, aMessage, 0);
	}

//-------------------------------------------------------------------------------------------------------------------	
void CLocalFileCB::WriteL(TInt aPos,TInt& aLength,const TAny* aDes,const RMessagePtr2& aMessage)
	{
	WriteL((TInt64)aPos, aLength, (TDesC8*)aDes, aMessage, 0);
	}

struct SRomMap
	{
	HBufC* iName;
	TUint8* iAddr;
	};
//-------------------------------------------------------------------------------------------------------------------	

TInt CLocalFileCB::RomAddress(const TDesC& aName, HANDLE aFile, TUint8*& aAddr)
	{
	static CArrayFixSeg<SRomMap>* gRomMap = new CArrayFixSeg<SRomMap>(64);
	for (TInt ii=0; ii<gRomMap->Count(); ii++)
		{
		if (*gRomMap->At(ii).iName == aName)
			{
			aAddr = gRomMap->At(ii).iAddr;
			return KErrNone;
			}
		}

	HANDLE fileMapping=CreateFileMappingA(aFile,NULL,PAGE_READONLY,0,0,NULL);
	if (fileMapping==0)
		return Emulator::LastError();
	aAddr=(TUint8*)MapViewOfFile(fileMapping,FILE_MAP_READ,0,0,0);
	SRomMap entry;
	entry.iAddr = aAddr;
	entry.iName = aName.Alloc();
	if (entry.iName)
		{
		TRAPD(ignore, gRomMap->AppendL(entry));
		}
	return KErrNone;
	}

//-------------------------------------------------------------------------------------------------------------------	
//
// If ROM file, do a memory map and return the address
//
TInt CLocalFileCB::Address(TInt& aPos) const
	{

	TBool isRomFile=IsRomDrive();
	if (!isRomFile)
		return(KErrNotSupported);
	
	if (aPos>Size64())
		return(KErrEof);
	if (iFilePtr==NULL)
		{
		CLocalFileCB* This=(CLocalFileCB*)this;
		TInt err = RomAddress(*iFileName, iWinHandle, This->iFilePtr);
		if (err)
			return err;
		}
	aPos=(TInt)((TUint8*)iFilePtr+aPos);
	return(KErrNone);
	}

//-------------------------------------------------------------------------------------------------------------------	
//
// Set the file size.
//
void CLocalFileCB::SetSizeL(TInt aSize)
	{
	SetSizeL(aSize);
	}

//-------------------------------------------------------------------------------------------------------------------	
//
// Set the entry's attributes and modified time.
//
void CLocalFileCB::SetEntryL(const TTime& aTime,TUint aSetAttMask,TUint aClearAttMask)
	{

	if (IsRomDrive())
		User::Leave(KErrAccessDenied);
	TUint setAttMask=aSetAttMask&KEntryAttMaskSupported;
	if (setAttMask|aClearAttMask)
		{
		iAtt|=setAttMask;
		iAtt&=(~aClearAttMask);
		iAtt|=KEntryAttModified;
		}
	if (aSetAttMask&KEntryAttModified)
		iModified=aTime;
	iAtt|=KEntryAttModified;
	}

//-------------------------------------------------------------------------------------------------------------------	
//
// Commit any buffered date to the media.
//
void CLocalFileCB::FlushAllL()
	{
	FlushDataL();
	}

//-------------------------------------------------------------------------------------------------------------------	
//
// Commit any buffered date to the media.
//
void CLocalFileCB::FlushDataL()
	{

	if (IsRomDrive())
		return;

	TFileName n;
	TInt driveNumber=Mount().Drive().DriveNumber();
	MapFileNameL(n,driveNumber,FileName());
	
    if(!Emulator::SetFileAttributes(StrPtrZL(n),iAtt&KEntryAttMaskSupported))
		User::Leave(Emulator::LastError()); //	Panic(EFileCloseSetAttributes);
	FILETIME f;
	timeToFileTimeL(iModified,&f);
	if (!SetFileTime(iWinHandle,&f,&f,&f))
		User::Leave(Emulator::LastError());

	iAtt&=(~KEntryAttModified);
	}

//-------------------------------------------------------------------------------------------------------------------	
//
// Rename the file while open
//
void CLocalFileCB::RenameL(const TDesC& aNewName)
	{

	TInt driveNumber=Mount().Drive().DriveNumber();

	TFileName n1;
	MapFileNameL(n1,driveNumber,FileName());
	TFileName n2;
	MapFileNameL(n2,driveNumber,aNewName);

	CloseHandle(iWinHandle);
	TInt ret=KErrNone;
	if (!Emulator::MoveFile(StrPtrZL(n1),StrPtrZL(n2)))
		{
		ret=Emulator::LastError();
		n2=n1;
		}
	DWORD access=GENERIC_READ|GENERIC_WRITE;
	DWORD share=FILE_SHARE_WRITE|FILE_SHARE_READ;
	DWORD create=OPEN_EXISTING;
	iWinHandle=Emulator::CreateFile(StrPtrZL(n2),access,share,NULL,create,FILE_FLAG_RANDOM_ACCESS,NULL);
	if (iWinHandle==INVALID_HANDLE_VALUE)
		User::Leave(Emulator::LastError());
	
	LARGE_INTEGER pos;
	pos.QuadPart = iCurrentPos;
	DWORD position = SetFilePointer(iWinHandle,pos.LowPart,&pos.HighPart,FILE_BEGIN);
	TInt r = Emulator::LastError();
	if ((KInvalidSetFilePointer == position) && (r != NO_ERROR))
		User::Leave(r);	
	
	User::LeaveIfError(ret);
	AllocBufferL(iFileName,aNewName);
	}

//-------------------------------------------------------------------------------------------------------------------	
TInt CLocalFileCB::GetInterface(TInt aInterfaceId,TAny*& aInterface,TAny* aInput)
	{
	switch(aInterfaceId)
		{
		case EExtendedFileInterface:
			((CFileCB::MExtendedFileInterface*&) aInterface) = this;
			return KErrNone;

		default:
			return CFileCB::GetInterface(aInterfaceId,aInterface,aInput);
		}
	}

//-------------------------------------------------------------------------------------------------------------------	
/**
    Read data from the file.
    
    @param  aFilePos    start read position within a file
    @param  aLength     how many bytes to read; on return will be how many bytes actually read
    @param  aDes        local buffer desctriptor
    @param  aMessage    from file server, used to write data to the buffer in different address space.
    @param  aDesOffset  offset within data descriptor where the data will be copied

    @leave on media read error

*/
void CLocalFileCB::ReadL(TInt64 aPos,TInt& aLength,TDes8* aDes,const RMessagePtr2& aMessage, TInt aOffset)
	{

	const TUint64 KMaxFilePosition = LocalMount().MaxFileSizeSupported()-1;
    

    if(KMaxFilePosition < (TUint64)aPos)
		User::Leave(KErrNotSupported);
	
	CheckPosL(aPos);
	TInt pos=0;
	TInt len=aLength;
	TBuf8<65536> buf;

	if (aMessage.Handle() == KLocalMessageHandle)
		((TPtr8* )aDes)->SetLength(0);

	while (len)
		{
		TInt s=Min(len,buf.MaxLength());
		DWORD res;
		BOOL b=ReadFile(iWinHandle,(TAny*)buf.Ptr(),s,&res,NULL);
		if(!b)
			User::Leave(Emulator::LastError());

		buf.SetLength(res);

	if (aMessage.Handle() == KLocalMessageHandle)
		((TPtr8* )aDes)->Append(buf);
	else
		aMessage.WriteL(0,buf,pos + aOffset);
	
		pos+=res;
		if (((TInt)res)<s)
			break;
		len-=s;
		}
	TInt delay = (ReadSpeed * aLength) >> 10;
	if (delay)
		User::AfterHighRes(delay);
	aLength=pos;
	iCurrentPos=aPos+pos;
	}

//-------------------------------------------------------------------------------------------------------------------	
/**
    Write data to the file.
    
    @param  aFilePos    start write position within a file
    @param  aLength     how many bytes to write; on return contain amount of data actually written
    @param  aDes        local buffer desctriptor
    @param  aMessage    from file server, used to write data to the media from different address space.
    @param  aDesOffset  offset within data descriptor 

    @leave on media read error

*/
void CLocalFileCB::WriteL(TInt64 aPos,TInt& aLength,const TDesC8* aDes,const RMessagePtr2& aMessage, TInt aOffset)
	{
	if (IsRomDrive())
		User::Leave(KErrAccessDenied);
	
	
    const TUint64 KMaxFileSize = LocalMount().MaxFileSizeSupported();
    const TUint64 KMaxFilePosition = KMaxFileSize - 1;

	if( KMaxFilePosition < (TUint64)aPos || KMaxFileSize < (TUint64)(aPos + aLength) )
		User::Leave(KErrNotSupported);
	
	CheckPosL(aPos);
	TInt pos=0;
	TInt len=aLength;
	TBuf8<65536> buf;

	while (len)
		{
		TInt s=Min(len,buf.MaxLength());

		if (aMessage.Handle() == KLocalMessageHandle)
			buf.Copy( ((TPtr8* )aDes)->MidTPtr(pos, s) );
		else
			aMessage.ReadL(0,buf,pos + aOffset);

		DWORD res;
		BOOL b=WriteFile(iWinHandle,buf.Ptr(),s,&res,NULL);
		
        if (!b)
			User::Leave(Emulator::LastError());

		if (((TInt)res)<s)
			User::Leave(KErrCorrupt);
		
        len-=s;
		pos+=s;
		}
	TInt delay = (WriteSpeed * aLength) >> 10;
	if (delay)
		User::AfterHighRes(delay);
	aLength=pos;
	iCurrentPos=aPos+pos;
	}

//-------------------------------------------------------------------------------------------------------------------	
/**
    Set file size.
    @param aSize new file size.
*/
void CLocalFileCB::SetSizeL(TInt64 aSize)
	{
    const TUint64 KMaxFileSize = LocalMount().MaxFileSizeSupported();

	if(KMaxFileSize < (TUint64)aSize)
		User::Leave(KErrNotSupported);
	
	CheckPosL(aSize);
	if(!SetEndOfFile(iWinHandle))
		{
		iCurrentPos= -1;
		User::Leave(Emulator::LastError());
		}

	SetSize64(aSize, EFalse);
	}

//#########################################################################################################################
//##        CLocalDirCB class implementation
//#########################################################################################################################

CLocalDirCB::CLocalDirCB()
	        :iEntry()
	{
	}

CLocalDirCB::~CLocalDirCB()
	{

	if (iWinHandle!=NULL && !FindClose(iWinHandle))
		Panic(EDirClose);
	}

//-------------------------------------------------------------------------------------------------------------------	
TBool CLocalDirCB::MatchUid()
	{

	if (iUidType[0]!=TUid::Null() || iUidType[1]!=TUid::Null() || iUidType[2]!=TUid::Null())
		return(ETrue);
	
    return(EFalse);
	}

//-------------------------------------------------------------------------------------------------------------------	
/** @return  ETrue if the aUidTrg matches aUidSuitor */
static TBool CompareUid(const TUidType& aUidTrg, const TUidType& aUidSuitor)
	{
	
	if (aUidTrg[0]!=TUid::Null() && aUidTrg[0]!=aUidSuitor[0])
		return(EFalse);
	if (aUidTrg[1]!=TUid::Null() && aUidTrg[1]!=aUidSuitor[1])
		return(EFalse);
	if (aUidTrg[2]!=TUid::Null() && aUidTrg[2]!=aUidSuitor[2])
		return(EFalse);
	return(ETrue);
	}

//-------------------------------------------------------------------------------------------------------------------	
/**
    Read current entry from the directory and move to the next one.
    This function must leave KErrEof when the end of directory is reached

    @param anEntry extracted directory entry
    @leave KErrEof when there are no more entries in the directory
           system-wide error code on media read fault.

*/
void CLocalDirCB::ReadL(TEntry& anEntry)
	{

	if (iWinHandle==NULL)
		User::Leave(KErrEof);

	FOREVER
		{
		if (!iPending)
			{
			WIN32_FIND_DATA info;
			if (!Emulator::FindNextFile(iWinHandle,&info))
				User::Leave(Emulator::LastError());

			iEntry.iName.Des()=(TText*)(&info.cFileName[0]);
			iEntry.iAtt=info.dwFileAttributes&KEntryAttMaskSupported;
			iEntry.SetFileSize(MAKE_TINT64(info.nFileSizeHigh,info.nFileSizeLow));
			fileTimeToTime(&info.ftLastWriteTime,iEntry.iModified);
			}
		iPending=EFalse;
		anEntry=iEntry;
		if (anEntry.iName==_L(".") || anEntry.iName==_L(".."))
			continue;
		if ((iFullName.NameAndExt()==_L("*.*") || iFullName.NameAndExt()==_L("*") || anEntry.iName.MatchF(iFullName.NameAndExt())!=KErrNotFound) && Mount().MatchEntryAtt(anEntry.iAtt&KEntryAttMaskSupported,iAtt))
			{
			if (MatchUid())
				{
				TParse fileName;
				TBuf<KMaxFileName> driveAndPath=iFullName.DriveAndPath();
				fileName.Set(anEntry.iName,&driveAndPath,NULL);
				(*(CLocalMountCB*)&Mount()).ReadUidL(fileName.FullName(),anEntry);
				if (CompareUid(iUidType,anEntry.iType))
					break;
				}
			else
				break;
			}
		}
	if ((iAtt&KEntryAttAllowUid)==0 || anEntry.iAtt&KEntryAttDir || MatchUid())
		return;
	TParse fileName;
	TBuf<KMaxFileName> driveAndPath=iFullName.DriveAndPath();
	fileName.Set(anEntry.iName,&driveAndPath,NULL);
	(*(CLocalMountCB*)&Mount()).ReadUidL(fileName.FullName(),anEntry);
	}

//#########################################################################################################################
//##        CLocalFormatCB class implementation
//#########################################################################################################################

CLocalFormatCB::CLocalFormatCB()
	{
	}

CLocalFormatCB::~CLocalFormatCB()
	{
	}

void CLocalFormatCB::DoFormatStepL()
	{
	iCurrentStep=0;
	User::Leave(KErrNotSupported);
	}


//#########################################################################################################################
//##        CLocal File System class implementation
//#########################################################################################################################

extern "C" 
{
//
// Create a new file system
//
EXPORT_C CFileSystem* CreateFileSystem()
	{
	return(new CLocal);
	}
}

CLocal::CLocal()
	{
	}

TInt CLocal::Install()
	{

	SetErrorMode(SEM_FAILCRITICALERRORS);
	EmulatorDiskSpeed(ReadSpeed, WriteSpeed);
	iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KF32BuildVersionNumber);
	_LIT(KWin32Name,"Win32");
	return(SetName(&KWin32Name));
	}

CMountCB* CLocal::NewMountL() const
//
// Create a new mount control block.
//
	{

	return(new(ELeave) CLocalMountCB);
	}

CFileCB* CLocal::NewFileL() const
//
// Create a new file.
//
	{

	return(new(ELeave) CLocalFileCB);
	}

CDirCB* CLocal::NewDirL() const
//
// Create a new directory lister.
//
	{
	return(new(ELeave) CLocalDirCB);
	}

CFormatCB* CLocal::NewFormatL() const
//
// Create a new media formatter.
//
	{
	return(new(ELeave) CLocalFormatCB);
	}

TInt CLocal::DefaultPath(TDes& aPath) const
//
// Return the initial default path.
//
	{
	aPath=_L("?:\\");
	aPath[0] = (TUint8) RFs::GetSystemDriveChar();
	return(KErrNone);
	}

void CLocal::DriveInfo(TDriveInfo& anInfo,TInt aDriveNumber) const
//
// Return the drive info.
//
	{

	anInfo.iMediaAtt=0;

// Get Fake drive info.
	if (aDriveNumber==EDriveZ)
		{
		anInfo.iType=EMediaRom;
		anInfo.iMediaAtt=KMediaAttWriteProtected;
		anInfo.iDriveAtt=KDriveAttRom|KDriveAttInternal;
		anInfo.iConnectionBusType=EConnectionBusInternal;
		return;
		}
	if (aDriveNumber==EDriveC)
		{
		anInfo.iType=EMediaHardDisk;
		anInfo.iMediaAtt=KMediaAttVariableSize;
		anInfo.iDriveAtt=KDriveAttLocal|KDriveAttInternal;
		anInfo.iConnectionBusType=EConnectionBusInternal;
		return;
		}
	TFileName envValue;
	if (MapDrive(envValue,aDriveNumber))
		{
		anInfo.iType=EMediaHardDisk;
		anInfo.iDriveAtt=KDriveAttLocal|KDriveAttInternal;
		anInfo.iConnectionBusType=EConnectionBusInternal;
		return;		
		}
	anInfo.iType=EMediaNotPresent;
	anInfo.iDriveAtt=0;
	}