diff -r 000000000000 -r d0791faffa3f mtpfws/mtpfw/dataproviders/dputility/src/cmtpsendobjectinfo.cpp --- /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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#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(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 :\ . 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")); + } +