|
1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <bautils.h> |
|
17 #include <f32file.h> |
|
18 #include <mtp/cmtptypearray.h> |
|
19 #include <mtp/cmtpobjectmetadata.h> |
|
20 |
|
21 #include "cmtpdataprovider.h" |
|
22 #include "cmtpmoveobject.h" |
|
23 #include "cmtpobjectmgr.h" |
|
24 #include "cmtpparserrouter.h" |
|
25 #include "cmtpstoragemgr.h" |
|
26 #include "mtpproxydppanic.h" |
|
27 #include "cmtpobjectbrowser.h" |
|
28 #include "mtpdppanic.h" |
|
29 |
|
30 __FLOG_STMT(_LIT8(KComponent,"PrxyMoveObj");) |
|
31 const TUint KInvalidDpId = 0xFF; |
|
32 /** |
|
33 Verification data for the MoveObject request |
|
34 */ |
|
35 const TMTPRequestElementInfo CMTPMoveObject::KMTPMoveObjectPolicy[] = |
|
36 { |
|
37 {TMTPTypeRequest::ERequestParameter1, EMTPElementTypeObjectHandle, EMTPElementAttrFileOrDir | EMTPElementAttrWrite, 0, 0, 0}, |
|
38 {TMTPTypeRequest::ERequestParameter2, EMTPElementTypeStorageId, EMTPElementAttrWrite, 0, 0, 0}, |
|
39 {TMTPTypeRequest::ERequestParameter3, EMTPElementTypeObjectHandle, EMTPElementAttrDir | EMTPElementAttrWrite, 1, 0, 0} |
|
40 }; |
|
41 |
|
42 /** |
|
43 Two-phase construction method |
|
44 @param aFramework The data provider framework |
|
45 @param aConnection The connection from which the request comes |
|
46 @return a pointer to the created request processor object |
|
47 */ |
|
48 MMTPRequestProcessor* CMTPMoveObject::NewL(MMTPDataProviderFramework& aFramework, MMTPConnection& aConnection) |
|
49 { |
|
50 CMTPMoveObject* self = new (ELeave) CMTPMoveObject(aFramework, aConnection); |
|
51 CleanupStack::PushL(self); |
|
52 self->ConstructL(); |
|
53 CleanupStack::Pop(self); |
|
54 return self; |
|
55 } |
|
56 |
|
57 /** |
|
58 Destructor |
|
59 */ |
|
60 CMTPMoveObject::~CMTPMoveObject() |
|
61 { |
|
62 iSingletons.Close(); |
|
63 iNewParent.Close(); |
|
64 delete iPathToCreate; |
|
65 |
|
66 delete iFileMan; |
|
67 iFolderToRemove.Close(); |
|
68 delete iObjInfoCache; |
|
69 iNewHandleParentStack.Close(); |
|
70 iHandleDepths.Close(); |
|
71 iHandles.Close(); |
|
72 delete iObjBrowser; |
|
73 iTargetDps.Close(); |
|
74 __FLOG(_L8("+/-Dtor")); |
|
75 __FLOG_CLOSE; |
|
76 } |
|
77 |
|
78 /** |
|
79 Constructor |
|
80 */ |
|
81 CMTPMoveObject::CMTPMoveObject(MMTPDataProviderFramework& aFramework, MMTPConnection& aConnection) : |
|
82 CMTPRequestProcessor(aFramework, aConnection, sizeof(KMTPMoveObjectPolicy)/sizeof(TMTPRequestElementInfo), KMTPMoveObjectPolicy) |
|
83 { |
|
84 __FLOG_OPEN( KMTPSubsystem, KComponent ); |
|
85 __FLOG( _L8("+/-Ctor") ); |
|
86 } |
|
87 |
|
88 /** |
|
89 Second phase constructor. |
|
90 */ |
|
91 void CMTPMoveObject::ConstructL() |
|
92 { |
|
93 __FLOG( _L8("+ConstructL") ); |
|
94 iNewParent.CreateL(KMaxFileName); |
|
95 iSingletons.OpenL(); |
|
96 iFolderToRemove.CreateL( KMaxFileName ); |
|
97 iOwnerDp = KInvalidDpId; |
|
98 __FLOG( _L8("-ConstructL") ); |
|
99 } |
|
100 |
|
101 /** |
|
102 MoveObject request handler |
|
103 */ |
|
104 void CMTPMoveObject::ServiceL() |
|
105 { |
|
106 __FLOG( _L8("+ServiceL") ); |
|
107 iTargetDps.Reset(); |
|
108 CMTPParserRouter& router(iSingletons.Router()); |
|
109 CMTPParserRouter::TRoutingParameters params(Request(), iConnection); |
|
110 router.ParseOperationRequestL(params); |
|
111 router.RouteOperationRequestL(params, iTargetDps); |
|
112 |
|
113 BrowseHandlesL(); |
|
114 __FLOG( _L8("-ServiceL") ); |
|
115 } |
|
116 |
|
117 void CMTPMoveObject::ProxyReceiveDataL(MMTPType& /*aData*/, const TMTPTypeRequest& /*aRequest*/, MMTPConnection& /*aConnection*/, TRequestStatus& /*aStatus*/) |
|
118 { |
|
119 Panic(EMTPWrongRequestPhase); |
|
120 } |
|
121 |
|
122 void CMTPMoveObject::ProxySendDataL(const MMTPType& /*aData*/, const TMTPTypeRequest& /*aRequest*/, MMTPConnection& /*aConnection*/, TRequestStatus& /*aStatus*/) |
|
123 { |
|
124 Panic(EMTPWrongRequestPhase); |
|
125 } |
|
126 |
|
127 #ifdef _DEBUG |
|
128 void CMTPMoveObject::ProxySendResponseL(const TMTPTypeResponse& aResponse, const TMTPTypeRequest& aRequest, MMTPConnection& aConnection, TRequestStatus& aStatus) |
|
129 #else |
|
130 void CMTPMoveObject::ProxySendResponseL(const TMTPTypeResponse& aResponse, const TMTPTypeRequest& /*aRequest*/, MMTPConnection& /*aConnection*/, TRequestStatus& aStatus) |
|
131 #endif |
|
132 { |
|
133 __FLOG( _L8("+ProxySendResponseL") ); |
|
134 __ASSERT_DEBUG(((&iCurrentRequest == &aRequest) && (&iConnection == &aConnection)), Panic(EMTPNotSameRequestProxy)); |
|
135 MMTPType::CopyL(aResponse, iResponse); |
|
136 TRequestStatus* status = &aStatus; |
|
137 User::RequestComplete(status, KErrNone); |
|
138 __FLOG( _L8("-ProxySendResponseL") ); |
|
139 } |
|
140 |
|
141 #ifdef _DEBUG |
|
142 void CMTPMoveObject::ProxyTransactionCompleteL(const TMTPTypeRequest& aRequest, MMTPConnection& aConnection) |
|
143 #else |
|
144 void CMTPMoveObject::ProxyTransactionCompleteL(const TMTPTypeRequest& /*aRequest*/, MMTPConnection& /*aConnection*/) |
|
145 #endif |
|
146 { |
|
147 __FLOG( _L8("+ProxyTransactionCompleteL") ); |
|
148 __ASSERT_DEBUG(((&iCurrentRequest == &aRequest) && (&iConnection == &aConnection)), Panic(EMTPNotSameRequestProxy)); |
|
149 TInt err((iResponse.Uint16(TMTPTypeResponse::EResponseCode) == EMTPRespCodeOK) ? KErrNone : KErrGeneral); |
|
150 if (err == KErrNone) |
|
151 { |
|
152 iCurrentHandle--; |
|
153 Schedule(err); |
|
154 } |
|
155 else |
|
156 { |
|
157 SendResponseL( iResponse.Uint16( TMTPTypeResponse::EResponseCode ) ); |
|
158 } |
|
159 |
|
160 __FLOG( _L8("-ProxyTransactionCompleteL") ); |
|
161 } |
|
162 |
|
163 /** |
|
164 Retrive the parameters of the request |
|
165 */ |
|
166 void CMTPMoveObject::GetParametersL() |
|
167 { |
|
168 __FLOG( _L8("+GetParametersL") ); |
|
169 |
|
170 TUint32 objectHandle = iCurrentRequest.Uint32( TMTPTypeRequest::ERequestParameter1 ); |
|
171 TUint32 newParentHandle = iCurrentRequest.Uint32( TMTPTypeRequest::ERequestParameter3 ); |
|
172 |
|
173 if(newParentHandle == 0) |
|
174 { |
|
175 GetDefaultParentObjectL( iNewParent ); |
|
176 } |
|
177 else |
|
178 { |
|
179 iFramework.ObjectMgr().ObjectL( TMTPTypeUint32( newParentHandle ), *iObjInfoCache ); |
|
180 iNewParent = iObjInfoCache->DesC(CMTPObjectMetaData::ESuid); |
|
181 } |
|
182 |
|
183 iFramework.ObjectMgr().ObjectL( TMTPTypeUint32( objectHandle ), *iObjInfoCache ); |
|
184 __FLOG( _L8("-GetParametersL") ); |
|
185 } |
|
186 |
|
187 /** |
|
188 Get a default parent object, when the current request does not specify a parent object |
|
189 */ |
|
190 void CMTPMoveObject::GetDefaultParentObjectL( TDes& aObjectName ) |
|
191 { |
|
192 __FLOG( _L8("+GetDefaultParentObjectL") ); |
|
193 const CMTPStorageMetaData& storageMetaData( iFramework.StorageMgr().StorageL(iStorageId) ); |
|
194 aObjectName = storageMetaData.DesC(CMTPStorageMetaData::EStorageSuid); |
|
195 __FLOG( _L8("-GetDefaultParentObjectL") ); |
|
196 |
|
197 } |
|
198 |
|
199 /** |
|
200 Check if we can move the file to the new location |
|
201 */ |
|
202 TMTPResponseCode CMTPMoveObject::CanMoveObjectL(const TDesC& aOldName, const TDesC& aNewName) const |
|
203 { |
|
204 __FLOG(_L8("+CanMoveObjectL")); |
|
205 TMTPResponseCode result = EMTPRespCodeOK; |
|
206 |
|
207 TEntry fileEntry; |
|
208 User::LeaveIfError(iFramework.Fs().Entry(aOldName, fileEntry)); |
|
209 TInt drive(iFramework.StorageMgr().DriveNumber(iStorageId)); |
|
210 User::LeaveIfError(drive); |
|
211 TVolumeInfo volumeInfo; |
|
212 User::LeaveIfError(iFramework.Fs().Volume(volumeInfo, drive)); |
|
213 |
|
214 if (BaflUtils::FileExists(iFramework.Fs(), aNewName)) |
|
215 { |
|
216 result = EMTPRespCodeInvalidParentObject; |
|
217 } |
|
218 __FLOG_VA((_L8("-CanMoveObjectL (Exit with response code 0x%04X)"), result)); |
|
219 return result; |
|
220 } |
|
221 |
|
222 void CMTPMoveObject::GetSuidFromHandleL(TUint aHandle, TDes& aSuid) const |
|
223 { |
|
224 CMTPObjectMetaData* meta(CMTPObjectMetaData::NewLC()); |
|
225 iFramework.ObjectMgr().ObjectL(aHandle, *meta); |
|
226 __ASSERT_DEBUG(meta, Panic(EMTPDpObjectNull)); |
|
227 aSuid = meta->DesC(CMTPObjectMetaData::ESuid); |
|
228 CleanupStack::PopAndDestroy(meta); |
|
229 } |
|
230 |
|
231 void CMTPMoveObject::RunL() |
|
232 { |
|
233 __FLOG( _L8("+RunL") ); |
|
234 if ( iStatus==KErrNone ) |
|
235 { |
|
236 switch ( iState ) |
|
237 { |
|
238 case ERemoveSourceFolderTree: |
|
239 SendResponseL(iResponse.Uint16(TMTPTypeResponse::EResponseCode)); |
|
240 break; |
|
241 default: |
|
242 NextObjectHandleL(); |
|
243 if ( iOwnerDp != KInvalidDpId ) |
|
244 { |
|
245 CMTPDataProvider& dp = iSingletons.DpController().DataProviderL( iOwnerDp ); |
|
246 dp.ExecuteProxyRequestL( iCurrentRequest, Connection(), *this ); |
|
247 } |
|
248 break; |
|
249 } |
|
250 } |
|
251 else |
|
252 { |
|
253 SendResponseL( iResponse.Uint16( TMTPTypeResponse::EResponseCode ) ); |
|
254 } |
|
255 |
|
256 __FLOG( _L8("-RunL") ); |
|
257 } |
|
258 |
|
259 TInt CMTPMoveObject::RunError(TInt /*aError*/) |
|
260 { |
|
261 TRAP_IGNORE(SendResponseL(EMTPRespCodeGeneralError)); |
|
262 return KErrNone; |
|
263 } |
|
264 |
|
265 /** |
|
266 Completes the current asynchronous request with the specified |
|
267 completion code. |
|
268 @param aError The asynchronous request completion request. |
|
269 */ |
|
270 void CMTPMoveObject::Schedule(TInt aError) |
|
271 { |
|
272 TRequestStatus* status = &iStatus; |
|
273 User::RequestComplete(status, aError); |
|
274 SetActive(); |
|
275 } |
|
276 |
|
277 /** |
|
278 Sends a response to the initiator. |
|
279 @param aCode MTP response code |
|
280 */ |
|
281 void CMTPMoveObject::SendResponseL(TUint16 aCode) |
|
282 { |
|
283 const TMTPTypeRequest& req(Request()); |
|
284 iResponse.SetUint16(TMTPTypeResponse::EResponseCode, aCode); |
|
285 iResponse.SetUint32(TMTPTypeResponse::EResponseSessionID, req.Uint32(TMTPTypeRequest::ERequestSessionID)); |
|
286 iResponse.SetUint32(TMTPTypeResponse::EResponseTransactionID, req.Uint32(TMTPTypeRequest::ERequestTransactionID)); |
|
287 iFramework.SendResponseL(iResponse, req, Connection()); |
|
288 } |
|
289 |
|
290 TMTPResponseCode CMTPMoveObject::CreateFolderL() |
|
291 { |
|
292 __FLOG( _L8("+CreateFolderL") ); |
|
293 TMTPResponseCode ret = EMTPRespCodeOK; |
|
294 |
|
295 GetParametersL(); |
|
296 __FLOG_1( _L("New folder parent: %S"), &iNewParent ); |
|
297 const TDesC& oldPath = iObjInfoCache->DesC( CMTPObjectMetaData::ESuid ); |
|
298 if ( iFolderToRemove.Length() == 0 ) |
|
299 { |
|
300 iFolderToRemove = oldPath; |
|
301 } |
|
302 |
|
303 TFileName fileNamePart; |
|
304 User::LeaveIfError( BaflUtils::MostSignificantPartOfFullName( oldPath, fileNamePart ) ); |
|
305 __FLOG_1( _L("Folder name: %S"), &fileNamePart ); |
|
306 |
|
307 if ( ( iNewParent.Length() + fileNamePart.Length() + 1 ) <= iNewParent.MaxLength() ) |
|
308 { |
|
309 iNewParent.Append( fileNamePart ); |
|
310 iNewParent.Append( KPathDelimiter ); |
|
311 } |
|
312 else |
|
313 { |
|
314 ret = EMTPRespCodeInvalidParentObject; |
|
315 } |
|
316 if ( EMTPRespCodeOK == ret ) |
|
317 { |
|
318 __FLOG_VA( ( _L("Try to move %S to %S"), &oldPath, &iNewParent ) ); |
|
319 ret = CanMoveObjectL( oldPath, iNewParent ); |
|
320 |
|
321 if ( EMTPRespCodeOK == ret ) |
|
322 { |
|
323 TInt err = iFramework.Fs().MkDir( iNewParent ); |
|
324 User::LeaveIfError( err ); |
|
325 iNewHandleParentStack.AppendL( iObjInfoCache->Uint( CMTPObjectMetaData::EHandle ) ); |
|
326 } |
|
327 } |
|
328 |
|
329 __FLOG( _L8("-CreateFolderL") ); |
|
330 return ret; |
|
331 } |
|
332 |
|
333 void CMTPMoveObject::RemoveSourceFolderTreeL() |
|
334 { |
|
335 __FLOG( _L8("+RemoveSourceFolderTreeL") ); |
|
336 |
|
337 if ( iFolderToRemove.Length() > 0 ) |
|
338 { |
|
339 __FLOG_1( _L("Removing %S"), &iFolderToRemove ); |
|
340 delete iFileMan; |
|
341 iFileMan = NULL; |
|
342 iFileMan = CFileMan::NewL( iFramework.Fs() ); |
|
343 |
|
344 iState = ERemoveSourceFolderTree; |
|
345 User::LeaveIfError( iFileMan->RmDir( iFolderToRemove, iStatus ) ); |
|
346 SetActive(); |
|
347 } |
|
348 else |
|
349 { |
|
350 SendResponseL( iResponse.Uint16( TMTPTypeResponse::EResponseCode ) ); |
|
351 } |
|
352 |
|
353 __FLOG( _L8("-RemoveSourceFolderTreeL") ); |
|
354 } |
|
355 |
|
356 void CMTPMoveObject::BrowseHandlesL() |
|
357 { |
|
358 __FLOG( _L8("+BrowseHandlesL") ); |
|
359 |
|
360 iFolderToRemove.SetLength( 0 ); |
|
361 iState = EInit; |
|
362 |
|
363 delete iObjBrowser; |
|
364 iObjBrowser = NULL; |
|
365 iObjBrowser = CMTPObjectBrowser::NewL( iFramework ); |
|
366 |
|
367 iHandles.Reset(); |
|
368 iHandleDepths.Reset(); |
|
369 |
|
370 delete iObjInfoCache; |
|
371 iObjInfoCache = NULL; |
|
372 iObjInfoCache = CMTPObjectMetaData::NewL(); |
|
373 |
|
374 iNewHandleParentStack.Reset(); |
|
375 |
|
376 MMTPType::CopyL( Request(), iCurrentRequest ); |
|
377 iStorageId = Request().Uint32( TMTPTypeRequest::ERequestParameter2 ); |
|
378 |
|
379 CMTPObjectBrowser::TBrowseCallback callback = { CMTPMoveObject::OnBrowseObjectL, this }; |
|
380 TUint32 handle = Request().Uint32( TMTPTypeRequest::ERequestParameter1 ); |
|
381 TUint32 newHandleParent = Request().Uint32( TMTPTypeRequest::ERequestParameter3 ); |
|
382 iNewHandleParentStack.AppendL( newHandleParent ); |
|
383 iObjBrowser->GoL( KMTPFormatsAll, handle, KMaxTUint32, callback ); |
|
384 __FLOG_1( _L8("iHandles.Count() = %d"), iHandles.Count() ); |
|
385 |
|
386 if ( iHandles.Count() > 0 ) |
|
387 { |
|
388 iCurrentHandle = iHandles.Count() - 1; |
|
389 Schedule( KErrNone ); |
|
390 } |
|
391 else |
|
392 { |
|
393 SendResponseL( EMTPRespCodeInvalidObjectHandle ); |
|
394 } |
|
395 |
|
396 __FLOG( _L8("-BrowseHandlesL") ); |
|
397 } |
|
398 |
|
399 void CMTPMoveObject::NextObjectHandleL() |
|
400 { |
|
401 __FLOG( _L8("+NextObjectHandleL") ); |
|
402 __ASSERT_DEBUG( ( iNewHandleParentStack.Count() > 0 ), User::Invariant() ); |
|
403 iOwnerDp = KInvalidDpId; |
|
404 if ( iCurrentHandle >=0 ) |
|
405 { |
|
406 __FLOG_1( _L8("iCurrentHandle = %d"), iCurrentHandle ); |
|
407 TUint32 handle = iHandles[iCurrentHandle]; |
|
408 TUint32 depth = iHandleDepths[iCurrentHandle]; |
|
409 __FLOG_1( _L8("depth = %d"), depth ); |
|
410 if ( iCurrentHandle != ( iHandles.Count() - 1 ) ) |
|
411 { |
|
412 TUint32 previousDepth = iHandleDepths[iCurrentHandle + 1]; |
|
413 __FLOG_1( _L8("previousDepth = %d"), previousDepth ); |
|
414 if ( depth < previousDepth ) |
|
415 { |
|
416 // Completed copying folder and all its sub-folder and files, pop all copied folders' handle which are not shallower than the current one. |
|
417 |
|
418 // Step 1: pop the previous handle itself if it is am empty folder |
|
419 if ( iIsMovingFolder ) |
|
420 { |
|
421 iNewHandleParentStack.Remove( iNewHandleParentStack.Count() - 1 ); |
|
422 } |
|
423 // Step 2: pop the other folders' handle which are not shallower than the current one |
|
424 TUint loopCount = previousDepth - depth; |
|
425 for ( TUint i = 0; i < loopCount; i++ ) |
|
426 { |
|
427 iNewHandleParentStack.Remove( iNewHandleParentStack.Count() - 1 ); |
|
428 } |
|
429 } |
|
430 else if ( ( depth == previousDepth ) && iIsMovingFolder ) |
|
431 { |
|
432 // Completed moving empty folder, pop its handle |
|
433 iNewHandleParentStack.Remove( iNewHandleParentStack.Count() - 1 ); |
|
434 } |
|
435 } |
|
436 iIsMovingFolder = EFalse; |
|
437 iOwnerDp = iSingletons.ObjectMgr().ObjectOwnerId( handle ); |
|
438 if ( iOwnerDp == KInvalidDpId ) |
|
439 { |
|
440 SendResponseL( EMTPRespCodeInvalidObjectHandle ); |
|
441 } |
|
442 else |
|
443 { |
|
444 iCurrentRequest.SetUint32( TMTPTypeRequest::ERequestParameter1, handle ); |
|
445 iCurrentRequest.SetUint32( TMTPTypeRequest::ERequestParameter3, iNewHandleParentStack[iNewHandleParentStack.Count()-1] ); |
|
446 } |
|
447 if ( iOwnerDp==iSingletons.DpController().DeviceDpId() ) |
|
448 { |
|
449 iIsMovingFolder = ETrue; |
|
450 if ( EMTPRespCodeOK != CreateFolderL() ) |
|
451 { |
|
452 iOwnerDp = KInvalidDpId; |
|
453 iIsMovingFolder = EFalse; |
|
454 SendResponseL( EMTPRespCodeInvalidParentObject ); |
|
455 } |
|
456 } |
|
457 } |
|
458 else |
|
459 { |
|
460 RemoveSourceFolderTreeL(); |
|
461 } |
|
462 |
|
463 __FLOG( _L8("-NextObjectHandleL") ); |
|
464 } |
|
465 |
|
466 void CMTPMoveObject::OnBrowseObjectL( TAny* aSelf, TUint aHandle, TUint32 aCurDepth ) |
|
467 { |
|
468 CMTPMoveObject* self = reinterpret_cast< CMTPMoveObject* >( aSelf ); |
|
469 if ( self->iTargetDps.Find(self->iSingletons.ObjectMgr().ObjectOwnerId(aHandle)) != KErrNotFound ) |
|
470 { |
|
471 self->iHandles.AppendL( aHandle ); |
|
472 self->iHandleDepths.AppendL( aCurDepth ); |
|
473 } |
|
474 } |
|
475 |