remotestoragefw/mountmanager/src/rsfwmountmanimpl.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:15:08 +0100
branchRCL_3
changeset 20 1aa8c82cb4cb
parent 0 3ad9d5175a89
child 12 fe0554130c0f
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201021 Kit: 201035

/*
* Copyright (c) 2002-2004 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:  Mount manager
 *
*/


// INCLUDE FILES
#include <badesca.h> 
#include <f32fsys.h> // KMaxVolumeNameLength
#include <rsfwmountman.h>
#include <rsfwmountentry.h>

#include "rsfwinterface.h"
#include "rsfwmountmanimpl.h"


// CONSTANTS
const TUint8 KDefaultDriveLetter = 'J';
 // system default if no other specified; 
 // remote drives should use letters from J: to Y:
 

// ============================ MEMBER FUNCTIONS ==============================

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::CRsfwMountManImpl
// Constructor
// ----------------------------------------------------------------------------
//
CRsfwMountManImpl::CRsfwMountManImpl()
    {
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::NewL
// ----------------------------------------------------------------------------
//
CRsfwMountManImpl* CRsfwMountManImpl::NewL(TUint aDefaultFlags,
                                   MRsfwMountManObserver* aMountManObserver)
    {
    CRsfwMountManImpl* self = new (ELeave) CRsfwMountManImpl();
    CleanupStack::PushL(self);
    self->ConstructL(aDefaultFlags, aMountManObserver);
    CleanupStack::Pop(self);
    return self;
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::~CRsfwMountManImpl
// ----------------------------------------------------------------------------
//
CRsfwMountManImpl::~CRsfwMountManImpl()
    {
    iFs.Close();
    if (iRsfwControlConnected)
        {
        iRsfwControl.Close();
        }
    delete iMountStore;
    
    iBlackList.Close();
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::GetMountNamesL
// ----------------------------------------------------------------------------
//
void CRsfwMountManImpl::GetMountNamesL(CDesC16Array* aNames)
    {
    iMountStore->GetNamesL(aNames);
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::MountEntry
// ----------------------------------------------------------------------------
//
const CRsfwMountEntry* CRsfwMountManImpl::MountEntryL(const TDesC& aName)
    {
    return iMountStore->LookupEntryByNameL(aName);
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::MountEntry
// ----------------------------------------------------------------------------
//
const CRsfwMountEntry* CRsfwMountManImpl::MountEntryL(TChar aDriveLetter)
    {
    return iMountStore->LookupEntryByDriveL(aDriveLetter);
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::AddMountEntryL
// ----------------------------------------------------------------------------
//
void CRsfwMountManImpl::AddMountEntryL(CRsfwMountEntry* aMountEntry)
    {
    // Take ownership
    CleanupStack::PushL(aMountEntry);
    
    // Look for existing configuration with the same friendly name
    // overwriting not allowed
    const HBufC* driveName = aMountEntry->Item(EMountEntryItemName);
    const CRsfwMountEntry* entry = MountEntryL(*driveName);
    if (entry)
        {
        User::Leave(KErrInUse);
        }
    // Also look for existing configuration with the same drive letter
    // overwriting not allowed
    TChar driveLetter = DriveLetterFromMountEntry(*aMountEntry);
    if (driveLetter != '?')
        {
        entry = MountEntryL(driveLetter);
        if (entry)
            {
            User::Leave(KErrInUse);
            }
        }
    else 
        {
        driveLetter = FreeDriveLetterL(driveLetter);
        TBuf<1> driveLetterBuf;
        driveLetterBuf.Append(driveLetter);
        // Replace '?' with the allocated drive letter
        aMountEntry->SetItemL(EMountEntryItemDrive, driveLetterBuf);
        }
   
    // find the number of remote drives in use
    // if 9 already new ones are not allowed
    TDriveList fsDriveList;   
    User::LeaveIfError(iFs.DriveList(fsDriveList, KDriveAttRemote));    
    TInt i;
    TInt remoteDrives = 0;
    for (i = EDriveA; i <= EDriveZ; i++)
        { 
        if (fsDriveList[i] & KDriveAttRemote)
            {
            remoteDrives++;
            }
        }
    
    if (remoteDrives == KMaxRemoteDrives)
        {
        User::Leave(KErrInUse);
        }
      
    // Save the friendly name (not guaranteed to survive CMountStore::AddEntryL
    HBufC* name = NULL;
    if (aMountEntry->Item(EMountEntryItemName))
        {
        name = aMountEntry->Item(EMountEntryItemName)->AllocL();
        }

    // Release ownership
    CleanupStack::Pop(aMountEntry);
    // Add mount configuration repository entry
    TRAPD(err, AddEntryL(aMountEntry));
    CleanupStack::PushL(name);
    User::LeaveIfError(err);
    
    // Add mount in File Server
    if (name)
        {
        User::LeaveIfError(MountFileSystem(*name, driveLetter));
        }
    else
        {
        _LIT(KRsfwNoName, "remotedrive");
        User::LeaveIfError(MountFileSystem(KRsfwNoName, driveLetter));
        }
        
    // finally set mountconnection state to disconnected
    // this will make in Remote File Engine what is called "disconnected dormant mount"    
    SetMountConnectionState(driveLetter, KMountNotConnected);
        
    CleanupStack::PopAndDestroy(name);
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::DeleteMountEntryL
// ----------------------------------------------------------------------------
//
void CRsfwMountManImpl::DeleteMountEntryL(const TDesC& aName)
    {
    const CRsfwMountEntry* mountEntry = iMountStore->LookupEntryByNameL(aName);
    if (mountEntry)
        {
        TChar driveLetter = DriveLetterFromMountEntry(*mountEntry);
        if (driveLetter != '?')
            {
            DeleteMountEntryL(driveLetter);
            }
        }
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::DeleteMountEntryL
// ----------------------------------------------------------------------------
//
void CRsfwMountManImpl::DeleteMountEntryL(TChar aDriveLetter)
    {
    const CRsfwMountEntry* mountEntry =
        iMountStore->LookupEntryByDriveL(aDriveLetter);
    if (mountEntry)
        {
        // Remove entry from configuration repository
        iMountStore->RemoveEntryL(aDriveLetter);
        // Dismount from file server and Remote File Engine
        ExecuteUnmount(aDriveLetter);
        }
    }
    
// ----------------------------------------------------------------------------
// CRsfwMountManImpl::EditMountEntryL
// ----------------------------------------------------------------------------
//
void CRsfwMountManImpl::EditMountEntryL(CRsfwMountEntry* aMountEntry)
    {
    // take ownership
    CleanupStack::PushL(aMountEntry);
    
    // look for the drive based on the letter
    TChar driveLetter = DriveLetterFromMountEntry(*aMountEntry);
    const CRsfwMountEntry* entryByDrive = MountEntryL(driveLetter);
    if ( !entryByDrive )
        {
        User::Leave(KErrNotFound);
        }

    // check whether the name has changed
    TBool nameChanged = EFalse;
    const HBufC* newName = aMountEntry->Item(EMountEntryItemName);
    const HBufC* oldName = entryByDrive->Item(EMountEntryItemName);
    if ( newName->Compare(*oldName) != KErrNone )
        {
        nameChanged = ETrue;
        }
        
    // check whether URI has changed
    TBool uriChanged = EFalse;
    const HBufC* newUri = aMountEntry->Item(EMountEntryItemUri);
    const HBufC* oldUri = entryByDrive->Item(EMountEntryItemUri);
    if ( newUri->Compare(*oldUri) != KErrNone )
        {
        uriChanged = ETrue;
        }

    // if the name has changed -> check whether it is not used by the other mount entry
    if ( nameChanged )
        {
        const CRsfwMountEntry* entryByName = MountEntryL(*newName);
        if ( entryByName && entryByDrive != entryByName )
            {
            User::Leave(KErrInUse);
            }        
        }
   
    // release ownership and call MountStore API
    CleanupStack::Pop(aMountEntry);    
    AddEntryL(aMountEntry);

    // if URI has changed we have to unmount the drive from RFE in order 
    // to clear the cache and mount it again
    // note there is no need to make unmounting from File System
    if ( uriChanged )
        {
        TInt err;
        User::LeaveIfError(GetRsfwControlConnection());
        err = iRsfwControl.DismountByDriveLetter(driveLetter);
        if ((err != KErrNone) && (err != KErrNotFound)) 
            {
            User::Leave(err);
            }
        User::LeaveIfError(iRsfwControl.SetMountConnectionState(driveLetter, KMountNotConnected));
        }

    // if the name has changed -> change label in File System
    if ( nameChanged )
        {
        User::LeaveIfError(SetDriveNameToFileSystem(driveLetter, *newName));
        }
    }    

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::MountL
// ----------------------------------------------------------------------------
//
void CRsfwMountManImpl::MountL(TChar& aDriveLetter)
    {
    TInt driveNumber;
    User::LeaveIfError(iFs.CharToDrive(aDriveLetter, driveNumber));
    User::LeaveIfError(GetRsfwControlConnection());
    User::LeaveIfError(iRsfwControl.Mount(driveNumber));
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::MountL
// ----------------------------------------------------------------------------
//
void CRsfwMountManImpl::MountBlindL(TChar& aDriveLetter)
    {
    TInt driveNumber;
    User::LeaveIfError(iFs.CharToDrive(aDriveLetter, driveNumber));
    User::LeaveIfError(GetRsfwControlConnection());
    User::LeaveIfError(iRsfwControl.MountBlind(driveNumber));
    }


// ----------------------------------------------------------------------------
// CRsfwMountManImpl::SetMountConnectionState
// ----------------------------------------------------------------------------
//
TInt CRsfwMountManImpl::SetMountConnectionState(TChar aDriveLetter,
                                            TUint aConnectionState)
    {
    TInt err = GetRsfwControlConnection();
    if (err != KErrNone)
        {
        return err;
        }

    err = iRsfwControl.SetMountConnectionState(aDriveLetter, aConnectionState);
    return err;
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::IsAppOnBlackList
// ----------------------------------------------------------------------------
//
TBool CRsfwMountManImpl::IsAppOnBlackList(TUid aUid)
    {
    TInt i;
    for ( i = 0; i < iBlackList.Count(); i++ )
        {
        if ( aUid == iBlackList[i] )
            {
            return ETrue;
            }
        }
    return EFalse;
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::GetAllDrivesL
// ----------------------------------------------------------------------------
//
TInt CRsfwMountManImpl::GetAllDrivesL(TDriveList& aDriveList)
    {
    GetFsDriveListL(aDriveList, EFalse);
    return aDriveList.Length();
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::GetRemoteMountList
// ----------------------------------------------------------------------------
//
TInt CRsfwMountManImpl::GetRemoteMountListL(TDriveList& aDriveList)
    {
    GetFsDriveListL(aDriveList, ETrue);
    return aDriveList.Length();
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::GetMountInfo
// ----------------------------------------------------------------------------
//
TInt CRsfwMountManImpl::GetMountInfo(TChar aDriveLetter,
                                 TRsfwMountInfo& aMountInfo)
    {
    TInt err = GetRsfwControlConnection();
    if (err == KErrNone)
        {
        err = iRsfwControl.GetMountInfo(aDriveLetter, aMountInfo);
        }
    return err;
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::GetRsfwControlConnection
// Set a Remote File Engine control connection unless
// we already have a connection
// ----------------------------------------------------------------------------
//
TInt CRsfwMountManImpl::GetRsfwControlConnection()
    {
    TInt err = KErrNone;
    if (!iRsfwControlConnected)
        {
        err = iRsfwControl.Connect();
        if (!err) 
            {
            iRsfwControlConnected = ETrue;   
            }
        }
    return err;
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::MountFileSystem
// Install ERemoteFS file system plugin (if not already done) and
// mount a filesystem designated with the given drive letter
// on that file system
// ----------------------------------------------------------------------------
//
TInt CRsfwMountManImpl::MountFileSystem(const TDesC& /*aDriveName*/,
                                    TChar aDriveLetter)
    {
    return SyncWithMounterExe(ETrue, aDriveLetter);
    }
        

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::RemoteDriveCount
// Get the number of remote mounts as seen by the File Server
// ----------------------------------------------------------------------------
//
TInt CRsfwMountManImpl::RemoteMountCountL()
    {
    // Check if how many mounts there are (also dormant mounts are counted)
    TDriveList driveList;
    return GetRemoteMountListL(driveList);
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::DoUnmountL
// Do conditional unmounting by consulting the user
// ----------------------------------------------------------------------------
//
void CRsfwMountManImpl::DoUnmountL(TChar aDriveLetter, TUint /* aFlags */)
    {
    TInt err = ExecuteUnmount(aDriveLetter);
    User::LeaveIfError(err);
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::ExecuteUnmount
// Do unconditional unmounting
// ----------------------------------------------------------------------------
//
TInt CRsfwMountManImpl::ExecuteUnmount(TChar aDriveLetter)
    {
    TInt err = GetRsfwControlConnection();
    if (err != KErrNone)
        {
        return err;
        }

    // Drop the mount both from the File Server and from Remote File Engine
    TInt errFs = KErrNone;
    TInt driveNumber;
    err = iFs.CharToDrive(aDriveLetter, driveNumber);
    if (err != KErrNone)
        {
        return err;
        }
    TDriveInfo driveInfo;
    err = iFs.Drive(driveInfo, driveNumber);
    if (err != KErrNone)
        {
        return err;
        }    
    if (driveInfo.iDriveAtt & KDriveAttRemote)
        {
        // The mount is known by the File Server
        errFs = iFs.DismountFileSystem(KRemoteFSName, driveNumber);
        if (errFs == KErrPermissionDenied) 
    	    {
    		// Client does not have sufficient capabilities to do the operation
    		// execute mount with the boot mounter application
    		SyncWithMounterExe(ETrue, aDriveLetter);
    	    }
        }
    
    // We also request dismount from the RFE because
    // The File Server (eremotefs) does not pass the
    // dismount request to the RFE.
    err = iRsfwControl.DismountByDriveLetter(aDriveLetter);
    if (errFs != KErrNone)
        {
        // give priority to the File Server error
        err = errFs;
        }
    return err;
    }


// ----------------------------------------------------------------------------
// CRsfwMountManImpl::ConstructL
// ----------------------------------------------------------------------------
//
void CRsfwMountManImpl::ConstructL(TUint aDefaultFlags,
                                   MRsfwMountManObserver* aMountManObserver)
    {
    iDefaultFlags = aDefaultFlags;

    User::LeaveIfError(iFs.Connect());
    iRsfwControlConnected = EFalse;
    iMountManObserver = aMountManObserver;
    iMountStore = CRsfwMountStore::NewL(this);
    LoadBlackListL();
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::FreeDriveLetterL
// Find a drive letter that has not yet been allocated by the File Server or
// defined in the mount configuration data base
// If the suggested drive letter (given as an input parameter)
// is already occupied, an adjacent letter in the alphabet is returned.
// Letter '?' as an input parameter is equal to KDefaultDriveLetter.
// Leave with KErrInUse if there are no free drive slots
// ----------------------------------------------------------------------------
//
TChar CRsfwMountManImpl::FreeDriveLetterL(TChar aDriveLetter)
    {
    if (aDriveLetter == '?')
        {
        // Use the system default drive letter if none is specified
        aDriveLetter = KDefaultDriveLetter;
        }
    else if ((aDriveLetter < 'A') || (aDriveLetter > 'Z'))
        {
        aDriveLetter.UpperCase();
        }

    TInt driveNumber;
    User::LeaveIfError(iFs.CharToDrive(aDriveLetter, driveNumber));

    // Try to find a free drive around the given drive

    // Get drives that are already mounted in the File Server
    TDriveList fsDriveList;
    User::LeaveIfError(iFs.DriveList(fsDriveList, KDriveAttAll));  
    // scan first upwards, then downwards from the requested drive 
    // (or default drive letter) until a free and legal drive letter is found
    // remote drives should use letters from J: to Y:
    TInt i;
    for (i = driveNumber; i <= EDriveY; i++)
        { 
        if (fsDriveList[i] == 0)
            {
            User::LeaveIfError(iFs.DriveToChar(i, aDriveLetter));
            return aDriveLetter;
            }
        }
    for (i = driveNumber - 1; i >= EDriveJ; i--)
        { 
        if (fsDriveList[i] == 0)
            {
            User::LeaveIfError(iFs.DriveToChar(i, aDriveLetter));
            return aDriveLetter;
            }
        }
    
    //  no free drive letters for remote drives
    User::Leave(KErrInUse);
    return 0;
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::DriveLetterFromMountEntry
// Build a TRsfwMountConfig
// ----------------------------------------------------------------------------
//
TChar CRsfwMountManImpl::DriveLetterFromMountEntry(const CRsfwMountEntry& aMountEntry)
    {
    const HBufC* drive = aMountEntry.Item(EMountEntryItemDrive);
    if (drive && drive->Length())
        {
        return (*drive)[0];
        }
    else
        {
        return '?';
        }
    }
 
// ----------------------------------------------------------------------------
// CRsfwMountManImpl::AddEntryL
// Add an entry in the mount configurarion store
// ----------------------------------------------------------------------------
//
void CRsfwMountManImpl::AddEntryL(CRsfwMountEntry* aMountEntry)
    {
    iMountStore->AddEntryL(aMountEntry);
    }
 

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::HandleMountStoreEvent
// Handle a mount store change notification
// ----------------------------------------------------------------------------
//
void CRsfwMountManImpl::HandleMountStoreEvent(TMountStoreEvent aEvent,
                                          TInt aStatus,
                                          TAny* aArg)
    {
    if (iMountManObserver)
        {
        if (aEvent == EMountStoreEventMountConfigurationChanged)
            {
            TRAP_IGNORE(iMountManObserver->HandleMountManEventL(
                EMountManEventMountConfigurationChanged,
                aStatus,
                aArg));
            }
        }
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::SyncWithMounterExe
// Uses boot mounter exe to mount or unmount remote drives in File Server
// ----------------------------------------------------------------------------
//
TInt CRsfwMountManImpl::SyncWithMounterExe(TBool aSetDrive, TChar aDrive) 
	{
	TInt err;
	RProcess mounter;
	TRequestStatus status;
	TBuf<5> parameter;
	if (!aSetDrive) 
	    {
	    err = mounter.Create(KRsfwMounterExe, _L(""));
	    }
    else 
        {
        parameter.Append(aDrive);
        err = mounter.Create(KRsfwMounterExe, parameter);
        }

    if (err == KErrNone) 
    	{
    	mounter.Resume();
    	mounter.Logon(status);
    	User::WaitForRequest(status);
    	mounter.Close();
    	err = status.Int();	
    	} 
    return err;
	}
        
// ----------------------------------------------------------------------------
// CRsfwMountManImpl::GetFsDriveList
//
// Returns drive letters. Letters for remote drives in order defined in CenRep
// ----------------------------------------------------------------------------
//
void CRsfwMountManImpl::GetFsDriveListL(TDriveList& aDriveList, TBool aRemoteOnly)
    {
    TDriveList driveList;
    // get local drives
    User::LeaveIfError(iFs.DriveList(driveList));
    
   // local drives are assumed to be from C:\ to R:\
    // these will go to the front of the list
    if (!aRemoteOnly) 
        {
        for (int i = EDriveC; i <= EDriveZ; i++) 
            {
            if ( (driveList[i]) && (!(driveList[i] & KDriveAttRemote)) )
                {
                TChar driveLetter;
                User::LeaveIfError(iFs.DriveToChar(i, driveLetter));
                aDriveList.Append(driveLetter);
                }
            }
        }
      
    GetRemoteDriveListL(driveList);   
    
    for (int i = 0; i < driveList.Length(); i++) 
        {
        aDriveList.Append(driveList[i]);
        }
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::GetRemoteDriveList
// ----------------------------------------------------------------------------
//
TInt CRsfwMountManImpl::GetRemoteDriveListL(TDriveList& aDriveList)
    {
    iMountStore->GetDriveLettersL(aDriveList); 
    return aDriveList.Length();
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::SetDriveNameToFileSystem
// ----------------------------------------------------------------------------
//
TInt CRsfwMountManImpl::SetDriveNameToFileSystem(TChar aDriveLetter,
                                                 const TDesC& /*aDriveName*/)
    {
    return SyncWithMounterExe(ETrue, aDriveLetter); 
    }
    
// ----------------------------------------------------------------------------
// CRsfwMountManImpl::RefreshDirectoryL
// ----------------------------------------------------------------------------
//
TInt CRsfwMountManImpl::RefreshDirectory(const TDesC& aPath)
    {
    TInt err;
    err = GetRsfwControlConnection();
    if (err != KErrNone) 
        {
        return err;
        }
    return iRsfwControl.RefreshDirectory(aPath); 
    }
    
// ----------------------------------------------------------------------------
// CRsfwMountManImpl::LoadBlackListL
// ----------------------------------------------------------------------------
//
void CRsfwMountManImpl::LoadBlackListL()
    {

//    const TUid app1 = TUid::Uid(0x00000000);
//    const TUid app2 = TUid::Uid(0x00000001);
//    const TUid app3 = TUid::Uid(0x00000002);
    
    iBlackList.Reset();
//    iBlackList.AppendL(app1);
//    iBlackList.AppendL(app2);
//    iBlackList.AppendL(app3);
    }

// ----------------------------------------------------------------------------
// CRsfwMountManImpl::LoadBlackListL
// ----------------------------------------------------------------------------
//
TInt CRsfwMountManImpl::CancelRemoteTransfer(const TDesC& aFile)
    {
    TInt err;
    err = GetRsfwControlConnection();
    if (err != KErrNone) 
        {
        return err;
        }
    return iRsfwControl.CancelRemoteTransfer(aFile);  
    }
    
//  End of File