mtpfws/mtpfw/datatypes/src/cmtptypefile.cpp
changeset 0 d0791faffa3f
child 1 f8e15b44d440
equal deleted inserted replaced
-1:000000000000 0:d0791faffa3f
       
     1 // Copyright (c) 2006-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 //
       
    15 
       
    16 /**
       
    17  @file
       
    18  @publishedPartner
       
    19  */
       
    20 
       
    21 #include <mtp/cmtptypefile.h>
       
    22 #include <mtp/mtpdatatypeconstants.h>
       
    23 
       
    24 // File type constants.
       
    25 const TInt KMTPFileChunkSizeForLargeFile(0x00080000); // 512K
       
    26 
       
    27 //For file size less than 512K, we will use this smaller chunk size to reduce the heap usage.
       
    28 const TInt KMTPFileChunkSizeForSmallFile(0x00010000); //64K
       
    29 
       
    30 //For file size larger than it, we will split one setSize() to several smaller one, each with the following size.
       
    31 const TInt64 KMTPFileSetSizeChunk(1<<30); //1G
       
    32 
       
    33 const TUint KUSBHeaderLen = 12;
       
    34 
       
    35 /**
       
    36  MTP file object data type factory method. 
       
    37  @param aFs The handle of an active file server session.
       
    38  @param aName The name of the file. Any path components (i.e. drive letter
       
    39  or directory), which are not specified, are taken from the session path. 
       
    40  @param aMode The mode in which the file is opened (@see TFileMode).
       
    41  @return A pointer to the MTP file object data type. Ownership IS transfered.
       
    42  @leave One of the system wide error codes, if a processing failure occurs.
       
    43  @see TFileMode
       
    44  */
       
    45 EXPORT_C CMTPTypeFile* CMTPTypeFile::NewL(RFs& aFs, const TDesC& aName, TFileMode aMode)
       
    46     {
       
    47     CMTPTypeFile* self = NewLC(aFs, aName, aMode);
       
    48     CleanupStack::Pop(self);
       
    49     return self;
       
    50     }
       
    51 
       
    52 /**
       
    53  MTP file object data type factory method. A pointer to the MTP file object data
       
    54  type is placed on the cleanup stack.
       
    55  @param aFs The handle of an active file server session.
       
    56  @param aName The name of the file. Any path components (i.e. drive letter
       
    57  or directory), which are not specified, are taken from the session path. 
       
    58  @param aMode The mode in which the file is opened (@see TFileMode).
       
    59  @return A pointer to the MTP file object data type. Ownership IS transfered.
       
    60  @leave One of the system wide error codes, if a processing failure occurs.
       
    61  @see TFileMode
       
    62  */
       
    63 EXPORT_C CMTPTypeFile* CMTPTypeFile::NewLC(RFs& aFs, const TDesC& aName, TFileMode aMode)
       
    64     {
       
    65     CMTPTypeFile* self = new(ELeave) CMTPTypeFile;
       
    66     CleanupStack::PushL(self);
       
    67     self->ConstructL(aFs, aName, aMode);
       
    68     return self;
       
    69     }
       
    70 
       
    71 EXPORT_C CMTPTypeFile* CMTPTypeFile::NewL(RFs& aFs, const TDesC& aName, TFileMode aMode, TInt64 aRequiredSize, TInt64 aOffSet)
       
    72     {
       
    73     CMTPTypeFile* self = NewLC(aFs, aName, aMode,aRequiredSize,aOffSet);
       
    74 	CleanupStack::Pop(self);
       
    75     return self;
       
    76     }
       
    77 
       
    78 EXPORT_C CMTPTypeFile* CMTPTypeFile::NewLC(RFs& aFs, const TDesC& aName, TFileMode aMode, TInt64 aRequiredSize, TInt64 aOffSet)
       
    79     {
       
    80     CMTPTypeFile* self = new(ELeave) CMTPTypeFile;
       
    81     CleanupStack::PushL(self);
       
    82     self->ConstructL(aFs, aName, aMode, aRequiredSize, aOffSet);
       
    83     return self;
       
    84     }
       
    85 
       
    86 /**
       
    87  Destructor
       
    88  */
       
    89 EXPORT_C CMTPTypeFile::~CMTPTypeFile()
       
    90     {
       
    91     if(iCurrentCommitChunk.Length() != 0)
       
    92         {
       
    93         ToggleRdWrBuffer();
       
    94         }
       
    95 
       
    96     iFile.Close();
       
    97 
       
    98     iBuffer1.Close();
       
    99     iBuffer2.Close();
       
   100     Cancel();
       
   101     }
       
   102 
       
   103 /**
       
   104  Sets the size of the file, this function must be called in case of file writting/receiving. related resouce
       
   105  will be allocated in this function to prepare to receive the incoming data.
       
   106  @param aSize The new size of the file (in bytes).
       
   107  @leave One of the system wide error codes, if a processing failure occurs.
       
   108  */
       
   109 EXPORT_C void CMTPTypeFile::SetSizeL(TUint64 aSize)
       
   110     {
       
   111     iTargetFileSize = (TInt64)aSize; //keep a record for the target file size
       
   112     
       
   113     iRemainingDataSize = (TInt64)aSize;//Current implemenation does not support file size with 2 x64 
       
   114 
       
   115     if(iRemainingDataSize> KMTPFileChunkSizeForLargeFile) //512K
       
   116         {
       
   117         iBuffer1.CreateMaxL(KMTPFileChunkSizeForLargeFile);
       
   118         iBuffer2.CreateMaxL(KMTPFileChunkSizeForLargeFile);
       
   119         }
       
   120     else
       
   121         {
       
   122         iBuffer1.CreateMaxL(KMTPFileChunkSizeForSmallFile);
       
   123         iBuffer2.CreateMaxL(KMTPFileChunkSizeForSmallFile);
       
   124         }
       
   125     if(iRemainingDataSize> KMTPFileSetSizeChunk)
       
   126         {
       
   127         //split the setSize to multiple calling of 512M
       
   128         User::LeaveIfError(iFile.SetSize(KMTPFileSetSizeChunk));
       
   129         iCurrentFileSetSize = KMTPFileSetSizeChunk;
       
   130         }
       
   131     else
       
   132         {
       
   133         User::LeaveIfError(iFile.SetSize(aSize));
       
   134         iCurrentFileSetSize = aSize;
       
   135         }
       
   136     }
       
   137 
       
   138 /**
       
   139  Provides a reference to the native file object encapsulate by the MTP file 
       
   140  object data type.
       
   141  @return The native file object reference.
       
   142  */
       
   143 #ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
       
   144 EXPORT_C RFile64& CMTPTypeFile::File()
       
   145 #else
       
   146 EXPORT_C RFile& CMTPTypeFile::File()
       
   147 #endif
       
   148     {
       
   149     return iFile;
       
   150     }
       
   151 
       
   152 EXPORT_C TInt CMTPTypeFile::FirstReadChunk(TPtrC8& aChunk) const
       
   153     {
       
   154     aChunk.Set(NULL, 0);
       
   155     iReadSequenceState = EIdle;
       
   156     iBuffer1.Zero();
       
   157 #ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
       
   158     TInt64 pos =iOffSet;
       
   159 #else
       
   160     TInt pos = static_cast<TInt>(iOffSet);
       
   161 #endif
       
   162     TInt err(iFile.Seek(ESeekStart, pos));
       
   163     if (err == KErrNone)
       
   164         {
       
   165         // The USB SIC header is 12 bytes long. If the first chunk is 128K - 12 bytes, 
       
   166         // the USB SIC transport will not buffer data, which will improve the transfer rate.
       
   167         err = iFile.Read(iBuffer1, iBuffer1.MaxLength() - KUSBHeaderLen);
       
   168         if (err == KErrNone)
       
   169             {
       
   170             //this chunk is going to be used by USB to read  data from it, only CMTPTypefile::RunL() can toggle this flag
       
   171             //When it finishe reading data into Buffer2.
       
   172             iBuffer1AvailForWrite = EFalse;
       
   173 
       
   174             aChunk.Set(iBuffer1.Ptr(), iBuffer1.Length());
       
   175 
       
   176             //Set the commit chunk to be filled in by CMTPTypeFile::RunL()
       
   177             iCurrentCommitChunk.Set(&iBuffer2[0], 0, iBuffer2.MaxLength());
       
   178 
       
   179             iRemainingDataSize -= aChunk.Length();
       
   180 
       
   181             if (aChunk.Length() == 0)
       
   182                 {
       
   183                 // Empty File.
       
   184                 iReadSequenceState = EIdle;
       
   185                 err = KMTPChunkSequenceCompletion;
       
   186                 }
       
   187             else
       
   188                 {
       
   189                 if (iRemainingDataSize <= 0)
       
   190                     {
       
   191                     // EOF.
       
   192                     iReadSequenceState = EIdle;
       
   193                     aChunk.Set(aChunk.Ptr(), aChunk.Length() + iRemainingDataSize);  //for partial
       
   194                     err = KMTPChunkSequenceCompletion;
       
   195                     }
       
   196                 else
       
   197                     {
       
   198                     iReadSequenceState = EInProgress;
       
   199                     //This is NOT the last chunk, issue more CMTPTypeFile::RunL()
       
   200                     if (!IsActive())
       
   201                         {
       
   202                         //Since the writting data into file sever will take a long time, will issue a dedicated Active Object to do that.
       
   203                         const_cast<CMTPTypeFile*>(this)->SetActive();
       
   204                         TRequestStatus* status = (TRequestStatus*)&iStatus;
       
   205                         User::RequestComplete(status, KErrNone);
       
   206                         }
       
   207                     else
       
   208                         {
       
   209                         //This is a very extreme cases, it only occurs when the following assumption is met
       
   210                         //1. USB already took buffer1 and already issue CMTPTypeFileRunL(), therefore, the ActiveObject has completed itself, 
       
   211                         //2. Somehow, this active object is not scheduled to be running even after the USB already use out the other buffer.
       
   212                         //3. USB's active object is scheduled to be running prior to the last File active object(this should not happen if ActiveScheduler follow the priority scheduler).
       
   213                         //4. USB call this function again to get the other data buffer.
       
   214                         //5. Then it find the previous active is not scheduled to run.
       
   215                         //in single-core platform, the code rely on the CActiveScheduler to guarantee the first active call which has higher priority to be running firstly before
       
   216                         //the 2nd USB active. but for multi-core platform, this should be re-evaluated .
       
   217                         iReadSequenceState = EIdle;
       
   218                         err = KMTPChunkSequenceCompletion;
       
   219                         }
       
   220                     }
       
   221                 }
       
   222             }
       
   223         else
       
   224             {
       
   225             iReadSequenceState = EIdle;
       
   226             iFileRdWrError = ETrue;
       
   227             }
       
   228         }
       
   229     iByteSent += aChunk.Length();
       
   230     return err;
       
   231     }
       
   232 
       
   233 EXPORT_C TInt CMTPTypeFile::NextReadChunk(TPtrC8& aChunk) const
       
   234     {
       
   235     TInt err(KErrNone);
       
   236 
       
   237     if((iReadSequenceState != EInProgress) || (iFileRdWrError))
       
   238         {
       
   239         aChunk.Set(NULL, 0);
       
   240         return KErrNotReady;
       
   241         }
       
   242 
       
   243     //This is called by USB's RunL(), here, the only possible scenarios is that the CMTPTypleFile::RunL() issued in FirReadChunk or last NextReadChunk must 
       
   244     //have already finished. Now take the buffer which is filled in by data in CMTPTypleFile::RunL().
       
   245     aChunk.Set(iCurrentCommitChunk.Ptr(), iCurrentCommitChunk.Length());
       
   246     if(iBuffer1AvailForWrite)
       
   247         {//We have already used buffer_1, now buffer2 contains data read into by CMTPTypeFile::RunL();
       
   248         //Set the commit chunk to be filled in by CMTPTypeFile::RunL()
       
   249         iCurrentCommitChunk.Set(&iBuffer1[0], 0, iBuffer1.MaxLength());
       
   250         }
       
   251     else
       
   252         {
       
   253         //Set the commit chunk to be filled in by CMTPTypeFile::RunL()
       
   254         iCurrentCommitChunk.Set(&iBuffer2[0], 0, iBuffer2.MaxLength());
       
   255         }
       
   256 
       
   257     iRemainingDataSize -= aChunk.Length();
       
   258 
       
   259     if(aChunk.Length() == 0)
       
   260         {
       
   261         iReadSequenceState = EIdle;
       
   262         err = KMTPChunkSequenceCompletion;
       
   263         }
       
   264     else if(iRemainingDataSize> 0)
       
   265         {
       
   266         //This is NOT the last chunk, issue more CMTPTypeFile::RunL()
       
   267         if (!IsActive())
       
   268             {
       
   269             //Since the writting data into file sever will take a long time, will issue a dedicated Active Object to do that.
       
   270             ((CMTPTypeFile*)this)->SetActive();
       
   271             TRequestStatus* status = (TRequestStatus*)&iStatus;
       
   272             User::RequestComplete(status, KErrNone);
       
   273             }
       
   274         else
       
   275             {
       
   276             //This is a very extreme cases, it only occurs when the following assumption is met
       
   277             //1. USB already took buffer1 and already issue CMTPTypeFileRunL(), therefore, the ActiveObject has completed itself, 
       
   278             //2. Somehow, this active object is not scheduled to be running even after the USB already use out the other buffer.
       
   279             //3. USB's active object is scheduled to be running prior to the last File active object(this should not happen if ActiveScheduler follow the priority scheduler).
       
   280             //4. USB call this function again to get the other data buffer.
       
   281             //5. Then it find the previous active is not scheduled to run.
       
   282             //in single-core platform, the code rely on the CActiveScheduler to guarantee the first active call which has higher priority to be running firstly before
       
   283             //the 2nd USB active. but for multi-core platform, this should be re-evaluated .
       
   284             iReadSequenceState = EIdle;
       
   285             err = KMTPChunkSequenceCompletion;
       
   286             }
       
   287         }
       
   288     else
       
   289         {//Last Chunk. Do not issue Active object. and indicate this completion of the chunk
       
   290         iReadSequenceState = EIdle;
       
   291         aChunk.Set(aChunk.Ptr(), aChunk.Length() + iRemainingDataSize); //for partial
       
   292         err = KMTPChunkSequenceCompletion;
       
   293         }
       
   294     iByteSent += aChunk.Length();
       
   295     return err;
       
   296     }
       
   297 
       
   298 EXPORT_C TInt CMTPTypeFile::FirstWriteChunk(TPtr8& aChunk)
       
   299     {
       
   300     __ASSERT_DEBUG(iBuffer1AvailForWrite, User::Invariant());
       
   301     __ASSERT_DEBUG(!iFileRdWrError, User::Invariant());
       
   302 
       
   303     aChunk.Set(NULL, 0, 0);
       
   304     iWriteSequenceState = EIdle;
       
   305     
       
   306 #ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
       
   307     TInt64 pos =0;
       
   308 #else
       
   309     TInt pos =0;
       
   310 #endif
       
   311     TInt err(iFile.Seek(ESeekStart, pos));
       
   312     if (err == KErrNone)
       
   313         {
       
   314         //Because USB HS's transmission rate is several time faster than the rate of writting data into File System.
       
   315         //If the first packet is a full chunk size packet, then the writting of that data will not start until the full-chunk
       
   316         //sized packet is received. Here we intentionly reduce the first packet size to 1/4 of the full chunk size, therefore,
       
   317         //the start of writting data into File system will start only after 1/4 of the full chunk size data is received.
       
   318         //This can make the writting of data to FS start earlier.
       
   319         aChunk.Set(&iBuffer1[0], 0, iBuffer1.MaxLength());
       
   320         iWriteSequenceState = EInProgress;
       
   321 
       
   322         //this chunk is going to be used by Transport to write data into it, and when it is full, transport
       
   323         //will call back CommitChunkL(), at that time, the EFalse means it already contains data in it.
       
   324         //it is ready for reading data from it. 
       
   325         //This is a initial value for it to trigger the double-buffering mechanism.
       
   326         iBuffer1AvailForWrite = EFalse;
       
   327         }
       
   328 
       
   329     return err;
       
   330     }
       
   331 
       
   332 EXPORT_C TInt CMTPTypeFile::NextWriteChunk(TPtr8& aChunk)
       
   333     {
       
   334     TInt err(KErrNone);
       
   335     aChunk.Set(NULL, 0, 0);
       
   336 
       
   337     if (iWriteSequenceState != EInProgress)
       
   338         {
       
   339         err = KErrNotReady;
       
   340         }
       
   341     else
       
   342         {//toggle between buffer 1 and buffer 2 here.
       
   343         if(iBuffer1AvailForWrite)
       
   344             {
       
   345             aChunk.Set(&iBuffer1[0], 0, iBuffer1.MaxLength());
       
   346             }
       
   347         else
       
   348             {
       
   349             aChunk.Set(&iBuffer2[0], 0, iBuffer2.MaxLength());
       
   350             }
       
   351         }
       
   352 
       
   353     return err;
       
   354     }
       
   355 
       
   356 EXPORT_C TUint64 CMTPTypeFile::Size() const
       
   357     {
       
   358     //The USB transport layer uses USB Container Length to determine the total size of data to be
       
   359     //transfered. In USB protocol, the Container Length is 32 bits long which is up to 4G-1, so 
       
   360     //for synchronization of a large file >=4G-12 bytes (the USB header is 12 bytes long), the
       
   361     //Container Length can't be used to determine the total size of data any more. In this kind of
       
   362     //case, our USB transport layer implementation will call this function to get the actual data size.
       
   363     
       
   364     //The RFile::SetSize() method may take over 40 seconds if we create a file and set its size
       
   365     //to a very large value, and this will cause timeout in MTP protocol layer. To avoid this 
       
   366     //timeout, when creating a large file(over 512MB), instead of setting its size directly to
       
   367     //the target size by one singile RFile::SetSize() call, we'll call RFile::SetSize() multiple
       
   368     //times and set the file size step by step acumulately. For example, for a 2GB file, its
       
   369     //size will be set to 0.5G first, and then 1G, 1.5G and at last 2G.
       
   370     
       
   371     //So if a file is transfering to device, the size of the file that returned by RFile::Size() is
       
   372     //just a temporary value and means nothing. In this case, let's return the target file size instead.
       
   373     if(!iFileOpenForRead && iRemainingDataSize)
       
   374         {        
       
   375         return iTargetFileSize;
       
   376         }
       
   377     
       
   378     //If the initiator get partial of the file, return the requested partial size 
       
   379     if (iFileOpenForRead && iTargetFileSize)
       
   380         {
       
   381         return iTargetFileSize;
       
   382         }
       
   383     
       
   384 #ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
       
   385     TInt64 size;
       
   386 #else
       
   387     TInt size;
       
   388 #endif
       
   389     iFile.Size(size);
       
   390     return size;
       
   391     }
       
   392 
       
   393 EXPORT_C TUint CMTPTypeFile::Type() const
       
   394     {
       
   395     return EMTPTypeFile;
       
   396     }
       
   397 
       
   398 EXPORT_C TBool CMTPTypeFile::CommitRequired() const
       
   399     {
       
   400     return ETrue;
       
   401     }
       
   402 
       
   403 EXPORT_C MMTPType* CMTPTypeFile::CommitChunkL(TPtr8& aChunk)
       
   404     {
       
   405 	if(iFileRdWrError)
       
   406 		{
       
   407 		return NULL;
       
   408 		}
       
   409 	if(0 == aChunk.Length())
       
   410 		{
       
   411 		ToggleRdWrBuffer();
       
   412 		return NULL;
       
   413 		}
       
   414     iCurrentCommitChunk.Set(aChunk);
       
   415 
       
   416     if(iRemainingDataSize> iCurrentCommitChunk.Length())
       
   417         {//This is NOT the last chunk, we issue an active object to commit it to File system.
       
   418         iRemainingDataSize -= iCurrentCommitChunk.Length();
       
   419 		/*
       
   420 		if (!IsActive())
       
   421 			{
       
   422 			//Since the writting data into file sever will take a long time, will issue a dedicated Active Object to do that.
       
   423 			SetActive();
       
   424 			TRequestStatus* thisAO = &iStatus;
       
   425 			User::RequestComplete(thisAO, KErrNone);
       
   426 			}
       
   427 		else
       
   428 			{
       
   429 			//This is a very extreme cases, it only occurs when the following assumption is met
       
   430 			//1. USB received buffer1 and already call this CommitChunkL(), therefore, the ActiveObject has completed itself, and USB then use another buffer to
       
   431 			//receive the data.
       
   432 			//2. Somehow, this active object is not scheduled to be running even after the USB already fill out the other buffer.
       
   433 			//3. USB's active object is scheduled to be running prior to the last File active object(this should not happen if ActiveScheduler follow the priority scheduler).
       
   434 			//4. USB call this function again to commit the other data buffer.
       
   435 			//5. Then it find the previous active is not scheduled to run.
       
   436 			//in single-core platform, the code rely on the CActiveScheduler to guarantee the first active call which has higher priority to be running firstly before
       
   437 			//the 2nd USB active. but for multi-core platform, this should be re-evaluated .
       
   438 			iFileRdWrError = ETrue;//if it really discard the incoming recevied file.			
       
   439 			//__FLOG(_L8("\nThe program should not arrive here !!!!!\n"));
       
   440 			}
       
   441 			*/
       
   442         }
       
   443     else
       
   444         {//This is the last chunk, we synchronous commit it 
       
   445         iRemainingDataSize = 0;
       
   446         ToggleRdWrBuffer();
       
   447 			return NULL;
       
   448         }
       
   449 	return this;
       
   450     }
       
   451 
       
   452 //for partial
       
   453 EXPORT_C Int64 CMTPTypeFile::GetByteSent()
       
   454     {
       
   455     return iByteSent;
       
   456     }
       
   457 
       
   458 CMTPTypeFile::CMTPTypeFile() :
       
   459     CActive(EPriorityUserInput), iBuffer1AvailForWrite(ETrue),
       
   460         iFileRdWrError(EFalse), iCurrentCommitChunk(NULL, 0)
       
   461     {
       
   462     CActiveScheduler::Add(this);
       
   463     }
       
   464 
       
   465 void CMTPTypeFile::ConstructL(RFs& aFs, const TDesC& aName, TFileMode aMode)
       
   466     {
       
   467     if (aMode & EFileWrite)
       
   468         {
       
   469         iFileOpenForRead = EFalse;
       
   470         User::LeaveIfError(iFile.Replace(aFs, aName, aMode|EFileWriteDirectIO));
       
   471         }
       
   472     else
       
   473         {
       
   474         iFileOpenForRead = ETrue;
       
   475         User::LeaveIfError(iFile.Open(aFs, aName, aMode|EFileReadDirectIO|EFileShareReadersOnly));
       
   476 #ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
       
   477         TInt64 size = 0;
       
   478 #else
       
   479         TInt size = 0;
       
   480 #endif
       
   481         User::LeaveIfError(iFile.Size(size));
       
   482         iRemainingDataSize = size;
       
   483 
       
   484         //For File reading, NO "SetSizeL()" will be called, therefore, create the buffer here.
       
   485         if (iRemainingDataSize > KMTPFileChunkSizeForLargeFile) //512K
       
   486             {
       
   487             iBuffer1.CreateMaxL(KMTPFileChunkSizeForLargeFile);
       
   488             iBuffer2.CreateMaxL(KMTPFileChunkSizeForLargeFile);
       
   489             }
       
   490         else
       
   491             {
       
   492             iBuffer1.CreateMaxL(KMTPFileChunkSizeForSmallFile);
       
   493             iBuffer2.CreateMaxL(KMTPFileChunkSizeForSmallFile);
       
   494             }
       
   495         }
       
   496     }
       
   497 
       
   498 void CMTPTypeFile::ConstructL(RFs& aFs, const TDesC& aName, TFileMode aMode, TInt64 aRequiredSize, TInt64 aOffSet)
       
   499 	{
       
   500     if (aMode & EFileWrite)
       
   501         {
       
   502         iFileOpenForRead = EFalse;
       
   503         User::LeaveIfError(iFile.Replace(aFs, aName, aMode|EFileWriteDirectIO));
       
   504         }
       
   505     else
       
   506         {
       
   507         iFileOpenForRead = ETrue;
       
   508         iOffSet = aOffSet;
       
   509         User::LeaveIfError(iFile.Open(aFs, aName, aMode|EFileReadDirectIO|EFileShareReadersOnly));
       
   510 #ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
       
   511         TInt64 size = 0;
       
   512 #else
       
   513         TInt size = 0;
       
   514 #endif
       
   515         User::LeaveIfError(iFile.Size(size));
       
   516         
       
   517         if(aRequiredSize < size)
       
   518             {
       
   519             iTargetFileSize = aRequiredSize;
       
   520             }
       
   521         else
       
   522             {
       
   523             iTargetFileSize = size;
       
   524             }
       
   525         iRemainingDataSize = iTargetFileSize;
       
   526         
       
   527         //For File reading, NO "SetSizeL()" will be called, therefore, create the buffer here.
       
   528         if (iRemainingDataSize > KMTPFileChunkSizeForLargeFile) //512K
       
   529             {
       
   530             iBuffer1.CreateMaxL(KMTPFileChunkSizeForLargeFile);
       
   531             iBuffer2.CreateMaxL(KMTPFileChunkSizeForLargeFile);
       
   532             }
       
   533         else
       
   534             {
       
   535             iBuffer1.CreateMaxL(KMTPFileChunkSizeForSmallFile);
       
   536             iBuffer2.CreateMaxL(KMTPFileChunkSizeForSmallFile);
       
   537             }
       
   538         }
       
   539 	}
       
   540 
       
   541 void CMTPTypeFile::DoCancel()
       
   542     {
       
   543     // Nothing to cancel here because this Active object does not issue any asynchronous call to others.
       
   544     }
       
   545 
       
   546 // Catch any leaves - the CActiveScheduler can't handle it.
       
   547 TInt CMTPTypeFile::RunError(TInt /* aError*/)
       
   548     {
       
   549     //We did not throw exception in RunL() in reality, therefore, we need not to cope with it.
       
   550     return KErrNone;
       
   551     }
       
   552 
       
   553 void CMTPTypeFile::RunL()
       
   554     {
       
   555     ToggleRdWrBuffer();
       
   556     }
       
   557 
       
   558 void CMTPTypeFile::ToggleRdWrBuffer()
       
   559     {
       
   560     //This is triggered by CommitChunkL(), this will write the received data into File system synchronously.
       
   561     //Since someone trigger this RunL(), therefore, there must be one of 2 buffer which is full of data to wait for writing buffer data into File system.
       
   562     //Each RunL(), only need to commit one chunk because transport only prepare one chunk for file system in one RunL().
       
   563 
       
   564     TInt err = KErrNone;
       
   565 
       
   566     if (!iFileOpenForRead)
       
   567         {
       
   568         if (!iFileRdWrError)
       
   569             {
       
   570             TInt64 temp = iCurrentCommitChunk.Length();            
       
   571             iTotalReceivedSize += temp;
       
   572             if (iTotalReceivedSize > iCurrentFileSetSize)
       
   573                 {
       
   574                 //temp += iRemainingDataSize;//Total uncommitted file size.
       
   575                 temp = iTotalReceivedSize-iCurrentFileSetSize+iRemainingDataSize;
       
   576                 if (temp >= KMTPFileSetSizeChunk)
       
   577                     {
       
   578                     iCurrentFileSetSize += KMTPFileSetSizeChunk;
       
   579                     }
       
   580                 else
       
   581                     {
       
   582                     iCurrentFileSetSize += temp;
       
   583                     }
       
   584                 err = iFile.SetSize(iCurrentFileSetSize);
       
   585                 }
       
   586                         
       
   587             if (err != KErrNone)
       
   588                 {
       
   589                 iFileRdWrError = ETrue;
       
   590                 }
       
   591             else
       
   592                 {
       
   593                 err = iFile.Write(iCurrentCommitChunk);
       
   594                 if (err != KErrNone)
       
   595                     {// file Write failed,	this means we cannot successfully received this file but however, we cannot disrupt a current DIOR phase according to MTP spec.
       
   596                     // We should continue to receive the data and discard this data, only after the data  phase is finished can we send back an error response
       
   597                     //to Initiator. Therefore, we pretend to continue to write this data into file, and let final processor to check the file size and then give back a 
       
   598                     //corresponding error code to MTP initiator.
       
   599                     iFileRdWrError = ETrue;
       
   600                     iFile.SetSize(0);
       
   601                     }
       
   602                 }
       
   603             }
       
   604         iCurrentCommitChunk.Zero();
       
   605         }
       
   606     else
       
   607         {
       
   608         if (!iFileRdWrError)
       
   609             {
       
   610             err = iFile.Read(iCurrentCommitChunk,
       
   611                     iCurrentCommitChunk.MaxLength());
       
   612             if (err != KErrNone)
       
   613                 {//Error, abort the current file reading.
       
   614                 iFileRdWrError = ETrue;
       
   615                 }
       
   616             }
       
   617         }
       
   618 
       
   619     iBuffer1AvailForWrite = !iBuffer1AvailForWrite;//toggle the flag.
       
   620     }