emulator/emulatorbsp/win_drive/win_media_device.cpp
changeset 0 cec860690d41
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/emulator/emulatorbsp/win_drive/win_media_device.cpp	Tue Feb 02 01:39:10 2010 +0200
@@ -0,0 +1,1104 @@
+// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "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:
+// Implementation of the classes that work directly with the windows devices - files, drives etc.
+// 
+//
+
+/**
+ @file
+*/
+
+#include "win_media_device.h"
+
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
+#endif
+
+
+const TInt KDiskOpError = 0x134AFF78; ///< internal Disk operation error ID.
+
+
+static TBool CheckBufFill(const TPtrC8& aBufPtr, TUint8 aFill);
+
+//#########################################################################################################################
+//##        CWinMediaDeviceBase abstract base class implementation
+//#########################################################################################################################
+
+//-----------------------------------------------------------------------------
+
+CWinMediaDeviceBase::CWinMediaDeviceBase()
+{
+    iDevHandle = NULL;
+    ipScratchBuf = NULL;
+}
+
+CWinMediaDeviceBase::~CWinMediaDeviceBase()
+{
+    Disconnect();
+}
+
+
+/**
+    Disconnect from the media device
+*/
+void CWinMediaDeviceBase::Disconnect()
+{
+    FlushFileBuffers(iDevHandle);
+    CloseHandle(iDevHandle);
+    iDevHandle = NULL;
+    
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+    "Erase" a region of the media. Effectively just fills the selected region with the specified pattern.
+    
+    @param  aPos     media position start 
+    @param  aLength  length of the media region to fill
+    @param  aFill    filler byte.
+
+    @return EPOC error code.
+
+*/
+TInt CWinMediaDeviceBase::Erase(TInt64 aPos, TUint32 aLength, TUint8 aFill)
+{
+    //-- this method is called to "format" media.
+    //-- Because Windows is absolute sux on everythins that concerns formattin the media (IOCTL_DISK_FORMAT_TRACKS seems to be applicable only 
+    //-- to floppy disks) we have to perform formatting by just filling media region with a given byte.
+    //-- This can be very slow for flash - based removable media (e.g. usb flash drives) so, there is a possibility to check 
+    //-- if the given media region is already filled with the pattern and write only if not. See bCheckReadBeforeErase switch.
+    
+    Mem::Fill(ipScratchBuf, KScratchBufSz, aFill);
+    
+    TUint32 rem = aLength;
+    TInt nRes = KErrNone;
+
+    //-- if True, we firstly will read media region and check if it is already filled with the given byte. 
+    //-- this is useful for slow - write media or sparse files on NTFS.
+    //TBool bCheckReadBeforeErase = EFalse; 
+    TBool bCheckReadBeforeErase = ETrue; 
+    
+    while(rem)
+    {
+        const TUint32 bytesToWrite = Min(KScratchBufSz, rem);
+        TPtr8 ptrData(ipScratchBuf, bytesToWrite, bytesToWrite);
+
+        if(bCheckReadBeforeErase)
+        {//-- try to read data first and check if we need to write anything
+            ptrData.SetLength(0);
+            nRes = Read(aPos, bytesToWrite, ptrData);
+            if(nRes != KErrNone)
+                break;
+
+            if(!CheckBufFill(ptrData, aFill))
+            {
+                Mem::Fill(ipScratchBuf, KScratchBufSz, aFill);
+
+                nRes = Write(aPos, bytesToWrite, ptrData);
+                if(nRes != KErrNone)
+                    break;
+            
+            }
+        }
+        else
+        {//-- no need to read first
+            nRes = Write(aPos, bytesToWrite, ptrData);
+            if(nRes != KErrNone)
+                break;
+            
+        }
+        
+
+        rem-=bytesToWrite;
+        aPos+=bytesToWrite;
+           
+    }
+
+    
+    return nRes;
+}
+
+
+//#########################################################################################################################
+//##        CWinVolumeDevice  class implementation
+//#########################################################################################################################
+
+
+CWinVolumeDevice::CWinVolumeDevice()
+                 :CWinMediaDeviceBase()
+{
+    //-- create scratch buffer
+    ipScratchBuf = ::new TUint8[KScratchBufSz];
+    ASSERT(ipScratchBuf);
+}
+
+CWinVolumeDevice::~CWinVolumeDevice()
+{
+    delete ipScratchBuf;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+    Open the device and do some initalisation work.
+    
+    @param  aParams device parameters
+    @return Epoc error code, KErrNone if everything is OK
+*/
+TInt CWinVolumeDevice::Connect(const TMediaDeviceParams& aParams)
+{
+    
+    __PRINT(_L("#-- CWinVolumeDevice::Connect()"));    
+    
+    if(!aParams.ipDevName)
+    {
+        __LOG(_L("#-- CWinVolumeDevice::Connect() device name is not set!"));    
+        return KErrBadName;
+    }
+
+    __PRINTF(aParams.ipDevName);
+    
+    ASSERT(!HandleValid() && ipScratchBuf);
+
+    //-- open the device
+    DWORD dwAccess = GENERIC_READ;
+    
+    if(!aParams.iReadOnly)
+        dwAccess |= GENERIC_WRITE;  
+    
+    iDevHandle = CreateFileA(aParams.ipDevName,
+                             dwAccess, 
+                             FILE_SHARE_READ,
+                             (LPSECURITY_ATTRIBUTES)NULL,
+                             OPEN_EXISTING,
+                             FILE_ATTRIBUTE_NORMAL,
+                             NULL);
+
+    if(!HandleValid())
+    {
+        __LOG1(_L("#-- CWinVolumeDevice::Connect() Error creating device handle! WinErr:%d"), GetLastError());
+        return KErrGeneral;
+    }     
+    
+    //-- find out device geometry
+    iMediaType = Unknown;
+    iDrvGeometry.iBytesPerSector = KDefaultSectorSz;
+
+    DWORD junk; 
+
+    //-- 1. try to query disk geometry, but it can produce wrong results for partitioned media
+    BOOL bResult = DeviceIoControl(Handle(),
+                                   IOCTL_DISK_GET_DRIVE_GEOMETRY,
+                                   NULL, 0,
+                                   ipScratchBuf, KScratchBufSz,
+                                   &junk, (LPOVERLAPPED)NULL);
+
+    if(bResult)
+    {
+        const DISK_GEOMETRY& dg = (const DISK_GEOMETRY&)*ipScratchBuf;
+        
+        iDrvGeometry.iBytesPerSector = dg.BytesPerSector;
+        iMediaType = dg.MediaType;
+
+        __PRINT3(_L("#-- dev geometry: Cyl:%d Heads:%d Sectors:%d"), dg.Cylinders.LowPart, dg.TracksPerCylinder, dg.SectorsPerTrack);    
+        __PRINT2(_L("#-- dev geometry: MediaType:%d, bps:%d"), dg.MediaType, dg.BytesPerSector);    
+
+    }
+    else
+    {
+        iMediaType = Unknown;
+        iDrvGeometry.iBytesPerSector = KDefaultSectorSz;
+
+        __LOG1(_L("#-- CWinVolumeDevice::Connect() IOCTL_DISK_GET_DRIVE_GEOMETRY WinError:%d !"), GetLastError());
+    }
+
+    //-- 1.1 check "bytes per sector" value and how it corresponds to the request from parameters
+    if(aParams.iDrvGeometry.iBytesPerSector == 0)
+    {//-- do nothing, this parameter is not set in config file, use media's
+    } 
+    else if(aParams.iDrvGeometry.iBytesPerSector != iDrvGeometry.iBytesPerSector)
+    {//-- we can't set "SectorSize" value for the physical media
+        __LOG1(_L("#-- CWinVolumeDevice::Connect() can not use 'Sec. Size' value from config:%d !"), aParams.iDrvGeometry.iBytesPerSector);
+        Disconnect();
+        return KErrArgument;
+    }
+
+
+    ASSERT(IsPowerOf2(BytesPerSector()) && BytesPerSector() >= KDefaultSectorSz && BytesPerSector() < 4096);
+
+    //-- find out partition information in order to determine volume size. 
+    bResult = DeviceIoControl(Handle(),
+                              IOCTL_DISK_GET_PARTITION_INFO,
+                              NULL, 0,
+                              ipScratchBuf, KScratchBufSz,
+                              &junk, (LPOVERLAPPED)NULL);
+
+    if(!bResult)
+    {//-- this is a fatal error
+        __LOG1(_L("#-- CWinVolumeDevice::Connect() IOCTL_DISK_GET_PARTITION_INFO WinError:%d !"), GetLastError());
+        Disconnect();
+        return KErrBadHandle;    
+    }
+
+    //-- get partition informaton
+    const PARTITION_INFORMATION& pi = (const PARTITION_INFORMATION&)*ipScratchBuf;
+    TInt64 volSz = MAKE_TINT64(pi.PartitionLength.HighPart, pi.PartitionLength.LowPart);
+    iDrvGeometry.iSizeInSectors = (TUint32)(volSz / iDrvGeometry.iBytesPerSector);
+            
+    __LOG3(_L("#-- partition size, bytes:%LU (%uMB), sectors:%u"), volSz, (TUint32)(volSz>>20), iDrvGeometry.iSizeInSectors);
+   
+    //-- check if the media size is set in coonfig and if we can use this setting.
+    if(aParams.iDrvGeometry.iSizeInSectors == 0)
+    {//-- do nothing, the media size is not set in the ini file, use existing media parameters
+    }
+    else if(aParams.iDrvGeometry.iSizeInSectors > iDrvGeometry.iSizeInSectors)
+    {//-- requested media size in ini file is bigger than physical media, error.
+     //-- we can't increase physical media size
+    __LOG2(_L("#-- CWinVolumeDevice::Connect() 'MediaSizeSectors' value from config:%d > than physical:%d !"), aParams.iDrvGeometry.iSizeInSectors, iDrvGeometry.iSizeInSectors);
+    Disconnect();
+    return KErrArgument;
+    }
+    else if(aParams.iDrvGeometry.iSizeInSectors < iDrvGeometry.iSizeInSectors)
+    {//-- settings specify smaller media than physical one, adjust the size
+    __PRINT1(_L("#-- reducing media size to %d sectors"), aParams.iDrvGeometry.iSizeInSectors);
+    iDrvGeometry.iSizeInSectors = aParams.iDrvGeometry.iSizeInSectors;
+    }
+
+
+    ASSERT(iDrvGeometry.iSizeInSectors > KMinMediaSizeInSectors);
+    return KErrNone;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+    Read a portion of data from the device. 
+    Note: at present it _APPENDS_ data to the aDataDes, so the caller must take care of setting its length
+
+    @param  aPos     media position in bytes
+    @param  aLength  how many bytes to read
+    @param  aDataDes data descriptor
+
+    @return KErrNone on success, standard Epoc error code otherwise
+
+*/
+TInt CWinVolumeDevice::Read(TInt64 aPos, TInt aLength, TDes8& aDataDes)
+{
+    //__PRINT2(_L("#-- CWinVolumeDevice::Read, pos:%LU, len:%u"), aPos, aLength);
+ 
+    ASSERT(HandleValid());
+    ASSERT(aLength <= aDataDes.MaxLength());
+
+    //-- check position on the volume
+    const TInt64 maxPos = iDrvGeometry.TotalSizeInBytes();
+    if(aPos < 0 || aPos > maxPos)
+        return KErrArgument;
+
+    const TInt64 lastPos = aPos+aLength;
+
+    if(lastPos > maxPos)
+        return KErrArgument;
+    //--
+
+
+    TUint32 dataLen = aLength;
+
+    if(dataLen == 0)
+        return KErrNone;
+
+    DWORD dwRes;
+    DWORD dwBytesRead = 0;
+
+    //aDataDes.SetLength(0);
+
+    const TUint32 KSectorSize = BytesPerSector();
+    
+    try
+    {
+        LONG    mediaPosHi = I64HIGH(aPos);
+        const TUint32 mediaPosLo = I64LOW(aPos);
+        const TUint32 startPosOffset = mediaPosLo & (KSectorSize-1);
+        
+        //-- 1. position to the media with sector size granularity and read 1st sector
+        dwRes = SetFilePointer(iDevHandle, mediaPosLo-startPosOffset, &mediaPosHi, FILE_BEGIN);
+        if(dwRes == INVALID_SET_FILE_POINTER)
+            throw KDiskOpError;
+
+        //-- 1.1 read 1st sector
+        if(!ReadFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytesRead, NULL))
+            throw KDiskOpError;
+        
+        const TUint32 firstChunkLen = Min(dataLen, KSectorSize - startPosOffset);
+        aDataDes.Append(ipScratchBuf+startPosOffset, firstChunkLen);
+        dataLen-=firstChunkLen;
+
+        if(dataLen == 0)
+            return KErrNone; //-- no more data to read
+    
+        //-- 2. read whole number of sectors from the meida
+        const TUint32 KBytesTail = dataLen & (KSectorSize-1); //-- number of bytes in the incomplete last sector
+    
+        ASSERT((KScratchBufSz % KSectorSize) == 0);
+
+        TUint32 rem = dataLen - KBytesTail;
+        while(rem)
+        {
+            const TUint32 bytesToRead = Min(KScratchBufSz, rem);
+    
+            if(!ReadFile(iDevHandle, ipScratchBuf, bytesToRead, &dwBytesRead, NULL))
+                throw KDiskOpError;        
+ 
+            aDataDes.Append(ipScratchBuf, bytesToRead);
+            rem-=bytesToRead;
+        }
+
+        //-- 3. read the rest of the bytes in the incomplete last sector
+        if(KBytesTail)
+        {
+            if(!ReadFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytesRead, NULL))
+                throw KDiskOpError;    
+
+            aDataDes.Append(ipScratchBuf, KBytesTail);
+        }
+
+    }//try
+    catch(TInt nErrId)
+    {//-- some disk operation finished with the error
+        (void)nErrId;
+        ASSERT(nErrId == KDiskOpError);
+        const DWORD dwWinErr = GetLastError();
+        const TInt  epocErr = MapWinError(dwWinErr);
+        
+        __PRINT2(_L("#-- CWinVolumeDevice::Read() error! WinErr:%d, EpocErr:%d"), dwWinErr, epocErr);
+        ASSERT(epocErr != KErrNone);
+
+        return epocErr;
+    }
+
+    return KErrNone;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Write some data to the device.
+
+    @param  aPos     media position in bytes
+    @param  aLength  how many bytes to read
+    @param  aDataDes data descriptor
+
+    @return KErrNone on success, standard Epoc error code otherwise
+*/
+TInt CWinVolumeDevice::Write(TInt64 aPos, TInt aLength, const TDesC8& aDataDes)
+{
+    //__PRINT2(_L("#-- CWinVolumeDevice::Write, pos:%LU, len:%u"), aPos, aLength);
+
+    ASSERT(HandleValid());
+    
+    if(aLength == 0 || aDataDes.Length() == 0)
+        return KErrNone;
+
+    if(aLength > aDataDes.Length())
+    {
+        ASSERT(0);
+        return KErrArgument;
+    }
+
+    //-- check position on the volume
+    const TInt64 maxPos = iDrvGeometry.TotalSizeInBytes();
+    if(aPos < 0 || aPos > maxPos)
+        return KErrArgument;
+
+    const TInt64 lastPos = aPos+aLength;
+    if(lastPos > maxPos)
+        return KErrArgument;
+
+    TUint32 dataLen = aLength;
+
+    DWORD dwRes;
+    DWORD dwBytes = 0;
+    
+    const TUint32 KSectorSize = BytesPerSector();
+    const TUint8 *pData = aDataDes.Ptr();
+    
+    try
+    {
+        LONG    mediaPosHi = I64HIGH(aPos);
+        const TUint32 mediaPosLo = I64LOW(aPos);
+        const TUint32 startPosOffset = mediaPosLo & (KSectorSize-1);
+        const TUint32 sectorPos = mediaPosLo-startPosOffset;
+
+        //-- 1. position to the media with sector size granularity 
+        dwRes = SetFilePointer(iDevHandle, sectorPos, &mediaPosHi, FILE_BEGIN);
+        if(dwRes == INVALID_SET_FILE_POINTER)
+        {    
+            throw KDiskOpError;
+        }
+
+        if(startPosOffset || dataLen <= KSectorSize)
+        {//-- need a read-modify-write here.
+            //-- 1.1 read first sector
+            if(!ReadFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytes, NULL))
+                throw KDiskOpError;
+
+            dwRes = SetFilePointer(iDevHandle, sectorPos, &mediaPosHi, FILE_BEGIN);
+            if(dwRes == INVALID_SET_FILE_POINTER)
+            {    
+                throw KDiskOpError;
+            }
+
+
+            if(dwRes == INVALID_SET_FILE_POINTER)
+                throw KDiskOpError;
+
+            //-- 1.2 copy chunk of data there
+            const TUint32 firstChunkLen = Min(dataLen, KSectorSize - startPosOffset);
+            Mem::Copy(ipScratchBuf+startPosOffset, pData, firstChunkLen);
+            
+            //-- 1.3 write sector
+            if(!WriteFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytes, NULL))
+                throw KDiskOpError;
+
+
+            dataLen-=firstChunkLen;
+            pData+=firstChunkLen;
+
+            if(dataLen == 0)
+                return KErrNone; //-- no more data to write
+        }
+
+        //-- 2. write whole number of sectors to the media
+        const TUint32 KBytesTail = dataLen & (KSectorSize-1); //-- number of bytes in the incomplete last sector
+        TUint32 KMainChunkBytes = dataLen - KBytesTail;
+
+        ASSERT((KMainChunkBytes % KSectorSize) == 0);
+
+        //-- the pointer to the data shall be 2-bytes aligned, otherwise WriteFile will fail
+        if(!((DWORD)pData & 0x01))
+        {//-- data pointer aligned, ok
+            if(!WriteFile(iDevHandle, pData, KMainChunkBytes, &dwBytes, NULL))
+                throw KDiskOpError;
+        
+            pData+=KMainChunkBytes;
+            dataLen-=KMainChunkBytes;
+
+        }
+        else
+        {//-- data pointer is odd, we need to copy data to the aligned buffer
+            TUint32 rem = KMainChunkBytes;
+            while(rem)
+            {
+                const TUint32 nBytesToWrite = Min(KScratchBufSz, rem);
+                Mem::Copy(ipScratchBuf, pData, nBytesToWrite);
+            
+                if(!WriteFile(iDevHandle, ipScratchBuf, nBytesToWrite, &dwBytes, NULL))
+                    throw KDiskOpError;
+        
+                rem-=nBytesToWrite;
+                pData+=nBytesToWrite;
+                dataLen-=nBytesToWrite;
+            }
+
+        }
+
+
+        //-- 3. write the rest of the bytes into the incomplete last sector
+        if(KBytesTail)
+        {
+            //-- 3.1 read last sector
+            if(!ReadFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytes, NULL))
+                throw KDiskOpError;    
+
+            LARGE_INTEGER liRelOffset;
+            liRelOffset.QuadPart = -(LONG)KSectorSize;
+
+            //dwRes = SetFilePointer(iDevHandle, -(LONG)KSectorSize, NULL, FILE_CURRENT);
+            
+            dwRes = SetFilePointer(iDevHandle, liRelOffset.LowPart, &liRelOffset.HighPart, FILE_CURRENT);
+            if(dwRes == INVALID_SET_FILE_POINTER)
+                throw KDiskOpError;
+
+            //-- 1.2 copy chunk of data there
+            Mem::Copy(ipScratchBuf, pData, KBytesTail);
+
+            //-- 1.3 write sector
+            if(!WriteFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytes, NULL))
+                throw KDiskOpError;
+            
+        }
+
+
+    }//try
+    catch(TInt nErrId)
+    {//-- some disk operation finished with the error
+        (void)nErrId;
+        ASSERT(nErrId == KDiskOpError);
+        const DWORD dwWinErr = GetLastError();
+        const TInt  epocErr = MapWinError(dwWinErr);
+        
+        __PRINT2(_L("#-- CWinVolumeDevice::Write() error! WinErr:%d, EpocErr:%d"), dwWinErr, epocErr);
+        ASSERT(epocErr != KErrNone);
+        return epocErr;
+    }
+ 
+    return KErrNone;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+    Check if the buffer is filled with aFill character.
+    @param  aBufPtr buffer descriptor
+    @param  aFill filling character
+    @return ETrue if the buffer is filled with aFill byte.
+*/
+static TBool CheckBufFill(const TPtrC8& aBufPtr, TUint8 aFill)
+{
+    const TUint32 bufSz = (TUint32)aBufPtr.Size();
+    
+    //-- optimised by using DWORD granularity
+    if(bufSz % sizeof(TUint32) == 0)
+    {
+        TUint32 wordPattern = aFill;
+        wordPattern <<= 8; wordPattern |= aFill;
+        wordPattern <<= 8; wordPattern |= aFill;
+        wordPattern <<= 8; wordPattern |= aFill;
+
+        const TUint nWords = bufSz / sizeof(TUint32);
+        const TUint32* pWords = (const TUint32*) aBufPtr.Ptr();
+
+        for(TUint32 i=0; i<nWords; ++i)
+        {
+            if(pWords[i] != wordPattern)
+                return EFalse;
+        }
+
+        return ETrue;
+    }
+    
+    //-- dumb implementation
+    for(TUint32 i=0; i<bufSz; ++i)
+    {
+        if(aBufPtr[i] != aFill)
+            return EFalse;
+    }
+
+    return ETrue;
+}
+
+
+//#########################################################################################################################
+//##        CWinImgFileDevice  class implementation
+//#########################################################################################################################
+
+
+//-----------------------------------------------------------------------------
+
+CWinImgFileDevice::CWinImgFileDevice()
+                  :CWinMediaDeviceBase() 
+{
+
+    ihFileMapping = NULL;
+    ipImageFile  = NULL;
+
+    //-- create scratch buffer
+    ipScratchBuf = ::new TUint8[KScratchBufSz];
+    ASSERT(ipScratchBuf);
+
+}
+
+CWinImgFileDevice::~CWinImgFileDevice()
+{
+    delete ipScratchBuf;
+}
+
+//-----------------------------------------------------------------------------
+void CWinImgFileDevice::Disconnect()
+{
+    CloseHandle(ihFileMapping);
+    ihFileMapping = NULL;
+    ipImageFile  = NULL;
+
+    CWinMediaDeviceBase::Disconnect();
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Open the device and do some initalisation work.
+    
+    @param  aParams device parameters
+    @return Epoc error code, KErrNone if everything is OK
+*/
+TInt CWinImgFileDevice::Connect(const TMediaDeviceParams& aParams)
+{
+    __PRINT(_L("#-- CWinImgFileDevice::Connect()"));    
+    
+    if(!aParams.ipDevName)
+    {
+        __LOG(_L("#-- CWinImgFileDevice::Connect() device name is not set!"));    
+        return KErrBadName;
+    }
+    __PRINTF(aParams.ipDevName);
+    ASSERT(!HandleValid());
+
+    //-- 1. try to locate an image file by given name.
+    WIN32_FIND_DATAA wfd;
+    iDevHandle = FindFirstFileA(aParams.ipDevName, &wfd);
+
+    const TBool ImgFileAlreadyExists = HandleValid(iDevHandle);
+    
+    FindClose(iDevHandle);
+    iDevHandle = NULL;
+    
+    //-- sector size we will use within image file
+    const TUint32   sectorSizeToUse = (aParams.iDrvGeometry.iBytesPerSector == 0) ? KDefaultSectorSz : aParams.iDrvGeometry.iBytesPerSector; 
+          TUint32   fileSzInSectorsToUse = 0;
+
+    const TUint32   reqSizeSec = aParams.iDrvGeometry.iSizeInSectors; //-- required size in sectors
+    const DWORD     dwAccessMode = (aParams.iReadOnly) ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE;  
+
+    if(ImgFileAlreadyExists)
+    {//-- if the image file already exists, try to open it and optionally adjust its size
+        const TInt64    ImgFileSize = MAKE_TINT64(wfd.nFileSizeHigh, wfd.nFileSizeLow);
+        const TUint32   ImgFileSectors = (TUint32)(ImgFileSize / sectorSizeToUse);
+        const TBool     ImgFileIsRO = wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY;
+        
+        DWORD dwFileCreationMode = 0;
+        TBool bNeedToAdjustFileSize = EFalse;
+
+        if(reqSizeSec == 0 || reqSizeSec == ImgFileSectors)
+        {//-- the required size is either not specified (auto) or the same as the existing file has.
+         //-- we can just open this file
+         dwFileCreationMode = OPEN_EXISTING;
+         fileSzInSectorsToUse = ImgFileSectors;
+        }
+        else
+        {//-- we will have to overwrite the image file
+            if(ImgFileIsRO)
+            {//-- we won't be able to overwrite existing file.
+                __LOG(_L("#-- CWinImgFileDevice::Connect() unable to adjust image file size!"));    
+                return KErrAccessDenied;
+            }
+
+         fileSzInSectorsToUse = reqSizeSec;
+         dwFileCreationMode = CREATE_ALWAYS;
+         bNeedToAdjustFileSize = ETrue;
+        }
+
+        iDevHandle = CreateFileA(aParams.ipDevName,
+                                dwAccessMode, 
+                                FILE_SHARE_READ,
+                                (LPSECURITY_ATTRIBUTES)NULL,
+                                dwFileCreationMode,
+                                FILE_ATTRIBUTE_NORMAL,
+                                NULL);
+
+        if(!HandleValid(iDevHandle))
+        {
+            const DWORD winErr = GetLastError();
+            __LOG1(_L("#-- CWinImgFileDevice::Connect() Error opening/creating file! WinErr:%d"), winErr);
+            return MapWinError(winErr);
+        }     
+
+        //-- adjust file size if we need
+        if(bNeedToAdjustFileSize)
+        {
+            const TInt64 newFileSize = (TInt64)reqSizeSec * sectorSizeToUse;
+            ASSERT(newFileSize);
+
+            LONG  newFSzHi = I64HIGH(newFileSize);
+            DWORD dwRes = SetFilePointer(iDevHandle, I64LOW(newFileSize), &newFSzHi, FILE_BEGIN);
+            if(dwRes == INVALID_SET_FILE_POINTER || !SetEndOfFile(iDevHandle))
+            {
+                const DWORD winErr = GetLastError();
+                Disconnect();
+                __LOG1(_L("#-- CWinImgFileDevice::Connect() unable to set file size! WinErr:%d"), winErr);
+                return MapWinError(winErr);
+            }
+        }
+
+    }
+    else //if(ImgFileAlreadyExists)
+    {//-- if the image file does not exist or its size differs from required. try to create it
+       
+        if(reqSizeSec == 0)
+        {
+            __LOG(_L("#-- CWinImgFileDevice::Connect() The image file doesn't exist ant its size isn't specified!"));    
+            return KErrArgument;
+        }
+       
+        fileSzInSectorsToUse = reqSizeSec;
+
+        //-- create a new image file
+        iDevHandle = CreateFileA(aParams.ipDevName,
+                                GENERIC_READ | GENERIC_WRITE, 
+                                FILE_SHARE_READ,
+                                (LPSECURITY_ATTRIBUTES)NULL,
+                                CREATE_ALWAYS,
+                                FILE_ATTRIBUTE_NORMAL,
+                                NULL);
+
+        if(!HandleValid(iDevHandle))
+        {
+            const DWORD winErr = GetLastError();
+            __LOG1(_L("#-- CWinImgFileDevice::Connect() can not create file! WinErr:%d"), winErr);
+            return MapWinError(winErr);
+        }     
+
+        //-- set its size
+        const TInt64 newFileSize = (TInt64)reqSizeSec * sectorSizeToUse;
+        ASSERT(newFileSize);
+
+        LONG  newFSzHi = I64HIGH(newFileSize);
+        DWORD dwRes = SetFilePointer(iDevHandle, I64LOW(newFileSize), &newFSzHi, FILE_BEGIN);
+        if(dwRes == INVALID_SET_FILE_POINTER || !SetEndOfFile(iDevHandle))
+        {
+            const DWORD winErr = GetLastError();
+            Disconnect();
+            __LOG1(_L("#-- CWinImgFileDevice::Connect() unable to set file size! WinErr:%d"), winErr);
+            return MapWinError(winErr);
+        }
+
+        //-- if parametrs require a read-only file, reopen it in RO mode, it doesn't make a lot of sense though...
+        if(aParams.iReadOnly)
+        {
+            CloseHandle(iDevHandle);
+            iDevHandle = NULL;
+
+            iDevHandle = CreateFileA(aParams.ipDevName,
+                                GENERIC_READ , 
+                                FILE_SHARE_READ,
+                                (LPSECURITY_ATTRIBUTES)NULL,
+                                OPEN_EXISTING,
+                                FILE_ATTRIBUTE_NORMAL,
+                                NULL);
+
+            if(!HandleValid(iDevHandle))
+            {
+                const DWORD winErr = GetLastError();
+                __LOG1(_L("#-- CWinImgFileDevice::Connect() Can't reopen a file in RO mode! WinErr:%d"), winErr);
+                return MapWinError(winErr);
+            }     
+            
+        }//if(aParams.iReadOnly)
+
+    }//else if(ImgFileAlreadyExists)
+    
+    //-- here we must have the image file created/opened and with correct size
+    ASSERT(HandleValid());
+    ASSERT(sectorSizeToUse);
+
+    if(fileSzInSectorsToUse < KMinMediaSizeInSectors)
+    {
+        __LOG1(_L("#-- CWinImgFileDevice::Connect() Image file is too small!  sectors:%d"), fileSzInSectorsToUse);
+        Disconnect();
+        return KErrGeneral;     
+    }
+
+    iDrvGeometry.iBytesPerSector = sectorSizeToUse;
+    iDrvGeometry.iSizeInSectors  = fileSzInSectorsToUse;
+    
+    //-- map the image file into memory.
+    ASSERT(!HandleValid(ihFileMapping));
+    ASSERT(!ipImageFile);
+    
+    /*
+    don't map image file, because it can be > 4G.
+    ihFileMapping = CreateFileMapping(Handle(), NULL,
+                                      aParams.iReadOnly ? PAGE_READONLY : PAGE_READWRITE,
+                                      0, 0, NULL);
+    if(HandleValid(ihFileMapping))
+    {
+    ipImageFile = (TUint8*)MapViewOfFile(ihFileMapping, 
+                                         aParams.iReadOnly ? FILE_MAP_READ : FILE_MAP_WRITE,
+                                         0,0,0);
+    }
+
+    if(!ipImageFile)
+    {
+        __PRINT1(_L("#-- CWinImgFileDevice::Connect() Error mapping file! WinErr:%d"), GetLastError());
+        Disconnect();
+        return KErrGeneral;
+    }
+    */
+
+    return KErrNone;
+}
+
+
+/**
+    Read a portion of data from the device.
+    Note: at present it _APPENDS_ data to the aDataDes, so the caller must take care of setting its length
+
+    @param  aPos     media position in bytes
+    @param  aLength  how many bytes to read
+    @param  aDataDes data descriptor
+
+    @return KErrNone on success, standard Epoc error code otherwise
+
+*/
+TInt CWinImgFileDevice::Read(TInt64 aPos,TInt aLength, TDes8& aDataDes)
+{
+    
+    //__PRINT3(_L("#-- CWinImgFileDevice::Read, pos:%LU, len:%u, desMaxLen:%u"), aPos, aLength, aDataDes.MaxLength());
+
+    ASSERT(HandleValid());
+    ASSERT(aLength <= aDataDes.MaxLength());
+
+    //-- check position on the volume
+    const TInt64 maxPos = iDrvGeometry.TotalSizeInBytes();
+    if(aPos < 0 || aPos > maxPos)
+        return KErrArgument;
+
+    const TInt64 lastPos = aPos+aLength;
+    if(lastPos > maxPos)
+        return KErrArgument;
+
+    TUint32 dataLen = aLength;
+
+    if(dataLen == 0)
+        return KErrNone;
+
+    DWORD dwRes;
+    DWORD dwBytesRead = 0;
+
+    //aDataDes.SetLength(0);
+
+    try
+    {
+        //-- 1. position to the media 
+        LONG  mediaPosHi = I64HIGH(aPos);
+        const TUint32 mediaPosLo = I64LOW(aPos);
+
+        dwRes = SetFilePointer(iDevHandle, mediaPosLo, &mediaPosHi, FILE_BEGIN);
+        if(dwRes == INVALID_SET_FILE_POINTER)
+            throw KDiskOpError;
+
+
+        //-- 2. read data to the scratch buffer and copy it to the descriptor.
+        ASSERT(ipScratchBuf);
+
+        TUint32 rem = dataLen;
+        
+        while(rem)
+        {
+            const TUint32 bytesToRead = Min(KScratchBufSz, rem);
+            if(!ReadFile(iDevHandle, ipScratchBuf, bytesToRead, &dwBytesRead, NULL))
+                throw KDiskOpError;
+
+            aDataDes.Append(ipScratchBuf, bytesToRead);
+            rem-=bytesToRead;
+        }
+
+    }
+    catch(TInt nErrId)
+    {//-- some disk operation finished with the error
+        (void)nErrId;
+        ASSERT(nErrId == KDiskOpError);
+        const DWORD dwWinErr = GetLastError();
+        const TInt  epocErr = MapWinError(dwWinErr);
+        
+        __PRINT2(_L("#-- CWinImgFileDevice::Read() error! WinErr:%d, EpocErr:%d"), dwWinErr, epocErr);
+        ASSERT(epocErr != KErrNone);
+
+        return epocErr;
+    }
+
+
+    return KErrNone;
+}
+
+/**
+    Write some data to the device.
+
+    @param  aPos     media position in bytes
+    @param  aLength  how many bytes to read
+    @param  aDataDes data descriptor
+
+    @return KErrNone on success, standard Epoc error code otherwise
+*/
+TInt CWinImgFileDevice::Write(TInt64 aPos, TInt aLength, const TDesC8& aDataDes)
+{
+    //__PRINT3(_L("#-- CWinImgFileDevice::Write, pos:%LU, len:%u, desLen:%u" ), aPos, aLength, aDataDes.Length());
+
+    ASSERT(HandleValid());
+
+
+    if(aLength == 0 || aDataDes.Length() == 0)
+        return KErrNone;
+
+    if(aLength > aDataDes.Length())
+    {
+        ASSERT(0);
+        return KErrArgument;
+    }
+
+    //-- check position on the volume
+    const TInt64 maxPos = iDrvGeometry.TotalSizeInBytes();
+    if(aPos < 0 || aPos > maxPos)
+        return KErrArgument;
+
+    const TInt64 lastPos = aPos+aLength;
+
+    if(lastPos > maxPos)
+        return KErrArgument;
+
+    TUint32 dataLen = aLength;
+
+
+    DWORD dwRes;
+    DWORD dwBytes = 0;
+    
+    const TUint8 *pData = aDataDes.Ptr();
+
+    try
+    {
+        //-- 1. position to the media
+        LONG  mediaPosHi = I64HIGH(aPos);
+        const TUint32 mediaPosLo = I64LOW(aPos);
+        dwRes = SetFilePointer(iDevHandle, mediaPosLo, &mediaPosHi, FILE_BEGIN);
+        if(dwRes == INVALID_SET_FILE_POINTER)
+        {    
+            throw KDiskOpError;
+        }
+    
+        //-- 2. write data to the media
+        //-- check if the pointer is word-aligned
+        const DWORD dwPtrMask = 0x01;
+        
+        if( (DWORD)pData & dwPtrMask)
+        {//-- data pointer isn't aligned, write non-aligned bytes through buffer
+            ASSERT(dataLen);
+
+            const int oddCnt = 1;
+            ipScratchBuf[0] = *pData;
+
+            ++pData;
+            --dataLen;
+
+            if(!WriteFile(iDevHandle, ipScratchBuf, oddCnt, &dwBytes, NULL))
+                throw KDiskOpError;
+        }
+        
+        ASSERT(!((DWORD)pData & dwPtrMask));
+        if(dataLen > 0)
+        {
+            if(!WriteFile(iDevHandle, pData, dataLen, &dwBytes, NULL))
+                throw KDiskOpError;
+        }
+    
+    }
+    catch(TInt nErrId)
+    {//-- some disk operation finished with the error
+        (void)nErrId;
+        ASSERT(nErrId == KDiskOpError);
+        const DWORD dwWinErr = GetLastError();
+        const TInt  epocErr = MapWinError(dwWinErr);
+        
+        __PRINT2(_L("#-- CWinImgFileDevice::Write() error! WinErr:%d, EpocErr:%d"), dwWinErr, epocErr);
+        ASSERT(epocErr != KErrNone);
+        return epocErr;
+    }
+
+
+    
+    return KErrNone;
+}
+
+
+//-----------------------------------------------------------------------------
+
+/**
+    Make the best effort to map Windows error codes (from GetLastError()) to Epos ones.
+    
+    @param aWinError MS Windows error code
+    @return corresponding EPOC eror code
+*/
+
+TInt CWinMediaDeviceBase::MapWinError(DWORD aWinError) const
+{
+    switch(aWinError)
+    {
+        case NO_ERROR:
+        return KErrNone;
+                          
+        case ERROR_NOT_READY:
+        return KErrNotReady;
+        
+        case ERROR_WRITE_PROTECT:
+        case ERROR_ACCESS_DENIED:
+        return KErrAccessDenied;
+        
+        case ERROR_INVALID_HANDLE:
+        return KErrBadHandle;
+        
+        case ERROR_NOT_ENOUGH_MEMORY:
+        return KErrNoMemory;
+        
+        case ERROR_OUTOFMEMORY:
+        return KErrDiskFull;
+                                        
+        case ERROR_CRC:
+        return KErrCorrupt;
+
+        case ERROR_WRITE_FAULT:
+        return KErrWrite;
+
+        case ERROR_GEN_FAILURE:
+        return KErrGeneral;
+
+        case ERROR_LOCK_VIOLATION:
+        return KErrLocked;
+
+        case ERROR_SHARING_VIOLATION:
+        return KErrInUse;
+
+        case ERROR_NOT_SUPPORTED:
+        return KErrNotSupported;
+
+        default:
+        return KErrGeneral;
+    
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+