--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/sfile/sf_drv.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,2634 @@
+// 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_drv.cpp
+//
+//
+
+#include "sf_std.h"
+#include "sf_file_cache.h"
+#include <hal.h>
+
+
+
+//const TInt KMaxNotifierAttempts=4; // not used anywhere
+
+static TPtrC StripBackSlash(const TDesC& aName)
+//
+// If aName ends in a backslash, strip it.
+//
+ {
+
+ __ASSERT_DEBUG(aName.Length(),Fault(EStripBackSlashBadName));
+ if (aName[aName.Length()-1]==KPathDelimiter)
+ return(aName.Left(aName.Length()-1));
+ return(aName);
+ }
+
+static void CheckSubClose(CFsObject* anObj,TInt aHandle, CSessionFs* aSession)
+//
+// Close anObj if its not NULL.
+//
+ {
+ __PRINT1(_L("CheckSubClose() session 0x0%x"),aSession);
+ __PRINT1(_L("CheckSubClose() anObj 0x0%x"),anObj);
+
+ if(!anObj)
+ return;
+
+ if(aHandle==0)
+ {
+ // can't have been added to the object index
+ __ASSERT_DEBUG(KErrNotFound==aSession->Handles().At(anObj,ETrue),Fault(ESubOpenBadHandle));
+ anObj->Close();
+ }
+ else
+ aSession->Handles().Remove(aHandle,ETrue);
+ }
+
+TInt ValidateDrive(TInt aDriveNumber,CFsRequest* aRequest)
+//
+// Validate a drive number and set iTheDrive.
+//
+ {
+ __CHECK_MAINTHREAD();
+ if (aDriveNumber==KDefaultDrive)
+ aDriveNumber=aRequest->Session()->CurrentDrive();
+ if (!RFs::IsValidDrive(aDriveNumber))
+ return(KErrBadName);
+ aRequest->SetDrive(&TheDrives[aDriveNumber]);
+ return(KErrNone);
+ }
+
+TInt ValidateDriveDoSubst(TInt aDriveNumber,CFsRequest* aRequest)
+//
+// Validate a drive number and set iTheDrive.
+//
+ {
+
+ TInt r=ValidateDrive(aDriveNumber,aRequest);
+ if (r!=KErrNone)
+ return(r);
+ if (aRequest->Drive()->IsSubsted())
+ {
+ aRequest->SetSubstedDrive(aRequest->Drive());
+ aRequest->SetDrive(&aRequest->Drive()->SubstedDrive());
+ }
+ return(KErrNone);
+ }
+
+void ValidateAtts(TUint /*anEntryAtts*/,TUint& aSetAttMask,TUint& aClearAttMask)
+//
+// Do not allow the entry type to be changed
+//
+ {
+ const TUint KReadOnlySetAtts = KEntryAttVolume |
+ KEntryAttDir |
+ KEntryAttRemote;
+
+ const TUint KReadOnlyClrAtts = KEntryAttVolume |
+ KEntryAttDir |
+ KEntryAttRemote |
+ KEntryAttModified;
+
+ aSetAttMask &= ~KReadOnlySetAtts;
+ aClearAttMask &= ~KReadOnlyClrAtts;
+ }
+
+void CheckForLeaveAfterOpenL(TInt leaveError, CFsRequest* aRequest, TInt aHandle)
+//
+// Tidy up in the event of a leave after opening a file or directory
+ {
+ if (leaveError)
+ {
+ CFsObject* anObj=(CFsObject* )aRequest->ScratchValue();
+ CheckSubClose(anObj,aHandle,aRequest->Session());
+ User::Leave(leaveError);
+ }
+ }
+
+TDrive::TDrive()
+//
+// Constructor.
+//
+ : iDriveNumber(0),iAtt(0),iChanged(EFalse),
+ iFSys(NULL),iCurrentMount(NULL),iSubstedDrive(NULL),iSubst(NULL),
+ iMount(NULL),iDriveFlags(0),iMountFailures(0)
+ {}
+
+void TDrive::CreateL(TInt aDriveNumber)
+//
+// Allocate the drive number and any resources.
+//
+ {
+ __PRINT1(_L("TDrive::CreateL(%d)"),aDriveNumber);
+ iDriveNumber=aDriveNumber;
+ iMount=TheContainer->CreateL();
+ TInt r=iLock.CreateLocal();
+ User::LeaveIfError(r);
+ }
+
+TInt TDrive::CheckMountAndEntryName(const TDesC& aName)
+//
+// Check drive is mounted then check aName is legal
+//
+ {
+
+ __PRINT1(_L("TDrive::CheckMountAndEntryName Drive%d"),DriveNumber());
+ TInt r=CheckMount();
+ if (r==KErrNone && IsIllegalFullName(aName))
+ return(KErrBadName);
+ return(r);
+ }
+
+void TDrive::MultiSlotDriveCheck()
+ {
+ // Check whether the current drive is a dual-slot/multi-slot
+ // if so, we need to check which drive is connected now and
+ // swap the mapping in LocalDrives::iMapping such that the
+ // mapping of driveNumber to localDriveNumber is correct.
+
+ Lock();
+ //Is this a multislot drive?
+ if(LocalDrives::iIsMultiSlotDrive[iDriveNumber])
+ {
+ for(TInt localDrvNum=0; localDrvNum<KMaxLocalDrives; localDrvNum++)
+ {
+ // ensure that this local drive is a multi-slot choice for this drive number..
+ if(LocalDrives::iReverseMapping[localDrvNum]==iDriveNumber)
+ {
+ // Caps - find out which one is connected
+ TLocalDriveCapsBuf capsInfo;
+ TInt r = LocalDrives::iLocalDrives[localDrvNum].Caps(capsInfo);
+ if(r==KErrNotReady)
+ {
+ continue; //go to next localdrive
+ }
+ //found a connected drive
+ //Update mapping
+ #ifdef _DEBUG
+ RDebug::Print(_L("Multislot drive mapping update: DriveNum %d to LocDrv %d"),iDriveNumber,localDrvNum);
+ #endif
+
+ LocalDrives::iMapping[iDriveNumber] = localDrvNum;
+ break; // Swap complete - don't look any further
+ }
+ }
+ }
+ UnLock();
+ }
+
+TInt TDrive::CheckMount()
+//
+// Check the drive and try to mount a media if not already mounted.
+//
+ {
+ __PRINT2(_L("TDrive::CheckMount Drive%d, changed:%d"),DriveNumber(), iChanged);
+ __CHECK_DRIVETHREAD(iDriveNumber);
+
+ if (!iFSys)
+ return KErrNotReady;
+
+ if (iChanged) // If a media change has occurred
+ {
+ iMountFailures = 0;
+ iChanged=EFalse; // Reset the flag
+ if (IsMounted()) // Dismount the mount if it is still marked as mounted
+ {
+ DoDismount();
+ }
+ //If we have a dual/multi removable media slot then we may need to
+ //swop the mappings.
+ MultiSlotDriveCheck();
+ }
+
+ if (!IsMounted()) // Checks that iCurrentMount!=NULL
+ {
+ __PRINT(_L("TDrive::CheckMount() Not Mounted"));
+ const TInt KMaxMountFailures = 3;
+ // if we've repeatedly failed to mount, give up until a media change
+ if (iMountFailures >= KMaxMountFailures)
+ {
+ __PRINT1(_L("TDrive::CheckMount() retries exceeded, last Err:%d"), iLastMountError);
+ return iLastMountError;
+ }
+
+ if (!ReMount()) // Have we just remounted a mount we have previously encountered?
+ {
+ MountFileSystem(EFalse); // If not, mount it for the first time now
+ }
+ else if(IsWriteProtected() && IsWriteableResource())
+ {
+ DoDismount();
+ return KErrAccessDenied;
+ }
+ }
+
+ if (iReason==KErrNone && CurrentMount().LockStatus() > 0)
+ {
+ //-- this meand that the mount has drive access objetcs opened (RFormat or RRawDisk)
+ __PRINT1(_L("TDrive::CheckMount() Mount is locked! LockStaus:%d"), CurrentMount().LockStatus());
+ return KErrInUse;
+ }
+
+ __PRINT1(_L("TDrive::CheckMount returned %d "),iReason);
+
+ return(iReason);
+ }
+
+//----------------------------------------------------------------------------
+/**
+ Try and re-mount any of the pending media
+
+ @return ETrue if the mount matching media found and been attached back (set as iCurrentMount)
+*/
+TBool TDrive::ReMount()
+ {
+ const TInt mCount=Mount().Count();
+ __PRINT1(_L("TDrive::ReMount() MountCnt:%d"), mCount);
+
+ const TInt u=(Mount().UniqueID()<<16);
+ iReason=KErrNone;
+
+ //-- try every instance of CMountCB that is associated with this object of TDrive.
+ //-- mounts are stored in the container of mCount elements.
+ //-- if some CMountCB recognises the media it belongs, it means that "remount succeded"
+ for(TInt i=0; i<mCount; i++)
+ {
+ CMountCB* pM=(CMountCB*)Mount().At(u|i);
+
+ if (ReMount(*pM))
+ return ETrue;
+ }
+
+ return EFalse;
+ }
+
+//----------------------------------------------------------------------------
+/**
+ Try and re-mount the specified media.
+
+ @return ETrue if remounting succeeded - i.e. the CMountCB instance that matches the media is found in the
+ mounts container (Mount()) and bound to the media.
+*/
+TBool TDrive::ReMount(CMountCB& aMount)
+ {
+ __PRINT1(_L("TDrive::ReMount(0x%x)"), &aMount);
+ iReason=KErrNone;
+
+ if (!aMount.IsDismounted() && !aMount.ProxyDriveDismounted())
+ {
+ aMount.SetDrive(this);
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECMountCBReMount, EF32TraceUidFileSys, DriveNumber());
+
+ //-- actually, this is asking CMountCB to see if it belongs to the current media.
+ iReason = aMount.ReMount();
+
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECMountCBReMountRet, EF32TraceUidFileSys, iReason);
+
+ if (iReason == KErrNone) // ReMount succeeded
+ {
+ aMount.Open();
+ iCurrentMount = &aMount;
+ __PRINT1(_L("TDrive::ReMount for Mount:0x%x OK!"), &aMount);
+ return ETrue;
+ }
+
+ __PRINT2(_L("TDrive::ReMount for Mount:0x%x failed iReason=%d"),&aMount,iReason);
+ }
+ else
+ {
+ __PRINT1(_L("TDrive::ReMount() failed - Mount:0x%x is dismounted"), &aMount);
+ }
+
+ return EFalse;
+ }
+
+
+
+//----------------------------------------------------------------------------
+/**
+ Mount the media on the drive. Optionally force a bad media to be mounted.
+
+ @param apMount out: pointer to the produced CMountCB object; NULL if the CMountCB is not constructed
+ @param aForceMount if ETrue, the filesystem will be forcedly mounted on the drive, disregarding what it contains.
+ @param aFsNameHash file system name hash; see TDrive::MountFileSystem()
+*/
+void TDrive::DoMountFileSystemL(CMountCB*& apMount, TBool aForceMount, TUint32 aFsNameHash)
+ {
+ CFileSystem* pMountsFs = NULL; //-- reference to the filesystem that will be producing CMountCB
+
+ apMount = NULL;
+
+ TRACE2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewMountL, EF32TraceUidFileSys, &FSys(), DriveNumber());
+
+ //-- construct a new CmountCB object.
+ //-- on return pMountsFs will be the pointer to the factory object of CFileSystem that produced this mount
+ apMount = FSys().NewMountExL(this, &pMountsFs, aForceMount, aFsNameHash);
+
+ TRACE2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewMountLRet, EF32TraceUidFileSys, KErrNone, apMount);
+ __PRINT2(_L("TDrive::MountMediaL created mount:0x%x FileSys:0x%x"), apMount, pMountsFs);
+
+ ASSERT(pMountsFs && apMount);
+
+ apMount->SetMountNumber(iMountNumber++);
+ apMount->InitL(*this, pMountsFs); //-- initialise Mount
+ apMount->MountL(aForceMount); //-- mount the file system
+ Mount().AddL(apMount,EFalse); //-- add mount object to the mounts container.
+
+ iCurrentMount=apMount;
+ }
+
+
+//----------------------------------------------------------------------------
+/*
+ Mount file system on the drive.
+ @param aForceMount if EFalse, will try to mount the file system normally, the file system implementation will decide if it can work on this drive or not.
+ if ETrue, will mount the file suystem by force, this is used mostly for formatting unrecognisable media.
+
+ @param aFsNameHash optional parameter. Can specify the concrete file system name (hash). It can be used to force mounting some specific
+ file system. Default value '0' means "not specified / not used"
+
+
+ TDrive::iReason on return contains the operation result code.
+*/
+void TDrive::MountFileSystem(TBool aForceMount, TUint32 aFsNameHash /*=0*/ )
+ {
+ __PRINT2(_L("TDrive::MountFileSystem aForceMount=%d, FSNameHash:0x%x"),aForceMount, aFsNameHash);
+ __CHECK_DRIVETHREAD(iDriveNumber);
+
+ iCurrentMount=NULL;
+ if(!iFSys)
+ {
+ iReason=KErrNotReady;
+ return;
+ }
+
+ CMountCB* pM=NULL;
+ TRAP(iReason, DoMountFileSystemL(pM, aForceMount, aFsNameHash));
+ if (iReason == KErrNone)
+ {
+ iMountFailures = 0;
+ ASSERT(iCurrentMount);
+ }
+ else
+ {
+ iLastMountError = iReason;
+ iMountFailures++;
+ __PRINT2(_L("TDrive::MountFileSystem 0x%x failed iReason=%d"),pM,iReason);
+ if(pM)
+ pM->Close();
+
+ ASSERT(!iCurrentMount);
+ }
+ }
+
+
+//----------------------------------------------------------------------------
+/**
+ Generic mount control method.
+ @param aLevel specifies the operation to perfrom on the mount
+ @param aOption specific option for the given operation
+ @param aParam pointer to generic parameter, its meaning depends on aLevel and aOption
+
+ @return standard error code.
+*/
+TInt TDrive::MountControl(TInt aLevel, TInt aOption, TAny* aParam)
+ {
+ TRACE4(UTF::EBorder, UTraceModuleFileSys::ECMountCBMountControl, EF32TraceUidFileSys, DriveNumber(), aLevel, aOption, aParam);
+ TInt r = CurrentMount().MountControl(aLevel, aOption, aParam);
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBMountControlRet, EF32TraceUidFileSys, r);
+
+ return r;
+ }
+
+//----------------------------------------------------------------------------
+/**
+ Request aFreeSpaceRequired free bytes from the mount associated with this drive.
+ The volume free space on for some filesystems can be changing (usually increasing) after it has been mounted.
+ If the mount supports this functionality, it can block this call until certain number of free bytes encounted if its free
+ space calculation activity hasn't finished yet.
+
+ @param aFreeSpaceRequired required free space, bytes.
+
+ @return KErrNone on success and if there is at least aFreeSpaceRequired bytes on the volume
+ KErrDiskFull on success and if there is no aFreeSpaceRequired bytes on the volume
+ system-wide error code otherwise
+*/
+TInt TDrive::RequestFreeSpaceOnMount(TUint64 aFreeSpaceRequired)
+ {
+ TInt nRes;
+
+ nRes = CheckMount();
+ if(nRes != KErrNone)
+ return nRes;
+
+ //-- 1. Try mount-specific request first. If the mount is still performing free space calculations,
+ //-- the caller will be suspended until aFreeSpaceRequired bytes is available or scanning process finishes
+ {
+ TUint64 freeSpaceReq = aFreeSpaceRequired;
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECMountCBFreeSpace, EF32TraceUidFileSys, DriveNumber());
+ nRes = CurrentMount().RequestFreeSpace(freeSpaceReq);
+ TRACERET3(UTF::EBorder, UTraceModuleFileSys::ECMountCBFreeSpaceRet, EF32TraceUidFileSys, nRes, I64LOW(freeSpaceReq), I64HIGH(freeSpaceReq));
+ if(nRes == KErrNone)
+ {
+ return (freeSpaceReq >= aFreeSpaceRequired) ? KErrNone : KErrDiskFull;
+ }
+ }
+
+ //-- given Mount doesn't support this functionality, use legacy method
+ TVolumeInfo volInfo;
+ nRes = Volume(volInfo);
+ if(nRes !=KErrNone)
+ return nRes;
+
+ return ((TUint64)volInfo.iFree >= aFreeSpaceRequired) ? KErrNone : KErrDiskFull;
+ }
+
+//----------------------------------------------------------------------------
+/**
+ Get size of the mounted volume. It can be less than physical volume size because FileSystem data may occupy some space.
+
+ @param aSize on success mounted volume size in bytes will be returned there
+ @return KErrNone on success, standard error code otherwise
+*/
+TInt TDrive::MountedVolumeSize(TUint64& aSize)
+ {
+ TInt nRes;
+
+ nRes = CheckMount();
+ if(nRes != KErrNone)
+ return nRes;
+
+ //-- 1. Try mount-specific request first. It won't block this call as CMountCB::VolumeL() can do if some background activity is going on the mount
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECMountCBVolumeSize, EF32TraceUidFileSys, DriveNumber());
+ nRes = CurrentMount().MountedVolumeSize(aSize);
+ TRACERET3(UTF::EBorder, UTraceModuleFileSys::ECMountCBVolumeSize, EF32TraceUidFileSys, nRes, I64LOW(aSize), I64HIGH(aSize));
+ if(nRes == KErrNone)
+ return nRes;
+
+ //-- given Mount doesn't support this functionality, use legacy method
+ TVolumeInfo volInfo;
+ nRes = Volume(volInfo);
+ if(nRes == KErrNone)
+ {
+ aSize = volInfo.iSize;
+ }
+
+ return nRes;
+ }
+
+//----------------------------------------------------------------------------
+/**
+ Get _current_ amount of free space on the volume. Some mounts implementations can be updating the amount of free space
+ in background.
+
+ @param aFreeDiskSpace on success will contain a current amount of free space
+ @return KErrNone on success, standard error code otherwise
+
+*/
+TInt TDrive::FreeDiskSpace(TInt64& aFreeDiskSpace)
+ {
+ TInt nRes;
+
+ nRes = CheckMount();
+ if(nRes != KErrNone)
+ return nRes;
+
+ //-- 1. Try mount-specific request first. It won't block this call as CMountCB::VolumeL() can do
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECMountCBCurrentFreeSpace, EF32TraceUidFileSys, DriveNumber());
+ nRes = CurrentMount().GetCurrentFreeSpaceAvailable(aFreeDiskSpace);
+ TRACERET3(UTF::EBorder, UTraceModuleFileSys::ECMountCBCurrentFreeSpaceRet, EF32TraceUidFileSys, nRes, I64LOW(aFreeDiskSpace), I64HIGH(aFreeDiskSpace));
+ if(nRes == KErrNone)
+ return nRes;
+
+ //-- given Mount doesn't support this functionality, use legacy method
+ TVolumeInfo volInfo;
+ nRes = Volume(volInfo);
+ if(nRes == KErrNone)
+ {
+ aFreeDiskSpace = volInfo.iFree;
+ }
+
+ return nRes;
+ }
+
+//----------------------------------------------------------------------------
+/**
+ Finalise drive (the mount).
+
+ @param aOperation describes finalisation operation ,see RFs::TFinaliseDrvMode
+ @param aParam1 not used, for future expansion
+ @param aParam2 not used, for future expansion
+
+ @return Standard error code
+*/
+TInt TDrive::FinaliseMount(TInt aOperation, TAny* aParam1/*=NULL*/, TAny* aParam2/*=NULL*/)
+ {
+ TInt r=CheckMount();
+ if (r!=KErrNone)
+ return(r);
+
+ r = FlushCachedFileInfo();
+ if (r!=KErrNone)
+ return(r);
+
+ if(IsWriteProtected())
+ return(KErrAccessDenied);
+
+ TRACE4(UTF::EBorder, UTraceModuleFileSys::ECMountCBFinaliseMount2, EF32TraceUidFileSys, DriveNumber(), aOperation, aParam1, aParam2);
+ TRAP(r,CurrentMount().FinaliseMountL(aOperation, aParam1, aParam2));
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBFinaliseMount2Ret, EF32TraceUidFileSys, r);
+
+ return r;
+ }
+
+//----------------------------------------------------------------------------
+/** old implementation */
+TInt TDrive::FinaliseMount()
+ {
+ TInt r=CheckMount();
+ if (r!=KErrNone)
+ return(r);
+
+ r = FlushCachedFileInfo();
+ if (r!=KErrNone)
+ return(r);
+
+ if(IsWriteProtected())
+ return(KErrAccessDenied);
+
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECMountCBFinaliseMount1, EF32TraceUidFileSys, DriveNumber());
+ TRAP(r,CurrentMount().FinaliseMountL());
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBFinaliseMount1Ret, EF32TraceUidFileSys, r);
+
+ return r;
+ }
+
+
+
+CFileCB* TDrive::LocateFile(const TDesC& aName)
+//
+// Locate a file of the same name already open on the drive.
+//
+ {
+ TDblQueIter<CFileCB> q(CurrentMount().iMountQ);
+ CFileCB* pF;
+ // early out for normal case, list is empty
+ if(q==NULL)
+ return NULL;
+
+ // strip off trailing dots
+ TInt length= aName.Length();
+ while((length !=0) && (aName[length-1]==KExtDelimiter))
+ {
+ length--;
+ }
+
+ TPtrC temp(aName.Ptr(),length);
+
+ TFileName tempName;
+ tempName.CopyF(temp);
+ TUint32 nameHash=CalcNameHash(tempName);
+
+ while ((pF=q++)!=NULL)
+ {
+ if(nameHash==pF->NameHash())
+ {
+ if (pF->FileNameF().Match(tempName)==KErrNone)
+ return(pF);
+ }
+ }
+ return(NULL);
+ }
+
+
+CFileCache* TDrive::LocateClosedFile(const TDesC& aName, TBool aResurrect)
+//
+// Locate a recently closed file of the same name on the drive.
+//
+ {
+ // strip off trailing dots
+ TInt length= aName.Length();
+ while((length !=0) && (aName[length-1]==KExtDelimiter))
+ {
+ length--;
+ }
+
+ TPtrC temp(aName.Ptr(),length);
+
+ TFileName tempName;
+ tempName.CopyF(temp);
+ TUint32 nameHash=CalcNameHash(tempName);
+
+ CFileCache* pF = NULL;
+ CMountCB* currentMount = &CurrentMount();
+
+
+ TClosedFileUtils::Lock();
+
+ TInt count = TClosedFileUtils::Count();
+ while(count--)
+ {
+ CFileCache* fileCache = TClosedFileUtils::At(count);
+ if (&fileCache->Drive() == this &&
+ fileCache->NameHash()== nameHash &&
+ fileCache->FileNameF().Match(tempName)==KErrNone &&
+ &fileCache->Mount() == currentMount)
+ {
+ __ASSERT_DEBUG(TClosedFileUtils::IsClosed(fileCache), Fault(EObjRemoveContainerNotFound));
+ __CACHE_PRINT2(_L("CLOSEDFILES: LocateClosedFile(%S, %d\n"), &fileCache->FileNameF(), aResurrect);
+ if (aResurrect)
+ {
+ TClosedFileUtils::ReOpen(fileCache, EFalse);
+ }
+ pF = fileCache;
+ break;
+ }
+
+ }
+ TClosedFileUtils::Unlock();
+
+ if (pF != NULL && !aResurrect)
+ {
+ pF->Close();
+ pF = NULL;
+ }
+
+ return(pF);
+ }
+
+
+static TBool IsSubDir(const TDesC& aFullName,const TDesC& aParent)
+//
+// Returns ETrue if aFullName is a subdirectory of aParent
+// Assumes aParent is a path name with the trailing backslash removed
+//
+ {
+
+ __ASSERT_DEBUG(aParent.Length() && aParent[aParent.Length()-1]!=KPathDelimiter,Fault(EIsSubDirBadDes));
+ TPtrC entryFullName(NULL,0);
+ TPtrC entryParent(NULL,0);
+ TInt posFullName=0;
+ TInt posParent=0;
+
+ FOREVER
+ {
+ NextInPath(aParent,entryParent,posParent);
+ if (entryParent.Length()==0)
+ break;
+ NextInPath(aFullName,entryFullName,posFullName);
+ if (entryParent!=entryFullName)
+ return(EFalse);
+ }
+
+ if (aFullName.Length()<=posFullName)
+ return(EFalse);
+ if (aFullName[posFullName]!=KPathDelimiter)
+ return(EFalse);
+ return(ETrue);
+ }
+
+CFileCB* TDrive::LocateFileByPath(const TDesC& aPath)
+//
+// Locate a file opened in a subdirectory of aPath
+//
+ {
+
+ TDblQueIter<CFileCB> q(CurrentMount().iMountQ);
+ CFileCB* pF;
+ while ((pF=q++)!=NULL)
+ {
+ if (IsSubDir(pF->FileName(),aPath))
+ return(pF);
+ }
+ return(NULL);
+ }
+
+void TDrive::FlushCachedFileInfoL()
+//
+// Flush data stored in the file control blocks
+//
+ {
+ __CHECK_DRIVETHREAD(iDriveNumber);
+ TDblQueIter<CFileCB> q(CurrentMount().iMountQ);
+ CFileCB* pF;
+ while ((pF=q++)!=NULL)
+ {
+ if (pF->iAtt&KEntryAttModified)
+ pF->FlushAllL();
+ }
+ }
+
+/**
+Flushes (asynchronously) all dirty data on this drive and optionally
+purges non-dirty data
+
+aPurgeCache - purges all file caches on this drive AFTER dirty data has ben flushed
+
+returns KErrNone if complete
+ CFsRequest::EReqActionBusy if flushing is in progress
+ otherwise one of the other system-wide error codes.
+*/
+TInt TDrive::FlushCachedFileInfo(TBool aPurgeCache)
+ {
+ if (iCurrentMount == NULL)
+ return KErrNone;
+
+ TBool driveThread = FsThreadManager::IsDriveThread(iDriveNumber,EFalse);
+
+ Lock();
+
+
+ TInt ret = KErrNone;
+
+ TDblQueIter<CFileCB> q(iCurrentMount->iMountQ);
+ CFileCB* pF;
+ while ((pF=q++)!=NULL)
+ {
+ CFileCache* fileCache = pF->FileCache();
+
+ // Write dirty data if there is a file cache
+ TInt flushDirtyRetCode = CFsRequest::EReqActionComplete;
+ if (fileCache)
+ {
+ flushDirtyRetCode = fileCache->FlushDirty();
+ if (flushDirtyRetCode == CFsRequest::EReqActionComplete) // nothing to flush
+ {
+ if (aPurgeCache)
+ fileCache->Purge(EFalse);
+ }
+ else if (flushDirtyRetCode == CFsRequest::EReqActionBusy) // flushing
+ {
+ ret = flushDirtyRetCode;
+ }
+ else // error
+ {
+ ret = flushDirtyRetCode;
+ break;
+ }
+ }
+ // if no file cache or no dirty data left, update the file entry & attributes
+ if (driveThread && (pF->iAtt&KEntryAttModified) && flushDirtyRetCode == CFsRequest::EReqActionComplete )
+ {
+ TRAP(ret, pF->FlushAllL());
+ if (ret != KErrNone)
+ break;
+ }
+ }
+
+ UnLock();
+
+
+ return ret;
+ }
+
+//----------------------------------------------------------------------------
+/**
+ Purge dirty cache data associated with all files on a given mount
+*/
+void TDrive::PurgeDirty(CMountCB& aMount)
+ {
+ TDblQueIter<CFileCB> q(aMount.iMountQ);
+ CFileCB* pF;
+ while ((pF=q++)!=NULL)
+ {
+ CFileCache* fileCache = pF->FileCache();
+ if (fileCache)
+ {
+ fileCache->Purge(ETrue);
+ fileCache->MarkFileClean();
+ }
+ }
+ }
+
+//----------------------------------------------------------------------------
+TInt TDrive::ValidateShare(CFileCB& aFile, TShare aReqShare)
+//
+// Check that the sharing rules are obeyed.
+//
+ {
+
+ switch (aReqShare)
+ {
+ case EFileShareExclusive:
+ case EFileShareReadersOnly:
+ case EFileShareAny:
+ case EFileShareReadersOrWriters:
+ break;
+ default:
+ return(KErrArgument);
+ }
+ switch (aFile.iShare)
+ {
+ case EFileShareExclusive:
+ return(KErrInUse);
+
+ case EFileShareReadersOnly:
+ case EFileShareAny:
+ if (aReqShare != aFile.iShare && aReqShare != EFileShareReadersOrWriters)
+ return(KErrInUse);
+ break;
+
+ case EFileShareReadersOrWriters:
+ if (aReqShare==EFileShareExclusive)
+ return(KErrInUse);
+ //
+ // If the file is currently open as EFileShareReadersOrWriters then
+ // promote the share to the requested share mode.
+ //
+ // If the requested share is EFileShareReadersOnly, verfiy that no
+ // other share has the file open for writing.
+ //
+
+ if (aReqShare == EFileShareReadersOnly)
+ {
+ FileShares->Lock();
+ TInt count = FileShares->Count();
+ while(count--)
+ {
+ CFileShare* share = (CFileShare*)(*FileShares)[count];
+ if (&share->File() == &aFile)
+ {
+ if(share->iMode & EFileWrite)
+ {
+ FileShares->Unlock();
+ return KErrInUse;
+ }
+ }
+ }
+ FileShares->Unlock();
+ }
+ break;
+
+ default:
+ Fault(EDrvIllegalShareValue);
+ break;
+ }
+ return(KErrNone);
+ }
+
+void TDrive::DriveInfo(TDriveInfo& anInfo)
+//
+// Get the drive info.
+//
+ {
+ anInfo.iType=EMediaNotPresent;
+ anInfo.iMediaAtt=0;
+
+ TInt batStatus=HAL::EPowerBatteryStatus_Zero;
+ TInt r=HAL::Get(HAL::EPowerBatteryStatus, batStatus);
+ if (r==KErrNone)
+ {
+ switch(batStatus)
+ {
+ case HAL::EPowerBatteryStatus_Zero:
+ anInfo.iBattery=EBatLow;
+ break;
+ case HAL::EPowerBatteryStatus_Replace:
+ anInfo.iBattery=EBatLow;
+ break;
+ case HAL::EPowerBatteryStatus_Low:
+ anInfo.iBattery=EBatLow;
+ break;
+ case HAL::EPowerBatteryStatus_Good:
+ anInfo.iBattery=EBatGood;
+ break;
+ }
+ }
+ else
+ anInfo.iBattery=EBatNotSupported;
+
+ if(iFSys)
+ {
+ TRACE2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemDriveInfo, EF32TraceUidFileSys, &FSys(), DriveNumber());
+ FSys().DriveInfo(anInfo,DriveNumber());
+ TRACE3(UTF::EBorder, UTraceModuleFileSys::ECFileSystemDriveInfoRet, EF32TraceUidFileSys,
+ anInfo.iType, anInfo.iDriveAtt, anInfo.iMediaAtt);
+ }
+
+ anInfo.iDriveAtt=Att();
+ }
+
+TInt TDrive::Volume(TVolumeInfo& aVolume)
+//
+// Get the drive volume info.
+//
+ {
+ TInt r=CheckMount();
+ if (r==KErrNone)
+ {
+ DriveInfo(aVolume.iDrive);
+ CMountCB& m=CurrentMount();
+ aVolume.iName=m.VolumeName();
+ aVolume.iUniqueID=m.iUniqueID;
+ aVolume.iSize=m.iSize;
+
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECMountCBVolumeL, EF32TraceUidFileSys, DriveNumber());
+ TRAP(r,m.VolumeL(aVolume))
+ TRACE7(UTF::EBorder, UTraceModuleFileSys::ECMountCBVolumeLRet, EF32TraceUidFileSys,
+ r, aVolume.iUniqueID, I64LOW(aVolume.iSize), I64HIGH(aVolume.iSize),
+ I64LOW(aVolume.iFree), I64HIGH(aVolume.iFree), aVolume.iFileCacheFlags);
+
+ }
+ return(r);
+ }
+
+
+void TDrive::SetVolumeL(const TDesC& aName,HBufC*& aBuf)
+//
+// Set the volume name.
+//
+ {
+ __CHECK_DRIVETHREAD(iDriveNumber);
+ aBuf=aName.AllocL();
+ TPtr volumeName=aBuf->Des();
+
+ TRACEMULT2(UTF::EBorder, UTraceModuleFileSys::ECMountCBSetVolumeL, EF32TraceUidFileSys, DriveNumber(), aName);
+ CurrentMount().SetVolumeL(volumeName);
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECMountCBSetVolumeLRet, EF32TraceUidFileSys, KErrNone);
+
+
+ delete &CurrentMount().VolumeName();
+ CurrentMount().SetVolumeName(aBuf);
+ }
+
+TInt TDrive::SetVolume(const TDesC& aName)
+//
+// Set the volume name.
+//
+ {
+ TInt r=CheckMount();
+ HBufC* pV=NULL;
+ if (r==KErrNone)
+ {
+ if(IsWriteProtected())
+ return(KErrAccessDenied);
+ TRAP(r,SetVolumeL(aName,pV))
+ if (r!=KErrNone)
+ delete pV;
+ }
+ return(r);
+ }
+
+TInt TDrive::MkDir(const TDesC& aName)
+//
+// Make a directory.
+//
+ {
+ TInt r=CheckMount();
+ if (r!=KErrNone)
+ return(r);
+ if(IsWriteProtected())
+ return(KErrAccessDenied);
+ TParse newDirName;
+ newDirName.Set(aName,NULL,NULL);
+
+ TRACEMULT2(UTF::EBorder, UTraceModuleFileSys::ECMountCBMkDirL, EF32TraceUidFileSys, DriveNumber(), aName);
+ TRAP(r,CurrentMount().MkDirL(newDirName.FullName()))
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBMkDirLRet, EF32TraceUidFileSys, r);
+
+ return(r);
+ }
+
+TInt TDrive::RmDir(const TDesC& aName)
+//
+// Remove a directory.
+//
+ {
+ TInt r=CheckMount();
+ if (r!=KErrNone)
+ return(r);
+ TEntry entry;
+ r=Entry(aName,entry);
+ if (r!=KErrNone)
+ return(r);
+ if (entry.IsDir()==EFalse)
+ return(KErrPathNotFound);
+ if ((entry.iAtt&KEntryAttReadOnly) || IsWriteProtected())
+ return(KErrAccessDenied);
+
+ TRACEMULT2(UTF::EBorder, UTraceModuleFileSys::ECMountCBRmDirL, EF32TraceUidFileSys, DriveNumber(), aName);
+ TRAP(r,CurrentMount().RmDirL(aName))
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBRmDirLRet, EF32TraceUidFileSys, r);
+
+ return(r);
+ }
+
+TInt TDrive::Delete(const TDesC& aName)
+//
+// Delete files allowing wild cards.
+//
+ {
+ TInt r=CheckMountAndEntryName(aName);
+ if (r!=KErrNone)
+ return(r);
+ CFileCB* pF=LocateFile(aName);
+ if (pF!=NULL)
+ return(KErrInUse);
+
+ // remove from closed queue - NB this isn't strictly necessary if file is read-only or write-protected...
+ LocateClosedFile(aName, EFalse);
+
+ TEntry entry;
+ r=Entry(aName,entry);
+ if (r!=KErrNone)
+ return(r);
+ if (entry.IsDir() || IsWriteProtected() || entry.IsReadOnly())
+ return(KErrAccessDenied);
+
+ TRACEMULT2(UTF::EBorder, UTraceModuleFileSys::ECMountCBDeleteL, EF32TraceUidFileSys, DriveNumber(), aName);
+ TRAP(r,CurrentMount().DeleteL(aName))
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBDeleteLRet, EF32TraceUidFileSys, r);
+
+ return(r);
+ }
+
+TInt TDrive::CheckMountAndEntryNames(const TDesC& anOldName,const TDesC& aNewName)
+//
+// Check mount, that neither is open, and that both names are legal.
+//
+ {
+
+ TInt r=CheckMountAndEntryName(anOldName);
+ if (r!=KErrNone)
+ return(r);
+ if (IsIllegalFullName(aNewName))
+ return(KErrBadName);
+ return(KErrNone);
+ }
+
+TInt TDrive::CheckDirectories(const TDesC& anOldName,const TDesC& aNewName)
+//
+// Return KErrAlreadyExists if aNewName exists and
+// KErrAccessDenied if anOldName is a directory being moved to a subdirectory of itself
+//
+ {
+
+ TEntry entry;
+ TInt r=Entry(anOldName,entry);
+ if (r!=KErrNone)
+ return(r);
+ if (entry.IsDir())
+ {
+ //-- check the length of the destination directory name. It shall not exceed 253 characters.
+ //-- aNewName looks like "\\dir1" i.e. drive letter and ':' is removed from the name and there is no trailing '\\' in this case.
+
+ const TInt maxDirNameLength = KMaxFileName - 3;
+ if(aNewName.Length() > maxDirNameLength)
+ return KErrBadName;
+ if(IsSubDir(aNewName,anOldName))
+ return(KErrInUse); // rename into a subdir of itself
+ if (LocateFileByPath(anOldName))
+ return(KErrInUse); // a file inside anOldName is open
+ }
+ else if (LocateFile(anOldName))
+ return(KErrInUse);
+
+ r=Entry(aNewName,entry);
+ if (r!=KErrNone && r!=KErrNotFound)
+ return(r);
+ return(KErrNone);
+ }
+
+TInt TDrive::Rename(const TDesC& anOldName,const TDesC& aNewName)
+//
+// Rename files or directories. No wild cards.
+//
+ {
+ __CHECK_DRIVETHREAD(iDriveNumber);
+ TInt r=CheckMountAndEntryNames(anOldName,aNewName);
+ if (r!=KErrNone)
+ return(r);
+ TPtrC oldEntryName(StripBackSlash(anOldName));
+ TPtrC newEntryName(StripBackSlash(aNewName));
+ r=CheckDirectories(oldEntryName,newEntryName);
+ if (r!=KErrNone)
+ return(r);
+ if(IsWriteProtected())
+ return(KErrAccessDenied);
+
+ // remove from closed queue
+ LocateClosedFile(anOldName, EFalse);
+ LocateClosedFile(aNewName, EFalse);
+
+ TRACEMULT3(UTF::EBorder, UTraceModuleFileSys::ECMountCBRenameL, EF32TraceUidFileSys, DriveNumber(), oldEntryName,newEntryName);
+ TRAP(r,CurrentMount().RenameL(oldEntryName,newEntryName))
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBRenameLRet, EF32TraceUidFileSys, r);
+
+ return(r);
+ }
+
+TInt TDrive::Replace(const TDesC& anOldName,const TDesC& aNewName)
+//
+// Replace anOldName with aNewName atomically. No wild cards. No directories
+//
+ {
+ TInt r=CheckMountAndEntryNames(anOldName,aNewName);
+ if (r!=KErrNone)
+ return(r);
+ TEntry entry;
+ r=Entry(aNewName,entry);
+ if (r!=KErrNotFound)
+ {
+ if (r!=KErrNone)
+ return(r);
+ if (entry.IsDir() || entry.IsReadOnly())
+ return(KErrAccessDenied);
+ if (LocateFile(aNewName))
+ return(KErrInUse);
+ }
+ r=Entry(anOldName,entry);
+ if (r!=KErrNone)
+ return(r);
+ if (entry.IsDir() || IsWriteProtected())
+ return(KErrAccessDenied);
+ if (LocateFile(anOldName))
+ return(KErrInUse);
+
+ // remove from closed queue
+ LocateClosedFile(anOldName, EFalse);
+ LocateClosedFile(aNewName, EFalse);
+
+ TRACEMULT3(UTF::EBorder, UTraceModuleFileSys::ECMountCBReplaceL, EF32TraceUidFileSys, DriveNumber(), anOldName, aNewName);
+ TRAP(r,CurrentMount().ReplaceL(anOldName,aNewName))
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBReplaceLRet, EF32TraceUidFileSys, r);
+
+ return(r);
+ }
+
+TInt TDrive::Entry(const TDesC& aName,TEntry& anEntry)
+//
+// Get the entry details.
+//
+ {
+ __CHECK_DRIVETHREAD(iDriveNumber);
+ TInt r=CheckMountAndEntryName(aName);
+ if (r!=KErrNone)
+ return(r);
+ TPtrC entryName(StripBackSlash(aName));
+ TRAP(r,DoEntryL(entryName,anEntry));
+
+ if (r==KErrHidden)
+ r=KErrNotFound;
+ else if (r==KErrPathHidden)
+ r=KErrPathNotFound;
+
+ return(r);
+ }
+
+void TDrive::DoEntryL(const TDesC& aName, TEntry& anEntry)
+//
+// Get entry details
+//
+ {
+ FlushCachedFileInfoL();
+
+ TRACEMULT2(UTF::EBorder, UTraceModuleFileSys::ECMountCBEntryL, EF32TraceUidFileSys, DriveNumber(), aName);
+ CurrentMount().EntryL(aName,anEntry);
+ TRACE5(UTF::EBorder, UTraceModuleFileSys::ECMountCBEntryLRet, EF32TraceUidFileSys,
+ KErrNone, anEntry.iAtt,
+ I64LOW(anEntry.iModified.Int64()), I64HIGH(anEntry.iModified.Int64()),
+ anEntry.iSize);
+
+ }
+
+TInt TDrive::CheckAttributes(const TDesC& aName,TUint& aSetAttMask,TUint& aClearAttMask)
+//
+// Validate the changes against the current entry attributes
+//
+ {
+
+ TEntry entry;
+ TRAPD(r,DoEntryL(aName,entry));
+ if (r!=KErrNone)
+ return(r);
+ ValidateAtts(entry.iAtt,aSetAttMask,aClearAttMask);
+ return(KErrNone);
+ }
+
+TInt TDrive::SetEntry(const TDesC& aName,const TTime& aTime,TUint aSetAttMask,TUint aClearAttMask)
+//
+// Set the entry details.
+//
+ {
+ __CHECK_DRIVETHREAD(iDriveNumber);
+ TInt r=CheckMountAndEntryName(aName);
+ if (r!=KErrNone)
+ return(r);
+ TPtrC entryName(StripBackSlash(aName));
+ CFileCB* pF=LocateFile(entryName);
+ if (pF!=NULL)
+ return(KErrInUse);
+ r=CheckAttributes(entryName,aSetAttMask,aClearAttMask);
+ if (r!=KErrNone)
+ return(r);
+ if (IsWriteProtected())
+ return(KErrAccessDenied);
+ TTime nullTime(0);
+ if (aTime!=nullTime)
+ aSetAttMask|=KEntryAttModified;
+
+ TRACEMULT6(UTF::EBorder, UTraceModuleFileSys::ECMountCBSetEntryL, EF32TraceUidFileSys,
+ DriveNumber(), aName, I64LOW(aTime.Int64()), I64HIGH(aTime.Int64()), aSetAttMask, aClearAttMask);
+ TRAP(r,CurrentMount().SetEntryL(entryName,aTime,aSetAttMask,aClearAttMask))
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBSetEntryLRet, EF32TraceUidFileSys, r);
+
+ return(r);
+ }
+
+TInt TDrive::FileTemp(CFsRequest* aRequest,TInt& aHandle,const TDesC& aPath,TDes& aName,TUint aMode)
+//
+// Create a temporary file and return the file name.
+//
+ {
+ __CHECK_DRIVETHREAD(iDriveNumber);
+ aName=aPath;
+ TInt len=aName.Length();
+ TInt t=User::TickCount()&0xfffff;
+ aMode|=EFileWrite;
+ for (TInt retry=0;retry<KMaxTempNameAttempts;retry++)
+ {
+ aName.SetLength(len);
+ aName.AppendFormat(_L("TMP%05x.$$$"),t);
+ TEntry e;
+ TInt r=Entry(aName,e);
+ if (r!=KErrNone)
+ {
+ if (r!=KErrNotFound)
+ return(r);
+ return(FileOpen(aRequest,aHandle,aName,aMode,EFileCreate));
+ }
+ t=((t|1)*13)&0xfffff;
+ }
+ return(KErrGeneral);
+ }
+
+LOCAL_C HBufC* CreateFileNameL(const TDesC& aName)
+//
+// Create a HBufC from aName
+// Converts _L("\\F32.\\GROUP\\release.") to _L("\\F32\\GROUP\\release")
+//
+ {
+
+ TParsePtrC name(aName);
+ TFileName fileName;
+ fileName.Append(KPathDelimiter);
+
+ if (name.Path().Length())
+ {
+ TInt pos=0;
+ TPtrC entry(NULL,0);
+ FOREVER
+ {
+ NextInPath(name.Path(),entry,pos);
+ if (entry.Length()==0)
+ break;
+ fileName.Append(entry);
+ fileName.Append(KPathDelimiter);
+ }
+ }
+
+ fileName.Append(name.Name());
+ if (name.Ext().Length()>1)
+ fileName.Append(name.Ext());
+ return(fileName.AllocL());
+ }
+
+void TDrive::FileOpenL(CFsRequest* aRequest,TInt& aHandle,const TDesC& aName,TUint aMode,TFileOpen anOpen,CFileCB*& aFileCB,CFileShare*& aFileShare)
+//
+// Open/Create/Replace a file.
+//
+ {
+ aFileCB=NULL;
+ aFileShare=NULL;
+ TInt r = CheckMount();
+ if (r!=KErrNone)
+ User::Leave(r);
+
+ if (IsIllegalFullName(aRequest->Src()))
+ User::Leave(KErrBadName);
+
+ if (CurrentMount().Locked())
+ User::Leave(KErrInUse);
+
+ if ((aMode & EFileWrite) != 0)
+ {
+ TDriveInfo driveInfo;
+ DriveInfo(driveInfo);
+ if (driveInfo.iType==EMediaRom || (driveInfo.iMediaAtt&KMediaAttWriteProtected)!=0)
+ User::Leave(KErrAccessDenied);
+ }
+
+ TShare share=(TShare)(aMode&KFileShareMask);
+ if (share==EFileShareReadersOnly && (aMode&EFileWrite)!=0)
+ User::Leave(KErrArgument);
+
+ if (aMode & EFileReadAsyncAll)
+ {
+ // Async read all mode is not compatible with EFileShareExclusive or EFileShareReadersOnly,
+ // as these modes prevent a writer from accessing the file and completing the request.
+ if(share == EFileShareExclusive || share == EFileShareReadersOnly)
+ User::Leave(KErrArgument);
+ }
+
+ // check for silly cache on / off combinations
+ const TUint KBadWriteMode = EFileWriteBuffered | EFileWriteDirectIO;
+ const TUint KBadReadMode = EFileReadBuffered | EFileReadDirectIO;
+ const TUint KBadReadAheadMode = EFileReadAheadOn | EFileReadAheadOff;
+ const TUint KBadReadAheadMode2 = EFileReadDirectIO | EFileReadAheadOn;
+ if (((aMode & KBadWriteMode) == KBadWriteMode) ||
+ ((aMode & KBadReadMode) == KBadReadMode) ||
+ ((aMode & KBadReadAheadMode) == KBadReadAheadMode) ||
+ ((aMode & KBadReadAheadMode2) == KBadReadAheadMode2))
+ {
+ User::Leave(KErrArgument);
+ }
+
+ // Only allow delete on close for a newly created file.
+ if ((aMode & EDeleteOnClose) && (anOpen!=EFileCreate))
+ User::Leave(KErrArgument);
+
+ CFileCB* pF=LocateFile(aName);
+ CFileCache* pFileCache = NULL;
+ TBool openFile=EFalse;
+ if (pF!=NULL)
+ {
+ if (pF->iShare==EFileShareReadersOnly && (aMode&EFileWrite)!=0)
+ User::Leave(KErrInUse);
+ if (anOpen==EFileCreate)
+ User::Leave(KErrAlreadyExists);
+ TInt r=ValidateShare(*pF,share);
+ if (r!=KErrNone)
+ User::Leave(r);
+ if ((r=pF->Open())!=KErrNone)
+ User::Leave(r);
+ aFileCB=pF;
+ pFileCache = pF->FileCache();
+ }
+ else
+ {
+ TRACE2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewFileL, EF32TraceUidFileSys, &FSys(), DriveNumber());
+
+ //-- construct CFileCB object, belonging to the corresponding mount
+ pF = aFileCB = CurrentMount().NewFileL();
+
+ TRACERET2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewFileLRet, EF32TraceUidFileSys, r, pF);
+ TDrive* createdDrive=!aRequest->SubstedDrive() ? this : aRequest->SubstedDrive();
+
+ HBufC* fileName = CreateFileNameL(aName);
+
+ pF->InitL(this, createdDrive, fileName);
+
+
+ pF->iShare = share;
+ openFile=ETrue;
+ CurrentMount().iMountQ.AddLast(*pF);
+ Files->AddL(pF,ETrue);
+ }
+
+ CFileShare* pS=aFileShare=new(ELeave) CFileShare(pF);
+
+ // We need to call CFileCB::PromoteShare immediately after the CFileShare
+ // instance is created since the destructor calls CFileCB::DemoteShare()
+ // which checks the share count is non-zero
+ pS->iMode=aMode;
+ pF->PromoteShare(pS);
+
+ pS->InitL();
+ aFileCB=NULL;
+ FileShares->AddL(pS,ETrue);
+ aHandle=aRequest->Session()->Handles().AddL(pS,ETrue);
+
+
+ if (openFile)
+ {
+ TRACEMULT5(UTF::EBorder, UTraceModuleFileSys::ECMountCBFileOpenL, EF32TraceUidFileSys, DriveNumber(), aName, aMode, (TUint) anOpen, (TUint) pF);
+ CurrentMount().FileOpenL(aName,aMode,anOpen,pF);
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECMountCBFileOpenLRet, EF32TraceUidFileSys, KErrNone);
+
+ // Delete on close may now be safely flagged if required.
+ // The file did not exist on the media prior to the
+ // CMountCB::FileOpenL() call for the case of a create.
+ if ((aMode & EDeleteOnClose) && (anOpen==EFileCreate))
+ pF->SetDeleteOnClose();
+
+ TBool localBufferSuppport = (CurrentMount().LocalBufferSupport(pF) == KErrNone)?(TBool)ETrue:(TBool)EFalse;
+ pF->SetLocalBufferSupport(localBufferSuppport);
+ if (localBufferSuppport)
+ {
+ // if file exists on closed queue resurrect it or discard it,
+ // depending on the file open mode
+ pFileCache = LocateClosedFile(aName, anOpen == EFileOpen?(TBool)ETrue:(TBool)EFalse);
+ if (pFileCache)
+ {
+ pFileCache = pFileCache->ReNewL(*pS); // NB may return NULL if caching not enabled
+ }
+ else
+ {
+ pFileCache = CFileCache::NewL(*pS); // NB may return NULL if caching not enabled
+ }
+ if (pFileCache)
+ // set the cached size to be the same as the uncached size
+ pF->SetCachedSize64(pF->Size64());
+ }
+ else
+ {
+ __CACHE_PRINT(_L("TDrive::FileOpenL(), Local buffers not supported"));
+ }
+ }
+
+ // initialize share mode flags
+ if (pFileCache != NULL)
+ pFileCache->Init(*pS);
+ }
+
+TInt TDrive::FileOpen(CFsRequest* aRequest,TInt& aHandle,const TDesC& aName,TUint aMode,TFileOpen anOpen)
+//
+// Open/Create/Replace a file.
+//
+ {
+ __CHECK_DRIVETHREAD(iDriveNumber);
+ CFileCB* pF=NULL;
+ CFileShare* pS=NULL;
+ aHandle=0;
+ TRAPD(r,FileOpenL(aRequest,aHandle,aName,aMode,anOpen,pF,pS))
+
+ // Allow files > 2GB-1 to be opened only if EFileBigFile is specified in iMode
+ if (r == KErrNone && pS && ((TUint64)pS->File().Size64() > KMaxLegacyFileSize) && (!(pS->IsFileModeBig())))
+ r = KErrTooBig;
+
+ if (r!=KErrNone)
+ {
+ if (r==KErrHidden)
+ r=KErrNotFound;
+ else if (r==KErrPathHidden)
+ r=KErrPathNotFound;
+
+ if(pF && !pS)
+ pF->Close();
+ CheckSubClose(pS,aHandle,aRequest->Session());
+ }
+ return(r);
+ }
+
+void TDrive::DirOpenL(CSessionFs* aSession,TInt& aHandle,const TDesC& aName,TUint anAtt,const TUidType& aUidType,CDirCB*& aDir)
+//
+// Open a directory listing. Leave on error.
+//
+ {
+ TRACE2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewDirL, EF32TraceUidFileSys, &FSys(), DriveNumber());
+
+ CDirCB* pD = aDir = CurrentMount().NewDirL(); //-- construct CDirCB object, belonging to the corresponding mount
+
+ TRACE2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewDirLRet, EF32TraceUidFileSys, KErrNone, pD);
+ pD->InitL(this);
+ // modify resource counter after initialisation to ensure correct cleanup
+ AddResource(CurrentMount());
+ pD->iAtt=anAtt;
+ pD->iUidType=aUidType;
+ Dirs->AddL(pD,ETrue);
+ aHandle=aSession->Handles().AddL(pD,ETrue);
+
+ TRACEMULT3(UTF::EBorder, UTraceModuleFileSys::ECMountCBDirOpenL, EF32TraceUidFileSys, DriveNumber(), aName, (TUint) pD);
+ CurrentMount().DirOpenL(aName,pD);
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECMountCBDirOpenLRet, EF32TraceUidFileSys, KErrNone);
+ }
+
+TInt TDrive::DirOpen(CSessionFs* aSession,TInt& aHandle,const TDesC& aName,TUint anAtt,const TUidType& aUidType)
+//
+// Open a directory listing.
+//
+ {
+ TInt r=CheckMountAndEntryName(aName);
+ if (r!=KErrNone)
+ return(r);
+ if (CurrentMount().Locked())
+ return(KErrInUse);
+ CDirCB* pD=NULL;
+ aHandle=0;
+ TRAP(r,DirOpenL(aSession,aHandle,aName,anAtt,aUidType,pD));
+
+ if (r==KErrHidden)
+ r=KErrNotFound;
+ else if (r==KErrPathHidden)
+ r=KErrPathNotFound;
+
+ if (r!=KErrNone)
+ CheckSubClose(pD,aHandle,aSession);
+ return(r);
+ }
+
+
+TInt TDrive::ReadFileSection(const TDesC& aName,TInt aPos,TAny* aTrg,TInt aLength,const RMessagePtr2& aMessage)
+//
+// Starting from aPos, read aLength bytes of a file into a Trg,
+// regardless of lock state
+//
+ {
+ return ReadFileSection64(aName, aPos, aTrg, aLength, aMessage);
+ }
+
+
+TInt TDrive::ReadFileSection64(const TDesC& aName,TInt64 aPos,TAny* aTrg,TInt aLength,const RMessagePtr2& aMessage)
+//
+// Starting from aPos, read aLength bytes of a file into a Trg,
+// regardless of lock state
+//
+ {
+
+ // flush dirty data if already open
+ CFileCB* file;
+ IsFileOpen(aName, file);
+ if (file && file->FileCache())
+ {
+ if (file->FileCache()->FlushDirty() == CFsRequest::EReqActionBusy)
+ return CFsRequest::EReqActionBusy;
+ }
+
+ __PRINT(_L("TDrive::ReadSection"));
+ TInt r=CheckMountAndEntryName(aName);
+ if (r!=KErrNone)
+ return(r);
+ TPtrC entryName(StripBackSlash(aName));
+
+ TRACETHREADID(aMessage);
+ TRACEMULT7(UTF::EBorder, UTraceModuleFileSys::ECMountCBReadFileSectionL, EF32TraceUidFileSys,
+ DriveNumber(), aName, I64LOW(aPos), I64HIGH(aPos), (TUint) aTrg, aLength, I64LOW(threadId));
+ TRAP(r,ReadSectionL(entryName,aPos,aTrg,aLength,aMessage));
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBReadFileSectionLRet, EF32TraceUidFileSys, r);
+
+ if (r==KErrHidden)
+ r=KErrNotFound;
+ else if (r==KErrPathHidden)
+ r=KErrPathNotFound;
+
+ return(r);
+ }
+
+
+void TDrive::ReadSectionL(const TDesC& aName,TInt64 aPos,TAny* aTrg,TInt aLength,const RMessagePtr2& aMessage)
+//
+// Starting from aPos, read aLength bytes of a file into a Trg,
+// regardless of lock state
+//
+ {
+ __PRINT(_L("TDrive::ReadSectionL"));
+
+ FlushCachedFileInfoL();
+ CurrentMount().ReadSection64L(aName,aPos,aTrg,aLength,aMessage);
+ }
+
+/**
+ Check the disk's integrity
+*/
+TInt TDrive::CheckDisk()
+ {
+ TInt r=CheckMount();
+ if (r==KErrNone)
+ TRAP(r,FlushCachedFileInfoL());
+ if (r==KErrNone)
+ {
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECMountCBCheckDisk1, EF32TraceUidFileSys, DriveNumber());
+ r=CurrentMount().CheckDisk();
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBCheckDisk1Ret, EF32TraceUidFileSys, r);
+ }
+ return(r);
+ }
+
+/**
+ @prototype
+*/
+TInt TDrive::CheckDisk(TInt aOperation, TAny* aParam1/*=NULL*/, TAny* aParam2/*=NULL*/)
+ {
+ TInt r=CheckMount();
+ if (r==KErrNone)
+ TRAP(r,FlushCachedFileInfoL());
+ if (r==KErrNone)
+ {
+ TRACE4(UTF::EBorder, UTraceModuleFileSys::ECMountCBCheckDisk2, EF32TraceUidFileSys, DriveNumber(), aOperation, aParam1, aParam2);
+ r=CurrentMount().CheckDisk(aOperation, aParam1, aParam2);
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBCheckDisk2Ret, EF32TraceUidFileSys, r);
+ }
+
+ return(r);
+ }
+
+TInt TDrive::ScanDrive()
+ {
+ __CHECK_DRIVETHREAD(iDriveNumber);
+ TInt r=CheckMount();
+ if(r==KErrNone)
+ {
+ if(IsWriteProtected())
+ return(KErrAccessDenied);
+ TRAP(r,FlushCachedFileInfoL());
+ }
+ if(r!=KErrNone)
+ return r;
+
+ // Empty closed file queue
+ TClosedFileUtils::Remove(DriveNumber());
+
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECMountCBScanDrive1, EF32TraceUidFileSys, DriveNumber());
+ r = CurrentMount().ScanDrive();
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBScanDrive1Ret, EF32TraceUidFileSys, r);
+
+ return r;
+ }
+
+
+/**
+ @prototype
+*/
+TInt TDrive::ScanDrive(TInt aOperation, TAny* aParam1/*=NULL*/, TAny* aParam2/*=NULL*/)
+ {
+ __CHECK_DRIVETHREAD(iDriveNumber);
+ TInt r=CheckMount();
+ if(r==KErrNone)
+ {
+ if(IsWriteProtected())
+ return(KErrAccessDenied);
+ TRAP(r,FlushCachedFileInfoL());
+ }
+ if(r!=KErrNone)
+ return r;
+
+ // Empty closed file queue
+ TClosedFileUtils::Remove(DriveNumber());
+
+ TRACE4(UTF::EBorder, UTraceModuleFileSys::ECMountCBScanDrive2, EF32TraceUidFileSys, DriveNumber(), aOperation, aParam1, aParam2);
+ r = CurrentMount().ScanDrive(aOperation, aParam1, aParam2);
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBScanDrive2Ret, EF32TraceUidFileSys, r);
+
+ return r;
+ }
+
+
+TInt TDrive::GetShortName(const TDesC& aName,TDes& aShortName)
+//
+// Get the short name associated with a long file name
+//
+ {
+ TInt r=CheckMountAndEntryName(aName);
+ if (r!=KErrNone)
+ return(r);
+ TPtrC entryName(StripBackSlash(aName));
+
+ TRACEMULT2(UTF::EBorder, UTraceModuleFileSys::ECMountCBGetShortNameL, EF32TraceUidFileSys, DriveNumber(), entryName);
+ TRAP(r,CurrentMount().GetShortNameL(entryName,aShortName));
+ TRACERETMULT2(UTF::EBorder, UTraceModuleFileSys::ECMountCBGetShortNameLRet, EF32TraceUidFileSys, r, aShortName);
+
+ return(r);
+ }
+
+TInt TDrive::GetLongName(const TDesC& aShortName,TDes& aLongName)
+//
+// Get the long name associated with a short file name
+//
+ {
+ TInt r=CheckMountAndEntryName(aShortName);
+ if (r!=KErrNone)
+ return(r);
+ TPtrC entryName(StripBackSlash(aShortName));
+
+ TRACEMULT2(UTF::EBorder, UTraceModuleFileSys::ECMountCBGetLongNameL, EF32TraceUidFileSys, DriveNumber(), entryName);
+ TRAP(r,CurrentMount().GetLongNameL(entryName,aLongName));
+ TRACERETMULT2(UTF::EBorder, UTraceModuleFileSys::ECMountCBGetLongNameLRet, EF32TraceUidFileSys, r, aLongName);
+
+ return(r);
+ }
+
+TInt TDrive::IsFileOpen(const TDesC& aFileName,CFileCB*& aFileCB)
+//
+// Query whether the file is open or not.
+//
+ {
+ __CHECK_DRIVETHREAD(iDriveNumber);
+
+ aFileCB = NULL;
+
+ TEntry dumEntry;
+ TInt r=Entry(aFileName,dumEntry);
+ if (r!=KErrNone)
+ return(r);
+ if(dumEntry.iAtt&KEntryAttDir)
+ return KErrArgument;
+
+ Files->Lock();
+ TInt count=Files->Count();
+
+ // create a hash to speed up the search
+
+ TFileName foldedName;
+ TUint32 nameHash=0;
+ if (count > 0)
+ {
+ foldedName.CopyF(aFileName);
+ nameHash=CalcNameHash(foldedName);
+ }
+
+ while(count--)
+ {
+ CFileCB* file=(CFileCB*)(*Files)[count];
+
+ if ((&file->Drive()==this) && nameHash == file->NameHash() && file->FileNameF().Match(foldedName)!=KErrNotFound)
+ {
+ aFileCB = file;
+ break;
+ }
+ }
+ Files->Unlock();
+ return(KErrNone);
+ }
+
+TInt TDrive::IsFileInRom(const TDesC& aFileName,TUint8*& aFileStart)
+//
+// Return the start of the file if it is in rom
+//
+ {
+ TInt r=CheckMount();
+ if (r==KErrNone)
+ CurrentMount().IsFileInRom(aFileName,aFileStart);
+ return(r);
+ }
+
+TBool TDrive::IsWriteProtected()
+//
+// return true if the media is write protected
+//
+ {
+// __CHECK_DRIVETHREAD(iDriveNumber);
+ TDriveInfo drvInfo;
+ drvInfo.iMediaAtt=0;
+ if(Att() && iFSys)
+ FSys().DriveInfo(drvInfo,DriveNumber());
+ return((drvInfo.iMediaAtt&KMediaAttWriteProtected)!=0);
+ }
+
+
+
+
+/**
+Checks whether any resource that could write to disk is open on
+the current mount.
+
+@return True, if a resource that could write to disk is open on
+ the current mount, false otherwise.
+*/
+EXPORT_C TBool TDrive::IsWriteableResource() const
+ {
+// __CHECK_DRIVETHREAD(iDriveNumber);
+ if(iCurrentMount==NULL)
+ return(EFalse);
+ if(iCurrentMount->LockStatus()>0)
+ {
+ // check format subsessions
+ Formats->Lock();
+ TInt count=Formats->Count();
+ while(count--)
+ {
+ CFormatCB* format=(CFormatCB*)(*Formats)[count];
+ if(&format->Mount()==iCurrentMount)
+ {
+ Formats->Unlock();
+ return(ETrue);
+ }
+ }
+ Formats->Unlock();
+ // check raw disk subsessions
+ RawDisks->Lock();
+ count=RawDisks->Count();
+ while(count--)
+ {
+ CRawDiskCB* rawDisk=(CRawDiskCB*)(*RawDisks)[count];
+ if(&rawDisk->Mount()==iCurrentMount && !rawDisk->IsWriteProtected())
+ {
+ Formats->Unlock();
+ return(ETrue);
+ }
+ }
+ Formats->Unlock();
+ }
+ else if(iCurrentMount->LockStatus()<0)
+ {
+ // check file share subsessions
+ FileShares->Lock();
+ TInt count=FileShares->Count();
+ while(count--)
+ {
+ CFileShare* fileShare=(CFileShare*)(*FileShares)[count];
+ if (&fileShare->File().Mount()==iCurrentMount && ((fileShare->iMode&EFileWrite)!=0))
+ {
+ FileShares->Unlock();
+ return(ETrue);
+ }
+ }
+ FileShares->Unlock();
+ }
+ return(EFalse);
+ }
+
+
+
+
+/**
+Tests whether the current function can cause a write to disk.
+
+@return True, if the current function can cause a write to disk,
+ false otherwise.
+*/
+EXPORT_C TBool TDrive::IsCurrentWriteFunction() const
+ {
+// __CHECK_DRIVETHREAD(iDriveNumber);
+ CDriveThread* pT=NULL;
+ TInt r=FsThreadManager::GetDriveThread(iDriveNumber, &pT);
+ __ASSERT_ALWAYS(r==KErrNone && pT,Fault(EDriveCurrentWriteFunction));
+ return(pT->IsRequestWriteable());
+ }
+
+
+
+
+TInt TDrive::ForceRemountDrive(const TDesC8* aMountInfo,TInt aMountInfoMessageHandle,TUint aFlags)
+//
+// Force a remount of the drive
+//
+ {
+ __PRINT(_L("TDrive::ForceRemountDrive"));
+ __CHECK_DRIVETHREAD(iDriveNumber);
+ if(iFSys==NULL)
+ return(KErrNotReady);
+ TInt r;
+ CMountCB* pM=NULL;
+ TRACE2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewMountL, EF32TraceUidFileSys, &FSys(), DriveNumber());
+ TRAP(r,pM=FSys().NewMountL());
+ TRACERET2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewMountLRet, EF32TraceUidFileSys, r, pM);
+ if(r!=KErrNone)
+ return(r);
+ pM->SetDrive(this);
+
+ TRACE4(UTF::EBorder, UTraceModuleFileSys::ECMountCBForceRemountDrive, EF32TraceUidFileSys,
+ DriveNumber(), aMountInfo, aMountInfoMessageHandle, aFlags);
+ r=pM->ForceRemountDrive(aMountInfo,aMountInfoMessageHandle,aFlags);
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBForceRemountDriveRet, EF32TraceUidFileSys, r);
+
+ pM->Close();
+ return(r);
+ }
+
+TBool TDrive::IsExtensionMounted(CProxyDriveFactory* aFactory)
+//
+// return ETrue if extension mounted on the drive
+//
+ {
+ for(TInt i=0;i<iExtInfo.iCount;++i)
+ {
+ if(iExtInfo.iInfo[i].iFactory==aFactory)
+ return(ETrue);
+ }
+ return(EFalse);
+ }
+
+TInt TDrive::MountExtension(CProxyDriveFactory* aFactory,TBool aIsPrimary)
+//
+// Mount an extension
+//
+ {
+ __PRINT1(_L("TDrive::MountExtension aIsPrimary=%d"),aIsPrimary);
+ if(aIsPrimary)
+ {
+ __CHECK_MAINTHREAD();
+ // primary extension mounted before file system since it must be present
+ // for successful mount
+ __ASSERT_ALWAYS(!iFSys,Fault(EMountExtensionFSys));
+ if(iExtInfo.iCount!=0)
+ return(KErrAccessDenied);
+ iExtInfo.iInfo[iExtInfo.iCount].iFactory=aFactory;
+ iExtInfo.iInfo[iExtInfo.iCount++].iIsPrimary=ETrue;
+ return(KErrNone);
+ }
+ __CHECK_DRIVETHREAD(iDriveNumber);
+ // must be a secondary extension
+ if(iFSys==NULL)
+ return(KErrNotReady);
+ TBool extSupported = iFSys->IsExtensionSupported();
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFileSystemIsExtensionSupported, EF32TraceUidFileSys, extSupported);
+ if(!extSupported)
+ return(KErrNotSupported);
+ if(IsExtensionMounted(aFactory))
+ return(KErrAlreadyExists);
+ if(iCurrentMount && (CurrentMount().LockStatus()!=0 || Mount().Count()>1))
+ return(KErrInUse);
+ if(iExtInfo.iCount>=KMaxExtensionCount)
+ return(KErrAccessDenied);
+ iExtInfo.iInfo[iExtInfo.iCount].iFactory=aFactory;
+ iExtInfo.iInfo[iExtInfo.iCount++].iIsPrimary=EFalse;
+ // now dismount and mount so that the extension incorporated
+ Dismount();
+ TInt r=CheckMount();
+ // if mount fails then remove the secondary extension
+ if(r!=KErrNone)
+ {
+ --iExtInfo.iCount;
+ __ASSERT_DEBUG(iExtInfo.iCount>=0,Fault(EExtensionInfoCount0));
+ }
+ return(r);
+ }
+
+TInt TDrive::DismountExtension(CProxyDriveFactory* aFactory, TBool /*aIsPrimary*/)
+//
+// Dismount an extension
+//
+ {
+ __PRINT(_L("TDrive::DismountExtension"));
+ __CHECK_DRIVETHREAD(iDriveNumber);
+
+ // Empty closed file queue
+ TClosedFileUtils::Remove(DriveNumber());
+
+ if(iExtInfo.iCount==0)
+ return(KErrNotFound);
+ if(iCurrentMount && (CurrentMount().LockStatus()!=0 || Mount().Count()>1))
+ return(KErrInUse);
+ for(TInt i=0;i<iExtInfo.iCount;++i)
+ {
+ if(iExtInfo.iInfo[i].iFactory==aFactory)
+ {
+ // cannot dismount a primary extension without dismounting the file system
+ if(i==0 && iExtInfo.iInfo[i].iIsPrimary)
+ return(KErrAccessDenied);
+ // slide any remaining extensions down
+ for(TInt j=i+1;j<iExtInfo.iCount;++j)
+ iExtInfo.iInfo[j-1].iFactory=iExtInfo.iInfo[j].iFactory;
+ iExtInfo.iCount--;
+ __ASSERT_DEBUG(iExtInfo.iCount>=0,Fault(EExtensionInfoCount1));
+ Dismount();
+ return(KErrNone);
+ }
+ }
+ return(KErrNotFound);
+ }
+
+TInt TDrive::ExtensionName(TDes& aExtensionName,TInt aPos)
+//
+// Return the extension name
+//
+ {
+ __CHECK_DRIVETHREAD(iDriveNumber);
+
+ if(iFSys==NULL)
+ return(KErrNotReady);
+
+ if(aPos<iExtInfo.iCount)
+ {
+ aExtensionName=iExtInfo.iInfo[aPos].iFactory->Name();
+ return(KErrNone);
+ }
+ return(KErrNotFound);
+ }
+
+#if defined(_LOCKABLE_MEDIA)
+
+TInt TDrive::LockDevice(TMediaPassword& aOld,TMediaPassword& aNew,TBool aStore)
+//
+// Lock media device
+//
+ {
+ __PRINT(_L("TDrive::LockDevice"));
+ __CHECK_DRIVETHREAD(iDriveNumber);
+ if(iFSys==NULL)
+ return(KErrNotReady);
+ TInt r;
+ CMountCB* pM=NULL;
+ TRACE2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewMountL, EF32TraceUidFileSys, &FSys(), DriveNumber());
+ TRAP(r,pM=FSys().NewMountL());
+ TRACERET2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewMountLRet, EF32TraceUidFileSys, r, pM);
+ if(r!=KErrNone)
+ return(r);
+ pM->SetDrive(this);
+
+ TRACE2(UTF::EBorder, UTraceModuleFileSys::ECMountCBLock, EF32TraceUidFileSys, DriveNumber(), aStore);
+ r=pM->Lock(aOld,aNew,aStore);
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBLockRet, EF32TraceUidFileSys, r);
+
+ pM->Close();
+ return(r);
+ }
+
+TInt TDrive::UnlockDevice(TMediaPassword& aPassword,TBool aStore)
+//
+// Unlock media device
+//
+ {
+ __PRINT(_L("TDrive::UnlockDevice"));
+ __CHECK_DRIVETHREAD(iDriveNumber);
+ if(iFSys==NULL)
+ return(KErrNotReady);
+ TInt r;
+ CMountCB* pM=NULL;
+ TRACE2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewMountL, EF32TraceUidFileSys, &FSys(), DriveNumber());
+ TRAP(r,pM=FSys().NewMountL());
+ TRACERET2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewMountLRet, EF32TraceUidFileSys, r, pM);
+ if(r!=KErrNone)
+ return(r);
+
+ // reset mount failure count - which is likely to be non-zero if drive is locked
+ iMountFailures = 0;
+
+ pM->SetDrive(this);
+
+ TRACE2(UTF::EBorder, UTraceModuleFileSys::ECMountCBUnlock, EF32TraceUidFileSys, DriveNumber(), aStore);
+ r=pM->Unlock(aPassword,aStore);
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBUnlockRet, EF32TraceUidFileSys, r);
+
+ pM->Close();
+ return(r);
+ }
+
+TInt TDrive::ClearDevicePassword(TMediaPassword& aPassword)
+//
+// Clear password of media device
+//
+ {
+ __PRINT(_L("TDrive::ClearDevicePassword"));
+ __CHECK_DRIVETHREAD(iDriveNumber);
+ if(iFSys==NULL)
+ return(KErrNotReady);
+ TInt r;
+ CMountCB* pM=NULL;
+ TRACE2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewMountL, EF32TraceUidFileSys, &FSys(), DriveNumber());
+ TRAP(r,pM=FSys().NewMountL());
+ TRACERET2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewMountLRet, EF32TraceUidFileSys, r, pM);
+ if(r!=KErrNone)
+ return(r);
+ pM->SetDrive(this);
+
+ // ClearPassword() will only work if the card is already unlocked.
+ // If the stack powers down, the card will become locked, so now that TBusLocalDrive::Caps()
+ // no longer powers up ths stack, we need to unlock the card first - but ignore the error as
+ // the stack may unlock from the password store.
+ TDriveInfo info;
+ DriveInfo(info);
+ if (info.iMediaAtt & KMediaAttLocked)
+ UnlockDevice(aPassword, EFalse);
+
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECMountCBClearPassword, EF32TraceUidFileSys, DriveNumber());
+ r=pM->ClearPassword(aPassword);
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBClearPasswordRet, EF32TraceUidFileSys, r);
+
+ pM->Close();
+ return(r);
+ }
+
+TInt TDrive::EraseDevicePassword()
+//
+// Erase password from the media device
+//
+ {
+ __PRINT(_L("TDrive::EraseDevicePassword"));
+ __CHECK_DRIVETHREAD(iDriveNumber);
+ if(iFSys==NULL)
+ return(KErrNotReady);
+ TInt r;
+ CMountCB* pM=NULL;
+ TRACE2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewMountL, EF32TraceUidFileSys, &FSys(), DriveNumber());
+ TRAP(r,pM=FSys().NewMountL());
+ TRACERET2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewMountLRet, EF32TraceUidFileSys, r, pM);
+ if(r!=KErrNone)
+ return(r);
+ pM->SetDrive(this);
+
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECMountCBErasePassword, EF32TraceUidFileSys, DriveNumber());
+ r=pM->ErasePassword();
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBErasePasswordRet, EF32TraceUidFileSys, r);
+
+ pM->Close();
+ return(r);
+ }
+
+#else
+
+TInt TDrive::LockDevice(TMediaPassword& /*aOld*/,TMediaPassword& /*aNew*/,TBool /*aStore*/)
+//
+// Lock media device
+//
+ {
+ return(KErrNotSupported);
+ }
+
+TInt TDrive::UnlockDevice(TMediaPassword& /*aPassword*/,TBool /*aStore*/)
+//
+// Unlock media device
+//
+ {
+ return(KErrNotSupported);
+ }
+
+TInt TDrive::ClearDevicePassword(TMediaPassword& /*aPassword*/)
+//
+// Clear password of media device
+//
+ {
+ return(KErrNotSupported);
+ }
+
+TInt TDrive::EraseDevicePassword(TMediaPassword& /*aPassword*/)
+//
+// Clear password of media device
+//
+ {
+ return(KErrNotSupported);
+ }
+
+#endif
+
+
+
+
+/**
+Gets the current notification state, which indicates whether the client
+is notified of any read or write failures.
+
+The notification status is a property of the current session with
+the file server, the value of which is stored in CSessionFs::iNotifyUser.
+If set to ETrue, the client will receive notifications from the file system.
+
+Called by CMountCB::GetNotifyUser().
+
+@return True, if the client receives notifications from the file system,
+ false otherwise.
+
+@see CMountCB
+*/
+EXPORT_C TBool TDrive::GetNotifyUser()
+ {
+ __CHECK_DRIVETHREAD(iDriveNumber);
+ if(iDriveFlags & ENotifyOff)
+ return(EFalse);
+ else
+ {
+ CDriveThread* pT=NULL;
+
+ const TInt r=FsThreadManager::GetDriveThread(iDriveNumber,&pT);
+
+ //-- if this drive is synchronous, i.e. all requests are processed in the main FS thread,
+ //-- pretend that user notifications are turned off to avoid panic in the assert below.
+ //-- for synch. drives pT will always be NULL and it's not possible to obtain CSessionFs by drive number.
+ if(r == KErrAccessDenied)
+ return EFalse;
+
+ __ASSERT_ALWAYS(r==KErrNone && pT,Fault(EDriveGetNotifyUser));
+ return(pT->IsSessionNotifyUser());
+ }
+ }
+
+
+
+
+/**
+Dismounts the current mount. This is method is called from outside, so do some finalisation work on mount.
+After calling this function there is no current mount on the drive.
+*/
+EXPORT_C void TDrive::Dismount()
+ {
+ __PRINT1(_L("TDrive::Dismount() iCurrentMount:0x%x"),iCurrentMount);
+
+ iMountFailures = 0;
+ if (!iCurrentMount)
+ return;
+
+ TRAP_IGNORE(FlushCachedFileInfoL());
+
+ //-- try our best to finalise the mount (the mount can decide to do some job during finalisation, e.g. write some data)
+ TRAP_IGNORE(iCurrentMount->FinaliseMountL());
+
+ DoDismount();
+ }
+
+
+
+
+/**
+Forcibly dismounts the current mount and prevents it being remounted.
+After calling this function there is no current mount on the drive.
+*/
+void TDrive::ForceDismount()
+ {
+ __PRINT1(_L("TDrive::ForceDismount() iCurrentMount:0x%x"),iCurrentMount);
+
+ iMountFailures = 0;
+
+ if(!iCurrentMount)
+ return;
+
+ TRAP_IGNORE(FlushCachedFileInfoL());
+ iCurrentMount->SetDismounted(); //! this affects TDrive::ReMount()
+ DoDismount();
+ }
+
+/**
+ An internal method. Dismounts and closes a current mount.
+ This method must not involve writing data to the media, because it could have beeen physically changed before.
+ Called only from TDrive::CheckMount().
+*/
+void TDrive::DoDismount()
+ {
+ __PRINT1(_L("TDrive::DoDismount() iCurrentMount:0x%x"),iCurrentMount);
+
+ iMountFailures = 0;
+
+ if (!iCurrentMount)
+ return;
+
+ TRACE1(UTF::EBorder, UTraceModuleFileSys::ECMountCBDismounted, EF32TraceUidFileSys, DriveNumber());
+ iCurrentMount->Dismounted();
+ TRACE0(UTF::EBorder, UTraceModuleFileSys::ECMountCBDismountedRet, EF32TraceUidFileSys);
+
+ iCurrentMount->Close();
+ iCurrentMount=NULL;
+ }
+
+
+/**
+Return the number of active mounts associated with this drive.
+(inactive mounts are those that have been forcibly dismounted)
+*/
+TInt TDrive::ActiveMounts() const
+ {
+ TInt activeMounts = 0;
+
+ TInt idx = Mount().Count();
+ while(idx--)
+ {
+ if(((CMountCB*)Mount()[idx])->IsDismounted())
+ {
+ activeMounts++;
+ }
+ }
+
+ __PRINT1(_L("TDrive::ActiveMounts = %d"), activeMounts);
+ return activeMounts;
+ }
+
+
+
+
+/**
+Reactivate any disactive mounts on the drive following a dismount.
+(inactive mounts are those that have been foribly dismounted)
+*/
+void TDrive::ReactivateMounts()
+ {
+ __PRINT(_L("TDrive::ReactivateMounts"));
+
+ TInt idx = Mount().Count();
+ while(idx--)
+ {
+ ((CMountCB*)Mount()[idx])->SetDismounted(EFalse);
+ }
+ }
+
+
+
+
+/**
+Increments the drive dismount lock. This defers dismount
+of a file system until all clients have notified that it
+is safe to do so.
+
+@see RFs::NotifyDismount
+*/
+void TDrive::DismountLock()
+ { iDismountLock++; }
+
+
+
+
+/**
+Decrements the drive dismount lock. When the lock count
+reaches zero, the file system may be unmounted
+
+@see RFs::AllowDismount
+@return The new lock count
+*/
+TInt TDrive::DismountUnlock()
+ {
+ return(--iDismountLock);
+ }
+
+
+
+
+/**
+Return the state of the dismount lock.
+*/
+TBool TDrive::DismountLocked() const
+ { return(iDismountLock); }
+
+
+
+
+/**
+Pending flag - set while waiting for clients to accept the dismount
+*/
+void TDrive::SetDismountDeferred(TBool aPending)
+ {
+ if(aPending)
+ iDriveFlags |= EDismountDeferred;
+ else
+ iDriveFlags &= ~EDismountDeferred;
+ }
+
+
+
+TInt TDrive::ControlIO(const RMessagePtr2& aMessage,TInt aCommand,TAny* aParam1,TAny* aParam2)
+//
+// General purpose test interface - .FSY specific.
+//
+ {
+ TInt r=CheckMount();
+ if(r==KErrNone || (r==KErrInUse && iReason==KErrNone))
+ {
+ TRACETHREADID(aMessage);
+ TRACE5(UTF::EBorder, UTraceModuleFileSys::ECMountCBControlIO, EF32TraceUidFileSys,
+ DriveNumber(), aCommand, aParam1, aParam2, I64LOW(threadId));
+ r=CurrentMount().ControlIO(aMessage,aCommand,aParam1,aParam2);
+ TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBControlIORet, EF32TraceUidFileSys, r);
+ }
+ return(r);
+ }
+
+
+
+
+/**
+Gets the drive attributes
+
+@return The drive attributes.
+*/
+EXPORT_C TUint TDrive::Att()
+ {
+ TUint a=iAtt;
+ return(a);
+ }
+
+void TDrive::SetAtt(TUint aValue)
+//
+// set drive attributes
+//
+ {
+ iAtt=aValue;
+ }
+
+EXPORT_C TBool TDrive::IsDriveThread() const
+//
+// Return ETrue if the current thread id is the same as that of the drive's drive thread
+//
+ {
+ return(FsThreadManager::IsDriveThread(iDriveNumber,ETrue));
+ }
+
+EXPORT_C TBool TDrive::IsMainThread() const
+//
+// Reture ETrue if the current thread id is the same as that of the main file server thread
+//
+ {
+ return(FsThreadManager::IsMainThread());
+ }
+
+EXPORT_C void TDrive::DriveFault(TBool aDriveError) const
+//
+//
+//
+ {
+ if(aDriveError)
+ ::Fault(EFsDriveThreadError);
+ else
+ ::Fault(EFsMainThreadError);
+ }
+
+TInt TDrive::ClampFile(const TDesC& aName, TAny* aHandle)
+//
+// Attempt to clamp file
+//
+ {
+ CMountCB* mount = (CMountCB*)&(CurrentMount());
+ TInt driveNo = DriveNumber();
+ return(mount->ClampFile(driveNo,aName,aHandle));
+ }
+
+
+TInt TDrive::UnclampFile(CMountCB* aMount, RFileClamp* aHandle)
+//
+// Attempt to unclamp file
+//
+ {
+ return(aMount->UnclampFile(aHandle));
+ }
+
+
+TInt TDrive::ClampsOnDrive()
+//
+// Returns the number of clamps on this drive
+//
+ {
+ Lock();
+ TInt clamps = IsMounted()?((CMountCB*)&(CurrentMount()))->NoOfClamps():0;
+ UnLock();
+ return (clamps);
+ }
+
+
+
+void TDrive::SetClampFlag(TBool aClamped)
+//
+// Indicate if any files are clamped
+//
+ {
+ if(aClamped)
+ iDriveFlags |= EClampPresent;
+ else
+ iDriveFlags &= ~EClampPresent;
+ }
+
+
+TBool TDrive::ClampFlag()
+//
+// Report if any files are clamped
+//
+ { return(iDriveFlags & EClampPresent); }
+
+
+
+#if defined(_DEBUG) || defined(_DEBUG_RELEASE)
+TInt TDrive::ClearDeferredDismount()
+// debug-only function for testing
+ {
+ Lock();
+ FsNotify::HandleDismount(EFsDismountRegisterClient, DriveNumber(), ETrue, KErrNone);
+ SetDismountDeferred(EFalse);
+ UnLock();
+ return KErrNone;
+ }
+#endif
+
+
+TInt TDrive::DismountProxyDrive()
+//
+// Dismount a proxy drive
+//
+ {
+ __PRINT(_L("TDrive::DismountProxyDrive"));
+ __CHECK_DRIVETHREAD(iDriveNumber);
+
+ if (!IsProxyDrive(iDriveNumber) || LocalDrives::DriveNumberToLocalDriveNumber(iDriveNumber) == KDriveInvalid)
+ return KErrArgument;
+
+ if(iCurrentMount)
+ return(KErrInUse);
+
+
+ // Prevent ALL inactive mounts from EVER being remounted as they MAY (& probably do) point to
+ // this proxy-drive which we are about to delete....
+ // NB We could try to find out which mounts actually use this particular proxy-drive, but that's
+ // a bit tricky to determine if there are extensions present as CMountCB::ProxyDrive() will only
+ // return the first proxy drive in the chain.
+ TInt mCount=Mount().Count();
+ TInt u=(Mount().UniqueID()<<16);
+ for (TInt i=0;i<mCount;i++)
+ {
+ CMountCB* pM=(CMountCB*)Mount().At(u|i);
+ pM->SetProxyDriveDismounted();
+ }
+
+ FsThreadManager::LockDrive(iDriveNumber);
+ // Proxy drives are responsible for managing the drive threads...
+ FsThreadManager::CloseDrive(iDriveNumber);
+ LocalDrives::ClearProxyDriveMapping(iDriveNumber);
+ FsThreadManager::UnlockDrive(iDriveNumber);
+
+ return KErrNone;
+ }
+
+//----------------------------------------------------------------------------
+/**
+ Complete, remove and delete notification requests
+ @param aCompletionCode completion code for some notifications
+*/
+void TDrive::DoCompleteDismountNotify(TInt aCompletionCode)
+ {
+ FsNotify::HandleDismount(EFsDismountRegisterClient, iDriveNumber, ETrue, KErrNone);
+ FsNotify::HandleDismount(EFsDismountNotifyClients, iDriveNumber, ETrue, aCompletionCode);
+ FsNotify::HandleDismount(EFsDismountForceDismount, iDriveNumber, ETrue, aCompletionCode);
+ }
+
+//----------------------------------------------------------------------------
+/**
+ a helper method that allows forced dismounting current mount for volume formatting.
+*/
+TInt TDrive::ForceUnmountFileSystemForFormatting()
+ {
+ TInt nRes;
+
+ //-- check if there are any clamps on this drive
+ nRes = ClampsOnDrive();
+ if(nRes > 0)
+ return KErrInUse;
+
+ //-- purge all dirty data in the files associated with this drive's mount
+ CDriveThread* pT=NULL;
+ nRes = FsThreadManager::GetDriveThread(DriveNumber(), &pT);
+ if(nRes == KErrNone && pT)
+ {
+ pT->CompleteReadWriteRequests();
+ }
+
+ PurgeDirty(CurrentMount());
+
+ //--
+
+ ForceDismount();
+
+ DoCompleteDismountNotify(KErrDisMounted); //-- complete all dismount notifications
+
+ return KErrNone;
+ }
+
+//-----------------------------------------------------------------------------
+/**
+ Instantiate CFormatCB object for formatting the file ssytem on the given TDrive.
+
+ @param aRequest file server request object
+ @param aFmtHandle out: format handle
+ @param aFmtMode format mode
+ @param apLDFormatInfo pointer to legacy parameters structure; NULL means "not used"
+ @param apVolFormatParam pointer to the newparameters structure; NULL means "not used"
+
+ @return pointer to the instantiated CFormatCB object.
+*/
+CFormatCB* TDrive::FormatOpenL(CFsRequest* aRequest, TInt& aFmtHandle, TFormatMode aFmtMode, const TLDFormatInfo* apLDFormatInfo, const TVolFormatParam* apVolFormatParam)
+ {
+ ASSERT(!(apLDFormatInfo && apVolFormatParam)); //-- these parameters are mutually exclusive
+
+ TRACE2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewFormatL, EF32TraceUidFileSys, &FSys(), DriveNumber());
+
+ CFormatCB* pFormat = CurrentMount().NewFormatL();
+
+ TRACE2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewFormatLRet, EF32TraceUidFileSys, KErrNone, pFormat);
+
+ Formats->AddL(pFormat, ETrue);
+ pFormat->InitL(this, aFmtMode);
+
+ if(aFmtMode & ESpecialFormat)
+ {
+ if(apLDFormatInfo)
+ {//-- the user has specified formatting parameters as TLDFormatInfo
+ pFormat->SetFormatParameters(apLDFormatInfo);
+ }
+ else if(apVolFormatParam && apVolFormatParam->SomeParamsSet())
+ {//-- the user has specified formatting parameters as TVolFormatParam
+ TInt nRes = pFormat->SetFormatParameters(apVolFormatParam);
+ User::LeaveIfError(nRes); //-- the particular file system might not support this feature
+ }
+ else
+ {//-- this is a special case, ESpecialFormat is set, but no parameters provided at all;
+ //-- invalidate CFormatCB::iSpecialInfo to make filesystem not to use it
+ pFormat->SetFormatParameters((TLDFormatInfo*)NULL);
+ }
+ }
+
+
+ // modify resource counter after initialised to ensure correct cleanup
+ AddDiskAccess(CurrentMount());
+ aFmtHandle = aRequest->Session()->Handles().AddL(pFormat, ETrue);
+
+ return pFormat;
+ }
+
+
+
+
+
+EXPORT_C void UNUSED1() {}
+EXPORT_C void UNUSED2() {}
+EXPORT_C void UNUSED3() {}
+
+
+
+
+
+
+
+
+