|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <mtp/cmtpobjectmetadata.h> |
|
20 #include <mtp/mmtpconnection.h> |
|
21 #include <mtp/mmtpdataproviderframework.h> |
|
22 #include <mtp/mmtpobjectmgr.h> |
|
23 #include <mtp/mmtpstoragemgr.h> |
|
24 |
|
25 #include "crequestchecker.h" |
|
26 #include "mmmtpdplogger.h" |
|
27 |
|
28 static const TInt KMTPRequestCheckerHandleGranularity = 2; |
|
29 |
|
30 // ----------------------------------------------------------------------------- |
|
31 // CRequestChecker::NewL |
|
32 // Two-phase construction method |
|
33 // ----------------------------------------------------------------------------- |
|
34 // |
|
35 CRequestChecker* CRequestChecker::NewL( MMTPDataProviderFramework& aFramework, |
|
36 MMTPConnection& aConnection ) |
|
37 { |
|
38 CRequestChecker* self = new (ELeave) CRequestChecker( aFramework, aConnection ); |
|
39 CleanupStack::PushL( self ); |
|
40 self->ConstructL(); |
|
41 CleanupStack::Pop( self ); |
|
42 return self; |
|
43 } |
|
44 |
|
45 // ----------------------------------------------------------------------------- |
|
46 // CRequestChecker::CRequestChecker |
|
47 // Standard c++ constructor |
|
48 // ----------------------------------------------------------------------------- |
|
49 // |
|
50 CRequestChecker::CRequestChecker( MMTPDataProviderFramework& aFramework, |
|
51 MMTPConnection& aConnection ) : |
|
52 iFramework( aFramework ), |
|
53 iConnection( aConnection ), |
|
54 iHandles( KMTPRequestCheckerHandleGranularity ), |
|
55 iObjectArray( KMTPRequestCheckerHandleGranularity ) |
|
56 { |
|
57 |
|
58 } |
|
59 |
|
60 // ----------------------------------------------------------------------------- |
|
61 // CRequestChecker::ConstructL |
|
62 // Two-phase construction method |
|
63 // ----------------------------------------------------------------------------- |
|
64 // |
|
65 void CRequestChecker::ConstructL() |
|
66 { |
|
67 |
|
68 } |
|
69 |
|
70 // ----------------------------------------------------------------------------- |
|
71 // CRequestChecker::~CRequestChecker |
|
72 // Destructor |
|
73 // ----------------------------------------------------------------------------- |
|
74 // |
|
75 CRequestChecker::~CRequestChecker() |
|
76 { |
|
77 iHandles.Close(); |
|
78 iObjectArray.ResetAndDestroy(); |
|
79 } |
|
80 |
|
81 // ----------------------------------------------------------------------------- |
|
82 // CRequestChecker::VerifyRequestL |
|
83 // Verfiy the request |
|
84 // ----------------------------------------------------------------------------- |
|
85 // |
|
86 TMTPResponseCode CRequestChecker::VerifyRequestL( const TMTPTypeRequest& aRequest, |
|
87 TInt aCount, |
|
88 const TMTPRequestElementInfo* aElementInfo ) |
|
89 { |
|
90 TMTPResponseCode result = EMTPRespCodeOK; |
|
91 iHandles.Close(); |
|
92 iObjectArray.ResetAndDestroy(); |
|
93 |
|
94 result = CheckRequestHeader( aRequest ); |
|
95 |
|
96 for ( TInt i = 0; i < aCount && EMTPRespCodeOK == result; i++ ) |
|
97 { |
|
98 TUint32 parameter = aRequest.Uint32( aElementInfo[i].iElementIndex ); |
|
99 PRINT3( _L( "MM MTP <> CRequestChecker parameter %d/%d = %d" ), |
|
100 i + 1, aCount, parameter ); |
|
101 |
|
102 if ( !IsSpecialValue( parameter, aElementInfo[i] ) ) |
|
103 { |
|
104 switch ( aElementInfo[i].iElementType ) |
|
105 { |
|
106 case EMTPElementTypeSessionID: |
|
107 result = VerifySessionId( parameter, aElementInfo[i] ); |
|
108 break; |
|
109 |
|
110 case EMTPElementTypeObjectHandle: |
|
111 result = VerifyObjectHandleL( parameter, aElementInfo[i] ); |
|
112 break; |
|
113 |
|
114 case EMTPElementTypeStorageId: |
|
115 result = VerifyStorageIdL( parameter, aElementInfo[i] ); |
|
116 break; |
|
117 |
|
118 case EMTPElementTypeFormatCode: |
|
119 result = VerifyFormatCode( parameter, aElementInfo[i] ); |
|
120 break; |
|
121 |
|
122 default: |
|
123 User::Invariant(); // Should never run |
|
124 break; |
|
125 } |
|
126 } |
|
127 } |
|
128 |
|
129 return result; |
|
130 } |
|
131 |
|
132 // ----------------------------------------------------------------------------- |
|
133 // CRequestChecker::GetObjectInfo |
|
134 // Return the object info for the handle |
|
135 // ----------------------------------------------------------------------------- |
|
136 // |
|
137 CMTPObjectMetaData* CRequestChecker::GetObjectInfo( TUint32 aHandle ) const |
|
138 { |
|
139 CMTPObjectMetaData* result = NULL; |
|
140 TInt count = iHandles.Count(); |
|
141 for( TInt i = 0; i < count; i++ ) |
|
142 { |
|
143 if ( iHandles[i] == aHandle ) |
|
144 { |
|
145 result = iObjectArray[i]; |
|
146 break; |
|
147 } |
|
148 } |
|
149 return result; |
|
150 } |
|
151 |
|
152 // ----------------------------------------------------------------------------- |
|
153 // CRequestChecker::CheckRequestHeader |
|
154 // Check the request header portion (session Id and transaction code) |
|
155 // ----------------------------------------------------------------------------- |
|
156 // |
|
157 TMTPResponseCode CRequestChecker::CheckRequestHeader( const TMTPTypeRequest& aRequest ) const |
|
158 { |
|
159 TMTPResponseCode ret = EMTPRespCodeOK; |
|
160 TUint16 operationCode = aRequest.Uint16( TMTPTypeRequest::ERequestOperationCode ); |
|
161 TUint32 sessionId = aRequest.Uint32( TMTPTypeRequest::ERequestSessionID ); |
|
162 TUint32 transactionCode = aRequest.Uint32( TMTPTypeRequest::ERequestTransactionID ); |
|
163 |
|
164 if ( operationCode == EMTPOpCodeCloseSession || operationCode == EMTPOpCodeResetDevice ) |
|
165 { |
|
166 if ( sessionId != 0 ) |
|
167 { |
|
168 ret = EMTPRespCodeInvalidParameter; |
|
169 } |
|
170 } |
|
171 else |
|
172 { |
|
173 // requests that are valid when there's no opened session. |
|
174 if ( sessionId == 0 ) |
|
175 { |
|
176 switch ( operationCode ) |
|
177 { |
|
178 case EMTPOpCodeGetDeviceInfo: |
|
179 case EMTPOpCodeOpenSession: |
|
180 { |
|
181 // Transaction id must be 0 when called out side an active session. |
|
182 if ( transactionCode != 0 ) |
|
183 { |
|
184 ret = EMTPRespCodeInvalidTransactionID; |
|
185 } |
|
186 } |
|
187 break; |
|
188 |
|
189 default: |
|
190 { |
|
191 ret = EMTPRespCodeSessionNotOpen; |
|
192 } |
|
193 break; |
|
194 } |
|
195 } |
|
196 else if ( !iConnection.SessionWithMTPIdExists( sessionId ) ) |
|
197 { |
|
198 ret = EMTPRespCodeSessionNotOpen; |
|
199 } |
|
200 } |
|
201 |
|
202 return ret; |
|
203 } |
|
204 |
|
205 // ----------------------------------------------------------------------------- |
|
206 // CRequestChecker::VerifySessionId |
|
207 // Check the session id in the request parameter (NOTE the session id is different from the one in the request header), |
|
208 // this usually only applies to the OpenSession request |
|
209 // ----------------------------------------------------------------------------- |
|
210 // |
|
211 TMTPResponseCode CRequestChecker::VerifySessionId( TUint32 aSessionId, |
|
212 const TMTPRequestElementInfo& /*aElementInfo*/ ) const |
|
213 { |
|
214 TMTPResponseCode ret = EMTPRespCodeOK; |
|
215 |
|
216 if ( aSessionId != 0 ) |
|
217 { |
|
218 if ( iConnection.SessionWithMTPIdExists( aSessionId ) ) |
|
219 { |
|
220 ret = EMTPRespCodeSessionAlreadyOpen; |
|
221 } |
|
222 } |
|
223 else |
|
224 { |
|
225 ret = EMTPRespCodeInvalidParameter; |
|
226 } |
|
227 |
|
228 return ret; |
|
229 } |
|
230 |
|
231 // ----------------------------------------------------------------------------- |
|
232 // CRequestChecker::VerifyObjectHandleL |
|
233 // Check the object handle in the request parameter, whether the handle is in the object store, |
|
234 // read/write, file/dir |
|
235 // ----------------------------------------------------------------------------- |
|
236 // |
|
237 TMTPResponseCode CRequestChecker::VerifyObjectHandleL( TUint32 aHandle, |
|
238 const TMTPRequestElementInfo& aElementInfo ) |
|
239 { |
|
240 PRINT1( _L("MM MTP => CRequestChecker::VerifyObjectHandleL aHandle = 0x%x"), aHandle ); |
|
241 TMTPResponseCode ret = EMTPRespCodeOK; |
|
242 |
|
243 CMTPObjectMetaData* object( CMTPObjectMetaData::NewLC() ); |
|
244 TBool result( iFramework.ObjectMgr().ObjectL( aHandle, *object ) ); |
|
245 iObjectArray.AppendL( object ); |
|
246 CleanupStack::Pop( object ); |
|
247 iHandles.AppendL( aHandle ); |
|
248 |
|
249 // Obj handle exists |
|
250 if ( result ) |
|
251 { |
|
252 const TDesC& suid( object->DesC( CMTPObjectMetaData::ESuid ) ); |
|
253 TEntry entry; |
|
254 TInt err = iFramework.Fs().Entry( suid, entry ); |
|
255 |
|
256 if ( object->Uint( CMTPObjectMetaData::EFormatCode ) == EMTPFormatCodeAssociation ) |
|
257 // && ( object->Uint( CMTPObjectMetaData::EFormatSubCode ) == EMTPAssociationTypeGenericFolder ) ) |
|
258 { |
|
259 // Special association type .. not always present on the filesystem. |
|
260 return ret; |
|
261 } |
|
262 else |
|
263 { |
|
264 User::LeaveIfError( err ); |
|
265 |
|
266 if ( iFramework.ObjectMgr().ObjectOwnerId( aHandle ) != iFramework.DataProviderId() ) |
|
267 { |
|
268 PRINT( _L(" ewrwe ret = EMTPRespCodeInvalidObjectHandle;")); |
|
269 ret = EMTPRespCodeInvalidObjectHandle; |
|
270 } |
|
271 } |
|
272 |
|
273 if ( aElementInfo.iElementAttr & EMTPElementAttrWrite ) |
|
274 { |
|
275 if ( entry.IsReadOnly() ) |
|
276 { |
|
277 ret = EMTPRespCodeObjectWriteProtected; |
|
278 } |
|
279 } |
|
280 |
|
281 //((EMTPRespCodeOK == ret) && (aElementInfo.iElementAttr & EMTPElementAttrFileOrDir)) is |
|
282 // covered implicitly here, EMTPRespCodeOK will be returned. It is a valid case for an object to be either a folder or file |
|
283 // for certain operation's request parameter, for instance the first parameter of copyObject or |
|
284 // moveObject can be either a file or a directory. |
|
285 |
|
286 // Other cases. |
|
287 if ( ( EMTPRespCodeOK == ret ) && ( aElementInfo.iElementAttr & EMTPElementAttrFile) ) |
|
288 { |
|
289 if ( entry.IsDir() ) |
|
290 { |
|
291 ret = EMTPRespCodeInvalidObjectHandle; |
|
292 } |
|
293 } |
|
294 |
|
295 if ( ( EMTPRespCodeOK == ret ) && ( aElementInfo.iElementAttr & EMTPElementAttrDir ) ) |
|
296 { |
|
297 if (!entry.IsDir()) |
|
298 { |
|
299 ret = EMTPRespCodeInvalidParentObject; |
|
300 } |
|
301 } |
|
302 } |
|
303 else |
|
304 { |
|
305 PRINT( _L( "MM MTP <> CRequestChecker::VerifyObjectHandleL, Object does not exist." ) ); |
|
306 ret = EMTPRespCodeInvalidObjectHandle; |
|
307 } |
|
308 PRINT1( _L( "MM MTP <= CRequestChecker::VerifyObjectHandleL ret = 0x%x" ), ret ); |
|
309 |
|
310 return ret; |
|
311 } |
|
312 |
|
313 // ----------------------------------------------------------------------------- |
|
314 // CRequestChecker::VerifyStorageIdL |
|
315 // Check the storage id parameter in the request, read/write attributes |
|
316 // ----------------------------------------------------------------------------- |
|
317 // |
|
318 TMTPResponseCode CRequestChecker::VerifyStorageIdL( TUint32 aStorageId, |
|
319 const TMTPRequestElementInfo& aElementInfo ) const |
|
320 { |
|
321 MMTPStorageMgr& mgr( iFramework.StorageMgr() ); |
|
322 TMTPResponseCode ret( EMTPRespCodeOK ); |
|
323 if ( !mgr.ValidStorageId( aStorageId ) ) |
|
324 { |
|
325 ret = EMTPRespCodeInvalidStorageID; |
|
326 } |
|
327 else |
|
328 { |
|
329 if ( !mgr.LogicalStorageId( aStorageId ) ) |
|
330 { |
|
331 ret = EMTPRespCodeStoreNotAvailable; |
|
332 } |
|
333 else |
|
334 { |
|
335 TInt drive( mgr.DriveNumber( aStorageId ) ); |
|
336 // StorageIDs which are not system owned do not correspond to drives. |
|
337 if ( drive != KErrNotFound ) |
|
338 { |
|
339 TDriveInfo info; |
|
340 User::LeaveIfError( iFramework.Fs().Drive( info, drive ) ); |
|
341 if ( info.iType == EMediaNotPresent ) |
|
342 { |
|
343 /** |
|
344 * Race conditions between media ejection and request processing |
|
345 * may result in a previously valid storage ID no longer being |
|
346 * available. |
|
347 */ |
|
348 ret = EMTPRespCodeStoreNotAvailable; |
|
349 } |
|
350 else |
|
351 if ( ( aElementInfo.iElementAttr & EMTPElementAttrWrite ) |
|
352 && ( ( info.iMediaAtt & KMediaAttWriteProtected ) |
|
353 || ( info.iDriveAtt & KDriveAttRom ) ) ) |
|
354 { |
|
355 ret = EMTPRespCodeStoreReadOnly; |
|
356 } |
|
357 } |
|
358 } |
|
359 } |
|
360 |
|
361 return ret; |
|
362 } |
|
363 |
|
364 // ----------------------------------------------------------------------------- |
|
365 // CRequestChecker::VerifyFormatCode |
|
366 // Check the format code parameter in the request |
|
367 // ----------------------------------------------------------------------------- |
|
368 // |
|
369 TMTPResponseCode CRequestChecker::VerifyFormatCode( TUint32 aFormatCode, |
|
370 const TMTPRequestElementInfo& aElementInfo ) const |
|
371 { |
|
372 PRINT1( _L( "MM MTP => CRequestChecker::VerifyFormatCode aFormatCode = 0x%x" ), aFormatCode ); |
|
373 TMTPResponseCode ret = EMTPRespCodeInvalidObjectFormatCode; |
|
374 |
|
375 if ( aElementInfo.iElementAttr == EMTPElementAttrFormatEnums ) |
|
376 { |
|
377 TUint32* formatArray = (TUint32*)( aElementInfo.iValue1 ); |
|
378 TUint32 i = 0; |
|
379 for ( i = 0; i < aElementInfo.iValue2; i++ ) |
|
380 { |
|
381 if ( aFormatCode == formatArray[i] ) |
|
382 { |
|
383 ret = EMTPRespCodeOK; |
|
384 break; |
|
385 } |
|
386 } |
|
387 } |
|
388 else |
|
389 { |
|
390 if ( ( aFormatCode >= EMTPFormatCodePTPStart ) |
|
391 && ( aFormatCode <= EMTPFormatCodeMTPEnd ) ) |
|
392 { |
|
393 ret = EMTPRespCodeOK; |
|
394 } |
|
395 } |
|
396 |
|
397 PRINT1( _L( "MM MTP => CRequestChecker::VerifyFormatCode ret = 0x%x" ), ret ); |
|
398 |
|
399 return ret; |
|
400 } |
|
401 |
|
402 // ----------------------------------------------------------------------------- |
|
403 // CRequestChecker::IsSpecialValue |
|
404 // Check if the parameter is one of the special values |
|
405 // ----------------------------------------------------------------------------- |
|
406 // |
|
407 TBool CRequestChecker::IsSpecialValue( TUint32 aParameter, |
|
408 const TMTPRequestElementInfo& aElementInfo ) const |
|
409 { |
|
410 TBool result = EFalse; |
|
411 switch ( aElementInfo.iCount ) |
|
412 { |
|
413 case 1: |
|
414 result = ( aParameter == aElementInfo.iValue1 ); |
|
415 break; |
|
416 |
|
417 case 2: |
|
418 result = ( aParameter == aElementInfo.iValue1 |
|
419 || aParameter == aElementInfo.iValue2 ); |
|
420 break; |
|
421 |
|
422 default: |
|
423 break; |
|
424 } |
|
425 |
|
426 return result; |
|
427 } |
|
428 |
|
429 // end of file |