mtpfws/mtpfw/dataproviders/dputility/src/cmtprequestchecker.cpp
changeset 0 d0791faffa3f
child 4 60a94a45d437
equal deleted inserted replaced
-1:000000000000 0:d0791faffa3f
       
     1 // Copyright (c) 2006-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 <f32file.h>
       
    17 #include <mtp/cmtpobjectmetadata.h>
       
    18 #include <mtp/mmtpconnection.h>
       
    19 #include <mtp/mmtpdataproviderframework.h>
       
    20 #include <mtp/mmtpobjectmgr.h>
       
    21 #include <mtp/mmtpstoragemgr.h>
       
    22 
       
    23 #include "cmtprequestchecker.h"
       
    24 #include "rmtpdpsingletons.h"
       
    25 #include "cmtpfsexclusionmgr.h"
       
    26 
       
    27 static const TInt KMTPRequestCheckerHandleGranularity = 2;
       
    28 __FLOG_STMT(_LIT8(KComponent,"MTPRequestChecker");)
       
    29 
       
    30 /**
       
    31 Two-phase construction method
       
    32 @param aFramework	The data provider framework
       
    33 @param aConnection	The connection object
       
    34 @return a pointer to the created request checker object
       
    35 */   
       
    36 EXPORT_C CMTPRequestChecker* CMTPRequestChecker::NewL(MMTPDataProviderFramework& aFramework, MMTPConnection& aConnection)
       
    37 	{
       
    38 	CMTPRequestChecker* self = new (ELeave) CMTPRequestChecker(aFramework, aConnection);
       
    39 	return self;
       
    40 	}
       
    41 
       
    42 /**
       
    43 Destructor
       
    44 */	
       
    45 EXPORT_C CMTPRequestChecker::~CMTPRequestChecker()
       
    46 	{
       
    47 	iHandles.Close();
       
    48 	iObjectArray.ResetAndDestroy();
       
    49 	__FLOG_CLOSE;
       
    50 	}
       
    51 
       
    52 /**
       
    53 Verfiy the request.  It check the request header first (session id and transaction code), and check for special values, last
       
    54 it iterates through the verification elements for checking individul parameters in the request
       
    55 
       
    56 @param aRequest	The request object to verify
       
    57 @param aCount	The number of verification elements
       
    58 @param aElementInfo	The array of verification elements
       
    59 @return reponse code to return to the initiator
       
    60 */	
       
    61 EXPORT_C TMTPResponseCode CMTPRequestChecker::VerifyRequestL(const TMTPTypeRequest& aRequest, TInt aCount, const TMTPRequestElementInfo* aElementInfo)
       
    62 	{
       
    63    	TMTPResponseCode result = EMTPRespCodeOK;
       
    64    	iHandles.Close();
       
    65    	iObjectArray.ResetAndDestroy();
       
    66     
       
    67 	result = CheckRequestHeader(aRequest);
       
    68 	
       
    69 	for (TInt i = 0; i < aCount && EMTPRespCodeOK == result; i++)
       
    70 		{
       
    71 		TUint32 parameter = aRequest.Uint32(aElementInfo[i].iElementIndex);
       
    72 		if (!IsSpecialValue(parameter, aElementInfo[i]))
       
    73 			{
       
    74 			switch (aElementInfo[i].iElementType)
       
    75 				{
       
    76 				case EMTPElementTypeSessionID:
       
    77 					result = VerifySessionId(parameter, aElementInfo[i]);
       
    78 					break;
       
    79 				case EMTPElementTypeObjectHandle:
       
    80 					result = VerifyObjectHandleL(parameter, aElementInfo[i]);
       
    81 					break;
       
    82 				case EMTPElementTypeStorageId:
       
    83 					result = VerifyStorageIdL(parameter, aElementInfo[i]);
       
    84 					break;
       
    85 				case EMTPElementTypeFormatCode:
       
    86 					result = VerifyFormatCode(parameter, aElementInfo[i]);
       
    87 					break;				
       
    88 				default:
       
    89 					User::Invariant();  // Should never run
       
    90 					break;				
       
    91 				}			
       
    92 			}
       
    93 	    }
       
    94 		
       
    95     return result;     
       
    96 	
       
    97 	}
       
    98 
       
    99 /**
       
   100 Return the object info for the handle.  This is to remove extra expensive DMBS retrieval operations.
       
   101 
       
   102 @param aHandle	the handle of the object requested
       
   103 @return an object info for the handle
       
   104 */
       
   105 EXPORT_C CMTPObjectMetaData* CMTPRequestChecker::GetObjectInfo(TUint32 aHandle) const
       
   106 	{
       
   107 	CMTPObjectMetaData* result = NULL;
       
   108 	TInt count = iHandles.Count();
       
   109 	for(TInt i = 0; i < count; i++)
       
   110 		{
       
   111 		if (iHandles[i] == aHandle)
       
   112 			{
       
   113 			result = iObjectArray[i];
       
   114 			break;
       
   115 			}
       
   116 		}
       
   117 	return result;
       
   118 	}
       
   119 
       
   120 /**
       
   121 Check the request header portion (session Id and transaction code)
       
   122 @param aRequest	the request object to check
       
   123 @return repsonse code to return to initiator
       
   124 */
       
   125 TMTPResponseCode CMTPRequestChecker::CheckRequestHeader(const TMTPTypeRequest& aRequest) const
       
   126 	{
       
   127     TMTPResponseCode ret = EMTPRespCodeOK; 
       
   128     TUint16 operationCode = aRequest.Uint16(TMTPTypeRequest::ERequestOperationCode);
       
   129   	TUint32 sessionId = aRequest.Uint32(TMTPTypeRequest::ERequestSessionID);
       
   130 	TUint32 transactionCode = aRequest.Uint32(TMTPTypeRequest::ERequestTransactionID);
       
   131 	
       
   132 	if (operationCode == EMTPOpCodeCloseSession || operationCode == EMTPOpCodeResetDevice)
       
   133 		{
       
   134 		if (sessionId != 0)
       
   135 			{
       
   136 			ret = EMTPRespCodeInvalidParameter;
       
   137 			}
       
   138 		}
       
   139 	else
       
   140 		{		
       
   141 	    // requests that are valid when there's no opened session.
       
   142 	    if (sessionId == 0)
       
   143 	        {
       
   144 	        switch (operationCode)
       
   145 	            {            	
       
   146 	            case EMTPOpCodeGetDeviceInfo:
       
   147 	            case EMTPOpCodeOpenSession: 
       
   148 	                {
       
   149 	                // Transaction id must be 0 when called out side an active session.
       
   150 	                if (transactionCode != 0)
       
   151 	                    {
       
   152 	                    ret = EMTPRespCodeInvalidTransactionID;
       
   153 	                    }
       
   154 
       
   155 	                }
       
   156 	                break;
       
   157 	            
       
   158 	            default:
       
   159 	                ret = EMTPRespCodeSessionNotOpen;
       
   160 	                break;
       
   161 	            }
       
   162 	        }
       
   163 	    else if (!iConnection.SessionWithMTPIdExists(sessionId))
       
   164 	        { 
       
   165 	        ret = EMTPRespCodeSessionNotOpen;
       
   166 	        }
       
   167 		}
       
   168     return ret;	
       
   169 	}
       
   170 
       
   171 /**
       
   172 Check the session id in the request parameter (NOTE the session id is different from the one in the request header),
       
   173 this usually only applies to the OpenSession request
       
   174 @param aSessionId	Session id of the request.
       
   175 @param aElementInfo ElementInfo data array to check against.
       
   176 @return repsonse code to return to initiator
       
   177 */	
       
   178 TMTPResponseCode CMTPRequestChecker::VerifySessionId(TUint32 aSessionId, const TMTPRequestElementInfo& /*aElementInfo*/) const
       
   179 	{
       
   180     TMTPResponseCode ret = EMTPRespCodeOK; 
       
   181     
       
   182     if (aSessionId != 0)   
       
   183     	{
       
   184     	if (iConnection.SessionWithMTPIdExists(aSessionId))
       
   185 			{
       
   186 			ret = EMTPRespCodeSessionAlreadyOpen;			
       
   187 			}
       
   188     	}
       
   189     else
       
   190     	{
       
   191     	ret = EMTPRespCodeInvalidParameter;
       
   192     	}
       
   193 		
       
   194     return ret;	
       
   195 	}
       
   196 
       
   197 /**
       
   198 Check the object handle in the request parameter, whether the handle is in the object store, read/write, file/dir
       
   199 @param aHandle	Object handle to be checked.
       
   200 @param aElementInfo Element info array to be checked against.
       
   201 @return repsonse code to return to initiator
       
   202 */		
       
   203 TMTPResponseCode CMTPRequestChecker::VerifyObjectHandleL(TUint32 aHandle, const TMTPRequestElementInfo& aElementInfo)
       
   204 	{
       
   205 	__FLOG_VA((_L8("VerifyObjectHandleL entry with handle 0x%08X"), aHandle));
       
   206     TMTPResponseCode ret = EMTPRespCodeOK; 
       
   207 
       
   208 	CMTPObjectMetaData* object(CMTPObjectMetaData::NewLC());
       
   209 	TBool result(iFramework.ObjectMgr().ObjectL(aHandle, *object));
       
   210 	iObjectArray.AppendL(object);
       
   211 	CleanupStack::Pop(object);
       
   212 	iHandles.AppendL(aHandle);
       
   213 		
       
   214 	// Obj handle exists
       
   215 	if (result)
       
   216 		{
       
   217 	    TUint storageID = object->Uint(CMTPObjectMetaData::EStorageId);
       
   218 		CMTPStorageMetaData* storageMetaData = (CMTPStorageMetaData *)& iFramework.StorageMgr().StorageL(storageID);
       
   219 		if (storageMetaData->Uint(CMTPStorageMetaData::EStorageSystemType) != CMTPStorageMetaData::ESystemTypeDefaultFileSystem)
       
   220 			{
       
   221 			return ret;
       
   222 			}
       
   223 		
       
   224 		const TDesC& suid(object->DesC(CMTPObjectMetaData::ESuid));
       
   225 		TEntry entry;
       
   226         TInt err = iFramework.Fs().Entry(suid, entry);
       
   227         
       
   228         if ( (object->Uint(CMTPObjectMetaData::EFormatCode) == EMTPFormatCodeAssociation) && 
       
   229              (object->Uint(CMTPObjectMetaData::EFormatSubCode) != EMTPAssociationTypeGenericFolder ) )
       
   230             {
       
   231             // Special association type .. not always present on the filesystem.
       
   232             return ret;
       
   233             }   
       
   234         else
       
   235             {
       
   236             User::LeaveIfError(err);
       
   237             }
       
   238 		
       
   239 		if (aElementInfo.iElementAttr & EMTPElementAttrWrite)
       
   240         	{
       
   241         	if (entry.IsReadOnly())
       
   242         		{
       
   243         		ret = EMTPRespCodeObjectWriteProtected;
       
   244         		}
       
   245         	}
       
   246         	
       
   247         //((EMTPRespCodeOK == ret) && (aElementInfo.iElementAttr & EMTPElementAttrFileOrDir)) is
       
   248         // covered implicitly here, EMTPRespCodeOK will be returned. It is a valid case for an object to be either a folder or file 
       
   249         // for certain operation's request parameter, for instance the first parameter of copyObject or
       
   250         // moveObject can be either a file or a directory.
       
   251         
       
   252 		// Other cases.
       
   253         if ((EMTPRespCodeOK == ret) && (aElementInfo.iElementAttr & EMTPElementAttrFile))
       
   254 	        	{
       
   255 	        	if (entry.IsDir())
       
   256 	        		{
       
   257 	        		ret = EMTPRespCodeInvalidObjectHandle;
       
   258 	        		}
       
   259 	        	}
       
   260 
       
   261        	if ((EMTPRespCodeOK == ret) && (aElementInfo.iElementAttr & EMTPElementAttrDir))
       
   262 	       	{
       
   263 	       	if (!entry.IsDir())
       
   264 	       		{
       
   265 	       		ret = EMTPRespCodeInvalidParentObject;
       
   266 	       		}        	
       
   267 	       	}
       
   268         	       		         
       
   269 		 }
       
   270 	else
       
   271 		{
       
   272 		__FLOG(_L8("Object does not exist."));
       
   273 		ret = EMTPRespCodeInvalidObjectHandle;
       
   274 		}
       
   275 	__FLOG_VA((_L8("VerifyObjectHandleL exit with repsonse code 0x%04X"), ret)); 
       
   276 	return ret;	
       
   277 	}
       
   278 
       
   279 /**
       
   280 Check the storage id parameter in the request, read/write attributes
       
   281 @param aStorageId	Storage id to be checked.
       
   282 @param aElementInfo Element info array to be checked against.
       
   283 @return repsonse code to return to initiator
       
   284 */			
       
   285 TMTPResponseCode CMTPRequestChecker::VerifyStorageIdL(TUint32 aStorageId, const TMTPRequestElementInfo& aElementInfo) const
       
   286 	{
       
   287 	MMTPStorageMgr& mgr(iFramework.StorageMgr());
       
   288     TMTPResponseCode ret(EMTPRespCodeOK);
       
   289     if (!mgr.ValidStorageId(aStorageId))
       
   290         {
       
   291         ret = EMTPRespCodeInvalidStorageID;
       
   292         }
       
   293     else if (!mgr.LogicalStorageId(aStorageId))
       
   294         {
       
   295         ret = EMTPRespCodeStoreNotAvailable;
       
   296         }
       
   297     else 
       
   298         {
       
   299         TInt drive(mgr.DriveNumber(aStorageId));
       
   300         // StorageIDs which are not system owned do not correspond to drives.
       
   301         if (drive != KErrNotFound)
       
   302             {
       
   303     		TDriveInfo info;
       
   304     		User::LeaveIfError(iFramework.Fs().Drive(info, drive));
       
   305     		if (info.iType == EMediaNotPresent)
       
   306     		    {
       
   307     		    /* 
       
   308     		    Race conditions between media ejection and request processing
       
   309     		    may result in a previously valid storage ID no longer being 
       
   310     		    available.
       
   311     		    */
       
   312     		    ret = EMTPRespCodeStoreNotAvailable;
       
   313     		    }
       
   314     		else if ((aElementInfo.iElementAttr & EMTPElementAttrWrite) &&
       
   315     		            ((info.iMediaAtt & KMediaAttWriteProtected) ||
       
   316     		             (info.iDriveAtt & KDriveAttRom)))
       
   317     		    {
       
   318         		ret = EMTPRespCodeStoreReadOnly;
       
   319     		    }
       
   320             }
       
   321         }
       
   322     return ret; 	
       
   323 	}
       
   324 	
       
   325 /**
       
   326 Check the format code parameter in the request,
       
   327 @param aStorageId	aFormatCode to be checked.
       
   328 @param aElementInfo Element info array to be checked against.
       
   329 @return repsonse code to return to initiator
       
   330 */
       
   331 TMTPResponseCode CMTPRequestChecker::VerifyFormatCode(TUint32 aFormatCode, const TMTPRequestElementInfo& aElementInfo) const
       
   332 	{
       
   333     TMTPResponseCode ret = EMTPRespCodeInvalidObjectFormatCode; 
       
   334 
       
   335 	if (aElementInfo.iElementAttr == EMTPElementAttrFormatEnums)
       
   336 		{
       
   337 		TUint32* formatArray = (TUint32*)(aElementInfo.iValue1);
       
   338 		TUint32 i = 0;
       
   339 		for(i = 0; i < aElementInfo.iValue2; i++)
       
   340 			{
       
   341 			if (aFormatCode == formatArray[i])
       
   342 				{
       
   343 				ret = EMTPRespCodeOK;
       
   344 				break;
       
   345 				}
       
   346 			}
       
   347 		}
       
   348 	else if (aFormatCode >= EMTPFormatCodePTPStart && aFormatCode <= EMTPFormatCodeMTPEnd)
       
   349 		{
       
   350 		ret = EMTPRespCodeOK;
       
   351 		}
       
   352 		
       
   353     return ret;	
       
   354 	}
       
   355 
       
   356 /**
       
   357 Check if the parameter is one of the special values
       
   358 @param aParameter	The parameter value in the request
       
   359 @param aElementInfo	The ElementInfo for the parameter
       
   360 @return ETrue if the parameter is one of the special values, otherwise, EFalse
       
   361 */
       
   362 TBool CMTPRequestChecker::IsSpecialValue(TUint32 aParameter, const TMTPRequestElementInfo& aElementInfo) const
       
   363 	{
       
   364 	TBool result = EFalse;
       
   365 	switch(aElementInfo.iCount)
       
   366 		{
       
   367 		case 1:
       
   368 			result = (aParameter == aElementInfo.iValue1);
       
   369 			break;
       
   370 		case 2:
       
   371 			result = (aParameter == aElementInfo.iValue1 || aParameter == aElementInfo.iValue2);
       
   372 			break;
       
   373 		default:
       
   374 			break;			
       
   375 		}
       
   376 	return result;
       
   377 	}
       
   378 
       
   379 /**
       
   380 Standard c++ constructor
       
   381 */	
       
   382 CMTPRequestChecker::CMTPRequestChecker(MMTPDataProviderFramework& aFramework, MMTPConnection& aConnection)
       
   383 	:iFramework(aFramework), 
       
   384 	iConnection(aConnection),
       
   385 	iHandles(KMTPRequestCheckerHandleGranularity),
       
   386 	iObjectArray(KMTPRequestCheckerHandleGranularity)
       
   387 	{
       
   388 	__FLOG_OPEN(KMTPSubsystem, KComponent);
       
   389 	}
       
   390 
       
   391 
       
   392