diff -r 000000000000 -r a41df078684a userlibandfileserver/fileserver/sfile/sf_fmt.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/userlibandfileserver/fileserver/sfile/sf_fmt.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,496 @@ +// 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; iDrive().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; iDrive().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 paramBuf; + + + if(fmtMode & ESpecialFormat) + { + //-- the user has provided format parameters structure. + //-- IPC argument #2 contains a structure: [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; + }