--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mtpfws/mtpfw/dataproviders/devdp/src/cmtpstoragewatcher.cpp Tue Feb 02 01:11:40 2010 +0200
@@ -0,0 +1,524 @@
+// Copyright (c) 2006-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 <mtp/cmtpdataproviderplugin.h>
+#include <mtp/mmtpdataproviderframework.h>
+#include <mtp/mtpprotocolconstants.h>
+#include <mtp/mtpdataproviderapitypes.h>
+
+#include "cmtpdataprovider.h"
+#include "cmtpdataprovidercontroller.h"
+#include "cmtpframeworkconfig.h"
+#include "cmtpstoragemgr.h"
+#include "cmtpobjectmgr.h"
+#include "cmtpstoragewatcher.h"
+#include "rmtpdevicedpsingletons.h"
+#include "cmtpdevicedpconfigmgr.h"
+
+
+// Class constants.
+__FLOG_STMT(_LIT8(KComponent,"StorageWatcher");)
+static const TBool KAllDrives(ETrue);
+static const TBool KAvailableDrives(EFalse);
+
+const TInt KFolderExclusionGranularity = 8;
+
+/**
+MTP system storage watcher factory method.
+@return A pointer to an MTP system storage watcher object. Ownership IS
+transfered.
+@leave One of the system wide error codes, if a processing failure occurs.
+*/
+CMTPStorageWatcher* CMTPStorageWatcher::NewL(MMTPDataProviderFramework& aFramework)
+ {
+ CMTPStorageWatcher* self = new (ELeave) CMTPStorageWatcher(aFramework);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+Destructor.
+*/
+CMTPStorageWatcher::~CMTPStorageWatcher()
+ {
+ __FLOG(_L8("~CMTPStorageWatcher - Entry"));
+ Cancel();
+ delete iFolderExclusionList;
+ iDpSingletons.Close();
+ iDrivesExcluded.Close();
+ iFrameworkSingletons.Close();
+ __FLOG(_L8("~CMTPStorageWatcher - Exit"));
+ __FLOG_CLOSE;
+ }
+
+void CMTPStorageWatcher::EnumerateStoragesL()
+ {
+ __FLOG(_L8("EnumerateStoragesL - Entry"));
+
+ //Use Hash to replace it
+ AppendFolderExclusionListL();
+
+ // Retrieve the drive exclusion list.
+ iFrameworkSingletons.FrameworkConfig().GetValueL(CMTPFrameworkConfig::EExcludedStorageDrives, iDrivesExcluded);
+ iDrivesExcluded.Sort();
+
+ // Claim system storages ownership.
+ CMTPStorageMgr& mgr(iFrameworkSingletons.StorageMgr());
+ mgr.SetFrameworkId(iFramework.DataProviderId());
+
+ /*
+ Enumerate the initial drive set.
+
+ 1. Enumerate each known drive as a physical storage.
+ */
+ iDrivesConfig = DriveConfigurationL(KAllDrives);
+ CMTPStorageMetaData* storage = CMTPStorageMetaData::NewLC();
+ storage->SetUint(CMTPStorageMetaData::EStorageSystemType, CMTPStorageMetaData::ESystemTypeDefaultFileSystem);
+ _LIT(KSuidTemplate, "?:");
+ RBuf suid;
+ suid.CleanupClosePushL();
+ suid.Assign((KSuidTemplate().AllocL()));
+
+ for (TInt drive(0); (drive < KMaxDrives); drive++)
+ {
+ const TUint32 mask(1 << drive);
+ if (iDrivesConfig & mask)
+ {
+ TChar driveChar;
+ User::LeaveIfError(iFramework.Fs().DriveToChar(drive, driveChar));
+ suid[0] = driveChar;
+ storage->SetDesCL(CMTPStorageMetaData::EStorageSuid, suid);
+
+ TUint32 id(mgr.AllocatePhysicalStorageIdL(iFramework.DataProviderId(), *storage));
+ mgr.SetDriveMappingL(static_cast<TDriveNumber>(drive), id);
+ }
+ }
+
+ CleanupStack::PopAndDestroy(&suid);
+ CleanupStack::PopAndDestroy(storage);
+
+ /*
+ 2. If so configured, enumerate a single logical storage for each of
+ the available drives.
+ */
+ if (iAllocateLogicalStorages)
+ {
+ iDrivesConfig = DriveConfigurationL(KAvailableDrives);
+
+ for (TInt drive(0); (drive < KMaxDrives); drive++)
+ {
+ const TUint32 mask(1 << drive);
+ if (iDrivesConfig & mask)
+ {
+ StorageAvailableL(static_cast<TDriveNumber>(drive));
+ }
+ }
+ }
+
+ // Set the default storage.
+ TUint defaultDrive;
+ iFrameworkSingletons.FrameworkConfig().GetValueL(CMTPFrameworkConfig::EDefaultStorageDrive, defaultDrive);
+
+ if ( defaultDrive <= EDriveZ )
+ {
+ // Default drive is specified by drive number.. retrieve from manager..
+ if (iAllocateLogicalStorages)
+ {
+ mgr.SetDefaultStorageId(mgr.FrameworkStorageId(static_cast<TDriveNumber>(defaultDrive)));
+ }
+ else
+ {
+ mgr.SetDefaultStorageId(mgr.PhysicalStorageId(static_cast<TDriveNumber>(defaultDrive)));
+ }
+ }
+ else
+ {
+ // Default drive is specified by storage number
+ mgr.SetDefaultStorageId(defaultDrive);
+ }
+
+ __FLOG(_L8("EnumerateStoragesL - Exit"));
+ }
+
+/**
+Initiates storage change notice subscription.
+*/
+void CMTPStorageWatcher::Start()
+ {
+ __FLOG(_L8("Start - Entry"));
+ if (!(iState & EStarted))
+ {
+ __FLOG(_L8("Starting RFs notifier"));
+ TRequestStatus* status(&iStatus);
+ User::RequestComplete(status, KErrNone);
+ SetActive();
+ iState |= EStarted;
+ }
+ __FLOG(_L8("Start - Exit"));
+ }
+
+void CMTPStorageWatcher::DoCancel()
+ {
+ __FLOG(_L8("DoCancel - Entry"));
+ __FLOG(_L8("Stopping RFs notifier"));
+ iFrameworkSingletons.Fs().NotifyChangeCancel();
+ iState &= (!EStarted);
+ __FLOG(_L8("DoCancel - Exit"));
+ }
+
+/**
+Append all DPs folder exclusion list strings in Device DP
+ */
+void CMTPStorageWatcher::AppendFolderExclusionListL()
+ {
+ CDesCArraySeg* folderExclusionSets = new (ELeave) CDesCArraySeg(KFolderExclusionGranularity);
+ CleanupStack::PushL(folderExclusionSets);
+ CMTPDataProviderController& dps(iFrameworkSingletons.DpController());
+ TUint currentDpIndex = 0, count = dps.Count();
+ while (currentDpIndex < count)
+ {
+ CMTPDataProvider& dp(dps.DataProviderByIndexL(currentDpIndex));
+ if(KMTPImplementationUidDeviceDp != dp.ImplementationUid().iUid)
+ {
+ folderExclusionSets->Reset();
+ dp.Plugin().SupportedL(EFolderExclusionSets,*folderExclusionSets);
+ for(TInt i = 0; i < folderExclusionSets->Count(); ++i)
+ {
+ TPtrC16 excludedFolder = (*folderExclusionSets)[i];
+ iFolderExclusionList->AppendL(excludedFolder);
+ }
+ }
+ currentDpIndex++;
+ }
+ CleanupStack::PopAndDestroy(folderExclusionSets);
+ }
+
+/**
+Handles leaves occurring in RunL.
+@param aError leave error code
+@return KErrNone
+*/
+#ifdef __FLOG_ACTIVE
+TInt CMTPStorageWatcher::RunError(TInt aError)
+#else
+TInt CMTPStorageWatcher::RunError(TInt /*aError*/)
+#endif
+ {
+ __FLOG(_L8("RunError - Entry"));
+ __FLOG_VA((_L8("Error = %d"), aError));
+
+ // Ignore the error, meaning that the storages may not be accurately accounted for
+ RequestNotification();
+
+ __FLOG(_L8("RunError - Exit"));
+ return KErrNone;
+ }
+
+void CMTPStorageWatcher::RunL()
+ {
+ __FLOG(_L8("RunL - Entry"));
+ const TUint32 previous(iDrivesConfig);
+ const TUint32 current(DriveConfigurationL(KAvailableDrives));
+ if (current != previous)
+ {
+ const TUint32 changed(current ^ previous);
+ const TUint32 added(changed & current);
+ const TUint32 removed(changed & previous);
+ TInt i(KMaxDrives);
+ while (i--)
+ {
+ const TUint32 mask(1 << i);
+ if (added & mask)
+ {
+ StorageAvailableL(static_cast<TDriveNumber>(i));
+ }
+ else if (removed & mask)
+ {
+ StorageUnavailableL(static_cast<TDriveNumber>(i));
+ }
+ }
+ }
+ iDrivesConfig = current;
+ RequestNotification();
+ __FLOG(_L8("RunL - Exit"));
+ }
+
+/**
+Constructor.
+@param aConnectionMgr The MTP connection manager interface.
+*/
+CMTPStorageWatcher::CMTPStorageWatcher(MMTPDataProviderFramework& aFramework) :
+ CActive(EPriorityStandard),
+ iFramework(aFramework)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+/**
+Second phase constructor.
+*/
+void CMTPStorageWatcher::ConstructL()
+ {
+ __FLOG_OPEN(KMTPSubsystem, KComponent);
+ __FLOG(_L8("ConstructL - Entry"));
+ iFrameworkSingletons.OpenL();
+ iFrameworkSingletons.FrameworkConfig().GetValueL(CMTPFrameworkConfig::ELogicalStorageIdsAllocationEnable, iAllocateLogicalStorages);
+
+ RMTPDeviceDpSingletons devSingletons;
+ devSingletons.OpenL(iFramework);
+ CleanupClosePushL(devSingletons);
+
+ iDpSingletons.OpenL(iFramework);
+ iFolderExclusionList = devSingletons.ConfigMgr().GetArrayValueL(CMTPDeviceDpConfigMgr::EFolderExclusionList);
+ CleanupStack::PopAndDestroy(&devSingletons);
+ __FLOG(_L8("ConstructL - Exit"));
+ }
+
+TUint32 CMTPStorageWatcher::DriveConfigurationL(TBool aAllDrives) const
+ {
+ __FLOG(_L8("DriveConfigurationL - Entry"));
+ TUint32 config(0);
+ TDriveList drives;
+ RFs& fs(iFrameworkSingletons.Fs());
+ User::LeaveIfError(fs.DriveList(drives));
+ TInt i(KMaxDrives);
+ while (i--)
+ {
+ __FLOG_VA((_L8("Drive number %d, available = 0x%02d"), i, drives [i]));
+ if ((drives[i]) &&
+ (!Excluded(static_cast<TDriveNumber>(i))))
+ {
+ TDriveInfo info;
+ User::LeaveIfError(fs.Drive(info, i));
+ if ((info.iType != EMediaNotPresent) || (aAllDrives))
+ {
+ TVolumeInfo volumeInfo;
+ if(KErrNone == fs.Volume(volumeInfo,i))
+ {
+ config |= (1 << i);
+ }
+ }
+ }
+ }
+ __FLOG_VA((_L8("Drives list = 0x%08X, AllDrives = %d"), config, aAllDrives));
+ __FLOG(_L8("DriveConfigurationL - Exit"));
+ return config;
+ }
+
+TBool CMTPStorageWatcher::Excluded(TDriveNumber aDriveNumber) const
+ {
+ __FLOG(_L8("Excluded - Entry"));
+ TBool ret(iDrivesExcluded.FindInOrder(aDriveNumber) != KErrNotFound);
+ __FLOG_VA((_L8("Drive = %d, excluded = %d"), aDriveNumber, ret));
+ __FLOG(_L8("Excluded - Exit"));
+ return ret;
+ }
+
+void CMTPStorageWatcher::RequestNotification()
+ {
+ __FLOG(_L8("RequestNotification - Entry"));
+ _LIT(KPath, "?:\\..");
+ iFrameworkSingletons.Fs().NotifyChange(ENotifyEntry, iStatus, KPath);
+ SetActive();
+ __FLOG(_L8("RequestNotification - Exit"));
+ }
+
+void CMTPStorageWatcher::SendEventL(TUint16 aEvent, TUint32 aStorageId)
+ {
+ __FLOG(_L8("SendEventL - Entry"));
+ if (iState & EStarted)
+ {
+ __FLOG_VA((_L8("Sending event 0x%04X for StorageID 0x%08X"), aEvent, aStorageId));
+ iEvent.Reset();
+ iEvent.SetUint16(TMTPTypeEvent::EEventCode, aEvent);
+ iEvent.SetUint32(TMTPTypeEvent::EEventSessionID, KMTPSessionAll);
+ iEvent.SetUint32(TMTPTypeEvent::EEventTransactionID, KMTPTransactionIdNone);
+ iEvent.SetUint32(TMTPTypeEvent::EEventParameter1, aStorageId);
+ iFramework.SendEventL(iEvent);
+ }
+ __FLOG(_L8("SendEventL - Exit"));
+ }
+
+/**
+Configures the specified drive as an available MTP storage.
+@param aDriveNumber The Symbian OS file system drive number.
+@leave One of the system wide error codes, if a processing failure occurs.
+*/
+void CMTPStorageWatcher::StorageAvailableL(TDriveNumber aDriveNumber)
+ {
+ __FLOG(_L8("StorageAvailableL - Entry"));
+ __FLOG_VA((_L8("Drive = %d is available."), aDriveNumber));
+ CMTPStorageMgr& mgr(iFrameworkSingletons.StorageMgr());
+ TInt32 physical(mgr.PhysicalStorageId(aDriveNumber));
+ _LIT(KSuidTemplate, "?:");
+ // Generate the storage SUID as the drive root folder.
+ RBuf suid;
+ suid.CleanupClosePushL();
+ suid.Assign((KSuidTemplate().AllocL()));
+ TChar driveChar;
+ User::LeaveIfError(iFramework.Fs().DriveToChar(aDriveNumber, driveChar));
+ driveChar.LowerCase();
+ suid[0] = driveChar;
+ // Create the storage meta-data.
+ CMTPStorageMetaData* storage = CMTPStorageMetaData::NewLC();
+ storage->SetUint(CMTPStorageMetaData::EStorageSystemType, CMTPStorageMetaData::ESystemTypeDefaultFileSystem);
+ storage->SetDesCL(CMTPStorageMetaData::EStorageSuid, suid);
+ if(physical == KErrNotFound)
+ {
+ TUint32 id(mgr.AllocatePhysicalStorageIdL(iFramework.DataProviderId(), *storage));
+ mgr.SetDriveMappingL(aDriveNumber, id);
+ }
+ physical = mgr.PhysicalStorageId(aDriveNumber);
+
+ User::LeaveIfError(physical);
+ TUint32 logical(physical);
+
+ // If configured to do so, assign a logical storage ID mapping.
+ if (iAllocateLogicalStorages)
+ {
+ __FLOG(_L8("Assigning local storage ID mapping"));
+
+ // Try to read from resource file to use a specified root dir path, if available.
+ RBuf rootDirPath;
+ rootDirPath.CreateL(KMaxFileName);
+ rootDirPath.CleanupClosePushL();
+ RMTPDeviceDpSingletons devSingletons;
+ devSingletons.OpenL(iFramework);
+ CleanupClosePushL(devSingletons);
+ TRAPD(resError, devSingletons.ConfigMgr().GetRootDirPathL(aDriveNumber, rootDirPath));
+ __FLOG_VA((_L8("ResError = %d"), resError));
+ if ((KErrNone == resError) && (0 < rootDirPath.Length()))
+ {
+ __FLOG(_L8("Reading resource file succeeded"));
+ // If there is a root directory information in rss file then check the directory exist or not.
+ // If not exists, then create it.
+ // Before doing anything, delete the leading and trailing white space.
+ rootDirPath.Trim();
+ TBuf<KMaxFileName> buffer;
+ buffer.Append(driveChar);
+ _LIT(KSeperator,":");
+ buffer.Append(KSeperator);
+ buffer.Append(rootDirPath);
+ TInt error = iFramework.Fs().MkDir(buffer);
+ suid.Close();
+ _LIT(KSuidTemplate, "?:\\");
+ suid.Assign((KSuidTemplate().AllocL()));
+ driveChar.LowerCase();
+ suid[0] = driveChar;
+
+ if ((KErrNone == error) || (KErrAlreadyExists == error))
+ {
+ __FLOG(_L8("Overwriting SUID to specified root dir path from resource file"));
+ //if dir already existed or created, make that as root directory
+ suid.ReAllocL(buffer.Length());
+ suid = buffer;
+ }
+ }
+ CleanupStack::PopAndDestroy(&devSingletons);
+ CleanupStack::PopAndDestroy(&rootDirPath);
+
+ // Set up folder exclusion list
+ CDesCArraySeg* storageExclusions = new (ELeave) CDesCArraySeg(KFolderExclusionGranularity);
+ CleanupStack::PushL(storageExclusions);
+ TInt excludedFolderCount = iFolderExclusionList->Count();
+
+ for (TInt i = 0; i < excludedFolderCount; ++i)
+ {
+ TPtrC16 excludedFolder = (*iFolderExclusionList)[i];
+
+ if (excludedFolder[0] == '?' ||
+ excludedFolder[0] == '*' ||
+ excludedFolder[0] == suid[0])
+ {
+ storageExclusions->AppendL(excludedFolder);
+ }
+ }
+ for ( TInt i=0; i<storageExclusions->Count();++i)
+ {
+ HBufC16* temp = static_cast<TPtrC16>((*storageExclusions)[i]).AllocL();
+ TPtr16 tempptr(temp->Des());
+ tempptr[0] = suid[0];
+ storage->SetHashPath(tempptr,i);
+ delete temp;
+ }
+
+ storage->SetDesCL(CMTPStorageMetaData::EStorageSuid, suid);
+ storage->SetDesCArrayL(CMTPStorageMetaData::EExcludedAreas, *storageExclusions);
+ CleanupStack::PopAndDestroy(storageExclusions);
+
+ // Create the logical StorageID and drive mapping.
+ logical = mgr.AllocateLogicalStorageIdL(iFramework.DataProviderId(), physical, *storage);
+ mgr.SetDriveMappingL(aDriveNumber, logical);
+
+ __FLOG_VA((_L8("Drive = %d mapped as storage 0x%08X"), aDriveNumber, logical));
+ }
+
+ CleanupStack::PopAndDestroy(storage);
+ CleanupStack::PopAndDestroy(&suid);
+
+ // Notify the active data providers.
+ if (iState & EStarted)
+ {
+ TMTPNotificationParamsStorageChange params = {physical};
+ iFrameworkSingletons.DpController().NotifyDataProvidersL(EMTPStorageAdded, static_cast<TAny*>(¶ms));
+ }
+
+ // Notify any connected Initiator(s).
+ if (iAllocateLogicalStorages)
+ {
+ SendEventL(EMTPEventCodeStoreAdded, logical);
+ }
+
+ __FLOG(_L8("StorageAvailableL - Exit"));
+ }
+
+/**
+Configures the specified drive as an unavailable MTP storage.
+@param aDriveNumber The Symbian OS file system drive number.
+@leave One of the system wide error codes, if a processing failure occurs.
+*/
+void CMTPStorageWatcher::StorageUnavailableL(TDriveNumber aDriveNumber)
+{
+ __FLOG(_L8("StorageUnavailableL - Entry"));
+ __FLOG_VA((_L8("Drive = %d is unavailable."), aDriveNumber));
+ CMTPStorageMgr& mgr(iFrameworkSingletons.StorageMgr());
+ TInt32 physical(mgr.PhysicalStorageId(aDriveNumber));
+ User::LeaveIfError(physical);
+ TUint32 logical(0);
+
+ // If configured to do so, assign a logical storage ID mapping.
+ if (iAllocateLogicalStorages)
+ {
+ logical = mgr.FrameworkStorageId(aDriveNumber);
+
+ // Deassign the logical storage ID mapping.
+ mgr.DeallocateLogicalStorageIds(iFramework.DataProviderId(), physical);
+ mgr.SetDriveMappingL(aDriveNumber, physical);
+ __FLOG_VA((_L8("Drive = %d unmapped as storage 0x%08X"), aDriveNumber, logical));
+ }
+
+ // Notify the active data providers.
+ TMTPNotificationParamsStorageChange params = {physical};
+ iFrameworkSingletons.DpController().NotifyDataProvidersL(EMTPStorageRemoved, static_cast<TAny*>(¶ms));
+
+ // Notify any connected Initiator(s).
+ if (iAllocateLogicalStorages)
+ {
+ SendEventL(EMTPEventCodeStoreRemoved, logical);
+ }
+ __FLOG(_L8("StorageUnavailableL - Exit"));
+ }