userlibandfileserver/fileserver/sfat32/sl_drv.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 6 0173bcd7697c
child 19 4a8fed1c0ef6
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "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:
// f32\sfat\sl_drv.cpp
// 
//

#include "sl_std.h"
#include "sl_cache.h"

const TInt KMaxRecoverableRetries=10;
const TInt KMaxCriticalRetries=10;


//---------------------------------------------------------------------------------------------------------------------------------------


TDriveInterface::TDriveInterface() 
                   :iMount(NULL)
{
}

/**
    Initialise the interface object.
    @param  aMount the CFatMountCB that owns this object
*/
TBool TDriveInterface::Init(CFatMountCB* aMount)
{
    ASSERT(aMount);
    iMount = aMount;
	aMount->LocalDrive()->SetMount(aMount);
    return iProxyDrive.Init(aMount->LocalDrive());
}

/**
    pseudo-destructor. 
*/
void TDriveInterface::Close()
{
	 if(iMount)
		iMount->LocalDrive()->SetMount(NULL);
     iMount = NULL;
}

//---------------------------------------------------------------------------------------------------------------------------------------

/**
    Read data from the media via CProxyDrive interface.
    This is non-critical read: on error Non-critical notifier is involved

    @param  aPos        absolute media position
    @param  aLength     how many bytes to read
    @param  aTrg        data descriptor

    @return KErrNone - success
    @return KErrNotReady - non-critical error
    @return KErrCorrupt - an illegal write is detected
    @return KErrBadPower - failure due to low power

*/
TInt TDriveInterface::ReadNonCritical(TInt64 aPos, TInt aLength, TDes8& aTrg) const
{
    TInt nRes = KErrNone;
    TInt cntRetry = KMaxRecoverableRetries;

    //__PRINT2(_L("#=+++ Read_nc1: pos:%LU, len:%u"), aPos, aLength);

    for(;;)
    {
        nRes = iProxyDrive.Read(aPos,aLength,aTrg);
        if (nRes==KErrNone)
            break;

        __PRINT4(_L("TDriveInterface::ReadNonCritical() failure! drv:%d Posl=%LU len=%d retval=%d"), iMount->DriveNumber(), aPos, aLength, nRes);
        
        if(--cntRetry <= 0)
        {
            nRes = KErrCorrupt;
            break;
        }

        nRes = HandleRecoverableError(nRes);
        if (nRes !=ERetry)
            break;
    }

    return nRes;
}

//---------------------------------------------------------------------------------------------------------------------------------------

/**
    Read data from the media via CProxyDrive interface. 
    This is non-critical read: on error Non-critical notifier is involved

    @param  aPos        absolute media position
    @param  aLength     how many bytes to read
    @param  aTrg        data descriptor
    @param  aMessage
    @param  anOffset

    @return KErrNone - success
    @return KErrNotReady - non-critical error
    @return KErrCorrupt - an illegal write is detected
    @return KErrBadPower - failure due to low power

*/
TInt TDriveInterface::ReadNonCritical(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset) const
{
    //__PRINT2(_L("#=+++ Read_nc2: pos:%LU, len:%u"), aPos, aLength);

    TInt nRes = KErrNone;
    TInt cntRetry = KMaxRecoverableRetries;

    for(;;)
    {
        nRes = iProxyDrive.Read(aPos, aLength, aTrg, aMessage, anOffset);
        if (nRes==KErrNone)
            break;

        __PRINT4(_L("TDriveInterface::ReadNonCritical() Failure! drv:%d aPosl=%d len=%d anOffset=%d"), iMount->DriveNumber(), aPos,aLength, anOffset);
        
        if(--cntRetry <= 0)
        {
            nRes = KErrCorrupt;
            break;
        }

        nRes = HandleRecoverableError(nRes);
        if (nRes !=ERetry)
            break;
    }

    return nRes;
}

//---------------------------------------------------------------------------------------------------------------------------------------

/**
    Read data from the media via CProxyDrive interface with a critical notifier.
    This method shall be used to read critical filesystem data, such as directory entries, FAT data.

    @param  aPos        absolute media position
    @param  aLength     how many bytes to read
    @param  aTrg        data descriptor

    @return KErrNone - success
    @return KErrNotReady - non-critical error
    @return KErrCorrupt - an illegal write is detected
    @return KErrAbort - user aborted read
*/
TInt TDriveInterface::ReadCritical(TInt64 aPos,TInt aLength,TDes8& aTrg) const
{
    //__PRINT2(_L("#=+++ Read_C: pos:%LU, len:%u"), aPos, aLength);

    TInt nRes = KErrNone;

    for(;;)
    {
        nRes = iProxyDrive.Read(aPos, aLength, aTrg);
		if(nRes == KErrNone)
            break;

		__PRINT4(_L("TDriveInterface::ReadCritical() Error! drv:%d Posl=%LU len=%d retval=%d"), iMount->DriveNumber(), aPos, aLength, nRes);
		
        nRes=HandleCriticalError(nRes);
		if (nRes != ERetry)
            break;
    }

    return nRes;
}

//---------------------------------------------------------------------------------------------------------------------------------------

/**
    Write data to the media via CProxyDrive interface.
    
    @param  aPos        absolute media position
    @param  aLength     how many bytes to write
    @param  aSrc        pointer to the data 
    @param  aMessage
    @param  anOffset
    
    @return KErrNone - success
    @return KErrNotReady - non-critical error
    @return KErrBadPower - write not attempted due to low batteries
    @return KErrCorrupt - an illegal write is detected
    @return KErrAccessDenied - write to protected media
*/
TInt TDriveInterface::WriteNonCritical(TInt64 aPos, TInt aLength, const TAny* aSrc, const RMessagePtr2 &aMessage, TInt anOffset)
{
    //__PRINT2(_L("#=+++ Write_NC: pos:%LU, len:%u"), aPos, aLength);

    
    TInt nRes = KErrNone;
    TInt cntRetry = KMaxRecoverableRetries;

    for(;;)
    {
        iMount->OpenMountForWrite(); //-- make a callback to CFatMountCB to perform some actions on 1st write.
        nRes = iProxyDrive.Write(aPos, aLength, aSrc, aMessage, anOffset);
        if (nRes==KErrNone)
            break;

        __PRINT4(_L("TDriveInterface::WriteNonCritical() failure! drv:%d, Pos=%LU len=%d anOffset=%d"), iMount->DriveNumber(), aPos, aLength, anOffset);
        
        if(--cntRetry <= 0)
        {
            nRes = KErrCorrupt;
            break;
        }

        nRes = HandleRecoverableError(nRes);
        if (nRes !=ERetry)
            break;
    }


    return nRes;
}

//---------------------------------------------------------------------------------------------------------------------------------------

/**
    Write data to the media via CProxyDrive interface. On error this method can invoke a critical notifier.
    This method is intended to be called for the filesstem critical data, i.e. FAT metadata, such as directory entries,
    FAT table etc.
    
    @param  aPos  absolute media position
    @param  aSrc  descriptor with the source data
    
    @return KErrNone - success
    @return KErrNotReady - non-critical error
    @return KErrBadPower - write not attempted due to low batteries
    @return KErrCorrupt - an illegal write is detected
    @return KErrAccessDenied - write to protected media
*/
TInt TDriveInterface::WriteCritical(TInt64 aPos, const TDesC8& aSrc)
{
    //__PRINT2(_L("#=+++ Write_C: pos:%LU, len:%u"), aPos, aSrc.Length());

    TInt nRes = KErrNone;

#ifdef _DEBUG
    
    TBool simulatedWriteFailure = EFalse; //-- if true it means that the write failure has been simulated

    //-- debug interface to simulate write failure
	if(iMount->IsWriteFail())
    {
		if(iMount->WriteFailCount() != 0)
        {
            iMount->DecWriteFailCount();
        }
        else
		{//-- simulate write failure
			if(iMount->WriteFailError()==-99)
				UserSvr::ResetMachine(EStartupWarmReset);
			else
			{
			    //-- invalidate caches, because actual write to the drive isn't going to happen
                if(iMount->RawDisk().DirCacheInterface())
                    iMount->RawDisk().DirCacheInterface()->InvalidateCache();

                iMount->SetWriteFail(EFalse);
				
                TRAP_IGNORE(iMount->RawDisk().InvalidateUidCache()); //-- invalidate whole UID data cache
                TRAP_IGNORE(iMount->FAT().InvalidateCacheL());       //-- invalidate whole FAT cache
                
                iMount->InvalidateLeafDirCache();

                nRes = iMount->WriteFailError(); 
                simulatedWriteFailure = ETrue; //-- won't perform actual write later
                __PRINT4(_L("TDriveInterface::WriteCritical() Simulating write failure. drv:%d, aPos=%LU len=%d Code=%d"), iMount->DriveNumber(), aPos,aSrc.Length(),nRes);

			}
		}
    }//if(iMount->IsWriteFail())

    if(!simulatedWriteFailure)
#endif // _DEBUG
    {
        //-- try to write data until success or user gives up
	    for(;;)
	    {
            for(TInt i=0; i<KMaxCriticalRetries; i++)
            {
                iMount->OpenMountForWrite();  //-- make a callback to CFatMountCB to perform some actions on 1st write.
                nRes=iProxyDrive.Write(aPos,aSrc);
			    if (nRes==KErrNone)
                    return nRes;
		    }

            //-- write error occured
            __PRINT4(_L("TDriveInterface::WriteCritical() failure! drv:%d, aPos=%LU len=%d retval=%d"), iMount->DriveNumber(), aPos,aSrc.Length(),nRes);

            nRes=HandleCriticalError(nRes);
            if (nRes!=ERetry)
                break;

	    }//for(;;)
    
    }// if(!simulatedWriteFailure)
    
    return nRes;
}


/**
    Get Last Error Info from the proxy drive
        
    @param  aErrorInfo data descriptor for the error info.
    @return KErrNone - success, interrogate aErrorInfo for further info
    @return KErrNotSupported - media driver does not support
*/
TInt TDriveInterface::GetLastErrorInfo(TDes8& aErrorInfo) const
{
    return iProxyDrive.GetLastErrorInfo(aErrorInfo);
}


//---------------------------------------------------------------------------------------------------------------------------------------

/**
    Handle critical error

    @param aResult result from the media driver (error code)

    @return ERetry - Attempt operation again
    @return KErrAbort - User aborted notifier
    @return KErrAccessDenied - media is read only
    @return KErrCorrupt - cf-card is corrupt
*/
TInt TDriveInterface::HandleCriticalError(TInt aResult) const
	{
    __PRINT2(_L("TDriveInterface::HandleCriticalError drv:%d, code:%d"), iMount->DriveNumber(),aResult);

	TLocaleMessage line1;
	TLocaleMessage line2;

	TInt r=KErrAbort;

	if (aResult==KErrLocked)
	{
		r=KErrLocked;
		goto End;
	}

	if (aResult==KErrAccessDenied)
		{
		r=KErrAccessDenied;
		goto End;
		}
	
	if (aResult==KErrArgument || aResult==KErrBadDescriptor)
		{
		r=KErrCorrupt;
		goto End;
		}

	if (iMount->Drive().IsChanged())
		{//-- check if the media we accessing is the same as it used to be
          if(iMount->CheckVolumeTheSame())
        	{//-- the media is the same
			if(!IsDriveWriteProtected())
				{
				iMount->Drive().SetChanged(EFalse);
				r=ERetry;
				goto End;
				}
			}
		}

	if (aResult==KErrAbort && !iMount->Drive().IsChanged())
		{
		r=ERetry;
		goto End;
		}

	if (aResult==KErrBadPower)
		{
		line1=EFileServer_LowPowerLine1;
		line2=EFileServer_LowPowerLine2;
		}
	else if (iMount->Drive().IsChanged())
		{
		line1=EFileServer_PutTheCardBackLine1;
		line2=EFileServer_PutTheCardBackLine2;
		}
	else
		{
		line1=EFileServer_DiskErrorLine1;
		line2=EFileServer_DiskErrorLine2;
		}
	
	if (NotifyUser())
		{
		FOREVER
			{
			TInt buttonVal;
			TInt ret=iMount->Notifier()->Notify(TLocaleMessageText(line1),
												TLocaleMessageText(line2),
												TLocaleMessageText(EFileServer_Button1),
												TLocaleMessageText(EFileServer_Button2),
												buttonVal);
			if (ret!=KErrNone)
				break; 
			if (buttonVal!=1)
				break; // Abort

			if (iMount->Drive().IsChanged())
				{
//
// Without this code, retry will indiscriminately write over whatever disk happens to be present.
// However if the write error is to the bootsector remounting will always fail because the boot
// sector will have changed and hence the disk is useless.
// 
                if(!iMount->CheckVolumeTheSame())
                    continue; //-- the media isn't the same as originally mounted; continue asking

                if(IsDriveWriteProtected())
                    continue; //-- still can not write to the drive


				iMount->Drive().SetChanged(EFalse);
				}

			r=ERetry; // Retry
			break;
			}
		}
End:
	return(r);
	}

//---------------------------------------------------------------------------------------------------------------------------------------

/**
    Handle recoverable error

    @param aResult result from the media driver (error code)

    @return ERetry - retry write
    @return KErrCorrupt - media is corrupt
    @return KErrBadPower - low power failure
    @return KErrNotReady - non-critical error
*/
TInt TDriveInterface::HandleRecoverableError(TInt aResult) const
	{
	__PRINT2(_L("TDriveInterface::HandleRecoverableError drv:%d, code:%d"), iMount->DriveNumber(),aResult);

	if (aResult==KErrAccessDenied)
		return(KErrAccessDenied);
	if (aResult == KErrLocked)
		return KErrLocked;
	if (aResult==KErrArgument || aResult==KErrBadDescriptor)
		return(KErrCorrupt);
	if (aResult==KErrBadPower)
		return(KErrBadPower);
	if (aResult==KErrDied)	// client thread died
		return(KErrDied);
	if (iMount->Drive().IsChanged())
		{

        if(! iMount->CheckVolumeTheSame())
            {//-- the media is different now.
            return KErrNotReady;
			}
		else if(!IsRecoverableRemount())
			{
			return KErrAccessDenied;
			}
		}
	return(ERetry);
	}	

/** @return true if the mount can be remounted for a recoverable error */
TBool TDriveInterface::IsRecoverableRemount() const
	{
	if(IsDriveWriteProtected()&&(iMount->Drive().IsWriteableResource()||iMount->Drive().IsCurrentWriteFunction()))
		return(EFalse);
	return(ETrue);
	}

/** return true if the media is write protected */
TBool TDriveInterface::IsDriveWriteProtected() const
	{
	TLocalDriveCapsV2Buf localDriveCaps;
    TInt r=iProxyDrive.Caps(localDriveCaps);

	if(r!=KErrNone)
		return(EFalse);

	return((localDriveCaps().iMediaAtt&KMediaAttWriteProtected)!=0);
	}



//---------------------------------------------------------------------------------------------------------------------------------------

TDriveInterface::XProxyDriveWrapper::XProxyDriveWrapper() 
                   :iLocalDrive(0) 
{
    TInt nRes = iLock.CreateLocal();
    ASSERT(nRes == KErrNone);
    (void)nRes; 
}


TDriveInterface::XProxyDriveWrapper::~XProxyDriveWrapper() 
{
    iLock.Close();
}

/** 
    Initialise interface wrapper.
    @param  aProxyDrive pointer to the raw drive access interface
    @return true on success
*/
TBool TDriveInterface::XProxyDriveWrapper::Init(CProxyDrive* aProxyDrive) 
{
    ASSERT(aProxyDrive);
    if(!iLock.Handle()) //-- the mutex must have been created by constructor
        return EFalse;
    
    iLocalDrive = aProxyDrive;
    return ETrue;
}

//-- see original TDriveInterface methods

TInt TDriveInterface::XProxyDriveWrapper::Read(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset) const
{
    EnterCriticalSection();
    TInt nRes = iLocalDrive->Read(aPos, aLength, aTrg, aMessage.Handle(), anOffset);
    LeaveCriticalSection();
    return nRes;
}
       
TInt TDriveInterface::XProxyDriveWrapper::Read(TInt64 aPos,TInt aLength,TDes8& aTrg) const
{
    EnterCriticalSection();
    TInt nRes = iLocalDrive->Read(aPos, aLength, aTrg);
    LeaveCriticalSection();
    return nRes;
}

TInt TDriveInterface::XProxyDriveWrapper::Write(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset)
{
    EnterCriticalSection();
    TInt nRes = iLocalDrive->Write(aPos, aLength, aSrc, aMessage.Handle(), anOffset);
    LeaveCriticalSection();
    return nRes;
}

TInt TDriveInterface::XProxyDriveWrapper::Write(TInt64 aPos, const TDesC8& aSrc)
{
    EnterCriticalSection();
    TInt nRes = iLocalDrive->Write(aPos, aSrc);
    LeaveCriticalSection();
    return nRes;
}

TInt TDriveInterface::XProxyDriveWrapper::GetLastErrorInfo(TDes8& aErrorInfo) const
{
    EnterCriticalSection();
    TInt nRes = iLocalDrive->GetLastErrorInfo(aErrorInfo);
    LeaveCriticalSection();
    return nRes;
}

TInt TDriveInterface::XProxyDriveWrapper::Caps(TDes8& anInfo) const
{
    EnterCriticalSection();
    TInt nRes = iLocalDrive->Caps(anInfo);
    LeaveCriticalSection();
    return nRes;
}