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