--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mtpfws/mtpfw/dataproviders/dputility/src/cmtpsendobjectinfo.cpp Tue Feb 02 01:11:40 2010 +0200
@@ -0,0 +1,1232 @@
+// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <f32file.h>
+#include <bautils.h>
+#include <mtp/cmtpdataproviderplugin.h>
+#include <mtp/mmtpdataproviderframework.h>
+
+#include <mtp/cmtpobjectmetadata.h>
+#include <mtp/cmtptypefile.h>
+#include <mtp/cmtptypeobjectinfo.h>
+#include <mtp/cmtptypeobjectproplist.h>
+#include <mtp/cmtptypestring.h>
+#include <mtp/mmtpobjectmgr.h>
+#include <mtp/mmtpstoragemgr.h>
+#include <mtp/mtpprotocolconstants.h>
+
+
+#include <mtp/tmtptyperequest.h>
+#include "cmtpconnection.h"
+#include "cmtpconnectionmgr.h"
+#include "cmtpsendobjectinfo.h"
+#include "mtpdppanic.h"
+#include "cmtpfsexclusionmgr.h"
+#include "cmtpdataprovidercontroller.h"
+#include "cmtpdataprovider.h"
+
+
+// Class constants.
+__FLOG_STMT(_LIT8(KComponent,"SendObjectInfo");)
+
+/**
+Verification data for the SendObjectInfo request
+*/
+const TMTPRequestElementInfo KMTPSendObjectInfoPolicy[] =
+ {
+ {TMTPTypeRequest::ERequestParameter1, EMTPElementTypeStorageId, EMTPElementAttrWrite, 1, 0, 0},
+ {TMTPTypeRequest::ERequestParameter2, EMTPElementTypeObjectHandle, EMTPElementAttrDir, 2, KMTPHandleAll, KMTPHandleNone}
+ };
+
+
+/**
+Two-phase construction method
+@param aFramework The data provider framework
+@param aConnection The connection from which the request comes
+@return a pointer to the created request processor object
+*/
+EXPORT_C MMTPRequestProcessor* CMTPSendObjectInfo::NewL(MMTPDataProviderFramework& aFramework, MMTPConnection& aConnection)
+ {
+ CMTPSendObjectInfo* self = new (ELeave) CMTPSendObjectInfo(aFramework, aConnection);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+Destructor
+*/
+EXPORT_C CMTPSendObjectInfo::~CMTPSendObjectInfo()
+ {
+ __FLOG(_L8("~CMTPSendObjectInfo - Entry"));
+
+ if ((iProgress == EObjectInfoSucceed ||
+ iProgress == EObjectInfoFail ||
+ iProgress == EObjectInfoInProgress) && !iNoRollback)
+ {
+ // Not finished SendObjectInfo/PropList SendObject pair detected.
+ Rollback();
+ }
+
+ iDpSingletons.Close();
+ delete iDateMod;
+ delete iFileReceived;
+ delete iParentSuid;
+ delete iReceivedObject;
+ delete iObjectInfo;
+ delete iObjectPropList;
+ iSingletons.Close();
+ __FLOG(_L8("~CMTPSendObjectInfo - Exit"));
+ __FLOG_CLOSE;
+ }
+
+/**
+Standard c++ constructor
+@param aFramework The data provider framework
+@param aConnection The connection from which the request comes
+*/
+CMTPSendObjectInfo::CMTPSendObjectInfo(MMTPDataProviderFramework& aFramework, MMTPConnection& aConnection) :
+ CMTPRequestProcessor(aFramework, aConnection, 0, NULL)
+ {
+ }
+
+/**
+Verify the request
+@return EMTPRespCodeOK if request is verified, otherwise one of the error response codes
+*/
+TMTPResponseCode CMTPSendObjectInfo::CheckRequestL()
+ {
+ __FLOG(_L8("CheckRequestL - Entry"));
+ TMTPResponseCode result = CheckSendingStateL();
+
+ if (result != EMTPRespCodeOK)
+ {
+ return result;
+ }
+
+ if (iProgress == EObjectNone) //this is the SendObjectInfo phase
+ {
+ iElementCount = sizeof(KMTPSendObjectInfoPolicy) / sizeof(TMTPRequestElementInfo);
+ iElements = KMTPSendObjectInfoPolicy;
+ }
+ else if (iProgress == EObjectInfoSucceed)
+ {
+ iElementCount = 0;
+ iElements = NULL;
+ }
+ //coverity[var_deref_model]
+ result = CMTPRequestProcessor::CheckRequestL();
+
+ if (EMTPRespCodeOK == result)
+ {
+ result = MatchStoreAndParentL();
+ }
+
+ if (result == EMTPRespCodeOK && iOperationCode == EMTPOpCodeSendObjectPropList)
+ {
+ TMTPFormatCode formatCode = static_cast<TMTPFormatCode>(Request().Uint32(TMTPTypeRequest::ERequestParameter3));
+ if (!iDpSingletons.ExclusionMgrL().IsFormatValid(formatCode))
+ {
+ result = EMTPRespCodeInvalidObjectFormatCode;
+ }
+ else
+ {
+ iStorageId = Request().Uint32(TMTPTypeRequest::ERequestParameter1);
+ TUint32 objectSizeHigh = Request().Uint32(TMTPTypeRequest::ERequestParameter4);
+ TUint32 objectSizeLow = Request().Uint32(TMTPTypeRequest::ERequestParameter5);
+ if (iStorageId == KMTPStorageDefault)
+ {
+ iStorageId = iFramework.StorageMgr().DefaultStorageId();
+ }
+ iObjectSize = MAKE_TUINT64(objectSizeHigh, objectSizeLow);
+ if (IsTooLarge(iObjectSize))
+ {
+ result = EMTPRespCodeObjectTooLarge;
+ }
+
+ //File size is limited to KMaxTInt64 that is 8ExaBytes
+ //if the object size is more,then report this error.
+ if (!CanStoreFileL(iStorageId, iObjectSize)||(iObjectSize > (KMaxTInt64)))
+ {
+ result = EMTPRespCodeStoreFull;
+ }
+ }
+ }
+
+ // If the previous request is not SendObjectInfo or SendObjectPropList, SendObject fails
+ if (result == EMTPRespCodeOK && iOperationCode == EMTPOpCodeSendObject)
+ {
+ if (iPreviousTransactionID + 1 != Request().Uint32(TMTPTypeRequest::ERequestTransactionID))
+ {
+ result = EMTPRespCodeNoValidObjectInfo;
+ }
+ }
+
+ __FLOG_VA((_L8("Result = 0x%04X"), result));
+ __FLOG(_L8("CheckRequestL - Exit"));
+ return result;
+ }
+
+TBool CMTPSendObjectInfo::HasDataphase() const
+ {
+ return ETrue;
+ }
+
+/**
+SendObjectInfo/SendObject request handler
+NOTE: SendObjectInfo has to be comes before SendObject requests. To maintain the state information
+between the two requests, the two requests are combined together in one request processor.
+*/
+void CMTPSendObjectInfo::ServiceL()
+ {
+ __FLOG(_L8("ServiceL - Entry"));
+ if (iProgress == EObjectNone)
+ {
+ iIsFolder = EFalse;
+ if (iOperationCode == EMTPOpCodeSendObjectInfo)
+ {
+ ServiceSendObjectInfoL();
+ }
+ else
+ {
+ ServiceSendObjectPropListL();
+ }
+ }
+ else
+ {
+ ServiceSendObjectL();
+ }
+ __FLOG(_L8("ServiceL - Exit"));
+ }
+
+/**
+Second-phase construction
+*/
+void CMTPSendObjectInfo::ConstructL()
+ {
+ __FLOG_OPEN(KMTPSubsystem, KComponent);
+ __FLOG(_L8("ConstructL - Entry"));
+ iExpectedSendObjectRequest.SetUint16(TMTPTypeRequest::ERequestOperationCode, EMTPOpCodeSendObject);
+ iReceivedObject = CMTPObjectMetaData::NewL();
+ iReceivedObject->SetUint(CMTPObjectMetaData::EDataProviderId, iFramework.DataProviderId());
+ iDpSingletons.OpenL(iFramework);
+ iNoRollback = EFalse;
+ iSingletons.OpenL();
+ __FLOG(_L8("ConstructL - Exit"));
+ }
+
+/**
+Override to match both the SendObjectInfo and SendObject requests
+@param aRequest The request to match
+@param aConnection The connection from which the request comes
+@return ETrue if the processor can handle the request, otherwise EFalse
+*/
+TBool CMTPSendObjectInfo::Match(const TMTPTypeRequest& aRequest, MMTPConnection& aConnection) const
+ {
+ __FLOG(_L8("Match - Entry"));
+ TBool result = EFalse;
+ TUint16 operationCode = aRequest.Uint16(TMTPTypeRequest::ERequestOperationCode);
+ if ((operationCode == EMTPOpCodeSendObjectInfo ||
+ operationCode == EMTPOpCodeSendObject ||
+ operationCode == EMTPOpCodeSendObjectPropList) &&
+ &iConnection == &aConnection)
+ {
+ result = ETrue;
+ }
+ __FLOG(_L8("Match - Exit"));
+ return result;
+ }
+
+/**
+Override to handle the response phase of SendObjectInfo and SendObject requests
+@return EFalse
+*/
+TBool CMTPSendObjectInfo::DoHandleResponsePhaseL()
+ {
+ __FLOG(_L8("DoHandleResponsePhaseL - Entry"));
+ //to check if the sending/receiving data is successful
+ TBool successful = !iCancelled;
+ if (iProgress == EObjectInfoInProgress)
+ {
+ if (iOperationCode == EMTPOpCodeSendObjectInfo)
+ {
+ successful = DoHandleSendObjectInfoCompleteL();
+ }
+ else
+ {
+ successful = DoHandleSendObjectPropListCompleteL();
+ }
+ iProgress = (successful ? EObjectInfoSucceed : EObjectInfoFail);
+ if(iIsFolder && iProgress == EObjectInfoSucceed)
+ {
+ iProgress = EObjectNone;
+ }
+ }
+ else if (iProgress == ESendObjectInProgress)
+ {
+ successful = DoHandleSendObjectCompleteL();
+ iProgress = (successful ? ESendObjectSucceed : ESendObjectFail);
+ }
+
+ __FLOG(_L8("DoHandleResponsePhaseL - Exit"));
+ return EFalse;
+ }
+
+/**
+Override to handle the completing phase of SendObjectInfo and SendObject requests
+@return ETrue if succesfully received the file, otherwise EFalse
+*/
+TBool CMTPSendObjectInfo::DoHandleCompletingPhaseL()
+ {
+ __FLOG(_L8("DoHandleCompletingPhaseL - Entry"));
+ TBool result = ETrue;
+ CMTPRequestProcessor::DoHandleCompletingPhaseL();
+ if (iProgress == EObjectInfoSucceed)
+ {
+ if (iOperationCode == EMTPOpCodeSendObjectInfo || iOperationCode == EMTPOpCodeSendObjectPropList)
+ {
+ iPreviousTransactionID = Request().Uint32(TMTPTypeRequest::ERequestTransactionID);
+ }
+ result = EFalse;
+ }
+ else if (iProgress == ESendObjectFail)
+ {
+ if (iOperationCode == EMTPOpCodeSendObject)
+ {
+ iPreviousTransactionID++;
+ }
+ iProgress = EObjectInfoSucceed;
+ result = EFalse;
+ }
+
+ __FLOG(_L8("DoHandleCompletingPhaseL - Exit"));
+ return result;
+ }
+
+
+/**
+Verify if the SendObject request comes after SendObjectInfo request
+@return EMTPRespCodeOK if SendObject request comes after a valid SendObjectInfo request, otherwise
+EMTPRespCodeNoValidObjectInfo
+*/
+TMTPResponseCode CMTPSendObjectInfo::CheckSendingStateL()
+ {
+ __FLOG(_L8("CheckSendingState - Entry"));
+ TMTPResponseCode result = EMTPRespCodeOK;
+ iOperationCode = Request().Uint16(TMTPTypeRequest::ERequestOperationCode);
+
+ if (iOperationCode == EMTPOpCodeSendObject)
+ {
+ //In ParseRouter everytime SendObject gets resolved then will be removed from Registry
+ //Right away therefore we need reRegister it here again in case possible cancelRequest
+ //Against this SendObject being raised.
+ iExpectedSendObjectRequest.SetUint32(TMTPTypeRequest::ERequestSessionID, iSessionId);
+ iFramework.RouteRequestRegisterL(iExpectedSendObjectRequest, iConnection);
+ }
+
+ if (iProgress == EObjectNone)
+ {
+ if (iOperationCode == EMTPOpCodeSendObject)
+ {
+ result = EMTPRespCodeNoValidObjectInfo;
+ }
+ }
+ else if (iProgress == EObjectInfoSucceed)
+ {
+ if (iOperationCode == EMTPOpCodeSendObjectInfo || iOperationCode == EMTPOpCodeSendObjectPropList)
+ {
+ //SendObjectInfo/SendObjectPropList sending the folder over which not necessarily
+ //being followed by SendObject as per MTP Specification in which case we need unregister RouteRequest of
+ //SendObject made by previous SendObjectInfo/SendObjectPropList transaction without SendObject being followed.
+ if( iIsFolder )
+ {
+ iFramework.RouteRequestUnregisterL(iExpectedSendObjectRequest, iConnection);
+ }
+
+ delete iObjectInfo;
+ iObjectInfo = NULL;
+ delete iObjectPropList;
+ iObjectPropList = NULL;
+ iProgress = EObjectNone;
+ }
+ }
+ else
+ {
+ Panic(EMTPDpSendObjectStateInvalid);
+ }
+ __FLOG(_L8("CheckSendingState - Exit"));
+ return result;
+ }
+
+/**
+SendObjectInfo request handler
+*/
+void CMTPSendObjectInfo::ServiceSendObjectInfoL()
+ {
+ __FLOG(_L8("ServiceSendObjectInfoL - Entry"));
+ delete iObjectInfo;
+ iObjectInfo = NULL;
+ iObjectInfo = CMTPTypeObjectInfo::NewL();
+ iCancelled = EFalse;
+ ReceiveDataL(*iObjectInfo);
+ iProgress = EObjectInfoInProgress;
+ __FLOG(_L8("ServiceSendObjectInfoL - Exit"));
+ }
+
+/**
+SendObjectPropList request handler
+*/
+void CMTPSendObjectInfo::ServiceSendObjectPropListL()
+ {
+ __FLOG(_L8("ServiceSendObjectPropListL - Entry"));
+ delete iObjectPropList;
+ iObjectPropList = NULL;
+ iObjectPropList = CMTPTypeObjectPropList::NewL();
+ iCancelled = EFalse;
+ iReceivedObject->SetUint(CMTPObjectMetaData::EFormatCode, iRequest->Uint32(TMTPTypeRequest::ERequestParameter3));
+ ReceiveDataL(*iObjectPropList);
+ iProgress = EObjectInfoInProgress;
+ __FLOG(_L8("ServiceSendObjectPropListL - Exit"));
+ }
+
+/**
+SendObject request handler
+*/
+void CMTPSendObjectInfo::ServiceSendObjectL()
+ {
+ __FLOG(_L8("ServiceSendObjectL - Entry"));
+ if (iIsFolder)
+ {
+ // A generic folder doesn't have anything interesting during its data phase
+ ReceiveDataL(iNullObject);
+ }
+ else
+ {
+ ReceiveDataL(*iFileReceived);
+ }
+
+ iProgress = ESendObjectInProgress;
+ __FLOG(_L8("ServiceSendObjectL - Exit"));
+ }
+
+/**
+Get a default parent object, if the request does not specify a parent object.
+*/
+void CMTPSendObjectInfo::GetDefaultParentObjectL()
+ {
+ __FLOG(_L8("GetDefaultParentObjectL - Entry"));
+ if (iStorageId == KMTPStorageDefault)
+ {
+ iStorageId = iFramework.StorageMgr().DefaultStorageId();
+ }
+ TInt drive(iFramework.StorageMgr().DriveNumber(iStorageId));
+ User::LeaveIfError(drive);
+
+ // Obtain the root of the drive. Logical storages can sometimes have a filesystem root
+ // other than <drive>:\ . For example an MP3 DP might have a root of c:\media\music\
+ // The DevDP needs to be aware of this when handling associations (folders) so they are
+ // created in the correct location on the filesystem.
+ delete iParentSuid;
+ iParentSuid = NULL;
+ iParentSuid=(iFramework.StorageMgr().StorageL(iStorageId).DesC(CMTPStorageMetaData::EStorageSuid)).AllocL();
+ iReceivedObject->SetUint(CMTPObjectMetaData::EParentHandle, KMTPHandleNoParent);
+ __FLOG(_L8("GetDefaultParentObjectL - Exit"));
+ }
+
+/**
+Get parent object and storage id
+@return EMTPRespCodeOK if successful, otherwise, EMTPRespCodeInvalidParentObject
+*/
+TMTPResponseCode CMTPSendObjectInfo::GetParentObjectAndStorageIdL()
+ {
+ __FLOG(_L8("GetParentObjectAndStorageIdL - Entry"));
+ __ASSERT_DEBUG(iRequestChecker, Panic(EMTPDpRequestCheckNull));
+
+ iStorageId = Request().Uint32(TMTPTypeRequest::ERequestParameter1);
+ iParentHandle = Request().Uint32(TMTPTypeRequest::ERequestParameter2);
+ //does not take ownership
+ CMTPObjectMetaData* parentObjectInfo = iRequestChecker->GetObjectInfo(iParentHandle);
+
+ if (!parentObjectInfo)
+ {
+ GetDefaultParentObjectL();
+ }
+ else
+ {
+ delete iParentSuid;
+ iParentSuid = NULL;
+ iParentSuid = parentObjectInfo->DesC(CMTPObjectMetaData::ESuid).AllocL();
+ iReceivedObject->SetUint(CMTPObjectMetaData::EParentHandle, iParentHandle);
+ }
+
+ __FLOG_VA((_L8("iParentSuid = %S"), iParentSuid));
+ __FLOG(_L8("GetParentObjectAndStorageIdL - Exit"));
+ return EMTPRespCodeOK;
+ }
+
+/**
+Handling the completing phase of SendObjectInfo request
+@return ETrue if the specified object can be saved on the specified location, otherwise, EFalse
+*/
+TBool CMTPSendObjectInfo::DoHandleSendObjectInfoCompleteL()
+ {
+ __FLOG(_L8("DoHandleSendObjectInfoCompleteL - Entry"));
+ TBool result(ETrue);
+ TUint16 format(iObjectInfo->Uint16L(CMTPTypeObjectInfo::EObjectFormat));
+
+ result = iDpSingletons.ExclusionMgrL().IsFormatValid(TMTPFormatCode(format));
+
+ if (result)
+ {
+ __FLOG_VA((_L8("ASSOCIATION TYPE IS: %X"), iObjectInfo->Uint16L(CMTPTypeObjectInfo::EAssociationType)));
+ if(format == EMTPFormatCodeAssociation)
+ {
+ if((iObjectInfo->Uint16L(CMTPTypeObjectInfo::EAssociationType) == EMTPAssociationTypeGenericFolder) ||
+ (iObjectInfo->Uint16L(CMTPTypeObjectInfo::EAssociationType) == EMTPAssociationTypeUndefined))
+ iIsFolder = ETrue;
+ else{
+ SendResponseL(EMTPRespCodeInvalidDataset);
+ result = EFalse;
+ }
+ }
+ delete iDateMod;
+ iDateMod = NULL;
+
+ iDateMod = iObjectInfo->StringCharsL(CMTPTypeObjectInfo::EDateModified).AllocL();
+
+ TMTPResponseCode responseCode(GetParentObjectAndStorageIdL());
+ if (responseCode != EMTPRespCodeOK)
+ {
+ SendResponseL(responseCode);
+ result = EFalse;
+ }
+ }
+ else
+ {
+ SendResponseL(EMTPRespCodeInvalidObjectFormatCode);
+ }
+
+ if (result)
+ {
+ iObjectSize = iObjectInfo->Uint32L(CMTPTypeObjectInfo::EObjectCompressedSize);
+
+ if (IsTooLarge(iObjectSize))
+ {
+ SendResponseL(EMTPRespCodeObjectTooLarge);
+ result = EFalse;
+ }
+ if(result && !CanStoreFileL(iStorageId, iObjectSize))
+ {
+ SendResponseL(EMTPRespCodeStoreFull);
+ result = EFalse;
+ }
+ }
+
+ if (result)
+ {
+ iProtectionStatus = iObjectInfo->Uint16L(CMTPTypeObjectInfo::EProtectionStatus);
+ result = GetFullPathNameL(iObjectInfo->StringCharsL(CMTPTypeObjectInfo::EFilename));
+ if (!result)
+ {
+ // File and/or parent pathname invalid.
+ SendResponseL(EMTPRespCodeInvalidDataset);
+ }
+ }
+
+ if (result)
+ {
+ result &= !Exists(iFullPath);
+ if (!result)
+ {
+ // Object with the same name already exists.
+ iNoRollback = ETrue;
+ SendResponseL(EMTPRespCodeAccessDenied);
+ }
+ }
+
+ if (result)
+ {
+ iReceivedObject->SetUint(CMTPObjectMetaData::EFormatCode, format);
+
+ if (iIsFolder)
+ {
+ iReceivedObject->SetUint(CMTPObjectMetaData::EFormatSubCode, EMTPAssociationTypeGenericFolder);
+ }
+
+ TRAPD(err, CreateFsObjectL());
+
+ if (err != KErrNone)
+ {
+ SendResponseL(ErrorToMTPError(err));
+ }
+ else
+ {
+ ReserveObjectL();
+ }
+ }
+ __FLOG(_L8("DoHandleSendObjectInfoCompleteL - Exit"));
+ return result;
+ }
+
+/**
+Handling the completing phase of SendObjectPropList request
+@return ETrue if the specified object can be saved on the specified location, otherwise, EFalse
+*/
+TBool CMTPSendObjectInfo::DoHandleSendObjectPropListCompleteL()
+ {
+ __FLOG(_L8("DoHandleSendObjectPropListCompleteL - Entry"));
+ TBool result(ETrue);
+
+ TMTPResponseCode responseCode(GetParentObjectAndStorageIdL());
+ if (responseCode != EMTPRespCodeOK)
+ {
+ SendResponseL(responseCode);
+ result = EFalse;
+ }
+
+ if (result)
+ {
+ // Any kind of association is treated as a folder
+ const TUint32 formatCode(Request().Uint32(TMTPTypeRequest::ERequestParameter3));
+ iIsFolder = (formatCode == EMTPFormatCodeAssociation);
+
+ TInt invalidParameterIndex = KErrNotFound;
+ responseCode = VerifyObjectPropListL(invalidParameterIndex);
+ result = (responseCode == EMTPRespCodeOK);
+ if (!result)
+ {
+ TUint32 parameters[4];
+ parameters[0] = 0;
+ parameters[1] = 0;
+ parameters[2] = 0;
+ parameters[3] = invalidParameterIndex;
+ SendResponseL(responseCode, 4, parameters);
+ }
+ }
+
+ if (result)
+ {
+ result = !Exists(iFullPath);
+ if (!result)
+ {
+ // Object with the same name already exists.
+ iNoRollback = ETrue;
+ SendResponseL(EMTPRespCodeAccessDenied);
+ }
+ }
+
+ if (result)
+ {
+ if (iIsFolder)
+ {
+ iReceivedObject->SetUint(CMTPObjectMetaData::EFormatSubCode, EMTPAssociationTypeGenericFolder);
+ }
+
+ TRAPD(err, CreateFsObjectL());
+
+ if (err != KErrNone)
+ {
+ SendResponseL(ErrorToMTPError(err));
+ }
+ else
+ {
+ ReserveObjectL();
+ }
+ }
+
+ __FLOG(_L8("DoHandleSendObjectPropListCompleteL - Exit"));
+ return result;
+ }
+
+/**
+Handling the completing phase of SendObject request
+@return ETrue if the object has been successfully saved on the device, otherwise, EFalse
+*/
+TBool CMTPSendObjectInfo::DoHandleSendObjectCompleteL()
+ {
+ __FLOG(_L8("DoHandleSendObjectCompleteL - Entry"));
+ TBool result(ETrue);
+
+ if (!iIsFolder)
+ {
+ delete iFileReceived;
+ iFileReceived = NULL;
+
+ TEntry fileEntry;
+ User::LeaveIfError(iFramework.Fs().Entry(iFullPath, fileEntry));
+
+ if (fileEntry.FileSize() != iObjectSize)
+ {
+ iFramework.RouteRequestUnregisterL(iExpectedSendObjectRequest, iConnection);
+
+ iFramework.Fs().Delete(iFullPath);
+ iFramework.ObjectMgr().UnreserveObjectHandleL(*iReceivedObject);
+ TMTPResponseCode responseCode = EMTPRespCodeObjectTooLarge;
+ if (fileEntry.FileSize() < iObjectSize)
+ {
+ responseCode = EMTPRespCodeInvalidDataset;
+ }
+ SendResponseL(responseCode);
+ result = EFalse;
+ }
+ }
+
+
+ // Get the result of the SendObject operation.
+ RMTPFramework frameworkSingletons;
+ frameworkSingletons.OpenL();
+ TUint connectionId = iConnection.ConnectionId();
+ CMTPConnectionMgr& connectionMgr = frameworkSingletons.ConnectionMgr();
+ CMTPConnection& connection = connectionMgr.ConnectionL(connectionId);
+ TInt ret = connection.GetDataReceiveResult();
+ frameworkSingletons.Close();
+ // SendObject is cancelled or connection is dropped.
+ if(result && (iCancelled || (ret == KErrAbort)))
+ {
+ __FLOG(_L8("It is a cancel for sendObject."));
+ iFramework.RouteRequestUnregisterL(iExpectedSendObjectRequest, iConnection);
+ Rollback();
+ SendResponseL(EMTPRespCodeTransactionCancelled);
+ }
+ else if (result && !iCancelled)
+ {
+ iFramework.RouteRequestUnregisterL(iExpectedSendObjectRequest, iConnection);
+
+ //The MTP spec states that it is not mandatory for SendObjectInfo/SendObjectPropList
+ //to be followed by a SendObject. An object is reserved in the ObjectStore on
+ //receiving a SendObjectInfo/SendObjectPropList request, but we only commit it
+ //on receiving the corresponding SendObject request. With Associations however
+ //we commit the object straight away as the SendObject phase is often absent
+ //with folder creation.
+
+ if(!iIsFolder)
+ {
+ SetPropertiesL();
+ iFramework.ObjectMgr().CommitReservedObjectHandleL(*iReceivedObject);
+
+ TParsePtrC file( iFullPath );
+ _LIT( KTxtExtensionODF, ".odf" );
+ if ( file.ExtPresent() && file.Ext().CompareF(KTxtExtensionODF)==0 )
+ {;
+ TUint32 DpId = iFramework.DataProviderId();
+ DpId = iDpSingletons.MTPUtility().GetDpId(file.Ext().Mid(1),KNullDesC);
+ //The data provider which owns all mimetypes of a file extension is not found
+ if ( 255 == DpId )
+ {
+ HBufC* mime = NULL;
+ mime = iDpSingletons.MTPUtility().ContainerMimeType(iFullPath);
+ if ( mime != NULL )
+ {
+ DpId = iDpSingletons.MTPUtility().GetDpId(file.Ext().Mid(1),*mime);
+ delete mime;
+ mime = NULL;
+ }
+ }
+ if ( DpId!=iFramework.DataProviderId() && DpId!=255)
+ {
+ iReceivedObject->SetUint(CMTPObjectMetaData::EDataProviderId,DpId);
+ //iReceivedObject->SetUint(CMTPObjectMetaData::EFormatCode,format);
+ iFramework.ObjectMgr().ModifyObjectL(*iReceivedObject);
+ TUint32 handle = iReceivedObject->Uint(CMTPObjectMetaData::EHandle);
+ iSingletons.DpController().NotifyDataProvidersL(DpId,EMTPObjectAdded,(TAny*)&handle);
+ }
+ }
+ }
+
+ SendResponseL(EMTPRespCodeOK);
+ }
+ __FLOG(_L8("DoHandleSendObjectCompleteL - Exit"));
+ return result;
+ }
+
+
+/**
+Get the full path name of the object to be saved
+@param aFileName, on entry, contains the file name of the object,
+on return, contains the full path name of the object to be saved
+@return ETrue if the name is valid, EFalse otherwise
+*/
+TBool CMTPSendObjectInfo::GetFullPathNameL(const TDesC& aFileName)
+ {
+ __FLOG(_L8("GetFullPathNameL - Entry"));
+ TBool result(EFalse);
+ if (aFileName.Length() > 0)
+ {
+ iFullPath = *iParentSuid;
+ if (iFullPath.Length() + aFileName.Length() < iFullPath.MaxLength())
+ {
+ iFullPath.Append(aFileName);
+ if (iIsFolder)
+ {
+ iFullPath.Append(KPathDelimiter);
+
+ TBool valid(EFalse);
+ if (BaflUtils::CheckWhetherFullNameRefersToFolder(iFullPath, valid) == KErrNone)
+ {
+ result = valid;
+ }
+ }
+ else
+ {
+ result = iFramework.Fs().IsValidName(iFullPath);
+ }
+ }
+ }
+
+#ifdef __FLOG_ACTIVE
+ TFileName tempName;
+ tempName.Copy(iFullPath);
+ tempName.Collapse();
+ __FLOG_VA((_L8("iFullPath = %S, Result = %d"), &tempName, result));
+ __FLOG(_L8("GetFullPathNameL - Exit"));
+#endif
+ return result;
+ }
+
+/**
+Check if we can store the file on the storage
+@return ETrue if yes, otherwise EFalse
+*/
+TBool CMTPSendObjectInfo::CanStoreFileL(TUint32 aStorageId, TInt64 aObjectSize) const
+ {
+ __FLOG(_L8("CanStoreFileL - Entry"));
+ TBool result(ETrue);
+ if (aStorageId == KMTPStorageDefault)
+ {
+ aStorageId = iFramework.StorageMgr().DefaultStorageId();
+ }
+ TInt drive( iFramework.StorageMgr().DriveNumber(aStorageId) );
+ User::LeaveIfError(drive);
+ TVolumeInfo volumeInfo;
+ User::LeaveIfError(iFramework.Fs().Volume(volumeInfo, drive));
+ if (volumeInfo.iFree < aObjectSize)
+ {
+ result = EFalse;
+ }
+ __FLOG_VA((_L8("Result = %d"), result));
+ __FLOG(_L8("CanStoreFileL - Exit"));
+ return result;
+ }
+
+/**
+Check if the object is too large
+@return ETrue if yes, otherwise EFalse
+*/
+TBool CMTPSendObjectInfo::IsTooLarge(TUint64 aObjectSize) const
+ {
+ __FLOG(_L8("IsTooLarge - Entry"));
+ TBool ret(aObjectSize > KMaxTInt64);
+
+ if(!ret)
+ {
+ TBuf<255> fsname;
+ TUint32 storageId = iStorageId;
+ if (storageId == KMTPStorageDefault)
+ {
+ storageId = iFramework.StorageMgr().DefaultStorageId();
+ }
+ TInt drive( iFramework.StorageMgr().DriveNumber(storageId) );
+ User::LeaveIfError(drive);
+ iFramework.Fs().FileSystemSubType(drive, fsname);
+
+ const TUint64 KMaxFatFileSize = 0xFFFFFFFF; //Maximal file size supported by all FAT filesystems (4GB-1)
+ _LIT(KFsFAT16, "FAT16");
+ _LIT(KFsFAT32, "FAT32");
+
+ if((fsname.CompareF(KFsFAT16) == 0 || fsname.CompareF(KFsFAT32) == 0) && aObjectSize > KMaxFatFileSize)
+ {
+ ret = ETrue;
+ }
+ }
+ __FLOG_VA((_L8("Result = %d"), ret));
+ __FLOG(_L8("IsTooLarge - Exit"));
+ return ret;
+ }
+
+/**
+Check if the file already exists on the storage.
+@return ETrue if file is exists, otherwise EFalse
+*/
+TBool CMTPSendObjectInfo::Exists(const TDesC& aName) const
+ {
+ __FLOG(_L8("Exists - Entry"));
+ // This detects both files and folders
+ TBool ret(EFalse);
+ ret = BaflUtils::FileExists(iFramework.Fs(), aName);
+ __FLOG_VA((_L8("Result = %d"), ret));
+ __FLOG(_L8("Exists - Exit"));
+ return ret;
+ }
+
+/**
+Check if the property list is valid and extract properties (file name)
+@param aInvalidParameterIndex if invalid, contains the index of the property. Undefined, if it is valid.
+@return if error, one of the error response code; otherwise EMTPRespCodeOK
+*/
+TMTPResponseCode CMTPSendObjectInfo::VerifyObjectPropListL(TInt& aInvalidParameterIndex)
+ {
+ __FLOG(_L8("VerifyObjectPropListL - Entry"));
+ TMTPResponseCode responseCode(EMTPRespCodeOK);
+ const TUint KCount(iObjectPropList->NumberOfElements());
+ iObjectPropList->ResetCursor();
+ for (TUint i(0); (i < KCount); i++)
+ {
+ CMTPTypeObjectPropListElement& KElement=iObjectPropList->GetNextElementL();
+ const TUint32 KHandle(KElement.Uint32L(CMTPTypeObjectPropListElement::EObjectHandle));
+ aInvalidParameterIndex = i;
+ if (KHandle != KMTPHandleNone)
+ {
+ responseCode = EMTPRespCodeInvalidObjectHandle;
+ break;
+ }
+
+ responseCode = CheckPropCodeL(KElement);
+ if (responseCode != EMTPRespCodeOK)
+ {
+ break;
+ }
+ responseCode = ExtractPropertyL(KElement);
+ if (responseCode != EMTPRespCodeOK)
+ {
+ break;
+ }
+ }
+ __FLOG_VA((_L8("Result = 0x%04X"), responseCode));
+ __FLOG(_L8("VerifyObjectPropListL - Exit"));
+ return responseCode;
+ }
+
+/**
+Extracts the file information from the object property list element
+@param aElement an object property list element
+@param aPropertyCode MTP property code for the element
+@return MTP response code
+*/
+TMTPResponseCode CMTPSendObjectInfo::ExtractPropertyL(const CMTPTypeObjectPropListElement& aElement)
+ {
+ __FLOG(_L8("ExtractPropertyL - Entry"));
+ TMTPResponseCode responseCode(EMTPRespCodeOK);
+ switch (aElement.Uint16L(CMTPTypeObjectPropListElement::EPropertyCode))
+ {
+ case EMTPObjectPropCodeAssociationDesc:
+ // Actually, any association is treated as a folder, and iIsFolder should already be set
+ iIsFolder = ((aElement.Uint32L(CMTPTypeObjectPropListElement::EValue) == EMTPAssociationTypeGenericFolder)||
+ (aElement.Uint32L(CMTPTypeObjectPropListElement::EValue) == EMTPAssociationTypeUndefined));
+ break;
+
+ case EMTPObjectPropCodeObjectFileName:
+ {
+ const TDesC& KFileName = aElement.StringL(CMTPTypeObjectPropListElement::EValue);
+ if (!GetFullPathNameL(KFileName))
+ {
+ responseCode = EMTPRespCodeInvalidDataset;
+ }
+ }
+ break;
+
+ case EMTPObjectPropCodeProtectionStatus:
+ {
+ iProtectionStatus = aElement.Uint16L(CMTPTypeObjectPropListElement::EValue);
+ if (iProtectionStatus != EMTPProtectionNoProtection &&
+ iProtectionStatus != EMTPProtectionReadOnly)
+ {
+ responseCode = EMTPRespCodeParameterNotSupported;
+ }
+ }
+ break;
+
+ case EMTPObjectPropCodeDateModified:
+ delete iDateMod;
+ iDateMod = NULL;
+ iDateMod = aElement.StringL(CMTPTypeObjectPropListElement::EValue).AllocL();
+ break;
+ case EMTPObjectPropCodeName:
+ iName = aElement.StringL(CMTPTypeObjectPropListElement::EValue);
+ break;
+ default:
+ break;
+ }
+ __FLOG_VA((_L8("Result = 0x%04X"), responseCode));
+ __FLOG(_L8("ExtractPropertyL - Exit"));
+ return responseCode;
+ }
+
+/**
+Validates the data type for a given property code.
+@param aElement an object property list element
+@param aPropertyCode MTP property code for the element
+@return EMTPRespCodeOK if the combination is valid, or another MTP response code if not
+*/
+TMTPResponseCode CMTPSendObjectInfo::CheckPropCodeL(const CMTPTypeObjectPropListElement& aElement) const
+ {
+ __FLOG(_L8("CheckPropCode - Entry"));
+ TMTPResponseCode responseCode(EMTPRespCodeOK);
+ switch(aElement.Uint16L(CMTPTypeObjectPropListElement::EPropertyCode))
+ {
+ case EMTPObjectPropCodeStorageID:
+ if (aElement.Uint16L(CMTPTypeObjectPropListElement::EDatatype) != EMTPTypeUINT32)
+ {
+ responseCode = EMTPRespCodeInvalidObjectPropFormat;
+ }
+ else if (iStorageId != aElement.Uint32L(CMTPTypeObjectPropListElement::EValue))
+ {
+ responseCode = EMTPRespCodeInvalidDataset;
+ }
+ break;
+
+ case EMTPObjectPropCodeObjectFormat:
+ if (aElement.Uint16L(CMTPTypeObjectPropListElement::EDatatype) != EMTPTypeUINT16)
+ {
+ responseCode = EMTPRespCodeInvalidObjectPropFormat;
+ }
+ else if (Request().Uint32(TMTPTypeRequest::ERequestParameter3) != aElement.Uint16L(CMTPTypeObjectPropListElement::EValue))
+ {
+ responseCode = EMTPRespCodeInvalidDataset;
+ }
+ break;
+
+ case EMTPObjectPropCodeObjectSize:
+ if (aElement.Uint16L(CMTPTypeObjectPropListElement::EDatatype) != EMTPTypeUINT64)
+ {
+ responseCode = EMTPRespCodeInvalidObjectPropFormat;
+ }
+ else if (iObjectSize != aElement.Uint64L(CMTPTypeObjectPropListElement::EValue))
+ {
+ responseCode = EMTPRespCodeInvalidDataset;
+ }
+ break;
+
+ case EMTPObjectPropCodeParentObject:
+ if (aElement.Uint16L(CMTPTypeObjectPropListElement::EDatatype) != EMTPTypeUINT32)
+ {
+ responseCode = EMTPRespCodeInvalidObjectPropFormat;
+ }
+ else if (Request().Uint32(TMTPTypeRequest::ERequestParameter2) != aElement.Uint32L(CMTPTypeObjectPropListElement::EValue))
+ {
+ responseCode = EMTPRespCodeInvalidDataset;
+ }
+ break;
+
+ case EMTPObjectPropCodePersistentUniqueObjectIdentifier:
+ responseCode = EMTPRespCodeAccessDenied;
+ break;
+
+ case EMTPObjectPropCodeProtectionStatus:
+ if (aElement.Uint16L(CMTPTypeObjectPropListElement::EDatatype) != EMTPTypeUINT16)
+ {
+ responseCode = EMTPRespCodeInvalidObjectPropFormat;
+ }
+ break;
+
+ case EMTPObjectPropCodeDateModified:
+ case EMTPObjectPropCodeObjectFileName:
+ case EMTPObjectPropCodeName:
+ if (aElement.Uint16L(CMTPTypeObjectPropListElement::EDatatype) != EMTPTypeString)
+ {
+ responseCode = EMTPRespCodeInvalidObjectPropFormat;
+ }
+ break;
+
+ case EMTPObjectPropCodeNonConsumable:
+ if (aElement.Uint16L(CMTPTypeObjectPropListElement::EDatatype) != EMTPTypeUINT8)
+ {
+ responseCode = EMTPRespCodeInvalidObjectPropFormat;
+ }
+ break;
+
+ case EMTPObjectPropCodeAssociationType:
+ if (aElement.Uint16L(CMTPTypeObjectPropListElement::EDatatype) != EMTPTypeUINT16)
+ {
+ responseCode = EMTPRespCodeInvalidObjectPropFormat;
+ }
+ break;
+
+ case EMTPObjectPropCodeAssociationDesc:
+ if (aElement.Uint16L(CMTPTypeObjectPropListElement::EDatatype) != EMTPTypeUINT32)
+ {
+ responseCode = EMTPRespCodeInvalidObjectPropFormat;
+ }
+ break;
+
+ default:
+ responseCode = EMTPRespCodeInvalidObjectPropCode;
+ break;
+ }
+ __FLOG_VA((_L8("Result = 0x%04X"), responseCode));
+ __FLOG(_L8("CheckPropCode - Exit"));
+ return responseCode;
+ }
+
+/**
+Validates the data type for a given property code.
+@return EMTPRespCodeOK if the parent handle matches the store id, or another MTP response code if not
+*/
+TMTPResponseCode CMTPSendObjectInfo::MatchStoreAndParentL() const
+ {
+ TMTPResponseCode ret = EMTPRespCodeOK;
+ const TUint32 storeId(Request().Uint32(TMTPTypeRequest::ERequestParameter1));
+ const TUint32 parentHandle(Request().Uint32(TMTPTypeRequest::ERequestParameter2));
+
+ // this checking is only valid when the second parameter is not a special value.
+ if (parentHandle != KMTPHandleAll && parentHandle != KMTPHandleNone)
+ {
+ //does not take owernship
+ CMTPObjectMetaData* parentObjInfo = iRequestChecker->GetObjectInfo(parentHandle);
+ __ASSERT_DEBUG(parentObjInfo, Panic(EMTPDpObjectNull));
+
+ if (parentObjInfo->Uint(CMTPObjectMetaData::EStorageId) != storeId)
+ {
+ ret = EMTPRespCodeInvalidObjectHandle;
+ }
+ }
+
+ return ret;
+ }
+
+/**
+Reserves space for and assigns an object handle to the received object, then
+sends a success response.
+*/
+void CMTPSendObjectInfo::ReserveObjectL()
+ {
+ __FLOG(_L8("ReserveObjectL - Entry"));
+ iReceivedObject->SetUint(CMTPObjectMetaData::EStorageId, iStorageId);
+ iReceivedObject->SetDesCL(CMTPObjectMetaData::ESuid, iFullPath);
+
+ iFramework.ObjectMgr().ReserveObjectHandleL(*iReceivedObject, iObjectSize);
+
+ if(iIsFolder)
+ {
+ SetPropertiesL();
+ iFramework.ObjectMgr().CommitReservedObjectHandleL(*iReceivedObject);
+ }
+ else
+ {
+ iExpectedSendObjectRequest.SetUint32(TMTPTypeRequest::ERequestSessionID, iSessionId);
+ iFramework.RouteRequestRegisterL(iExpectedSendObjectRequest, iConnection);
+ }
+ TUint32 parameters[3];
+ parameters[0] = iStorageId;
+ parameters[1] = iParentHandle;
+ parameters[2] = iReceivedObject->Uint(CMTPObjectMetaData::EHandle);
+ SendResponseL(EMTPRespCodeOK, (sizeof(parameters) / sizeof(parameters[0])), parameters);
+ __FLOG(_L8("ReserveObjectL - Exit"));
+ }
+
+void CMTPSendObjectInfo::CreateFsObjectL()
+ {
+ if (iIsFolder)
+ {
+ User::LeaveIfError(iFramework.Fs().MkDirAll(iFullPath));
+ }
+ else
+ {
+ delete iFileReceived;
+ iFileReceived = NULL;
+ iFileReceived = CMTPTypeFile::NewL(iFramework.Fs(), iFullPath, EFileWrite);
+ iFileReceived->SetSizeL(iObjectSize);
+ }
+ }
+
+void CMTPSendObjectInfo::Rollback()
+ {
+ if(iIsFolder)
+ {
+ __FLOG(_L8("It is a folder cancel process."));
+ iFramework.Fs().RmDir(iFullPath);
+ // If it is folder, delete it from MTP database, i.e ObjectStore.
+ TRAP_IGNORE(iFramework.ObjectMgr().RemoveObjectL(iFullPath));
+ }
+ else
+ {
+ __FLOG(_L8("It is a file cancel process."));
+ // Delete this object from file system.
+ iFramework.Fs().Delete(iFullPath);
+ TRAP_IGNORE(iFramework.ObjectMgr().UnreserveObjectHandleL(*iReceivedObject));
+ }
+ }
+
+TMTPResponseCode CMTPSendObjectInfo::ErrorToMTPError(TInt aError) const
+ {
+ TMTPResponseCode resp = EMTPRespCodeGeneralError;
+
+ switch (aError)
+ {
+ case KErrNone:
+ resp = EMTPRespCodeOK;
+ break;
+
+ case KErrAccessDenied:
+ resp = EMTPRespCodeAccessDenied;
+ break;
+
+ case KErrDiskFull:
+ resp = EMTPRespCodeStoreFull;
+ break;
+ }
+
+ return resp;
+ }
+
+/**
+Sets the read only status on the current file to match the sent object.
+*/
+void CMTPSendObjectInfo::SetPropertiesL()
+ {
+ __FLOG(_L8("SetPropertiesL - Entry"));
+ TEntry entry;
+ User::LeaveIfError(iFramework.Fs().Entry(iFullPath, entry));
+
+ TUint16 assoc(EMTPAssociationTypeUndefined);
+ if (entry.IsDir())
+ {
+ assoc = EMTPAssociationTypeGenericFolder;
+ }
+ iReceivedObject->SetUint(CMTPObjectMetaData::EFormatSubCode, assoc);
+
+ if (iName.Length() == 0)
+ {
+ if (entry.IsDir())
+ {
+ TParsePtrC pathParser(iFullPath.Left(iFullPath.Length() - 1)); // Ignore the trailing "\".
+ iName = pathParser.Name();
+ }
+ else
+ {
+ TParsePtrC pathParser(iFullPath);
+ iName = pathParser.Name();
+ }
+ }
+
+ if (iProtectionStatus == EMTPProtectionNoProtection ||
+ iProtectionStatus == EMTPProtectionReadOnly)
+ {
+ entry.iAtt &= ~(KEntryAttNormal | KEntryAttReadOnly);
+ if (iProtectionStatus == EMTPProtectionNoProtection)
+ {
+ entry.iAtt |= KEntryAttNormal;
+ }
+ else
+ {
+ entry.iAtt |= KEntryAttReadOnly;
+ }
+ User::LeaveIfError(iFramework.Fs().SetAtt(iFullPath, entry.iAtt, ~entry.iAtt));
+ }
+ iReceivedObject->SetDesCL(CMTPObjectMetaData::EName, iName);
+
+ __FLOG(_L8("SetPropertiesL - Exit"));
+ }
+