mtpfws/mtpfw/dataproviders/dputility/src/cmtpfsenumerator.cpp
changeset 0 d0791faffa3f
child 6 f8e15b44d440
child 17 aabe5387f5ce
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mtpfws/mtpfw/dataproviders/dputility/src/cmtpfsenumerator.cpp	Tue Feb 02 01:11:40 2010 +0200
@@ -0,0 +1,606 @@
+// Copyright (c) 2007-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 <f32file.h>
+#include <bautils.h>
+#include <mtp/cmtpdataproviderplugin.h>
+#include <mtp/cmtpobjectmetadata.h>
+#include <mtp/mmtpdataproviderframework.h>
+#include <mtp/mmtpobjectmgr.h>
+#include <mtp/mmtpstoragemgr.h>
+#include <mtp/mtpprotocolconstants.h>
+#include <mtp/tmtptypeevent.h>
+#include "cmtpfsexclusionmgr.h"
+#include "cmtpfsenumerator.h"
+#include "mmtpenumerationcallback.h"
+#include "cmtpdataprovidercontroller.h"
+#include "cmtpdataprovider.h"
+
+// Class constants.
+__FLOG_STMT(_LIT8(KComponent,"FSEnumerator");)
+
+/**
+ * the files should not be owned by any dp. 
+ */
+#define FILES_OWNED_BY_NONE             0
+
+/**
+ * the missed files of other dps should be owned by file dp
+ */
+#define MISSED_FILES_OWNED_BY_FILE_DP   1
+
+/**
+ * the missed files of other dps should be owned by counterparter dps
+ */
+#define MISSED_FILES_OWNED_BY_OTHER_DP  2
+
+/**
+ * the files of other dps should be owned by counterparter dps
+ */
+#define FILES_OWNED_BY_OTHER_DP         3
+
+/**
+Two-phase construction
+@param aFramework    data provider framework of data provider
+@param aObjectMgr    the reference to the object manager
+@param aExclusionMgr    the reference to the exclusion manager 
+@param aCallback callback to be called when enumeration is complete
+*/
+EXPORT_C CMTPFSEnumerator* CMTPFSEnumerator::NewL(MMTPDataProviderFramework& aFramework, CMTPFSExclusionMgr& aExclusionMgr, MMTPEnumerationCallback& aCallback, TInt aProcessLimit)
+    {
+    CMTPFSEnumerator* self = new (ELeave) CMTPFSEnumerator(aFramework, aExclusionMgr, aCallback, aProcessLimit);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+/**
+destructor
+*/    
+EXPORT_C CMTPFSEnumerator::~CMTPFSEnumerator()
+	{
+	Cancel();	
+	iDir.Close();
+	iDirStack.Close();
+	iStorages.Close();
+	iDpSingletons.Close();
+	iSingletons.Close();
+	delete iObject;
+	__FLOG_CLOSE; 
+	}
+
+/**
+Kick off the enumeration on the specified storage
+@param aStorageId storage to be enumerated
+*/
+EXPORT_C void CMTPFSEnumerator::StartL(TUint32 aStorageId)
+	{
+	__ASSERT_DEBUG(!IsActive(), User::Invariant());
+	MMTPStorageMgr& storageMgr(iFramework.StorageMgr());
+	if (aStorageId == KMTPStorageAll)
+	    {
+        // Retrieve the available logical StorageIDs
+        RPointerArray<const CMTPStorageMetaData> storages;
+        CleanupClosePushL(storages);
+        TMTPStorageMgrQueryParams params(KNullDesC, CMTPStorageMetaData::ESystemTypeDefaultFileSystem);
+        storageMgr.GetLogicalStoragesL(params, storages);
+        
+        // Construct the StorageIDs list.
+        const TUint KCount(storages.Count());
+        for (TUint i(0); (i < KCount); i++)
+            {
+            iStorages.Insert(storages[i]->Uint(CMTPStorageMetaData::EStorageId),0);
+            __FLOG_VA((_L8("FileEnumerator is doing storage id = %x\r\n"), storages[i]->Uint(CMTPStorageMetaData::EStorageId) ));
+            }
+        CleanupStack::PopAndDestroy(&storages);
+	    }
+    else if (aStorageId != KMTPNotSpecified32)
+        {
+		__ASSERT_DEBUG(storageMgr.ValidStorageId(aStorageId), User::Invariant());
+		const CMTPStorageMetaData& storage(storageMgr.StorageL(aStorageId));
+		if (storage.Uint(CMTPStorageMetaData::EStorageSystemType) == CMTPStorageMetaData::ESystemTypeDefaultFileSystem)
+		    {
+    	    if (storageMgr.LogicalStorageId(aStorageId))
+    		    {
+    		    // Logical StorageID.
+    			iStorages.AppendL(aStorageId);
+    		    }
+    		else
+    		    {
+    		    // Physical StorageID. Enumerate all eligible logical storages.
+    		    const RArray<TUint>& logicalIds(storage.UintArray(CMTPStorageMetaData::EStorageLogicalIds));
+    		    const TUint KCountLogicalIds(logicalIds.Count());
+                for (TUint i(0); (i < KCountLogicalIds); i++)
+                    {
+                    iStorages.AppendL(logicalIds[i]);
+                    }
+    		    }
+		    }
+		}
+
+	iStorageId = aStorageId;
+	iSkipCurrentStorage = EFalse;
+	
+	if (iStorages.Count() > 0)
+		{
+		 TRAPD(err, ScanStorageL(iStorages[0]));        
+		 if(err != KErrNone)
+			 {
+			 if( !storageMgr.ValidStorageId(iStorages[0]) )
+				 {
+				 //Scan storage leave because storage(memory card) removed.
+				 //Scan next specified storage in RunL, if there is.
+				 __FLOG_VA(_L8("StartL - iSkipCurrentStorage - ETrue."));
+				 iSkipCurrentStorage = ETrue;
+				TRequestStatus* status = &iStatus;
+				User::RequestComplete(status, iStatus.Int());
+				 SetActive();
+				 }
+			 else
+				 {
+				 User::Leave(err);
+				 }
+			 }
+		}
+	else
+		{
+		iCallback.NotifyEnumerationCompleteL(iStorageId, KErrNone);
+		
+		TMTPTypeEvent event;
+		
+		event.SetUint16(TMTPTypeEvent::EEventCode, EMTPEventCodeUnreportedStatus);
+		event.SetUint32(TMTPTypeEvent::EEventSessionID, KMTPSessionAll);
+		
+		iFramework.SendEventL(event);
+		}
+	}
+	
+/**
+Cancel the enumeration process
+*/    
+void CMTPFSEnumerator::DoCancel()
+	{
+	iDir.Close();
+	}
+
+void CMTPFSEnumerator::ScanStorageL(TUint32 aStorageId)
+	{
+	__FLOG_VA(_L8("ScanStorageL - entry"));
+    const CMTPStorageMetaData& storage(iFramework.StorageMgr().StorageL(aStorageId));
+    __ASSERT_DEBUG((storage.Uint(CMTPStorageMetaData::EStorageSystemType) == CMTPStorageMetaData::ESystemTypeDefaultFileSystem), User::Invariant());
+    TFileName root(storage.DesC(CMTPStorageMetaData::EStorageSuid));
+    
+    #ifdef __FLOG_ACTIVE    
+	TBuf8<KMaxFileName> tmp;
+	tmp.Copy(root);
+ 	__FLOG_VA((_L8("StorageSuid - %S"), &tmp));	
+	#endif // __FLOG_ACTIVE
+ 	
+ 	if ( iExclusionMgr.IsFolderAcceptedL(root, aStorageId) )
+ 	    {
+ 	    iParentHandle = KMTPHandleNoParent;
+ 	    iPath.Set(root, NULL, NULL);
+ 	    User::LeaveIfError(iDir.Open(iFramework.Fs(), iPath.DriveAndPath(), KEntryAttNormal | KEntryAttDir));
+ 	    ScanDirL();
+ 	    }
+ 	else
+ 	    {
+ 	    TRequestStatus* status = &iStatus;
+ 	    User::RequestComplete(status, iStatus.Int());
+ 	    SetActive();
+ 	    }
+ 	__FLOG_VA(_L8("ScanStorageL - exit"));
+	}
+
+/**
+Scans directory at aPath recursing into subdirectories on a depth first basis.
+
+Directory entries are kept in iDirStack - which is a LIFO stack.
+The current path, needed since TEntries don't keep track of it, 
+is kept in iPath.
+
+The algorithm works as follows:
+
+1. Read directory entries.
+2. ProcessEntriesL is called if no error occurs and >= 1 entries are read.
+3. ProcessEntriesL adds entries to database, if entry is directory add to iDirStack.
+4. When all entries are processed pop entry off the dirstack, 
+	if entry is empty TEntry remove one directory from iPath.
+5. Append entry name onto iPath - to update path with new depth (parent/subdir).
+6. Push an empty TEntry onto iDirStack - this tells us we have recursed one,
+	think of it as pushing the '\' separator onto iDirStack.
+7. Repeat 1-7 until iDirStack is empty.
+*/
+
+void CMTPFSEnumerator::ScanDirL()
+	{
+	__FLOG_VA(_L8("ScanDirL - entry"));
+	iFirstUnprocessed = 0;
+	iDir.Read(iEntries, iStatus);
+	SetActive();
+	__FLOG_VA(_L8("ScanDirL - exit"));
+	}
+
+void CMTPFSEnumerator::ScanNextStorageL()
+	{
+	__FLOG_VA(_L8("ScanNextStorageL - entry"));
+	// If there are one or more unscanned storages left
+	// (the currently scanned one is still on the list)
+	if (iStorages.Count() > 1)
+		{
+		iStorages.Remove(0);
+		ScanStorageL(iStorages[0]);
+		}
+	else
+		{
+		// We are done
+		iStorages.Reset();
+		iCallback.NotifyEnumerationCompleteL(iStorageId, KErrNone);
+		}
+	__FLOG_VA(_L8("ScanNextStorageL - exit"));
+	}
+
+void CMTPFSEnumerator::ScanNextSubdirL()
+	{
+	__FLOG_VA(_L8("ScanNextSubdirL - entry"));
+	// A empty (non-constructed) TEntry is our marker telling us to pop a directory 
+	// from iPath when we see this
+	iDirStack.AppendL(TEntry());
+			
+	// Leave with KErrNotFound if we don't find the object handle since it shouldn't be on the 
+	// dirstack if the entry wasn't added
+	TPtrC suid = iPath.DriveAndPath().Left(iPath.DriveAndPath().Length());
+	// Update the current parentId with object of the directory
+	iParentHandle = iFramework.ObjectMgr().HandleL(suid);
+				
+	// Kick-off a scan of the next directory
+	iDir.Close();
+	User::LeaveIfError(iDir.Open(iFramework.Fs(), iPath.DriveAndPath(), KEntryAttNormal | KEntryAttDir));
+	ScanDirL();
+	__FLOG_VA(_L8("ScanNextSubdirL - exit"));
+	}
+
+/**
+Recurse into the next directory on the stack
+and scan it for entries.
+*/
+
+void CMTPFSEnumerator::ScanNextL()
+	{
+	__FLOG_VA(_L8("ScanNextL - entry"));
+	TInt count = iDirStack.Count();
+	
+	if (count == 0)
+		{
+		// No more directories on the stack, try the next storage
+		ScanNextStorageL();
+		}
+	else
+		{
+		TEntry& entry = iDirStack[count - 1];
+		
+		// Empty TEntry, no more subdirectories in
+		// the current path
+		if (entry.iName == KNullDesC)
+			{
+			// Remove current dir from path
+			iPath.PopDir();
+			iDirStack.Remove(count - 1);
+			iDir.Close();
+			
+			// Scan the next directory of the parent
+			ScanNextL();
+			}
+			
+		// Going into a subdirectory of current
+		else 
+			{
+			// Add directory to path		
+			iPath.AddDir(entry.iName);
+			// Remove directory so we don't think it's a subdirectory
+			iDirStack.Remove(count - 1);
+	
+			ScanNextSubdirL();
+			}
+		}
+	__FLOG_VA(_L8("ScanNextL - exit"));
+	}
+
+void CMTPFSEnumerator::RunL()
+	{
+	__FLOG_VA(_L8("RunL - entry"));
+	if(iSkipCurrentStorage)
+		{
+		__FLOG_VA(_L8("RunL - iSkipCurrentStorage - ETrue."));
+		iSkipCurrentStorage = EFalse;
+		ScanNextStorageL();
+		}
+	else if (iEntries.Count() == 0)
+		{
+		// No entries to process, scan next dir or storage
+		ScanNextL();
+		}
+	else if (iFirstUnprocessed < iEntries.Count())
+		{
+		ProcessEntriesL();
+		
+		// Complete ourselves with current TRequestStatus
+		// since we need to run again to either scan a new dir or drive
+		// or process more entries
+		TRequestStatus* status = &iStatus;
+		User::RequestComplete(status, iStatus.Int());
+		SetActive();
+		}
+	else
+		{
+		switch (iStatus.Int())
+			{
+			case KErrNone:
+				// There are still entries left to be read
+				ScanDirL();
+				break;
+			
+			case KErrEof:
+				// There are no more entries
+			default:
+				// Error, ignore and continue with next dir
+				ScanNextL();
+				break;
+			}
+		}
+	__FLOG_VA(_L8("RunL - exit"));
+	}
+
+/**
+Ignore the error, continue with the next one
+*/    
+TInt CMTPFSEnumerator::RunError(TInt aError)
+	{
+	__FLOG_VA((_L8("RunError - entry with error %d"), aError));
+	 if(!iFramework.StorageMgr().ValidStorageId(iStorages[0]))
+		 {
+		 if (iStorages.Count()>1)
+			 {
+			 //Not necessary to process any entry on the storage, since the storage removed.
+			 //Then need to start from root dir of next storage if there is.
+			 //So, the dir stack is popped to bottom.
+			 iDirStack.Reset();
+			 }
+		 iSkipCurrentStorage = ETrue;
+		 }
+	
+	// Reschedule ourselves
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, aError);
+	SetActive();
+	
+	__FLOG(_L8("RunError - Exit"));
+	return KErrNone;
+	}
+	
+/**
+Standard c++ constructor
+*/	
+CMTPFSEnumerator::CMTPFSEnumerator(MMTPDataProviderFramework& aFramework, CMTPFSExclusionMgr& aExclusionMgr, MMTPEnumerationCallback& aCallback, TInt aProcessLimit)
+	: CActive(EPriorityLow),
+  	iFramework(aFramework),
+  	iExclusionMgr(aExclusionMgr),
+    iCallback(aCallback),
+    iProcessLimit(aProcessLimit)
+	{
+	__FLOG_OPEN(KMTPSubsystem, KComponent);
+	CActiveScheduler::Add(this);
+	}
+
+void CMTPFSEnumerator::ConstructL()
+	{
+	iSingletons.OpenL();
+	iDpSingletons.OpenL(iFramework);
+	iObject = CMTPObjectMetaData::NewL();	
+	iDpID = iFramework.DataProviderId();
+	}
+
+/**
+Iterates iEntries adding entries as needed to object manager and iDirStack.
+*/
+
+void CMTPFSEnumerator::ProcessEntriesL()
+	{
+	const TUint KMTPMaxFullFileName = 259;
+
+	TBuf<KMTPMaxFullFileName> path = iPath.DriveAndPath();
+	
+	// Start looping through entries at where we left off
+	TInt count = iEntries.Count() - iFirstUnprocessed;
+	// Process no more than KProcessLimit entries
+	count = Min(count, iProcessLimit);
+	iFirstUnprocessed += count;		
+	
+		
+	for (TInt i = (iFirstUnprocessed - count); i < iFirstUnprocessed; ++i)
+		{
+		const TEntry& entry = iEntries[i];
+		path.Append(entry.iName);
+		
+#ifdef __FLOG_ACTIVE    
+		TBuf8<KMTPMaxFullFileName> tmp;
+        tmp.Copy(path);
+        TInt pathLen=path.Length();
+        if(pathLen > KLogBufferSize)
+            {
+            TBuf8<KLogBufferSize> tmp1;
+            tmp1.Copy(tmp.Ptr(),KLogBufferSize);
+			__FLOG_VA(_L8("Entry - "));
+	        __FLOG_VA((_L8("%S"), &tmp1));
+
+	        tmp1.Copy(tmp.Ptr()+KLogBufferSize, pathLen-KLogBufferSize);
+	        __FLOG_VA((_L8("%S"), &tmp1));
+            }
+        else
+            {
+            __FLOG_VA(_L8("Entry - "));
+			__FLOG_VA((_L8("%S"), &tmp));
+            }
+#endif // __FLOG_ACTIVE
+		
+		TInt len = entry.iName.Length();
+		TInt totalLen = path.Length();
+		if(totalLen > KMaxFileName)
+		    {
+			// Remove filename part
+		    path.SetLength(totalLen - len);
+		    __FLOG_VA(_L8("Full name exceeds KMaxFileName, ignored."));
+		    continue;
+		    }
+		TUint32 handle = 0;
+		TMTPFormatCode format;
+		  TParsePtrC parse(path);
+		if (entry.IsDir())
+			{
+			if (iExclusionMgr.IsFolderAcceptedL(path, iStorages[0]))
+				{
+				path.Append('\\');
+				++len;
+				format = EMTPFormatCodeAssociation;
+				AddEntryL(path, handle, format, iDpID, entry);
+				iDirStack.AppendL(entry);
+				}
+			}
+		else if ( iExclusionMgr.IsFileAcceptedL(path,iStorages[0]) )
+			{
+			format = EMTPFormatCodeUndefined;
+			AddEntryL(path, handle, format, iDpID, entry);
+			}
+		else if ( parse.ExtPresent() )
+		    {
+		    switch(iDpSingletons.MTPUtility().GetEnumerationFlag(parse.Ext().Mid(1)))
+		        {
+            case MISSED_FILES_OWNED_BY_FILE_DP:
+                if (KMTPHandleNone == iFramework.ObjectMgr().HandleL(path))
+                    {
+                    format = EMTPFormatCodeUndefined;
+                    AddEntryL(path, handle, format, iDpID, entry);		   
+                    }
+                break;
+                
+            case MISSED_FILES_OWNED_BY_OTHER_DP:
+                if (KMTPHandleNone == iFramework.ObjectMgr().HandleL(path))
+                    {
+                    format = iDpSingletons.MTPUtility().GetFormatByExtension(parse.Ext().Mid(1));  
+                    TUint32 DpId = iDpSingletons.MTPUtility().GetDpId(parse.Ext().Mid(1), KNullDesC);
+                    AddFileEntryForOtherDpL(path, handle, format, DpId, entry);
+                    }
+                break;
+                
+            case FILES_OWNED_BY_OTHER_DP:
+                {
+                format = iDpSingletons.MTPUtility().GetFormatByExtension(parse.Ext().Mid(1));  
+                TUint32 DpId = iDpSingletons.MTPUtility().GetDpId(parse.Ext().Mid(1), KNullDesC);
+                AddFileEntryForOtherDpL(path, handle, format, DpId, entry);
+                }
+                break;
+                
+//          case FILES_OWNED_BY_NONE:
+            default:
+                //nothing to do
+                break;
+		        }    
+		    }
+		// Remove filename part					
+		path.SetLength(path.Length() - len);
+		}
+		
+	}
+
+/**
+Add a file entry to the object store
+@param aEntry    The file Entry to be added
+@param aPath    The full path name of the entry
+@return MTP object handle, or KMTPHandleNone if entry was not accepted
+*/    
+void CMTPFSEnumerator::AddEntryL(const TDesC& aPath, TUint32 &aHandle, TMTPFormatCode format, TUint32 aDPId, const TEntry& aEntry)
+	{
+#ifdef __FLOG_ACTIVE    
+	TBuf8<KMaxFileName> tmp;
+	tmp.Copy(aPath);
+	
+	__FLOG_VA((_L8("AddEntryL - entry: %S"), &tmp));
+#endif // __FLOG_ACTIVE
+
+    TUint16 assoc;
+    TPtrC name;
+    if (format == EMTPFormatCodeAssociation)
+        {
+        assoc = EMTPAssociationTypeGenericFolder;
+        TParsePtrC pathParser(aPath.Left(aPath.Length() - 1)); // Ignore the trailing "\".
+		name.Set(aEntry.iName);
+        }
+    else
+        {
+        assoc = EMTPAssociationTypeUndefined;
+        TParsePtrC pathParser(aPath);
+		name.Set(pathParser.Name());	
+        }
+    
+    if(iExclusionMgr.IsFormatValid(format))
+        {
+        aHandle = KMTPHandleNone;
+        
+        iObject->SetUint(CMTPObjectMetaData::EDataProviderId, aDPId);
+        iObject->SetUint(CMTPObjectMetaData::EFormatCode, format);
+        iObject->SetUint(CMTPObjectMetaData::EStorageId, iStorages[0]);
+        iObject->SetDesCL(CMTPObjectMetaData::ESuid, aPath);
+        iObject->SetUint(CMTPObjectMetaData::EFormatSubCode, assoc);
+        iObject->SetUint(CMTPObjectMetaData::EParentHandle, iParentHandle);
+        iObject->SetUint(CMTPObjectMetaData::ENonConsumable, EMTPConsumable);
+        iObject->SetDesCL(CMTPObjectMetaData::EName, name);
+        iFramework.ObjectMgr().InsertObjectL(*iObject);
+        }
+	__FLOG_VA(_L8("AddEntryL - exit"));	
+	}
+
+void CMTPFSEnumerator::AddFileEntryForOtherDpL(const TDesC& aPath, TUint32 &aHandle, TMTPFormatCode format, TUint32 aDPId, const TEntry& /*aEntry*/)
+    {
+#ifdef __FLOG_ACTIVE    
+    TBuf8<KMaxFileName> tmp;
+    tmp.Copy(aPath);
+    
+    __FLOG_VA((_L8("AddFileEntryForOtherDpL - entry: %S"), &tmp));
+#endif // __FLOG_ACTIVE
+
+    TUint16 assoc = EMTPAssociationTypeUndefined;
+    TParsePtrC pathParser(aPath);
+    TPtrC name(pathParser.Name());    
+    
+    aHandle = KMTPHandleNone;
+    
+    iObject->SetUint(CMTPObjectMetaData::EDataProviderId, aDPId);
+    iObject->SetUint(CMTPObjectMetaData::EFormatCode, format);
+    iObject->SetUint(CMTPObjectMetaData::EStorageId, iStorages[0]);
+    iObject->SetDesCL(CMTPObjectMetaData::ESuid, aPath);
+    iObject->SetUint(CMTPObjectMetaData::EFormatSubCode, assoc);
+    iObject->SetUint(CMTPObjectMetaData::EParentHandle, iParentHandle);
+    iObject->SetUint(CMTPObjectMetaData::ENonConsumable, EMTPConsumable);
+    iObject->SetDesCL(CMTPObjectMetaData::EName, name);
+    iFramework.ObjectMgr().InsertObjectL(*iObject);
+    __FLOG_VA(_L8("AddEntryL - exit")); 
+    }
+
+void CMTPFSEnumerator::NotifyObjectAddToDP(const TUint32 aHandle,const TUint DpId)
+    {
+    iSingletons.DpController().NotifyDataProvidersL(DpId,EMTPObjectAdded,(TAny*)&aHandle);
+    }
+