diff -r a41df078684a -r 4122176ea935 userlibandfileserver/fileserver/sfat32/sl_drv.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/userlibandfileserver/fileserver/sfat32/sl_drv.cpp Mon Dec 21 16:14:42 2009 +0000 @@ -0,0 +1,601 @@ +// 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; + + +//--------------------------------------------------------------------------------------------------------------------------------------- + + +TFatDriveInterface::TFatDriveInterface() + :iMount(NULL) +{ +} + +/** + Initialise the interface object. + @param aMount the CFatMountCB that owns this object +*/ +TBool TFatDriveInterface::Init(CFatMountCB* aMount) +{ + ASSERT(aMount); + iMount = aMount; + aMount->LocalDrive()->SetMount(aMount); + return iProxyDrive.Init(aMount->LocalDrive()); +} + +/** + pseudo-destructor. +*/ +void TFatDriveInterface::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 TFatDriveInterface::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("TFatDriveInterface::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 TFatDriveInterface::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("TFatDriveInterface::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 TFatDriveInterface::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("TFatDriveInterface::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 TFatDriveInterface::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("TFatDriveInterface::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 TFatDriveInterface::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("TFatDriveInterface::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; iOpenMountForWrite(); //-- 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("TFatDriveInterface::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 TFatDriveInterface::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 TFatDriveInterface::HandleCriticalError(TInt aResult) const + { + __PRINT2(_L("TFatDriveInterface::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 TFatDriveInterface::HandleRecoverableError(TInt aResult) const + { + __PRINT2(_L("TFatDriveInterface::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 TFatDriveInterface::IsRecoverableRemount() const + { + if(IsDriveWriteProtected()&&(iMount->Drive().IsWriteableResource()||iMount->Drive().IsCurrentWriteFunction())) + return(EFalse); + return(ETrue); + } + +/** return true if the media is write protected */ +TBool TFatDriveInterface::IsDriveWriteProtected() const + { + TLocalDriveCapsV2Buf localDriveCaps; + TInt r=iProxyDrive.Caps(localDriveCaps); + + if(r!=KErrNone) + return(EFalse); + + return((localDriveCaps().iMediaAtt&KMediaAttWriteProtected)!=0); + } + + + +//--------------------------------------------------------------------------------------------------------------------------------------- + +TFatDriveInterface::XProxyDriveWrapper::XProxyDriveWrapper() + :iLocalDrive(0) +{ + TInt nRes = iLock.CreateLocal(); + ASSERT(nRes == KErrNone); + (void)nRes; +} + + +TFatDriveInterface::XProxyDriveWrapper::~XProxyDriveWrapper() +{ + iLock.Close(); +} + +/** + Initialise interface wrapper. + @param aProxyDrive pointer to the raw drive access interface + @return true on success +*/ +TBool TFatDriveInterface::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 TFatDriveInterface methods + +TInt TFatDriveInterface::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 TFatDriveInterface::XProxyDriveWrapper::Read(TInt64 aPos,TInt aLength,TDes8& aTrg) const +{ + EnterCriticalSection(); + TInt nRes = iLocalDrive->Read(aPos, aLength, aTrg); + LeaveCriticalSection(); + return nRes; +} + +TInt TFatDriveInterface::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 TFatDriveInterface::XProxyDriveWrapper::Write(TInt64 aPos, const TDesC8& aSrc) +{ + EnterCriticalSection(); + TInt nRes = iLocalDrive->Write(aPos, aSrc); + LeaveCriticalSection(); + return nRes; +} + +TInt TFatDriveInterface::XProxyDriveWrapper::GetLastErrorInfo(TDes8& aErrorInfo) const +{ + EnterCriticalSection(); + TInt nRes = iLocalDrive->GetLastErrorInfo(aErrorInfo); + LeaveCriticalSection(); + return nRes; +} + +TInt TFatDriveInterface::XProxyDriveWrapper::Caps(TDes8& anInfo) const +{ + EnterCriticalSection(); + TInt nRes = iLocalDrive->Caps(anInfo); + LeaveCriticalSection(); + return nRes; +} + + + + + + + + + + + +