os/boardsupport/emulator/emulatorbsp/win_drive/win_media_device.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // Implementation of the classes that work directly with the windows devices - files, drives etc.
    15 // 
    16 //
    17 
    18 /**
    19  @file
    20 */
    21 
    22 #include "win_media_device.h"
    23 
    24 #ifndef INVALID_SET_FILE_POINTER
    25 #define INVALID_SET_FILE_POINTER 0xFFFFFFFF
    26 #endif
    27 
    28 
    29 const TInt KDiskOpError = 0x134AFF78; ///< internal Disk operation error ID.
    30 
    31 
    32 static TBool CheckBufFill(const TPtrC8& aBufPtr, TUint8 aFill);
    33 
    34 //#########################################################################################################################
    35 //##        CWinMediaDeviceBase abstract base class implementation
    36 //#########################################################################################################################
    37 
    38 //-----------------------------------------------------------------------------
    39 
    40 CWinMediaDeviceBase::CWinMediaDeviceBase()
    41 {
    42     iDevHandle = NULL;
    43     ipScratchBuf = NULL;
    44 }
    45 
    46 CWinMediaDeviceBase::~CWinMediaDeviceBase()
    47 {
    48     Disconnect();
    49 }
    50 
    51 
    52 /**
    53     Disconnect from the media device
    54 */
    55 void CWinMediaDeviceBase::Disconnect()
    56 {
    57     FlushFileBuffers(iDevHandle);
    58     CloseHandle(iDevHandle);
    59     iDevHandle = NULL;
    60     
    61 }
    62 
    63 //-----------------------------------------------------------------------------
    64 
    65 /**
    66     "Erase" a region of the media. Effectively just fills the selected region with the specified pattern.
    67     
    68     @param  aPos     media position start 
    69     @param  aLength  length of the media region to fill
    70     @param  aFill    filler byte.
    71 
    72     @return EPOC error code.
    73 
    74 */
    75 TInt CWinMediaDeviceBase::Erase(TInt64 aPos, TUint32 aLength, TUint8 aFill)
    76 {
    77     //-- this method is called to "format" media.
    78     //-- Because Windows is absolute sux on everythins that concerns formattin the media (IOCTL_DISK_FORMAT_TRACKS seems to be applicable only 
    79     //-- to floppy disks) we have to perform formatting by just filling media region with a given byte.
    80     //-- This can be very slow for flash - based removable media (e.g. usb flash drives) so, there is a possibility to check 
    81     //-- if the given media region is already filled with the pattern and write only if not. See bCheckReadBeforeErase switch.
    82     
    83     Mem::Fill(ipScratchBuf, KScratchBufSz, aFill);
    84     
    85     TUint32 rem = aLength;
    86     TInt nRes = KErrNone;
    87 
    88     //-- if True, we firstly will read media region and check if it is already filled with the given byte. 
    89     //-- this is useful for slow - write media or sparse files on NTFS.
    90     //TBool bCheckReadBeforeErase = EFalse; 
    91     TBool bCheckReadBeforeErase = ETrue; 
    92     
    93     while(rem)
    94     {
    95         const TUint32 bytesToWrite = Min(KScratchBufSz, rem);
    96         TPtr8 ptrData(ipScratchBuf, bytesToWrite, bytesToWrite);
    97 
    98         if(bCheckReadBeforeErase)
    99         {//-- try to read data first and check if we need to write anything
   100             ptrData.SetLength(0);
   101             nRes = Read(aPos, bytesToWrite, ptrData);
   102             if(nRes != KErrNone)
   103                 break;
   104 
   105             if(!CheckBufFill(ptrData, aFill))
   106             {
   107                 Mem::Fill(ipScratchBuf, KScratchBufSz, aFill);
   108 
   109                 nRes = Write(aPos, bytesToWrite, ptrData);
   110                 if(nRes != KErrNone)
   111                     break;
   112             
   113             }
   114         }
   115         else
   116         {//-- no need to read first
   117             nRes = Write(aPos, bytesToWrite, ptrData);
   118             if(nRes != KErrNone)
   119                 break;
   120             
   121         }
   122         
   123 
   124         rem-=bytesToWrite;
   125         aPos+=bytesToWrite;
   126            
   127     }
   128 
   129     
   130     return nRes;
   131 }
   132 
   133 
   134 //#########################################################################################################################
   135 //##        CWinVolumeDevice  class implementation
   136 //#########################################################################################################################
   137 
   138 
   139 CWinVolumeDevice::CWinVolumeDevice()
   140                  :CWinMediaDeviceBase()
   141 {
   142     //-- create scratch buffer
   143     ipScratchBuf = ::new TUint8[KScratchBufSz];
   144     ASSERT(ipScratchBuf);
   145 }
   146 
   147 CWinVolumeDevice::~CWinVolumeDevice()
   148 {
   149     delete ipScratchBuf;
   150 }
   151 
   152 //-----------------------------------------------------------------------------
   153 
   154 /**
   155     Open the device and do some initalisation work.
   156     
   157     @param  aParams device parameters
   158     @return Epoc error code, KErrNone if everything is OK
   159 */
   160 TInt CWinVolumeDevice::Connect(const TMediaDeviceParams& aParams)
   161 {
   162     
   163     __PRINT(_L("#-- CWinVolumeDevice::Connect()"));    
   164     
   165     if(!aParams.ipDevName)
   166     {
   167         __LOG(_L("#-- CWinVolumeDevice::Connect() device name is not set!"));    
   168         return KErrBadName;
   169     }
   170 
   171     __PRINTF(aParams.ipDevName);
   172     
   173     ASSERT(!HandleValid() && ipScratchBuf);
   174 
   175     //-- open the device
   176     DWORD dwAccess = GENERIC_READ;
   177     
   178     if(!aParams.iReadOnly)
   179         dwAccess |= GENERIC_WRITE;  
   180     
   181     iDevHandle = CreateFileA(aParams.ipDevName,
   182                              dwAccess, 
   183                              FILE_SHARE_READ,
   184                              (LPSECURITY_ATTRIBUTES)NULL,
   185                              OPEN_EXISTING,
   186                              FILE_ATTRIBUTE_NORMAL,
   187                              NULL);
   188 
   189     if(!HandleValid())
   190     {
   191         __LOG1(_L("#-- CWinVolumeDevice::Connect() Error creating device handle! WinErr:%d"), GetLastError());
   192         return KErrGeneral;
   193     }     
   194     
   195     //-- find out device geometry
   196     iMediaType = Unknown;
   197     iDrvGeometry.iBytesPerSector = KDefaultSectorSz;
   198 
   199     DWORD junk; 
   200 
   201     //-- 1. try to query disk geometry, but it can produce wrong results for partitioned media
   202     BOOL bResult = DeviceIoControl(Handle(),
   203                                    IOCTL_DISK_GET_DRIVE_GEOMETRY,
   204                                    NULL, 0,
   205                                    ipScratchBuf, KScratchBufSz,
   206                                    &junk, (LPOVERLAPPED)NULL);
   207 
   208     if(bResult)
   209     {
   210         const DISK_GEOMETRY& dg = (const DISK_GEOMETRY&)*ipScratchBuf;
   211         
   212         iDrvGeometry.iBytesPerSector = dg.BytesPerSector;
   213         iMediaType = dg.MediaType;
   214 
   215         __PRINT3(_L("#-- dev geometry: Cyl:%d Heads:%d Sectors:%d"), dg.Cylinders.LowPart, dg.TracksPerCylinder, dg.SectorsPerTrack);    
   216         __PRINT2(_L("#-- dev geometry: MediaType:%d, bps:%d"), dg.MediaType, dg.BytesPerSector);    
   217 
   218     }
   219     else
   220     {
   221         iMediaType = Unknown;
   222         iDrvGeometry.iBytesPerSector = KDefaultSectorSz;
   223 
   224         __LOG1(_L("#-- CWinVolumeDevice::Connect() IOCTL_DISK_GET_DRIVE_GEOMETRY WinError:%d !"), GetLastError());
   225     }
   226 
   227     //-- 1.1 check "bytes per sector" value and how it corresponds to the request from parameters
   228     if(aParams.iDrvGeometry.iBytesPerSector == 0)
   229     {//-- do nothing, this parameter is not set in config file, use media's
   230     } 
   231     else if(aParams.iDrvGeometry.iBytesPerSector != iDrvGeometry.iBytesPerSector)
   232     {//-- we can't set "SectorSize" value for the physical media
   233         __LOG1(_L("#-- CWinVolumeDevice::Connect() can not use 'Sec. Size' value from config:%d !"), aParams.iDrvGeometry.iBytesPerSector);
   234         Disconnect();
   235         return KErrArgument;
   236     }
   237 
   238 
   239     ASSERT(IsPowerOf2(BytesPerSector()) && BytesPerSector() >= KDefaultSectorSz && BytesPerSector() < 4096);
   240 
   241     //-- find out partition information in order to determine volume size. 
   242     bResult = DeviceIoControl(Handle(),
   243                               IOCTL_DISK_GET_PARTITION_INFO,
   244                               NULL, 0,
   245                               ipScratchBuf, KScratchBufSz,
   246                               &junk, (LPOVERLAPPED)NULL);
   247 
   248     if(!bResult)
   249     {//-- this is a fatal error
   250         __LOG1(_L("#-- CWinVolumeDevice::Connect() IOCTL_DISK_GET_PARTITION_INFO WinError:%d !"), GetLastError());
   251         Disconnect();
   252         return KErrBadHandle;    
   253     }
   254 
   255     //-- get partition informaton
   256     const PARTITION_INFORMATION& pi = (const PARTITION_INFORMATION&)*ipScratchBuf;
   257     TInt64 volSz = MAKE_TINT64(pi.PartitionLength.HighPart, pi.PartitionLength.LowPart);
   258     iDrvGeometry.iSizeInSectors = (TUint32)(volSz / iDrvGeometry.iBytesPerSector);
   259             
   260     __LOG3(_L("#-- partition size, bytes:%LU (%uMB), sectors:%u"), volSz, (TUint32)(volSz>>20), iDrvGeometry.iSizeInSectors);
   261    
   262     //-- check if the media size is set in coonfig and if we can use this setting.
   263     if(aParams.iDrvGeometry.iSizeInSectors == 0)
   264     {//-- do nothing, the media size is not set in the ini file, use existing media parameters
   265     }
   266     else if(aParams.iDrvGeometry.iSizeInSectors > iDrvGeometry.iSizeInSectors)
   267     {//-- requested media size in ini file is bigger than physical media, error.
   268      //-- we can't increase physical media size
   269     __LOG2(_L("#-- CWinVolumeDevice::Connect() 'MediaSizeSectors' value from config:%d > than physical:%d !"), aParams.iDrvGeometry.iSizeInSectors, iDrvGeometry.iSizeInSectors);
   270     Disconnect();
   271     return KErrArgument;
   272     }
   273     else if(aParams.iDrvGeometry.iSizeInSectors < iDrvGeometry.iSizeInSectors)
   274     {//-- settings specify smaller media than physical one, adjust the size
   275     __PRINT1(_L("#-- reducing media size to %d sectors"), aParams.iDrvGeometry.iSizeInSectors);
   276     iDrvGeometry.iSizeInSectors = aParams.iDrvGeometry.iSizeInSectors;
   277     }
   278 
   279 
   280     ASSERT(iDrvGeometry.iSizeInSectors > KMinMediaSizeInSectors);
   281     return KErrNone;
   282 }
   283 
   284 //-----------------------------------------------------------------------------
   285 
   286 /**
   287     Read a portion of data from the device. 
   288     Note: at present it _APPENDS_ data to the aDataDes, so the caller must take care of setting its length
   289 
   290     @param  aPos     media position in bytes
   291     @param  aLength  how many bytes to read
   292     @param  aDataDes data descriptor
   293 
   294     @return KErrNone on success, standard Epoc error code otherwise
   295 
   296 */
   297 TInt CWinVolumeDevice::Read(TInt64 aPos, TInt aLength, TDes8& aDataDes)
   298 {
   299     //__PRINT2(_L("#-- CWinVolumeDevice::Read, pos:%LU, len:%u"), aPos, aLength);
   300  
   301     ASSERT(HandleValid());
   302     ASSERT(aLength <= aDataDes.MaxLength());
   303 
   304     //-- check position on the volume
   305     const TInt64 maxPos = iDrvGeometry.TotalSizeInBytes();
   306     if(aPos < 0 || aPos > maxPos)
   307         return KErrArgument;
   308 
   309     const TInt64 lastPos = aPos+aLength;
   310 
   311     if(lastPos > maxPos)
   312         return KErrArgument;
   313     //--
   314 
   315 
   316     TUint32 dataLen = aLength;
   317 
   318     if(dataLen == 0)
   319         return KErrNone;
   320 
   321     DWORD dwRes;
   322     DWORD dwBytesRead = 0;
   323 
   324     //aDataDes.SetLength(0);
   325 
   326     const TUint32 KSectorSize = BytesPerSector();
   327     
   328     try
   329     {
   330         LONG    mediaPosHi = I64HIGH(aPos);
   331         const TUint32 mediaPosLo = I64LOW(aPos);
   332         const TUint32 startPosOffset = mediaPosLo & (KSectorSize-1);
   333         
   334         //-- 1. position to the media with sector size granularity and read 1st sector
   335         dwRes = SetFilePointer(iDevHandle, mediaPosLo-startPosOffset, &mediaPosHi, FILE_BEGIN);
   336         if(dwRes == INVALID_SET_FILE_POINTER)
   337             throw KDiskOpError;
   338 
   339         //-- 1.1 read 1st sector
   340         if(!ReadFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytesRead, NULL))
   341             throw KDiskOpError;
   342         
   343         const TUint32 firstChunkLen = Min(dataLen, KSectorSize - startPosOffset);
   344         aDataDes.Append(ipScratchBuf+startPosOffset, firstChunkLen);
   345         dataLen-=firstChunkLen;
   346 
   347         if(dataLen == 0)
   348             return KErrNone; //-- no more data to read
   349     
   350         //-- 2. read whole number of sectors from the meida
   351         const TUint32 KBytesTail = dataLen & (KSectorSize-1); //-- number of bytes in the incomplete last sector
   352     
   353         ASSERT((KScratchBufSz % KSectorSize) == 0);
   354 
   355         TUint32 rem = dataLen - KBytesTail;
   356         while(rem)
   357         {
   358             const TUint32 bytesToRead = Min(KScratchBufSz, rem);
   359     
   360             if(!ReadFile(iDevHandle, ipScratchBuf, bytesToRead, &dwBytesRead, NULL))
   361                 throw KDiskOpError;        
   362  
   363             aDataDes.Append(ipScratchBuf, bytesToRead);
   364             rem-=bytesToRead;
   365         }
   366 
   367         //-- 3. read the rest of the bytes in the incomplete last sector
   368         if(KBytesTail)
   369         {
   370             if(!ReadFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytesRead, NULL))
   371                 throw KDiskOpError;    
   372 
   373             aDataDes.Append(ipScratchBuf, KBytesTail);
   374         }
   375 
   376     }//try
   377     catch(TInt nErrId)
   378     {//-- some disk operation finished with the error
   379         (void)nErrId;
   380         ASSERT(nErrId == KDiskOpError);
   381         const DWORD dwWinErr = GetLastError();
   382         const TInt  epocErr = MapWinError(dwWinErr);
   383         
   384         __PRINT2(_L("#-- CWinVolumeDevice::Read() error! WinErr:%d, EpocErr:%d"), dwWinErr, epocErr);
   385         ASSERT(epocErr != KErrNone);
   386 
   387         return epocErr;
   388     }
   389 
   390     return KErrNone;
   391 }
   392 
   393 //-----------------------------------------------------------------------------
   394 /**
   395     Write some data to the device.
   396 
   397     @param  aPos     media position in bytes
   398     @param  aLength  how many bytes to read
   399     @param  aDataDes data descriptor
   400 
   401     @return KErrNone on success, standard Epoc error code otherwise
   402 */
   403 TInt CWinVolumeDevice::Write(TInt64 aPos, TInt aLength, const TDesC8& aDataDes)
   404 {
   405     //__PRINT2(_L("#-- CWinVolumeDevice::Write, pos:%LU, len:%u"), aPos, aLength);
   406 
   407     ASSERT(HandleValid());
   408     
   409     if(aLength == 0 || aDataDes.Length() == 0)
   410         return KErrNone;
   411 
   412     if(aLength > aDataDes.Length())
   413     {
   414         ASSERT(0);
   415         return KErrArgument;
   416     }
   417 
   418     //-- check position on the volume
   419     const TInt64 maxPos = iDrvGeometry.TotalSizeInBytes();
   420     if(aPos < 0 || aPos > maxPos)
   421         return KErrArgument;
   422 
   423     const TInt64 lastPos = aPos+aLength;
   424     if(lastPos > maxPos)
   425         return KErrArgument;
   426 
   427     TUint32 dataLen = aLength;
   428 
   429     DWORD dwRes;
   430     DWORD dwBytes = 0;
   431     
   432     const TUint32 KSectorSize = BytesPerSector();
   433     const TUint8 *pData = aDataDes.Ptr();
   434     
   435     try
   436     {
   437         LONG    mediaPosHi = I64HIGH(aPos);
   438         const TUint32 mediaPosLo = I64LOW(aPos);
   439         const TUint32 startPosOffset = mediaPosLo & (KSectorSize-1);
   440         const TUint32 sectorPos = mediaPosLo-startPosOffset;
   441 
   442         //-- 1. position to the media with sector size granularity 
   443         dwRes = SetFilePointer(iDevHandle, sectorPos, &mediaPosHi, FILE_BEGIN);
   444         if(dwRes == INVALID_SET_FILE_POINTER)
   445         {    
   446             throw KDiskOpError;
   447         }
   448 
   449         if(startPosOffset || dataLen <= KSectorSize)
   450         {//-- need a read-modify-write here.
   451             //-- 1.1 read first sector
   452             if(!ReadFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytes, NULL))
   453                 throw KDiskOpError;
   454 
   455             dwRes = SetFilePointer(iDevHandle, sectorPos, &mediaPosHi, FILE_BEGIN);
   456             if(dwRes == INVALID_SET_FILE_POINTER)
   457             {    
   458                 throw KDiskOpError;
   459             }
   460 
   461 
   462             if(dwRes == INVALID_SET_FILE_POINTER)
   463                 throw KDiskOpError;
   464 
   465             //-- 1.2 copy chunk of data there
   466             const TUint32 firstChunkLen = Min(dataLen, KSectorSize - startPosOffset);
   467             Mem::Copy(ipScratchBuf+startPosOffset, pData, firstChunkLen);
   468             
   469             //-- 1.3 write sector
   470             if(!WriteFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytes, NULL))
   471                 throw KDiskOpError;
   472 
   473 
   474             dataLen-=firstChunkLen;
   475             pData+=firstChunkLen;
   476 
   477             if(dataLen == 0)
   478                 return KErrNone; //-- no more data to write
   479         }
   480 
   481         //-- 2. write whole number of sectors to the media
   482         const TUint32 KBytesTail = dataLen & (KSectorSize-1); //-- number of bytes in the incomplete last sector
   483         TUint32 KMainChunkBytes = dataLen - KBytesTail;
   484 
   485         ASSERT((KMainChunkBytes % KSectorSize) == 0);
   486 
   487         //-- the pointer to the data shall be 2-bytes aligned, otherwise WriteFile will fail
   488         if(!((DWORD)pData & 0x01))
   489         {//-- data pointer aligned, ok
   490             if(!WriteFile(iDevHandle, pData, KMainChunkBytes, &dwBytes, NULL))
   491                 throw KDiskOpError;
   492         
   493             pData+=KMainChunkBytes;
   494             dataLen-=KMainChunkBytes;
   495 
   496         }
   497         else
   498         {//-- data pointer is odd, we need to copy data to the aligned buffer
   499             TUint32 rem = KMainChunkBytes;
   500             while(rem)
   501             {
   502                 const TUint32 nBytesToWrite = Min(KScratchBufSz, rem);
   503                 Mem::Copy(ipScratchBuf, pData, nBytesToWrite);
   504             
   505                 if(!WriteFile(iDevHandle, ipScratchBuf, nBytesToWrite, &dwBytes, NULL))
   506                     throw KDiskOpError;
   507         
   508                 rem-=nBytesToWrite;
   509                 pData+=nBytesToWrite;
   510                 dataLen-=nBytesToWrite;
   511             }
   512 
   513         }
   514 
   515 
   516         //-- 3. write the rest of the bytes into the incomplete last sector
   517         if(KBytesTail)
   518         {
   519             //-- 3.1 read last sector
   520             if(!ReadFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytes, NULL))
   521                 throw KDiskOpError;    
   522 
   523             LARGE_INTEGER liRelOffset;
   524             liRelOffset.QuadPart = -(LONG)KSectorSize;
   525 
   526             //dwRes = SetFilePointer(iDevHandle, -(LONG)KSectorSize, NULL, FILE_CURRENT);
   527             
   528             dwRes = SetFilePointer(iDevHandle, liRelOffset.LowPart, &liRelOffset.HighPart, FILE_CURRENT);
   529             if(dwRes == INVALID_SET_FILE_POINTER)
   530                 throw KDiskOpError;
   531 
   532             //-- 1.2 copy chunk of data there
   533             Mem::Copy(ipScratchBuf, pData, KBytesTail);
   534 
   535             //-- 1.3 write sector
   536             if(!WriteFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytes, NULL))
   537                 throw KDiskOpError;
   538             
   539         }
   540 
   541 
   542     }//try
   543     catch(TInt nErrId)
   544     {//-- some disk operation finished with the error
   545         (void)nErrId;
   546         ASSERT(nErrId == KDiskOpError);
   547         const DWORD dwWinErr = GetLastError();
   548         const TInt  epocErr = MapWinError(dwWinErr);
   549         
   550         __PRINT2(_L("#-- CWinVolumeDevice::Write() error! WinErr:%d, EpocErr:%d"), dwWinErr, epocErr);
   551         ASSERT(epocErr != KErrNone);
   552         return epocErr;
   553     }
   554  
   555     return KErrNone;
   556 }
   557 
   558 //-----------------------------------------------------------------------------
   559 
   560 /**
   561     Check if the buffer is filled with aFill character.
   562     @param  aBufPtr buffer descriptor
   563     @param  aFill filling character
   564     @return ETrue if the buffer is filled with aFill byte.
   565 */
   566 static TBool CheckBufFill(const TPtrC8& aBufPtr, TUint8 aFill)
   567 {
   568     const TUint32 bufSz = (TUint32)aBufPtr.Size();
   569     
   570     //-- optimised by using DWORD granularity
   571     if(bufSz % sizeof(TUint32) == 0)
   572     {
   573         TUint32 wordPattern = aFill;
   574         wordPattern <<= 8; wordPattern |= aFill;
   575         wordPattern <<= 8; wordPattern |= aFill;
   576         wordPattern <<= 8; wordPattern |= aFill;
   577 
   578         const TUint nWords = bufSz / sizeof(TUint32);
   579         const TUint32* pWords = (const TUint32*) aBufPtr.Ptr();
   580 
   581         for(TUint32 i=0; i<nWords; ++i)
   582         {
   583             if(pWords[i] != wordPattern)
   584                 return EFalse;
   585         }
   586 
   587         return ETrue;
   588     }
   589     
   590     //-- dumb implementation
   591     for(TUint32 i=0; i<bufSz; ++i)
   592     {
   593         if(aBufPtr[i] != aFill)
   594             return EFalse;
   595     }
   596 
   597     return ETrue;
   598 }
   599 
   600 
   601 //#########################################################################################################################
   602 //##        CWinImgFileDevice  class implementation
   603 //#########################################################################################################################
   604 
   605 
   606 //-----------------------------------------------------------------------------
   607 
   608 CWinImgFileDevice::CWinImgFileDevice()
   609                   :CWinMediaDeviceBase() 
   610 {
   611 
   612     ihFileMapping = NULL;
   613     ipImageFile  = NULL;
   614 
   615     //-- create scratch buffer
   616     ipScratchBuf = ::new TUint8[KScratchBufSz];
   617     ASSERT(ipScratchBuf);
   618 
   619 }
   620 
   621 CWinImgFileDevice::~CWinImgFileDevice()
   622 {
   623     delete ipScratchBuf;
   624 }
   625 
   626 //-----------------------------------------------------------------------------
   627 void CWinImgFileDevice::Disconnect()
   628 {
   629     CloseHandle(ihFileMapping);
   630     ihFileMapping = NULL;
   631     ipImageFile  = NULL;
   632 
   633     CWinMediaDeviceBase::Disconnect();
   634 }
   635 
   636 //-----------------------------------------------------------------------------
   637 /**
   638     Open the device and do some initalisation work.
   639     
   640     @param  aParams device parameters
   641     @return Epoc error code, KErrNone if everything is OK
   642 */
   643 TInt CWinImgFileDevice::Connect(const TMediaDeviceParams& aParams)
   644 {
   645     __PRINT(_L("#-- CWinImgFileDevice::Connect()"));    
   646     
   647     if(!aParams.ipDevName)
   648     {
   649         __LOG(_L("#-- CWinImgFileDevice::Connect() device name is not set!"));    
   650         return KErrBadName;
   651     }
   652     __PRINTF(aParams.ipDevName);
   653     ASSERT(!HandleValid());
   654 
   655     //-- 1. try to locate an image file by given name.
   656     WIN32_FIND_DATAA wfd;
   657     iDevHandle = FindFirstFileA(aParams.ipDevName, &wfd);
   658 
   659     const TBool ImgFileAlreadyExists = HandleValid(iDevHandle);
   660     
   661     FindClose(iDevHandle);
   662     iDevHandle = NULL;
   663     
   664     //-- sector size we will use within image file
   665     const TUint32   sectorSizeToUse = (aParams.iDrvGeometry.iBytesPerSector == 0) ? KDefaultSectorSz : aParams.iDrvGeometry.iBytesPerSector; 
   666           TUint32   fileSzInSectorsToUse = 0;
   667 
   668     const TUint32   reqSizeSec = aParams.iDrvGeometry.iSizeInSectors; //-- required size in sectors
   669     const DWORD     dwAccessMode = (aParams.iReadOnly) ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE;  
   670 
   671     if(ImgFileAlreadyExists)
   672     {//-- if the image file already exists, try to open it and optionally adjust its size
   673         const TInt64    ImgFileSize = MAKE_TINT64(wfd.nFileSizeHigh, wfd.nFileSizeLow);
   674         const TUint32   ImgFileSectors = (TUint32)(ImgFileSize / sectorSizeToUse);
   675         const TBool     ImgFileIsRO = wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY;
   676         
   677         DWORD dwFileCreationMode = 0;
   678         TBool bNeedToAdjustFileSize = EFalse;
   679 
   680         if(reqSizeSec == 0 || reqSizeSec == ImgFileSectors)
   681         {//-- the required size is either not specified (auto) or the same as the existing file has.
   682          //-- we can just open this file
   683          dwFileCreationMode = OPEN_EXISTING;
   684          fileSzInSectorsToUse = ImgFileSectors;
   685         }
   686         else
   687         {//-- we will have to overwrite the image file
   688             if(ImgFileIsRO)
   689             {//-- we won't be able to overwrite existing file.
   690                 __LOG(_L("#-- CWinImgFileDevice::Connect() unable to adjust image file size!"));    
   691                 return KErrAccessDenied;
   692             }
   693 
   694          fileSzInSectorsToUse = reqSizeSec;
   695          dwFileCreationMode = CREATE_ALWAYS;
   696          bNeedToAdjustFileSize = ETrue;
   697         }
   698 
   699         iDevHandle = CreateFileA(aParams.ipDevName,
   700                                 dwAccessMode, 
   701                                 FILE_SHARE_READ,
   702                                 (LPSECURITY_ATTRIBUTES)NULL,
   703                                 dwFileCreationMode,
   704                                 FILE_ATTRIBUTE_NORMAL,
   705                                 NULL);
   706 
   707         if(!HandleValid(iDevHandle))
   708         {
   709             const DWORD winErr = GetLastError();
   710             __LOG1(_L("#-- CWinImgFileDevice::Connect() Error opening/creating file! WinErr:%d"), winErr);
   711             return MapWinError(winErr);
   712         }     
   713 
   714         //-- adjust file size if we need
   715         if(bNeedToAdjustFileSize)
   716         {
   717             const TInt64 newFileSize = (TInt64)reqSizeSec * sectorSizeToUse;
   718             ASSERT(newFileSize);
   719 
   720             LONG  newFSzHi = I64HIGH(newFileSize);
   721             DWORD dwRes = SetFilePointer(iDevHandle, I64LOW(newFileSize), &newFSzHi, FILE_BEGIN);
   722             if(dwRes == INVALID_SET_FILE_POINTER || !SetEndOfFile(iDevHandle))
   723             {
   724                 const DWORD winErr = GetLastError();
   725                 Disconnect();
   726                 __LOG1(_L("#-- CWinImgFileDevice::Connect() unable to set file size! WinErr:%d"), winErr);
   727                 return MapWinError(winErr);
   728             }
   729         }
   730 
   731     }
   732     else //if(ImgFileAlreadyExists)
   733     {//-- if the image file does not exist or its size differs from required. try to create it
   734        
   735         if(reqSizeSec == 0)
   736         {
   737             __LOG(_L("#-- CWinImgFileDevice::Connect() The image file doesn't exist ant its size isn't specified!"));    
   738             return KErrArgument;
   739         }
   740        
   741         fileSzInSectorsToUse = reqSizeSec;
   742 
   743         //-- create a new image file
   744         iDevHandle = CreateFileA(aParams.ipDevName,
   745                                 GENERIC_READ | GENERIC_WRITE, 
   746                                 FILE_SHARE_READ,
   747                                 (LPSECURITY_ATTRIBUTES)NULL,
   748                                 CREATE_ALWAYS,
   749                                 FILE_ATTRIBUTE_NORMAL,
   750                                 NULL);
   751 
   752         if(!HandleValid(iDevHandle))
   753         {
   754             const DWORD winErr = GetLastError();
   755             __LOG1(_L("#-- CWinImgFileDevice::Connect() can not create file! WinErr:%d"), winErr);
   756             return MapWinError(winErr);
   757         }     
   758 
   759         //-- set its size
   760         const TInt64 newFileSize = (TInt64)reqSizeSec * sectorSizeToUse;
   761         ASSERT(newFileSize);
   762 
   763         LONG  newFSzHi = I64HIGH(newFileSize);
   764         DWORD dwRes = SetFilePointer(iDevHandle, I64LOW(newFileSize), &newFSzHi, FILE_BEGIN);
   765         if(dwRes == INVALID_SET_FILE_POINTER || !SetEndOfFile(iDevHandle))
   766         {
   767             const DWORD winErr = GetLastError();
   768             Disconnect();
   769             __LOG1(_L("#-- CWinImgFileDevice::Connect() unable to set file size! WinErr:%d"), winErr);
   770             return MapWinError(winErr);
   771         }
   772 
   773         //-- if parametrs require a read-only file, reopen it in RO mode, it doesn't make a lot of sense though...
   774         if(aParams.iReadOnly)
   775         {
   776             CloseHandle(iDevHandle);
   777             iDevHandle = NULL;
   778 
   779             iDevHandle = CreateFileA(aParams.ipDevName,
   780                                 GENERIC_READ , 
   781                                 FILE_SHARE_READ,
   782                                 (LPSECURITY_ATTRIBUTES)NULL,
   783                                 OPEN_EXISTING,
   784                                 FILE_ATTRIBUTE_NORMAL,
   785                                 NULL);
   786 
   787             if(!HandleValid(iDevHandle))
   788             {
   789                 const DWORD winErr = GetLastError();
   790                 __LOG1(_L("#-- CWinImgFileDevice::Connect() Can't reopen a file in RO mode! WinErr:%d"), winErr);
   791                 return MapWinError(winErr);
   792             }     
   793             
   794         }//if(aParams.iReadOnly)
   795 
   796     }//else if(ImgFileAlreadyExists)
   797     
   798     //-- here we must have the image file created/opened and with correct size
   799     ASSERT(HandleValid());
   800     ASSERT(sectorSizeToUse);
   801 
   802     if(fileSzInSectorsToUse < KMinMediaSizeInSectors)
   803     {
   804         __LOG1(_L("#-- CWinImgFileDevice::Connect() Image file is too small!  sectors:%d"), fileSzInSectorsToUse);
   805         Disconnect();
   806         return KErrGeneral;     
   807     }
   808 
   809     iDrvGeometry.iBytesPerSector = sectorSizeToUse;
   810     iDrvGeometry.iSizeInSectors  = fileSzInSectorsToUse;
   811     
   812     //-- map the image file into memory.
   813     ASSERT(!HandleValid(ihFileMapping));
   814     ASSERT(!ipImageFile);
   815     
   816     /*
   817     don't map image file, because it can be > 4G.
   818     ihFileMapping = CreateFileMapping(Handle(), NULL,
   819                                       aParams.iReadOnly ? PAGE_READONLY : PAGE_READWRITE,
   820                                       0, 0, NULL);
   821     if(HandleValid(ihFileMapping))
   822     {
   823     ipImageFile = (TUint8*)MapViewOfFile(ihFileMapping, 
   824                                          aParams.iReadOnly ? FILE_MAP_READ : FILE_MAP_WRITE,
   825                                          0,0,0);
   826     }
   827 
   828     if(!ipImageFile)
   829     {
   830         __PRINT1(_L("#-- CWinImgFileDevice::Connect() Error mapping file! WinErr:%d"), GetLastError());
   831         Disconnect();
   832         return KErrGeneral;
   833     }
   834     */
   835 
   836     return KErrNone;
   837 }
   838 
   839 
   840 /**
   841     Read a portion of data from the device.
   842     Note: at present it _APPENDS_ data to the aDataDes, so the caller must take care of setting its length
   843 
   844     @param  aPos     media position in bytes
   845     @param  aLength  how many bytes to read
   846     @param  aDataDes data descriptor
   847 
   848     @return KErrNone on success, standard Epoc error code otherwise
   849 
   850 */
   851 TInt CWinImgFileDevice::Read(TInt64 aPos,TInt aLength, TDes8& aDataDes)
   852 {
   853     
   854     //__PRINT3(_L("#-- CWinImgFileDevice::Read, pos:%LU, len:%u, desMaxLen:%u"), aPos, aLength, aDataDes.MaxLength());
   855 
   856     ASSERT(HandleValid());
   857     ASSERT(aLength <= aDataDes.MaxLength());
   858 
   859     //-- check position on the volume
   860     const TInt64 maxPos = iDrvGeometry.TotalSizeInBytes();
   861     if(aPos < 0 || aPos > maxPos)
   862         return KErrArgument;
   863 
   864     const TInt64 lastPos = aPos+aLength;
   865     if(lastPos > maxPos)
   866         return KErrArgument;
   867 
   868     TUint32 dataLen = aLength;
   869 
   870     if(dataLen == 0)
   871         return KErrNone;
   872 
   873     DWORD dwRes;
   874     DWORD dwBytesRead = 0;
   875 
   876     //aDataDes.SetLength(0);
   877 
   878     try
   879     {
   880         //-- 1. position to the media 
   881         LONG  mediaPosHi = I64HIGH(aPos);
   882         const TUint32 mediaPosLo = I64LOW(aPos);
   883 
   884         dwRes = SetFilePointer(iDevHandle, mediaPosLo, &mediaPosHi, FILE_BEGIN);
   885         if(dwRes == INVALID_SET_FILE_POINTER)
   886             throw KDiskOpError;
   887 
   888 
   889         //-- 2. read data to the scratch buffer and copy it to the descriptor.
   890         ASSERT(ipScratchBuf);
   891 
   892         TUint32 rem = dataLen;
   893         
   894         while(rem)
   895         {
   896             const TUint32 bytesToRead = Min(KScratchBufSz, rem);
   897             if(!ReadFile(iDevHandle, ipScratchBuf, bytesToRead, &dwBytesRead, NULL))
   898                 throw KDiskOpError;
   899 
   900             aDataDes.Append(ipScratchBuf, bytesToRead);
   901             rem-=bytesToRead;
   902         }
   903 
   904     }
   905     catch(TInt nErrId)
   906     {//-- some disk operation finished with the error
   907         (void)nErrId;
   908         ASSERT(nErrId == KDiskOpError);
   909         const DWORD dwWinErr = GetLastError();
   910         const TInt  epocErr = MapWinError(dwWinErr);
   911         
   912         __PRINT2(_L("#-- CWinImgFileDevice::Read() error! WinErr:%d, EpocErr:%d"), dwWinErr, epocErr);
   913         ASSERT(epocErr != KErrNone);
   914 
   915         return epocErr;
   916     }
   917 
   918 
   919     return KErrNone;
   920 }
   921 
   922 /**
   923     Write some data to the device.
   924 
   925     @param  aPos     media position in bytes
   926     @param  aLength  how many bytes to read
   927     @param  aDataDes data descriptor
   928 
   929     @return KErrNone on success, standard Epoc error code otherwise
   930 */
   931 TInt CWinImgFileDevice::Write(TInt64 aPos, TInt aLength, const TDesC8& aDataDes)
   932 {
   933     //__PRINT3(_L("#-- CWinImgFileDevice::Write, pos:%LU, len:%u, desLen:%u" ), aPos, aLength, aDataDes.Length());
   934 
   935     ASSERT(HandleValid());
   936 
   937 
   938     if(aLength == 0 || aDataDes.Length() == 0)
   939         return KErrNone;
   940 
   941     if(aLength > aDataDes.Length())
   942     {
   943         ASSERT(0);
   944         return KErrArgument;
   945     }
   946 
   947     //-- check position on the volume
   948     const TInt64 maxPos = iDrvGeometry.TotalSizeInBytes();
   949     if(aPos < 0 || aPos > maxPos)
   950         return KErrArgument;
   951 
   952     const TInt64 lastPos = aPos+aLength;
   953 
   954     if(lastPos > maxPos)
   955         return KErrArgument;
   956 
   957     TUint32 dataLen = aLength;
   958 
   959 
   960     DWORD dwRes;
   961     DWORD dwBytes = 0;
   962     
   963     const TUint8 *pData = aDataDes.Ptr();
   964 
   965     try
   966     {
   967         //-- 1. position to the media
   968         LONG  mediaPosHi = I64HIGH(aPos);
   969         const TUint32 mediaPosLo = I64LOW(aPos);
   970         dwRes = SetFilePointer(iDevHandle, mediaPosLo, &mediaPosHi, FILE_BEGIN);
   971         if(dwRes == INVALID_SET_FILE_POINTER)
   972         {    
   973             throw KDiskOpError;
   974         }
   975     
   976         //-- 2. write data to the media
   977         //-- check if the pointer is word-aligned
   978         const DWORD dwPtrMask = 0x01;
   979         
   980         if( (DWORD)pData & dwPtrMask)
   981         {//-- data pointer isn't aligned, write non-aligned bytes through buffer
   982             ASSERT(dataLen);
   983 
   984             const int oddCnt = 1;
   985             ipScratchBuf[0] = *pData;
   986 
   987             ++pData;
   988             --dataLen;
   989 
   990             if(!WriteFile(iDevHandle, ipScratchBuf, oddCnt, &dwBytes, NULL))
   991                 throw KDiskOpError;
   992         }
   993         
   994         ASSERT(!((DWORD)pData & dwPtrMask));
   995         if(dataLen > 0)
   996         {
   997             if(!WriteFile(iDevHandle, pData, dataLen, &dwBytes, NULL))
   998                 throw KDiskOpError;
   999         }
  1000     
  1001     }
  1002     catch(TInt nErrId)
  1003     {//-- some disk operation finished with the error
  1004         (void)nErrId;
  1005         ASSERT(nErrId == KDiskOpError);
  1006         const DWORD dwWinErr = GetLastError();
  1007         const TInt  epocErr = MapWinError(dwWinErr);
  1008         
  1009         __PRINT2(_L("#-- CWinImgFileDevice::Write() error! WinErr:%d, EpocErr:%d"), dwWinErr, epocErr);
  1010         ASSERT(epocErr != KErrNone);
  1011         return epocErr;
  1012     }
  1013 
  1014 
  1015     
  1016     return KErrNone;
  1017 }
  1018 
  1019 
  1020 //-----------------------------------------------------------------------------
  1021 
  1022 /**
  1023     Make the best effort to map Windows error codes (from GetLastError()) to Epos ones.
  1024     
  1025     @param aWinError MS Windows error code
  1026     @return corresponding EPOC eror code
  1027 */
  1028 
  1029 TInt CWinMediaDeviceBase::MapWinError(DWORD aWinError) const
  1030 {
  1031     switch(aWinError)
  1032     {
  1033         case NO_ERROR:
  1034         return KErrNone;
  1035                           
  1036         case ERROR_NOT_READY:
  1037         return KErrNotReady;
  1038         
  1039         case ERROR_WRITE_PROTECT:
  1040         case ERROR_ACCESS_DENIED:
  1041         return KErrAccessDenied;
  1042         
  1043         case ERROR_INVALID_HANDLE:
  1044         return KErrBadHandle;
  1045         
  1046         case ERROR_NOT_ENOUGH_MEMORY:
  1047         return KErrNoMemory;
  1048         
  1049         case ERROR_OUTOFMEMORY:
  1050         return KErrDiskFull;
  1051                                         
  1052         case ERROR_CRC:
  1053         return KErrCorrupt;
  1054 
  1055         case ERROR_WRITE_FAULT:
  1056         return KErrWrite;
  1057 
  1058         case ERROR_GEN_FAILURE:
  1059         return KErrGeneral;
  1060 
  1061         case ERROR_LOCK_VIOLATION:
  1062         return KErrLocked;
  1063 
  1064         case ERROR_SHARING_VIOLATION:
  1065         return KErrInUse;
  1066 
  1067         case ERROR_NOT_SUPPORTED:
  1068         return KErrNotSupported;
  1069 
  1070         default:
  1071         return KErrGeneral;
  1072     
  1073     }
  1074 }
  1075 
  1076 
  1077 
  1078 
  1079 
  1080 
  1081 
  1082 
  1083 
  1084 
  1085 
  1086 
  1087 
  1088 
  1089 
  1090 
  1091 
  1092 
  1093 
  1094 
  1095 
  1096 
  1097 
  1098 
  1099 
  1100 
  1101 
  1102 
  1103 
  1104