diff -r 000000000000 -r d0791faffa3f mtpfws/mtpfw/dataproviders/devdp/src/cmtpstoragewatcher.cpp --- /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 +#include +#include +#include + +#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(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(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(defaultDrive))); + } + else + { + mgr.SetDefaultStorageId(mgr.PhysicalStorageId(static_cast(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(i)); + } + else if (removed & mask) + { + StorageUnavailableL(static_cast(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(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 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; iCount();++i) + { + HBufC16* temp = static_cast((*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(¶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(¶ms)); + + // Notify any connected Initiator(s). + if (iAllocateLogicalStorages) + { + SendEventL(EMTPEventCodeStoreRemoved, logical); + } + __FLOG(_L8("StorageUnavailableL - Exit")); + }