diff -r 000000000000 -r a2952bb97e68 mmappcomponents/mmmtpdataprovider/mmmtpdprequestprocessor/src/cdeleteobject.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmappcomponents/mmmtpdataprovider/mmmtpdprequestprocessor/src/cdeleteobject.cpp Thu Dec 17 08:55:47 2009 +0200 @@ -0,0 +1,362 @@ +/* +* Copyright (c) 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: Implement the operation: DeleteObject +* +*/ + + +#include +#include +#include + +#include "cdeleteobject.h" +#include "mmmtpdplogger.h" +#include "mmmtpdpconfig.h" +#include "cmmmtpdpmetadataaccesswrapper.h" + +// static const TInt KMTPDriveGranularity = 5; + +// ----------------------------------------------------------------------------- +// Verification data for the DeleteObject request +// ----------------------------------------------------------------------------- +// +const TMTPRequestElementInfo KMTPDeleteObjectPolicy[] = + { + { + TMTPTypeRequest::ERequestParameter1, + EMTPElementTypeObjectHandle, + EMTPElementAttrWrite, + 1, + KMTPHandleAll, + 0 + }, + }; + +// ----------------------------------------------------------------------------- +// CDeleteObject::NewL +// Two-phase construction method +// CDeleteObject is an abstract class and shouldn't be instaniated. +// ----------------------------------------------------------------------------- +// +EXPORT_C MMmRequestProcessor* CDeleteObject::NewL( MMTPDataProviderFramework& aFramework, + MMTPConnection& aConnection, + MMmMtpDpConfig& aDpConfig ) + { + CDeleteObject* self = new (ELeave) CDeleteObject( aFramework, aConnection, aDpConfig ); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CDeleteObject::ConstructL() + { + CActiveScheduler::Add( this ); + SetPSStatus(); + } + +// ----------------------------------------------------------------------------- +// CDeleteObject::~CDeleteObject +// Destructor +// ----------------------------------------------------------------------------- +// +EXPORT_C CDeleteObject::~CDeleteObject() + { + Cancel(); + iObjectsToDelete.Close(); + } + +// ----------------------------------------------------------------------------- +// CDeleteObject::CDeleteObject +// Standard c++ constructor +// ----------------------------------------------------------------------------- +// +CDeleteObject::CDeleteObject( MMTPDataProviderFramework& aFramework, + MMTPConnection& aConnection, + MMmMtpDpConfig& aDpConfig ) : + CRequestProcessor( aFramework, + aConnection, + sizeof( KMTPDeleteObjectPolicy ) / sizeof( TMTPRequestElementInfo ), + KMTPDeleteObjectPolicy ), + iObjectMgr( aFramework.ObjectMgr() ), + iFs( aFramework.Fs() ), + iObjectsToDelete( KMmMtpRArrayGranularity ), + iDeleteError( KErrNone ), + iDpConfig( aDpConfig ) + { + PRINT( _L( "Operation: DeleteObject(0x100B)" ) ); + } + +// ----------------------------------------------------------------------------- +// CDeleteObject::ServiceL +// DeleteObject request handler +// ----------------------------------------------------------------------------- +// +EXPORT_C void CDeleteObject::ServiceL() + { + iObjectsToDelete.Reset(); + iDeleteError = KErrNone; + TUint32 objectHandle = Request().Uint32( TMTPTypeRequest::ERequestParameter1 ); + + PRINT3( _L( "MM MTP <> CDeleteObject::ServiceL, objectHandle = 0x%x, numObject = %d, iDeleteError = %d" ), + objectHandle, + iObjectsToDelete.Count(), + iDeleteError ); + + // Check to see whether the request is to delete all files or a specific file/directory + if ( objectHandle == KMTPHandleAll ) + { + iIsMultiDelete = ETrue; + // Get the complete list of all the media files that are to be deleted + GetObjectHandlesL( KMTPStorageAll, KMTPHandleNoParent ); + StartL(); + } + else + { + iIsMultiDelete = EFalse; + // Not Owned the object + // TODO: need to check if this is best way and if it is applicable to other processors + CMTPObjectMetaData* objectInfo = iRequestChecker->GetObjectInfo( objectHandle ); + + if ( objectInfo->Uint( CMTPObjectMetaData::EFormatCode ) == EMTPFormatCodeAssociation ) + { + TUint parentHandle = objectInfo->Uint( CMTPObjectMetaData::EHandle ); + GetObjectHandlesL( KMTPStorageAll, parentHandle ); + if ( iObjectsToDelete.Count() > 0 ) + iIsMultiDelete = ETrue; + StartL(); + } + else + { + DeleteObjectL( *objectInfo ); + ProcessFinalPhaseL(); + } + } + + PRINT( _L( "MM MTP <= CDeleteObject::ServiceL" ) ); + } + +// ----------------------------------------------------------------------------- +// MTPDeleteObject::StartL +// Control the deletion +// ----------------------------------------------------------------------------- +// +void CDeleteObject::StartL() + { + TInt numObjectsToDelete = iObjectsToDelete.Count(); + PRINT2( _L( "MM MTP <> CDeleteObject::StartL, numObjectsToDelete = %d, iDeleteError = %d" ), + numObjectsToDelete, + iDeleteError ); + + TBool isOk = iDeleteError == KErrNone || iDeleteError == KErrNotFound; + if ( numObjectsToDelete > 0 && isOk ) + { + //Set the active object going to delete the file + TRequestStatus* status = &iStatus; + User::RequestComplete( status, KErrNone ); + SetActive(); + } + else + { + ProcessFinalPhaseL(); + } + PRINT( _L( "MM MTP <= CDeleteObject::StartL" ) ); + } + +// ----------------------------------------------------------------------------- +// CDeleteObject::RunL +// AO Run method, deletes a selection of files on the system +// ----------------------------------------------------------------------------- +// +EXPORT_C void CDeleteObject::RunL() + { + TInt numObjectsToDelete = iObjectsToDelete.Count(); + PRINT1( _L( "MM MTP => CDeleteObject::RunL, numObjectsToDelete = %d" ), + numObjectsToDelete ); + + if ( numObjectsToDelete > 0 ) + { + // Get the next object + CMTPObjectMetaData* objectInfo = CMTPObjectMetaData::NewLC(); // + objectInfo + + TUint32 handle = iObjectsToDelete[0]; + iObjectMgr.ObjectL( handle, *objectInfo ); + TFileName fileName( objectInfo->DesC( CMTPObjectMetaData::ESuid ) ); + PRINT2( _L( "MM MTP <> CDeleteObject::RunL delete object handle is 0x%x, fileName is %S" ), handle, &fileName ); + + if ( objectInfo->Uint( CMTPObjectMetaData::EFormatCode ) == EMTPFormatCodeAssociation ) + { + TUint parentHandle = objectInfo->Uint( CMTPObjectMetaData::EHandle ); + GetObjectHandlesL( KMTPStorageAll, parentHandle ); + } + else + { + DeleteObjectL( *objectInfo ); + } + + CleanupStack::PopAndDestroy( objectInfo ); // - objectInfo + + iObjectsToDelete.Remove( 0 ); + } + + // Start the process again to read the next row... + StartL(); + PRINT( _L( "MM MTP <= CDeleteObject::RunL" ) ); + } + +// ----------------------------------------------------------------------------- +// CDeleteObject::DeleteObjectL() +// Deletes the object from the file system and the object from the store +// ----------------------------------------------------------------------------- +// +void CDeleteObject::DeleteObjectL( const CMTPObjectMetaData& aObjectInfo ) + { + TFileName fileName( aObjectInfo.DesC( CMTPObjectMetaData::ESuid ) ); + PRINT1( _L( "MM MTP <> CDeleteObject::DeleteObjectL fileName = %S" ), &fileName ); + + TParsePtrC parse( fileName ); + iDpConfig.GetWrapperL().SetStorageRootL( parse.Drive() ); + + // To capture special situation: After copy, move, rename playlist folder name, + // record in MPX is not inlined with framework db, playlist should not be deleted + // until next session. + // This is used to keep the same behavior in mass storage and device file manager. + if ( aObjectInfo.Uint(CMTPObjectMetaData::EFormatCode ) + == EMTPFormatCodeAbstractAudioVideoPlaylist + && !iDpConfig.GetWrapperL().IsExistL( fileName ) ) + { + iDeleteError = KErrGeneral; + PRINT( _L( "MM MTP <= CDeleteObject::DeleteObjectL playlist file not exist in the MPX DB" ) ); + return; + } + + // 1. Delete object from file system + TEntry fileInfo; + iFs.Entry( fileName, fileInfo ); + if ( fileInfo.IsReadOnly() ) + { + iDeleteError = KErrAccessDenied; + PRINT1( _L( "MM MTP <= CDeleteObject::DeleteObjectL, \"%S\" is a read-only file"), &fileName ); + return; + } + iDeleteError = iFs.Delete( fileName ); + if ( iDeleteError != KErrNone && iDeleteError != KErrNotFound ) + { + PRINT1( _L( "MM MTP <= CDeleteObject::DeleteObjectL, Delete from file system failed, err = %d" ), iDeleteError ); + return; + } + + // 2. Delete object from metadata db + TRAP( iDeleteError, iDpConfig.GetWrapperL().DeleteObjectL( fileName, aObjectInfo.Uint( CMTPObjectMetaData::EFormatCode ) )); + PRINT1( _L( "MM MTP <> CDeleteObject::DeleteObjectL, Delete from Media DB, err = %d" ), iDeleteError ); + + // 3. Delete object from framework db + iObjectMgr.RemoveObjectL( aObjectInfo.Uint( CMTPObjectMetaData::EHandle ) ); + + PRINT( _L( "MM MTP <= CDeleteObject::DeleteObjectL" ) ); + } + +// ----------------------------------------------------------------------------- +// CDeleteObject::DoCancel +// Used to cancel the deletion of the files +// ----------------------------------------------------------------------------- +// +EXPORT_C void CDeleteObject::DoCancel() + { + TRAP_IGNORE( ProcessFinalPhaseL() ); + } + +// ----------------------------------------------------------------------------- +// CDeleteObject::ProcessFinalPhaseL +// Delete all of the associations if file deletion was successful +// Then signals that the deletion has been completed +// ----------------------------------------------------------------------------- +// +void CDeleteObject::ProcessFinalPhaseL() + { + PRINT( _L( "MM MTP => CDeleteObject::ProcessFinalPhaseL" ) ); + + TInt num = iObjectsToDelete.Count(); + TBool isOk = iDeleteError == KErrNone || iDeleteError == KErrNotFound; + + if ( num == 0 && isOk ) + { + SendResponseL( EMTPRespCodeOK ); + } + else if ( iIsMultiDelete && !isOk ) + { + SendResponseL( EMTPRespCodePartialDeletion ); + } + else if( !iIsMultiDelete && iDeleteError == KErrAccessDenied ) + { + SendResponseL( EMTPRespCodeObjectWriteProtected ); + } + else + { + SendResponseL( EMTPRespCodeAccessDenied ); + } + } + +// ----------------------------------------------------------------------------- +// CDeleteObject::GetObjectHandlesL +// Gets all object handles (for GetObjectHandlesL) +// ----------------------------------------------------------------------------- +// +void CDeleteObject::GetObjectHandlesL( TUint32 aStorageId, + TUint32 aParentHandle ) + { + PRINT2( _L( "MM MTP => CDeleteObject::GetObjectHandlesL, StorageId = 0x%x, ParentHandle = 0x%x" ), + aStorageId, aParentHandle ); + RMTPObjectMgrQueryContext context; + RArray handles; + CleanupClosePushL( context ); // + context + CleanupClosePushL( handles ); // + handles + + TMTPObjectMgrQueryParams params( aStorageId, KMTPFormatsAll, aParentHandle ); + + do + { + iFramework.ObjectMgr().GetObjectHandlesL( params, context, handles ); + + for ( TInt i = 0; i < handles.Count(); i++ ) + { + if ( iFramework.ObjectMgr().ObjectOwnerId( handles[i] ) + == iFramework.DataProviderId() ) + { + iObjectsToDelete.Append( handles[i] ); + } + // TODO: should not know dp id of device dp, + // else if ( iFramework.ObjectMgr().ObjectOwnerId( handles[i] ) == 0 ) // We know that the device dp id is always 0, otherwise the whole MTP won't work. + // iParentHandles.AppendL( handles[i] ); + else + { + CMTPObjectMetaData* objectInfo = CMTPObjectMetaData::NewLC(); // + objectInfo + iObjectMgr.ObjectL( handles[i], *objectInfo ); + if ( EMTPFormatCodeAssociation == objectInfo->Uint( CMTPObjectMetaData::EFormatCode ) ) + { + GetObjectHandlesL( KMTPStorageAll, handles[i] ); + } + CleanupStack::PopAndDestroy( objectInfo ); // - objectInfo + } + } + } + while ( !context.QueryComplete() ); + + CleanupStack::PopAndDestroy( &handles ); // - handles + CleanupStack::PopAndDestroy( &context ); // - context + + PRINT( _L( "MM MTP <= CDeleteObject::GetObjectHandlesL" ) ); + } + +// end of file