userlibandfileserver/fileserver/sfile/sf_fmt.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
child 43 c1f20ce4abcf
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) 1995-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\sfile\sf_fmt.cpp
// 
//

#include "sf_std.h"

LOCAL_C CFormatCB* GetFormatFromHandle(TInt aHandle,CSessionFs* aSession)
//
// Get the format control block from aHandle
//
	{
	return((CFormatCB*)(SessionObjectFromHandle(aHandle,Formats->UniqueID(),aSession)));
	}



/**
Default constructor.
*/
EXPORT_C CFormatCB::CFormatCB()
	{
	}




/**
    Destructor.
    Frees resources before destruction of the object.
*/
EXPORT_C CFormatCB::~CFormatCB()
	{

	if (iMount)
		{
		RemoveDiskAccess(*iMount);
		iMount->Drive().SetChanged(ETrue);
		iMount->Close();
		}
	}




/**
    Checks that the disk media is still mounted.
    @return KErrNone if the media is still mounted; KErrDisMounted otherwise.
*/
EXPORT_C TInt CFormatCB::CheckMount()
	{

	TDrive& d=Drive();
	TInt r=d.CheckMount();
	if (r!=KErrNone)
		return(r);
	if (&Mount()!=&d.CurrentMount())
		return(KErrDisMounted);
	return(KErrNone);
	}

void CFormatCB::InitL(TDrive* aDrive,TFormatMode aMode)
	{
	DoInitL(aDrive->DriveNumber());
	iDrive=aDrive;
	iMount=&iDrive->CurrentMount();
	iMode=aMode;
	User::LeaveIfError(iMount->Open());
	}


EXPORT_C TInt CFormatCB::GetInterface(TInt /*aInterfaceId*/,TAny*& /*aInterface*/,TAny* /*aInput*/)
	{
	return(KErrNotSupported);
	}


//----------------------------------------------------------------------------
/** 
    set volume formatting parameters, which are provided in TLDFormatInfo structure 
    @param  apLDFormatInfo  pointer to the parameters structure. If NULL, iSpecialInfo will be initialised
*/
void CFormatCB::SetFormatParameters(const TLDFormatInfo* apLDFormatInfo)
    {
    TLDFormatInfo& fmtInfo = iSpecialInfo();

    if(!apLDFormatInfo)
        {//-- special meaning; invalidate iSpecialInfo by setting its package size as 0
        iSpecialInfo.SetLength(0);
        }
    else
        {
        Mem::Copy(&fmtInfo, apLDFormatInfo, sizeof(TLDFormatInfo));
        }
    }

//----------------------------------------------------------------------------
/** set volume formatting parameters, which are provided in TVolFormatParam structure */
TInt CFormatCB::SetFormatParameters(const TVolFormatParam* apVolFormatParam)
    {
    ASSERT(apVolFormatParam);
    TAny* dummy;
    //-- push parameters to the particular implementation of the CFormatCB. Default behaviour: KErrNotSupported
    return GetInterface(ESetFmtParameters, dummy, (TAny*)apVolFormatParam);
    }

//----------------------------------------------------------------------------
#ifdef _DEBUG
#define DUMP_OPENED_OBJECTS
#endif

/**
    Debug helper method. Dumps names of opened files and directories on this drive
    define DUMP_OPENED_OBJECTS to have it called
*/
#ifdef DUMP_OPENED_OBJECTS
static void DumpOpenedObjects(TDrive& aDrive)
    {
        {//-- 1. files 
        const TInt nFiles = Files->Count();
        for(TInt i=0; i<nFiles; ++i)
            {
            CFileCB* pFile=(CFileCB*)(*Files)[i];
            if(pFile->Drive().DriveNumber() == aDrive.DriveNumber())
                {
                __PRINT1(_L("FsFormatOpen() opened file:'%S'"), &pFile->FileName());
                }
            }
        
        }

        {//-- 2. directories; CDirCB doesn't have associated name.
        const TInt nDirs = Dirs->Count();
        TInt cntDirs = 0;
        for(TInt i=0; i<nDirs; ++i)
            {
            CDirCB* pDir = (CDirCB*)(*Dirs)[i];
            if(pDir->Drive().DriveNumber() == aDrive.DriveNumber())
                {
                ++cntDirs;
                }
            }
            
        if(cntDirs)
            {
            __PRINT1(_L("FsFormatOpen() opened directories:%d"), cntDirs);
            }

        }

    }
#endif //DUMP_OPENED_OBJECTS

//----------------------------------------------------------------------------
/**
    Open a drive for formatting.
*/
TInt FsFormatOpen(CFsRequest* aRequest)
	{
    TDrive& drive = *aRequest->Drive();

	__PRINT1(_L("FsFormatOpen() drv:%d"), drive.DriveNumber());
    
    TInt nMountRes = drive.CheckMount();
    //-- KErrNotReady means that there is no file system mounted on this drive
    //-- KErrInUse means that there are some "disk access" objects, like RFormat or RRawDisk opened on the mount.
    if(nMountRes == KErrNotReady || nMountRes == KErrInUse) 
        {
        __PRINT1(_L("FsFormatOpen() ChkMount:%d"), nMountRes);
        return nMountRes;
        }
    
    const TFormatMode fmtMode = (TFormatMode)aRequest->Message().Int1();
    TName buf;
    TUint32 currFsNameHash = 0; //-- current file system name hash, 0 means "not set"; used during forced FS dismounting

    if((nMountRes == KErrNone) && drive.CurrentMount().LockStatus() < 0)
        {//-- the mount is locked, it has normal objects (files, directories) opened on it. 
        
        //-- if someone is interested in the list of opened files and number of opened directories, compile this code in.
        #ifdef DUMP_OPENED_OBJECTS
            DumpOpenedObjects(drive);
        #endif //DUMP_OPENED_OBJECTS


        if(!(fmtMode & EForceFormat))
            {
            __PRINT(_L("FsFormatOpen() The mount is in use"));
            return KErrInUse;
            }    

        //-- there is a special flag that tells to force media dismounting even if it has files or dirs opened.
        __PRINT(_L("FsFormatOpen() The mount is in use, forcing dismounting!"));

        //-- record currently mounted FS name hash, it may be used after forced dismounting
        drive.CurrentMount().FileSystemName(buf); //-- the iCurrentMount is alive
        currFsNameHash = TVolFormatParam::CalcFSNameHash(buf);

        //-- kill the current mount
        FsThreadManager::LockDrive(drive.DriveNumber());
        TInt nRes = drive.ForceUnmountFileSystemForFormatting();
        FsThreadManager::UnlockDrive(drive.DriveNumber());

        
        switch(nRes)
            {
            case KErrInUse: 
            __PRINT(_L("FsFormatOpen() The mount has clamps! Can't force dismount"));    
            return KErrInUse; //-- there are clamps on this drive - can't dismount

            case KErrNone:
            break;

            default:
            ASSERT(0); //-- unexpected error code
            return nRes;

            };

        if(fmtMode & EQuickFormat)
            {//-- quick format may require the normally mounted FS, make the best effrot to mount it
            nMountRes = drive.CheckMount();
            }
        else
            {//-- this will make the FS mounted by force; for full format it will be quicker
            nMountRes = KErrCorrupt;
            }

        }

	//-- if True, we will need mount (probably specific) file system by force because normal mounting has failed
    TBool bNeedForceMount = (nMountRes != KErrNone); 

    //-- find out if we have optional data structure that describes format parameter
    TUint32 newFsNameHash = 0; //-- file system name hash, may be used for selecting which file system to put onto the volume. 0 means "not specified"

    const TLDFormatInfo*    pLDFormatInfo   = NULL;
    const TVolFormatParam*  pVolFormatParam = NULL;

    __ASSERT_COMPILE(sizeof(TVolFormatParam) >= sizeof(TLDFormatInfo));
    TBuf8<sizeof(TVolFormatParam)> paramBuf;
   
    
    if(fmtMode & ESpecialFormat)  
        {   
        //-- the user has provided format parameters structure.
        //-- IPC argument #2 contains a structure: <TUint32>[optional package descriptor]
        //-- where 1st mandatory TUint32 is a pointer to format counter and the optional additional package is a data structure passed to the filesystem by the client of RFormat
        const TInt desLen = aRequest->GetDesLength(KMsgPtr2);
        ASSERT((TUint32)desLen >= sizeof(TUint32));
    
        const TInt dataPckgLen = desLen - sizeof(TUint32);

        if((TUint32)dataPckgLen > sizeof(TUint32))
            {
            aRequest->ReadL(KMsgPtr2, paramBuf); 
            }
        
        if(dataPckgLen == sizeof(TLDFormatInfo))
            {//-- the user has provided formatting parameters via TLDFormatInfo structure.
            pLDFormatInfo = (const TLDFormatInfo*)(paramBuf.Ptr() + sizeof(TUint32));
            }
        else if(dataPckgLen == sizeof(TVolFormatParam))
            {//-- it's likely to be TVolFormatParam, need to check UId to be sure.
            pVolFormatParam = (const TVolFormatParam*)(const TVolFormatParam*)(paramBuf.Ptr() + sizeof(TUint32));

            if(pVolFormatParam->iUId == TVolFormatParam::KUId)  //-- check the class UID
                {//-- this is the real TVolFormatParam object passed
                newFsNameHash = pVolFormatParam->FSNameHash();
                }
            }
        else if(dataPckgLen >0)
            {//-- parameters data structure has strange length
            return KErrArgument;
            }
    
        }

    //-------------------
    if(!newFsNameHash && currFsNameHash)
        {//-- new file system name isn't specified (default formatting), but the volume had been forcedly dismounted.
         //-- restore the original file system   
        newFsNameHash = currFsNameHash;
        }
    
    if(newFsNameHash)
        {//-- check if the specified FS is already mounted on the volume
        if(!bNeedForceMount)
            {
            drive.CurrentMount().FileSystemName(buf); //-- the iCurrentMount is alive
            }
        else
            { //-- the iCurrentMount can be NULL, use the iFsys - the real file system associated with this drive
            buf = drive.GetFSys()->Name();
            }

        const TUint32 currFSNameHash = TVolFormatParam::CalcFSNameHash(buf);
        if(currFSNameHash == newFsNameHash)
            {//-- no need to do anything, the required FS is already mounted
            newFsNameHash = 0; 
            } 
        }

    if(newFsNameHash) 
        {
        //-- the user has specified some filesystem to be mounted on the volume. Check if this FS is supported at all.
        //-- if it is supported, but some other FS is currently mounted, it will be dismounted and the new one will be forced.
        TInt nRes;
            
        for(TInt cntFS=0; ;++cntFS)
            {
            nRes = drive.FSys().GetSupportedFileSystemName(cntFS, buf); //-- enumerate possible child file systems
            
            if(nRes != KErrNone)
                return KErrNotSupported; //-- the filesystem with the given name (fsNameHash) is not supported.

            if(newFsNameHash == TVolFormatParam::CalcFSNameHash(buf))
                {//-- the filesystem with the given name (fsNameHash) is supported, but some other filesystem can be already mounted
                drive.Dismount();
                bNeedForceMount = ETrue; //-- this will force the desired FS to be mounted
                break;
                }
            }
    
        }//if(fsNameHash) 


    //-- try force mounting the desired file system if it is required
    if(bNeedForceMount)
        {
        const TInt KMaxRetries = 3;
        for(TInt cnt=0; ; ++cnt)
            {
            drive.MountFileSystem(ETrue, newFsNameHash);

            nMountRes = drive.GetReason();
            if(nMountRes == KErrNone || nMountRes == KErrLocked)
                break;
            
            drive.Dismount(); //-- will reset mount retries counter
            
            if(cnt >= KMaxRetries)
                {
                __PRINT1(_L("FsFormatOpen() can't mount FS! res:%d"), nMountRes);    
                return nMountRes;
                }
            }
        }

    ASSERT(nMountRes == KErrNone || nMountRes == KErrLocked);
    
    __ASSERT_DEBUG(drive.CurrentMount().LockStatus()==0, Fault(ESvrFormatOpenFailed));


	TDriveInfo dInfo;
	drive.DriveInfo(dInfo);
	const TInt mediaAtt = dInfo.iMediaAtt;

#if defined(_LOCKABLE_MEDIA)
	if (!(fmtMode & EForceErase) && (mediaAtt & KMediaAttLocked))
		{
		// if attempting to format a locked drive, dismount otherwise subsequent 
		// requests will operate on a mount that has been forcibly mounted (a few lines above)
		CMountCB* pM = &drive.CurrentMount();
		
        if(pM)
			pM->Close();

		drive.MountFileSystem(EFalse);	// clear iCurrentMount
		return KErrLocked;
		}
#endif

	if (!(mediaAtt & KMediaAttFormattable) || (mediaAtt & KMediaAttWriteProtected))
		{
		CMountCB* pM = &drive.CurrentMount();
		
        if(pM)
			pM->Close();

		drive.MountFileSystem(EFalse);
        return KErrAccessDenied;
		}

	//-- instantinate and open CFormatCB object for this drive
    CFormatCB* formatCB=NULL;
	TInt fmtHandle;
    
    TRAPD(ret, formatCB = drive.FormatOpenL(aRequest, fmtHandle, fmtMode, pLDFormatInfo, pVolFormatParam ));

	if (ret!=KErrNone)
		{
		if(formatCB)
			formatCB->Close();

		return ret;
		}

	TPtrC8 pH((TUint8*)&fmtHandle,sizeof(TInt));
	aRequest->WriteL(KMsgPtr3,pH);
	TInt count=100;

	TPtrC8 pCount((TUint8*)&count,sizeof(TInt));
	aRequest->WriteL(KMsgPtr2,pCount);
	aRequest->Session()->IncResourceCount();
	
    return KErrNone;
	}

TInt TFsFormatOpen::DoRequestL(CFsRequest* aRequest)
//
// Open a drive for formatting.
//
	{
	// Can not format if any files are clamped
	TInt r=FsFormatOpen(aRequest);
	return r;
	}

TInt TFsFormatOpen::Initialise(CFsRequest* aRequest)
//
//
//
	{
	TInt r;
	if (!KCapFsFormatOpen.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("Format Open")))
		return KErrPermissionDenied;
	r=ParseNoWildSubstPtr0(aRequest,aRequest->Src());
	if (r!=KErrNone)
		return(r);
	if (aRequest->Src().NameOrExtPresent())
		return(KErrBadName);
	if (aRequest->SubstedDrive())
		return(KErrAccessDenied);
	return(r);
	}


TInt TFsFormatNext::DoRequestL(CFsRequest* aRequest)
//
// Format the next part of the media.
//
	{

	__PRINT1(_L("TFsFormatNext::DoRequestL() drv:%d"), aRequest->DriveNumber());
	CFormatCB* format=(CFormatCB*)aRequest->ScratchValue();
	TInt r=format->CheckMount();
	if (r!=KErrNone && r!=KErrInUse)
        {
    	__PRINT1(_L("TFsFormatNext::DoRequestL() err:%d"), r);
        return r;
        }

	TPtr8 pStep((TUint8*)&format->CurrentStep(),sizeof(TInt));
	aRequest->ReadL(KMsgPtr0,pStep);

	TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFormatCBDoFormatStepL, EF32TraceUidFileSys, format);
	TRAP(r,format->DoFormatStepL());
	TRACERET2(UTF::EBorder, UTraceModuleFileSys::ECFormatCBDoFormatStepLRet, EF32TraceUidFileSys, r, format->CurrentStep());

	if (r==KErrNone)
		aRequest->WriteL(KMsgPtr0,pStep);
	if (r==KErrNone && format->CurrentStep()==0)
		{
		FsNotify::DiskChange(aRequest->DriveNumber());
		}
	return(r);
	}

TInt TFsFormatNext::Initialise(CFsRequest* aRequest)
//
//
//
	{
	if (!KCapFsFormatNext.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("Format Next")))
		return KErrPermissionDenied;
	CFormatCB* format;
	format=GetFormatFromHandle(aRequest->Message().Int3(), aRequest->Session());
	if(!format)
		return(KErrBadHandle);	
	aRequest->SetDrive(&format->Drive());
	aRequest->SetScratchValue((TUint)format);
	return KErrNone;
	}