userlibandfileserver/fileserver/sfile/sf_obj.cpp
changeset 43 96e5fb8b040d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/sfile/sf_obj.cpp	Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,953 @@
+// Copyright (c) 2002-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_obj.cpp
+// 
+//
+
+#include "sf_std.h"
+
+const TInt KObjectIxGranularity=8;		
+const TInt KObjectConGranularity=8;
+const TInt KObjectConIxGranularity=4;
+const TInt KObjectIndexMask=0x7fff;
+const TInt KObjectMaxIndex=0x7fff;
+const TInt KObjectInstanceShift=16;
+const TInt KObjectInstanceMask=0x3fff;
+const TInt KObjectUniqueIDShift=16;
+const TInt KObjectIxMaxHandles=0x8000;
+
+inline TInt index(TInt aHandle)
+	{return(aHandle&KObjectIndexMask);}
+inline TInt instance(TInt aHandle)
+	{return((aHandle>>KObjectInstanceShift)&KObjectInstanceMask);}
+inline TInt instanceLimit(TInt& aCount)
+	{return ((aCount&KObjectInstanceMask)==0) ? ((++aCount)&KObjectInstanceMask) : aCount&KObjectInstanceMask;}
+inline TInt makeHandle(TInt anIndex,TInt anInstance)
+	{return((TInt)((anInstance<<KObjectInstanceShift)|anIndex));}
+
+inline TInt uniqueID(TInt aHandle)
+	{return((aHandle>>KObjectUniqueIDShift)&KObjectInstanceMask);}
+inline TInt makeFindHandle(TInt anIndex,TInt anUniqueID)
+	{return((TInt)((anUniqueID<<KObjectUniqueIDShift)|anIndex));}
+
+
+CFsObjectConIx* CFsObjectConIx::NewL()
+//
+// Create an instance of this class.
+//
+	{
+
+	return new(ELeave) CFsObjectConIx;
+	}
+
+CFsObjectConIx::CFsObjectConIx()
+//
+// Constructor
+//
+	: iNextUniqueID(1)
+	{
+	}
+
+CFsObjectConIx::~CFsObjectConIx()
+//
+// Destructor
+//
+	{
+	if (iCount)
+		{
+		TInt i=-1;
+		while(++i<iCount)
+			{
+			CFsObjectCon* pS=iContainers[i];
+			delete pS;
+			}
+		}
+	delete iContainers;
+	}
+
+void CFsObjectConIx::CreateContainerL(CFsObjectCon*& aContainer)
+//
+// Actually create the container
+//
+	{
+
+	aContainer=CFsObjectCon::NewL();
+	aContainer->iUniqueID=iNextUniqueID;
+	if (iCount==iAllocated)
+		{
+		TInt newAlloc=iAllocated+KObjectConIxGranularity;
+		iContainers=(CFsObjectCon**)User::ReAllocL(iContainers, newAlloc*sizeof(CFsObjectCon*));
+		iAllocated=newAlloc;
+		}
+	iContainers[iCount++]=aContainer;
+	}
+
+CFsObjectCon* CFsObjectConIx::CreateL()
+//
+// Create a new container.
+//
+	{
+
+	CFsObjectCon* pC=NULL;
+	TRAPD(r,CreateContainerL(pC))
+	if (r!=KErrNone)
+		{
+		delete pC;
+		User::Leave(r);
+		}
+	iNextUniqueID++;
+	return pC;
+	}
+
+void CFsObjectConIx::Remove(CFsObjectCon* aCon)
+//
+// Remove a container from the index.
+//
+	{
+	if (!aCon)
+		return;
+	CFsObjectCon** pS=iContainers;
+	CFsObjectCon** pE=pS+iCount;
+	while(pS<pE)
+		{
+		if (*pS==aCon)
+			{
+			Mem::Move((TAny*)pS,(TAny*)(pS+1),TInt(pE)-TInt(pS)-sizeof(CFsObjectCon*));
+			TInt newAlloc=--iCount;
+			newAlloc=(newAlloc+(KObjectConIxGranularity-1))&~(KObjectConIxGranularity-1);
+			if (newAlloc!=iAllocated)
+				{
+				if (newAlloc)
+					iContainers=(CFsObjectCon**)User::ReAlloc(iContainers,newAlloc*sizeof(CFsObjectCon*));
+				else
+					{
+					delete iContainers;
+					iContainers=NULL;
+					}
+				iAllocated=newAlloc;
+				}
+			delete aCon;
+			return;
+			}
+		pS++;
+		}
+	Fault(EObjRemoveContainerNotFound);
+	}
+
+
+/**
+Constructs the object and initializes the reference count to one. 
+ 
+Once constructed, a reference counting object cannot be deleted until its 
+reference count is reduced to zero. 
+ 
+@see CFsObject::Close
+*/
+EXPORT_C CFsObject::CFsObject()
+	{
+
+//	iContainer=NULL;
+//	iName=NULL;
+	iAccessCount=1;
+	}
+
+
+/**
+Destructor.
+ 
+Deallocates memory associated with this objects name, if a name 
+has been set.
+ 
+@panic FSERV 104 if the reference count is not zero when
+       the destructor is called.
+*/
+EXPORT_C  CFsObject::~CFsObject()
+	{
+	__PRINT1(_L("CFsObject::~CFsObject() 0x%x"),this);
+	__ASSERT_ALWAYS(Dec()==0,Fault(EObjDestructorAccessCount));	
+	__ASSERT_ALWAYS(!iContainer,Fault(EObjDestructorContainer));
+	if(iName)
+		User::Free(iName);
+	}
+
+
+/**
+Opens this reference counting object.
+
+The default behaviour increments the reference count by one. 
+
+Where a derived class implements its own version of this function, it must 
+either use the protected member function Inc() to increment the reference 
+count or make a base call to this function.
+
+@return KErrNone, or another system-wide error code.
+*/
+
+EXPORT_C TInt CFsObject::Open()
+	{
+	TInt count=Inc();
+	(void)count;
+	__THRD_PRINT2(_L("CFsObject::Open() object=0x%x count=%d"),this,count);
+	__ASSERT_DEBUG(count>=1,Fault(EFsObjectOpen));
+	return KErrNone;
+	}
+
+
+/**
+Removes an assigned container object then deletes this reference
+counting object.
+*/
+void CFsObject::DoClose()
+	{
+	__THRD_PRINT(_L("CFsObject::DoClose()"));
+	if(iContainer)
+		{
+		iContainer->Remove(this,ETrue);
+		iContainer=NULL;
+		}
+	delete(this);
+	}
+
+
+/**
+Closes this reference counting object.
+
+The default behaviour decrements the reference count by one. If this becomes 
+zero, then the function calls DoClose on this reference counting object.
+ 
+Where a derived class implements its own version of this function, it can 
+use the protected member functions Dec() & DoClose() or make a base call to 
+this function.
+
+@see CFsObject::DoClose
+*/
+EXPORT_C void CFsObject::Close()
+	{
+	__THRD_PRINT(_L("CFsObject::Close()"));
+	if(Dec()==1)
+		DoClose();
+	}
+
+
+/**
+Determine if this object is within the correct drive thread context 
+for file based operations.
+
+The default behaviour is to return True.
+
+A derived class implementation is required.
+
+@return ETrue
+*/
+EXPORT_C TBool CFsObject::IsCorrectThread()
+	{
+	return(ETrue);
+	}
+
+
+
+/**
+Sets or clears this reference counting object's name.
+
+To set the name, the specified descriptor must contain the name to be set. 
+Once the name has been successfully set, then the specified source descriptor 
+can be discarded.
+
+To clear an existing name, specify a NULL argument.
+
+@param aName A pointer to the descriptor containing the name to be set, or 
+             NULL if an existing name is to be cleared.
+
+@return KErrNone if the function is successful;
+        KErrNoMemory if there is insufficient memory available.
+
+@panic USER 11 if the length of aName is greater than KMaxName
+       for a 16-bit descriptor.
+@panic USER 23 if the length of aName is greater than KMaxName
+       for an 8-bit descriptor.
+*/
+EXPORT_C TInt CFsObject::SetName(const TDesC *aName)
+	{
+	User::Free(iName);
+	iName=NULL;
+	if (aName!=NULL)
+		{
+		iName=aName->Alloc();
+		if (iName==NULL)
+			return(KErrNoMemory);
+		}
+	return(KErrNone);
+	}
+
+
+/**
+Gets the name of this reference counting object.
+
+The default behaviour provided by this function depends on whether a name 
+has been explicitly set into the object:
+
+If a name has previously been set, then the function returns that name.
+
+If a name has not been set, then the function returns NULL.
+
+@return A modifiable buffer descriptor with a defined maximum length containing 
+        the name of this reference counting object or a TName with no contents.
+*/
+EXPORT_C TName CFsObject::Name() const
+	{
+	if (iName)
+		return(*iName);
+	
+	TName empty;
+	return empty;
+	}
+
+
+/**
+Gets the Unique ID of the assigned object container to this object.
+
+@return A unique number for file system container objects.
+*/
+TInt CFsObject::UniqueID() const {return(iContainer->UniqueID());}
+
+
+CFsObjectIx* CFsObjectIx::NewL()
+//
+// Create an instance of this class.
+//
+	{
+	CFsObjectIx* pO=new(ELeave) CFsObjectIx;
+	TInt r=pO->iLock.CreateLocal();
+	if(r!=KErrNone)
+		{
+		delete(pO);
+		User::Leave(r);
+		}
+	return(pO);
+	}
+
+CFsObjectIx::CFsObjectIx()
+//
+// Constructor
+//
+	: iNextInstance(1)
+	{
+//	iAllocated=0;
+//	iNumEntries=0;
+//	iHighWaterMark=0;
+//	iObjects=NULL;
+	}
+
+
+/**
+    Close all objects that were created in the main file server thread.
+    For sync. drives all objects must be closed in the main file server thread, because
+    they are created in this thread, as soon as all synch. requests are processed there.
+*/
+void CFsObjectIx::CloseMainThreadObjects()
+	{
+	__ASSERT_DEBUG(FsThreadManager::IsMainThread(),Fault(EObjectIxMainThread));
+	__PRINT(_L("CFsObjectIx::CloseThreadObjects()"));
+    
+	Lock();
+	// We have to be very careful here. Calling Close() on the objects in the array
+	// may result in other entries being removed from the array before we delete
+	// them here, and may result in the array being ReAlloc()ed, corrupting the removed
+	// entries, hence we must check the iHighWaterMark value each time round the loop.
+	TInt i=-1;
+	while(++i<iHighWaterMark)
+		{
+		SFsObjectIxRec* pS=iObjects+i;
+		CFsObject *pO=pS->obj;
+		if (pO && pO->IsCorrectThread())
+			{
+			// invalidate entry before closing it
+			pS->obj=NULL;
+			pO->Close();	
+			}
+		}
+	Unlock();
+	}
+
+
+CFsObjectIx::~CFsObjectIx()
+//
+// Destructor
+// Assumes that no need to lock
+//
+	{
+	__PRINT1(_L("CFsObjectIx::~CFsObjectIx() 0x%x"),this);
+    
+	// We have to be very careful here. Calling Close() on the objects in the array
+	// may result in other entries being removed from the array before we delete
+	// them here, and may result in the array being ReAlloc()ed, corrupting the removed
+	// entries, hence we must check the iHighWaterMark value each time round the loop.
+	TInt i=-1;
+	while(++i<iHighWaterMark)
+		{
+		SFsObjectIxRec* pS=iObjects+i;
+		CFsObject *pO=pS->obj;
+		if (pO)
+			{
+			// invalidate entry before closing it
+			pS->obj=NULL;
+			pO->Close();	
+			}
+		}
+	delete iObjects;
+	iLock.Close();
+	}
+
+TInt CFsObjectIx::AddL(CFsObject* anObj,TBool aLock)
+//
+// Add a new object to the index.
+//
+	{
+	if(aLock)
+		Lock();
+	SFsObjectIxRec *pS=iObjects;
+	SFsObjectIxRec *pE=pS+iHighWaterMark;
+	TInt i=0;
+	TInt inc=0;
+	while(pS<pE && pS->obj)
+		pS++, i++;
+	if (pS==pE)
+		inc=1;
+	if (pS==pE && iAllocated==iHighWaterMark)
+		{
+		// no slots free, so reallocate array
+		if (iHighWaterMark==KObjectIxMaxHandles)
+			{
+			if(aLock)
+				Unlock();
+			User::LeaveNoMemory();
+			}
+		TInt newAlloc=iAllocated + KObjectIxGranularity;
+		SFsObjectIxRec* pA=(SFsObjectIxRec*)User::ReAlloc(iObjects, newAlloc*sizeof(SFsObjectIxRec));
+		if(!pA)
+			{
+			if(aLock)
+				Unlock();
+			User::Leave(KErrNoMemory);
+			}
+		iObjects=pA;
+		iAllocated=newAlloc;
+		i=iHighWaterMark;
+		pS=pA+i;
+		}
+	pS->obj=anObj;
+	pS->uniqueID=(TUint16)anObj->UniqueID();
+	pS->instance=(TUint16)instanceLimit(iNextInstance);
+	iNextInstance++;
+	iHighWaterMark+=inc;
+	++iNumEntries;
+	TInt h=makeHandle(i,pS->instance);
+	if(aLock)
+		Unlock();
+	return(h);
+	}
+
+void CFsObjectIx::Remove(TInt aHandle,TBool aLock)
+//
+// Remove an object from the index.
+//
+	{
+	if(aLock)
+		Lock();
+	TInt i=index(aHandle);
+	__ASSERT_ALWAYS(i<iHighWaterMark,Fault(EObjRemoveBadHandle));
+	SFsObjectIxRec* pR=iObjects+i;
+	CFsObject *pO=pR->obj;
+	if (!pO || pR->instance!=instance(aHandle) || pR->uniqueID!=pO->UniqueID())
+		Fault(EObjRemoveBadHandle);
+	pR->obj=NULL;
+	--iNumEntries;
+	if (i==iHighWaterMark-1)
+		{
+		do
+			{
+			i--;
+			pR--;
+			} while(i>=0 && !pR->obj);
+		TInt newAlloc=(i+KObjectIxGranularity)&~(KObjectIxGranularity-1);
+		if (newAlloc!=iAllocated)
+			{
+			if (newAlloc)
+				iObjects=(SFsObjectIxRec*)User::ReAlloc(iObjects,newAlloc*sizeof(SFsObjectIxRec));
+			else
+				{
+				delete iObjects;
+				iObjects=NULL;
+				}
+			iAllocated=newAlloc;
+			}
+		iHighWaterMark=i+1;
+		}
+	if(aLock)
+		Unlock();
+	pO->Close();
+	}
+
+CFsObject *CFsObjectIx::At(TInt aHandle,TInt aUniqueID,TBool aLock)
+//
+// Return the object from its handle.
+//
+	{
+	if(aLock)
+		Lock();
+	TInt i=index(aHandle);
+	if (i>=iHighWaterMark)
+		{
+		if(aLock)
+			Unlock();
+		return NULL;
+		}
+	SFsObjectIxRec *pS=iObjects+i;
+	if (pS->instance!=instance(aHandle) || pS->uniqueID!=aUniqueID)
+		{
+		if(aLock)
+			Unlock();
+		return NULL;
+		}
+	if(aLock)
+		Unlock();
+	return pS->obj;	
+	}
+
+CFsObject *CFsObjectIx::At(TInt aHandle,TBool aLock)
+//
+// Return the object from its handle.
+//
+	{
+	if(aLock)
+		Lock();
+	TInt i=index(aHandle);
+	if (i>=iHighWaterMark)
+		{
+		if(aLock)
+			Unlock();
+		return NULL;
+		}
+	SFsObjectIxRec *pS=iObjects+i;
+	if (pS->instance!=instance(aHandle))
+		{
+		if(aLock)
+			Unlock();
+		return NULL;
+		}
+	if(aLock)
+		Unlock();
+	return pS->obj;
+	}
+
+TInt CFsObjectIx::At(const CFsObject* anObj,TBool aLock)
+//
+// Return the handle from an object.
+//
+	{
+	if(aLock)
+		Lock();
+	if (iHighWaterMark)
+		{
+		SFsObjectIxRec* pS=iObjects;
+		SFsObjectIxRec* pE=pS+iHighWaterMark;
+		TInt i=0;
+		while(pS<pE && pS->obj!=anObj)
+			pS++, i++;
+		if (pS<pE)
+			{
+			TInt h=makeHandle(i,pS->instance);
+			if(aLock)
+				Unlock();	
+			return(h);	
+			}
+		}
+	if(aLock)
+		Unlock();
+	return KErrNotFound;
+	}
+
+
+CFsObject* CFsObjectIx::operator[](TInt anIndex)
+//
+// Return the object at anIndex
+//
+	{
+
+	__ASSERT_ALWAYS(anIndex>=0 && anIndex<iHighWaterMark,Fault(EArrayIndexOutOfRange));
+	return iObjects[anIndex].obj;
+	}
+
+CFsObjectCon* CFsObjectCon::NewL()
+//
+// Create a new instance of this class.
+//
+	{
+	CFsObjectCon* pO=new(ELeave) CFsObjectCon(ENotOwnerID);
+	TInt r=pO->iLock.CreateLocal();
+	if(r!=KErrNone)
+		{
+		delete(pO);
+		User::Leave(r);
+		}
+	return(pO);
+	}
+
+CFsObjectCon::CFsObjectCon(TInt aUniqueID)
+//
+// Constructor
+//
+	: iUniqueID(aUniqueID)
+	{
+//	iAllocated=0;
+//	iCount=0;
+//	iObjects=NULL;
+	}
+
+CFsObjectCon::~CFsObjectCon()
+//
+// Destructor
+//
+	{
+	__ASSERT_ALWAYS(iCount==0,Fault(EObjectConDestructor));
+	iLock.Close();
+	delete iObjects;
+	}
+
+void CFsObjectCon::AddL(CFsObject* anObj,TBool aLock)
+//
+// Install a new object to the container. The full name must be unique.
+//
+	{
+	if(anObj->iName)
+		User::LeaveIfError(CheckUniqueName(anObj));
+	if(aLock)
+		Lock();
+	if (iCount==iAllocated)
+		{
+		TInt newAlloc=iAllocated+KObjectConGranularity;
+		CFsObject** pO=(CFsObject**)User::ReAlloc(iObjects, newAlloc*sizeof(CFsObject*));
+		if(!pO)
+			{
+			if(aLock)
+				Unlock();
+			User::Leave(KErrNoMemory);
+			}
+		iObjects=pO;
+		iAllocated=newAlloc;
+		}
+	iObjects[iCount++]=anObj;
+	if (iUniqueID!=ENotOwnerID)
+		anObj->iContainer=this;
+	if(aLock)
+		Unlock();
+	}
+
+void CFsObjectCon::Remove(CFsObject *anObj,TBool aLock)	
+//
+// Remove an object from the container.
+// This assumes that close is called by the calling function
+// 
+	{
+	if(aLock)
+		Lock();
+	CFsObject** pS=iObjects;
+	CFsObject** pE=pS+iCount;
+	while(pS<pE)
+		{
+		if (*pS==anObj)
+			{
+			Mem::Move((TAny*)pS,(TAny*)(pS+1),TInt(pE)-TInt(pS)-sizeof(CFsObject*));
+			TInt newAlloc=--iCount;
+			newAlloc=(newAlloc+(KObjectConGranularity-1))&~(KObjectConGranularity-1);
+			if (newAlloc!=iAllocated)
+				{
+				if (newAlloc)
+					iObjects=(CFsObject**)User::ReAlloc(iObjects,newAlloc*sizeof(CFsObject*));
+				else
+					{
+					delete iObjects;
+					iObjects=NULL;
+					}
+				iAllocated=newAlloc;
+				}
+			if(aLock)
+				Unlock();
+			anObj->iContainer = NULL;
+			return;
+			}
+		pS++;
+		}
+	Fault(EObjRemoveObjectNotFound);
+	}
+
+CFsObject *CFsObjectCon::operator[](TInt anIndex)
+//
+// Return the object at anIndex.
+//
+	{
+	__ASSERT_ALWAYS(anIndex>=0 && anIndex<iCount, Fault(EArrayIndexOutOfRange));
+	return iObjects[anIndex];
+	}
+
+CFsObject *CFsObjectCon::At(TInt aFindHandle) const
+//
+// Return the object at aFindHandle.
+// Should only be used there is no other access to the CFsObject
+//
+	{
+
+	__ASSERT_ALWAYS(uniqueID(aFindHandle)==iUniqueID,Fault(EObjFindBadHandle));
+	TInt ix=index(aFindHandle);
+	__ASSERT_ALWAYS(ix<iCount,Fault(EObjFindIndexOutOfRange));
+	return iObjects[ix];
+	}
+
+CFsObject *CFsObjectCon::AtL(TInt aFindHandle) const
+//
+// Return the object at aFindHandle.
+// Should only be used if no other access to the CFsObject
+//
+	{
+
+	__ASSERT_ALWAYS(uniqueID(aFindHandle)==iUniqueID,User::Leave(KErrBadHandle));
+	TInt ix=index(aFindHandle);
+	__ASSERT_ALWAYS(ix<iCount,User::Leave(KErrArgument));
+	return iObjects[ix];
+	}
+
+LOCAL_C TInt validateName(const TDesC &aName)
+//
+// Return KErrBadName if the name is invalid.
+//
+	{
+
+	if (aName.Locate('*')!=KErrNotFound || aName.Locate('?')!=KErrNotFound || aName.Locate(':')!=KErrNotFound)
+		return(KErrBadName);
+	return(KErrNone);
+	}
+
+
+TBool CFsObjectCon::NamesMatch(const TName& anObjectName, const CFsObject* aCurrentObject) const
+//
+// 
+//
+	{
+
+	if (aCurrentObject->iName==NULL) // current object has no name, therefore not the same
+		return(EFalse);
+	return(anObjectName.Compare(*aCurrentObject->iName)==0); // short names are different, therefore not the same
+	}
+
+TInt CFsObjectCon::CheckUniqueName(const CFsObject* anObject) const
+//
+// Returns KErrBadName if the name is invalid or
+// returns KErrAlreadyExists if the full name is not unique.
+//
+	{
+
+	TName name(*(anObject->iName));
+	TInt r=validateName(name);
+	if (r!=KErrNone)
+		return r;
+
+	if (!iCount)
+		return KErrNone;
+
+	CFsObject** pS=iObjects;
+	CFsObject** pE=pS+iCount;
+
+	// if it's name is null, just need to check it's not already there
+	if (!anObject->iName)
+		{
+		do
+			{
+			if (*pS==anObject)
+				return KErrAlreadyExists;
+			} while(++pS<pE);
+		return KErrNone;
+		}
+
+	do
+		{
+		if (NamesMatch(name,*pS))
+			return KErrAlreadyExists;
+		} while(++pS<pE);
+	return KErrNone;
+	}
+
+TInt CFsObjectCon::FindByName(TInt &aFindHandle,const TDesC &aMatch) const
+//
+// Find an object starting at aFindHandle which matches aMatch
+// just using the objects name.
+//
+	{
+
+	if (!iCount)
+		return KErrNotFound;
+	TInt ix=0;
+	if (aFindHandle!=0)
+		{
+		__ASSERT_ALWAYS(uniqueID(aFindHandle)==iUniqueID,Fault(EObjFindBadHandle));
+		ix=index(aFindHandle)+1;
+		};
+	CFsObject** pS=iObjects;
+	CFsObject** pE=pS+iCount;
+	pS+=ix;
+	while(pS<pE)
+		{
+		TName name=*((*pS++)->iName);
+		if (name.MatchF(aMatch)!=KErrNotFound)
+			{
+			aFindHandle=makeFindHandle(ix,iUniqueID);
+			return KErrNone;
+			}
+		ix++;
+		}
+	aFindHandle=makeFindHandle(KObjectMaxIndex,iUniqueID);
+	return KErrNotFound;
+	}
+
+/**
+Constructs the object and initializes the Drive number as an invalid drive. 
+ 
+Once constructed, a dispatch object cannot be deleted until its reference 
+count is reduced to zero. 
+ 
+@see CFsDispatchObject::Close
+*/
+CFsDispatchObject::CFsDispatchObject()
+	: iDriveNumber(-1) 
+	{}
+
+/**
+Initialises dispatch object
+
+Creates an internal request and sets it as a file resource close operation.
+Initialises drive number as specified.
+
+@param aDrvNumber Drive for which the request is intended.
+*/
+void CFsDispatchObject::DoInitL(TInt aDrvNumber)
+	{
+	CFsInternalRequest* PR= new(ELeave) CFsInternalRequest;
+	__THRD_PRINT1(_L("internal request = 0x%x"),PR);
+	PR->Set(DispatchObjectCloseOp,NULL);
+	iRequest = PR;
+	iRequest->SetDriveNumber(aDrvNumber);
+	iRequest->SetScratchValue((TUint)this);
+	iDriveNumber=aDrvNumber;
+	}
+
+/**
+Closes this dispatch object.
+
+Decrements the reference count by one. If this becomes zero then the request 
+will either call Dispatch() if currently not within the correct thread 
+context otherwise the function calls DoClose() on this dispatch object.
+
+@see CFsDispatchObject::IsCorrectThread
+     CFsDispatchObject::Dispatch
+     CFsObject::DoClose
+*/
+EXPORT_C void CFsDispatchObject::Close()
+	{
+	__THRD_PRINT1(_L("CFsDispatchObject::Close() 0x%x"),this);
+	if(Dec()!=1)
+		return;
+	if(!IsCorrectThread())
+		Dispatch();
+	else
+		DoClose();
+	}
+
+/**
+Destructor.
+ 
+Deletes assigned CFsRequest object.
+*/
+CFsDispatchObject::~CFsDispatchObject()
+	{
+	__THRD_PRINT(_L("CFsDispatchObject::~CFsDispatchObject()"));
+	if(iRequest)
+		delete(iRequest);
+	}
+
+/**
+Dispatches an assigned CFsRequest object.
+
+@see CFsRequest::Dispatch()
+*/
+void CFsDispatchObject::Dispatch()
+	{
+	__ASSERT_DEBUG(iRequest,Fault(EDispatchObjectDispatch));
+	iRequest->Dispatch();
+	}
+
+
+/**
+Determine if this object is within the correct drive thread context 
+for file resource request.
+For example subsession close request.
+
+@return ETrue if within the correct drive thread context.
+*/
+EXPORT_C TBool CFsDispatchObject::IsCorrectThread()
+	{
+	if(!iRequest)
+		return(ETrue);
+	FsThreadManager::LockDrive(iRequest->DriveNumber());
+	TBool b;
+	__ASSERT_ALWAYS(FsThreadManager::IsDriveAvailable(iRequest->DriveNumber(),EFalse) || FsThreadManager::IsMainThread(), Fault(EDispatchObjectThread));
+	if(!FsThreadManager::IsDriveAvailable(iRequest->DriveNumber(),EFalse) && FsThreadManager::IsMainThread())
+		b=ETrue;
+	else if(FsThreadManager::IsDriveSync(iRequest->DriveNumber(),EFalse) && FsThreadManager::IsMainThread())
+		b=ETrue;
+	else
+		b=FsThreadManager::IsDriveThread(iRequest->DriveNumber(),EFalse);
+	FsThreadManager::UnlockDrive(iRequest->DriveNumber());
+	return(b);
+	}
+
+TInt TFsCloseObject::Initialise(CFsRequest* /*aRequest*/)
+//
+//
+//
+	{
+	return(KErrNone);
+	}
+
+TInt TFsCloseObject::DoRequestL(CFsRequest* /*aRequest*/)
+//
+//
+//
+	{
+	__PRINT(_L("TFsCloseObject::DoRequestL()"));
+	return(KErrNone);
+	}
+
+TInt TFsCloseObject::Complete(CFsRequest* aRequest)
+//
+//
+//
+	{
+	__PRINT(_L("TFsCloseObject::Complete()"));
+	CFsDispatchObject* pO=(CFsDispatchObject*)aRequest->ScratchValue();
+	// set CFsDispatchObject::iRequest to NULL since request will be deleted in Free()
+	pO->iRequest=NULL;
+	pO->DoClose();
+	return(KErrNone);
+	}
+
+