mtpfws/mtpfw/datatypes/src/cmtptypefile.cpp
changeset 17 aabe5387f5ce
parent 0 d0791faffa3f
child 12 8b094906a049
child 18 1b39655331a3
equal deleted inserted replaced
0:d0791faffa3f 17:aabe5387f5ce
    30 //For file size larger than it, we will split one setSize() to several smaller one, each with the following size.
    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
    31 const TInt64 KMTPFileSetSizeChunk(1<<30); //1G
    32 
    32 
    33 const TUint KUSBHeaderLen = 12;
    33 const TUint KUSBHeaderLen = 12;
    34 
    34 
       
    35 
       
    36 
       
    37 CMTPTypeFile::CFileWriter* CMTPTypeFile::CFileWriter::NewL(RFile&  aFile, RBuf8& aWriteBuf)
       
    38     {
       
    39     CFileWriter *self = new(ELeave)CFileWriter(aFile, aWriteBuf);
       
    40     CleanupStack::PushL(self);
       
    41     self->ConstructL();
       
    42     CleanupStack::Pop(self);
       
    43     return self;
       
    44     }
       
    45 
       
    46 void CMTPTypeFile::CFileWriter::GetWriteBuf(TPtr8& aChunk)
       
    47     {
       
    48     WaitForWriteComplete();
       
    49     aChunk.Set(&iBuf[0], 0, iBuf.MaxLength());
       
    50     }
       
    51     
       
    52 TInt CMTPTypeFile::CFileWriter::GetResult() const
       
    53     {
       
    54     return iWriteResult;
       
    55     }
       
    56     
       
    57 void CMTPTypeFile::CFileWriter::Write(TInt aLength)
       
    58     {
       
    59     iFile.Write(iBuf, aLength, iStatus);
       
    60     SetActive();
       
    61     }
       
    62     
       
    63 void CMTPTypeFile::CFileWriter::WaitForWriteComplete()
       
    64     {
       
    65     /*
       
    66      * We didn't want to cancel the file write here.
       
    67      * But we need to wait until the file write complete.
       
    68      * The Cancel() function of CActive will do the wait until the file write complete.
       
    69      * If the Write already complete and the RunL() invoked there's nothing happened in the Cancel().
       
    70      */
       
    71     Cancel(); 
       
    72     //Have to save the result.
       
    73     iWriteResult = iStatus.Int();
       
    74     }
       
    75 
       
    76 void CMTPTypeFile::CFileWriter::RunL()
       
    77     {
       
    78     //Have to save the result.
       
    79     iWriteResult = iStatus.Int();
       
    80     }
       
    81     
       
    82     
       
    83 CMTPTypeFile::CFileWriter::~CFileWriter()
       
    84     {
       
    85     WaitForWriteComplete(); //make sure all async request complete
       
    86     if(iWriteResult != KErrNone)
       
    87         {
       
    88         iFile.SetSize(0);
       
    89         }
       
    90     }
       
    91 
       
    92 
       
    93 void CMTPTypeFile::CFileWriter::DoCancel()
       
    94     {
       
    95     //We didn't really want to cancel the file write, so we do nothing here
       
    96     }
       
    97 
       
    98 
       
    99 CMTPTypeFile::CFileWriter::CFileWriter(RFile&  aFile, RBuf8& aBuf):CActive(EPriorityStandard), iWriteResult(KErrNone), iFile(aFile), iBuf(aBuf) 
       
   100     {
       
   101     }
       
   102     
       
   103 
       
   104 void CMTPTypeFile::CFileWriter::ConstructL()
       
   105     {
       
   106     CActiveScheduler::Add(this);
       
   107     }
       
   108 
    35 /**
   109 /**
    36  MTP file object data type factory method. 
   110  MTP file object data type factory method. 
    37  @param aFs The handle of an active file server session.
   111  @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
   112  @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. 
   113  or directory), which are not specified, are taken from the session path. 
    86 /**
   160 /**
    87  Destructor
   161  Destructor
    88  */
   162  */
    89 EXPORT_C CMTPTypeFile::~CMTPTypeFile()
   163 EXPORT_C CMTPTypeFile::~CMTPTypeFile()
    90     {
   164     {
    91     if(iCurrentCommitChunk.Length() != 0)
   165     delete iFileWriter1;
    92         {
   166     delete iFileWriter2;
    93         ToggleRdWrBuffer();
       
    94         }
       
    95 
       
    96     iFile.Close();
   167     iFile.Close();
    97 
       
    98     iBuffer1.Close();
   168     iBuffer1.Close();
    99     iBuffer2.Close();
   169     iBuffer2.Close();
   100     Cancel();
   170     Cancel();
   101     }
   171     }
   102 
   172 
   131     else
   201     else
   132         {
   202         {
   133         User::LeaveIfError(iFile.SetSize(aSize));
   203         User::LeaveIfError(iFile.SetSize(aSize));
   134         iCurrentFileSetSize = aSize;
   204         iCurrentFileSetSize = aSize;
   135         }
   205         }
       
   206     iFileWriter1 = CFileWriter::NewL(iFile, iBuffer1);
       
   207     iFileWriter2 = CFileWriter::NewL(iFile, iBuffer2);
   136     }
   208     }
   137 
   209 
   138 /**
   210 /**
   139  Provides a reference to the native file object encapsulate by the MTP file 
   211  Provides a reference to the native file object encapsulate by the MTP file 
   140  object data type.
   212  object data type.
   309     TInt pos =0;
   381     TInt pos =0;
   310 #endif
   382 #endif
   311     TInt err(iFile.Seek(ESeekStart, pos));
   383     TInt err(iFile.Seek(ESeekStart, pos));
   312     if (err == KErrNone)
   384     if (err == KErrNone)
   313         {
   385         {
   314         //Because USB HS's transmission rate is several time faster than the rate of writting data into File System.
   386         iFileWriter1->GetWriteBuf(aChunk);
   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;
   387         iWriteSequenceState = EInProgress;
   321 
   388 
   322         //this chunk is going to be used by Transport to write data into it, and when it is full, transport
   389         //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.
   390         //will call back CommitChunkL(), at that time, the ETrue means it already contains data in it.
   324         //it is ready for reading data from it. 
   391         //it is ready for reading data from it. 
   325         //This is a initial value for it to trigger the double-buffering mechanism.
   392         //This is a initial value for it to trigger the double-buffering mechanism.
   326         iBuffer1AvailForWrite = EFalse;
   393         iBuffer1AvailForWrite = ETrue;
   327         }
   394         }
   328 
   395 
   329     return err;
   396     return err;
   330     }
   397     }
   331 
   398 
   340         }
   407         }
   341     else
   408     else
   342         {//toggle between buffer 1 and buffer 2 here.
   409         {//toggle between buffer 1 and buffer 2 here.
   343         if(iBuffer1AvailForWrite)
   410         if(iBuffer1AvailForWrite)
   344             {
   411             {
   345             aChunk.Set(&iBuffer1[0], 0, iBuffer1.MaxLength());
   412             iFileWriter1->GetWriteBuf(aChunk);
   346             }
   413             }
   347         else
   414         else
   348             {
   415             {
   349             aChunk.Set(&iBuffer2[0], 0, iBuffer2.MaxLength());
   416             iFileWriter2->GetWriteBuf(aChunk);
   350             }
   417             }
   351         }
   418         }
   352 
   419 
   353     return err;
   420     return err;
   354     }
   421     }
   400     return ETrue;
   467     return ETrue;
   401     }
   468     }
   402 
   469 
   403 EXPORT_C MMTPType* CMTPTypeFile::CommitChunkL(TPtr8& aChunk)
   470 EXPORT_C MMTPType* CMTPTypeFile::CommitChunkL(TPtr8& aChunk)
   404     {
   471     {
   405 	if(iFileRdWrError)
   472     if(iFileRdWrError)
   406 		{
   473         {
   407 		return NULL;
   474         return NULL;
   408 		}
   475         }
   409 	if(0 == aChunk.Length())
       
   410 		{
       
   411 		ToggleRdWrBuffer();
       
   412 		return NULL;
       
   413 		}
       
   414     iCurrentCommitChunk.Set(aChunk);
   476     iCurrentCommitChunk.Set(aChunk);
   415 
       
   416     if(iRemainingDataSize> iCurrentCommitChunk.Length())
   477     if(iRemainingDataSize> iCurrentCommitChunk.Length())
   417         {//This is NOT the last chunk, we issue an active object to commit it to File system.
   478         {
   418         iRemainingDataSize -= iCurrentCommitChunk.Length();
   479         iRemainingDataSize -= iCurrentCommitChunk.Length();    
   419 		/*
   480         }
   420 		if (!IsActive())
   481     else
   421 			{
   482         {
   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;
   483         iRemainingDataSize = 0;
   446         ToggleRdWrBuffer();
   484         }
   447 			return NULL;
   485     //wait until previous write complete
   448         }
   486     if(iBuffer1AvailForWrite)
   449 	return this;
   487         {
       
   488         iFileWriter2->WaitForWriteComplete();
       
   489         iFileRdWrError = (iFileWriter2->GetResult() != KErrNone); 
       
   490         }
       
   491     else
       
   492         {
       
   493         iFileWriter1->WaitForWriteComplete();
       
   494         iFileRdWrError = (iFileWriter1->GetResult() != KErrNone);
       
   495         }
       
   496     ToggleRdWrBuffer();
       
   497     if(iRemainingDataSize <= 0) //last chunk need wait the write complete
       
   498         {
       
   499         iFileWriter1->WaitForWriteComplete();
       
   500         iFileWriter2->WaitForWriteComplete();
       
   501         if(iFileWriter1->GetResult() != KErrNone || iFileWriter2->GetResult() != KErrNone)
       
   502             {
       
   503             iFile.SetSize(0);
       
   504             iFileRdWrError = ETrue;
       
   505             }
       
   506         }
       
   507     
       
   508     return NULL;
   450     }
   509     }
   451 
   510 
   452 //for partial
   511 //for partial
   453 EXPORT_C Int64 CMTPTypeFile::GetByteSent()
   512 EXPORT_C Int64 CMTPTypeFile::GetByteSent()
   454     {
   513     {
   588                 {
   647                 {
   589                 iFileRdWrError = ETrue;
   648                 iFileRdWrError = ETrue;
   590                 }
   649                 }
   591             else
   650             else
   592                 {
   651                 {
   593                 err = iFile.Write(iCurrentCommitChunk);
   652                 if(iBuffer1AvailForWrite)
   594                 if (err != KErrNone)
   653                     {
   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.
   654                     iFileWriter1->Write(iCurrentCommitChunk.Length());
   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
   655                     }
   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 
   656                 else
   598                     //corresponding error code to MTP initiator.
   657                     {
   599                     iFileRdWrError = ETrue;
   658                     iFileWriter2->Write(iCurrentCommitChunk.Length());
   600                     iFile.SetSize(0);
       
   601                     }
   659                     }
   602                 }
   660                 }
       
   661             }
       
   662         else
       
   663             {
       
   664             iFile.SetSize(0);
   603             }
   665             }
   604         iCurrentCommitChunk.Zero();
   666         iCurrentCommitChunk.Zero();
   605         }
   667         }
   606     else
   668     else
   607         {
   669         {