--- /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;
+
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+