diff -r 000000000000 -r 96e5fb8b040d userlibandfileserver/fileserver/sfsrv/cl_scan.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/userlibandfileserver/fileserver/sfsrv/cl_scan.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,747 @@ +// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include "cl_std.h" +#include "cl_scan.h" + +const TInt KDirStackGranularity=8; + +/** Replace long names in path and filename with their sohrter version (if exists). Optionally appends +filename to path name creating fully qualified file name. +@param aFs (connected) File system session +@param aCurrentPath on input contains current full path name, +upon return contains the shortest version (using either shor or long names) of the same path +@param aItem on input contains item with long name in the current path, +upon return contains shorter name of either long or short name +@param aAppend if ETrue aItem will be appended to aCurrentPath before successful return +@return KErrNone if successful, otherwise one of the other system-wide error codes. +*/ +TInt ShrinkNames(RFs& aFs, TFileName& aCurrentPath, TFileName& aItem, TBool aAppend) + { + TInt ret = KErrNone; + TBuf<8+1+3> shortname; + TFileName* current = NULL; + TRAPD(r,current = new (ELeave) TFileName); + if (r) + return r; + + TInt pos = 0; + TInt lastslash = KErrNotFound; + TInt lastnewslash = KErrNotFound; + while(ret == KErrNone && pos < aCurrentPath.Length()) + { + if(aCurrentPath[pos] == KPathDelimiter) + { + if(lastslash != KErrNotFound) + { + ret = aFs.GetShortName(*current, shortname); + if(ret == KErrNone && pos-lastslash > shortname.Length()) + { + current->SetLength(lastnewslash); + current->Append(shortname); + } + } + lastslash = pos+1; + lastnewslash = current->Length()+1; + } + current->Append(aCurrentPath[pos++]); + } + if(ret == KErrNone && current->Length() + aItem.Length() <= KMaxFileName) + { + aCurrentPath = *current; + TInt lenBefore = aCurrentPath.Length(); + aCurrentPath.Append(aItem); + ret = aFs.GetShortName(aCurrentPath, shortname); + aCurrentPath.SetLength(lenBefore); + + if(ret == KErrNone && aItem.Length() > shortname.Length()) + { + aItem = shortname; + } + } + if(aAppend && ret == KErrNone && aCurrentPath.Length() + aItem.Length() <= KMaxFileName) + { + aCurrentPath.Append(aItem); + } + delete current; + return ret; +} + +LOCAL_C TPtrC LeafDir(const TDesC& aPath) +// +// Returns the leaf directory of a path +// + { + + TInt end=aPath.LocateReverse('\\'); + __ASSERT_DEBUG(end!=KErrNotFound,Panic(EDirListError)); + TPtrC ret(aPath.Ptr(),end); + TInt start=ret.LocateReverse('\\'); + if (start==KErrNotFound) + start=end-1; + return ret.Right(end-start-1); + } + +CDirScan::CDirScan(RFs& aFs) +// +// Constructor +// + : iFs(&aFs) + { + } + + + + +EXPORT_C CDirScan* CDirScan::NewLC(RFs& aFs) +/** +Constructs and allocates memory for a new CDirScan object, putting a pointer +to the object onto the cleanup stack. + +@param aFs The file server session. + +@return A pointer to the new directory scan object. +*/ + { + TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanNewLC, MODULEUID, aFs.Handle()); + + CDirScan* scan=new(ELeave) CDirScan(aFs); + CleanupStack::PushL(scan); + scan->iStack=CDirStack::NewL(); + + TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanNewLCReturn, MODULEUID, scan); + return scan; + } + + + + +EXPORT_C CDirScan* CDirScan::NewL(RFs& aFs) +/** +Constructs and allocates memory for a new CDirScan object. + +@param aFs The file server session. + +@return A pointer to the new directory scan object. +*/ + { + TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanNewL, MODULEUID, aFs.Handle()); + + CDirScan* scan=CDirScan::NewLC(aFs); + CleanupStack::Pop(); + + TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanNewLReturn, MODULEUID, scan); + return scan; + } + + + + +EXPORT_C CDirScan::~CDirScan() +/** +Desctructor. + +Frees all resources owned by the object, prior to its destruction. +*/ + { + TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanDestructor, MODULEUID, this); + + delete iStack; + + TRACE0(UTF::EBorder, UTraceModuleEfsrv::ECDirScanDestructorReturn, MODULEUID); + } + + + + +EXPORT_C void CDirScan::SetScanDataL(const TDesC& aMatchName,TUint anEntryAttMask,TUint anEntrySortKey,TScanDirection aScanDir) +/** +Initialises the scan. + +This involves specifying: + +1. the directory at the top of the structure to be scanned + +2. a filter for the entry types of interest + +3. the order in which the entries in each directory in the structure are to be sorted + +4. the scan direction. + +Whether the scan direction is upwards or downwards, the directories that are +scanned are those in the part of the hierarchy below the directory +specified in aMatchName. By default, the scan direction is downwards. +If the scan direction is set to CDirScan::EScanUpTree, then all branches of +the tree are explored starting at the lowest level directory in +the tree below aMatchName, and ending at aMatchName. +This option is provided for deleting a directory structure. + +@param aMatchName The top level directory for the scan. Any path components + that are not specified here are taken from the session path. + Note that the trailing backslash is required to specify the directory. + I.e. path x:\\dir1\\dir2\\ means that the scan will start from dir2, while + path x:\\dir1\\dir2 assumes scan starting from x:\\dir1\\ + +@param anEntryAttMask A bit mask that filters the entry types which should be returned by + NextL(). The mask works as follows: + To match files only, specify KEntryAttNormal. + To match both files and directories, + specify KEntryAttDir. + To match directories only, + specify KEntryAttDir|KEntryAttMatchExclusive. + To match files with a specific attribute, + then OR the attribute involved with + KEntryAttMatchExclusive. + For example, to match read-only files, + specify KEntryAttReadOnly|KEntryAttMatchExclusive. + For more information, + see KEntryAttNormal or + the other file/directory attributes. +@param anEntrySortKey The order in which the directories are scanned by + NextL(). This flag is defined in TEntryKey. +@param aScanDir The direction of the scan. The default is downwards. +*/ + { + TRACEMULT5(UTF::EBorder, UTraceModuleEfsrv::ECDirScanSetScanDataL, MODULEUID, (TUint) + this, aMatchName, anEntryAttMask, anEntrySortKey, (TUint) aScanDir); + + TInt r = Fs().Parse(aMatchName,iFullPath); + if (r != KErrNone) + { + TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanSetScanDataLReturn, MODULEUID, r); + User::Leave(r); + } + + iScanning = ETrue; + iEntryAttMask=anEntryAttMask; + iEntrySortMask=anEntrySortKey; + iStack->ResetL(LeafDir(iFullPath.FullName())); + iAbbreviatedPathPos=iFullPath.DriveAndPath().Length()-1; + iAbbreviatedPath.Set(_L("\\")); + iScanDir=aScanDir; + if (aScanDir==EScanDownTree) + iFullPath.PopDir(); + + TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanSetScanDataLReturn, MODULEUID, KErrNone); + } + +void CDirScan::UpdateAbbreviatedPath() +// +// Set the abbreviated path based on the full path +// + { + + TInt length=iFullPath.DriveAndPath().Length(); + TPtrC fullName=iFullPath.FullName(); + if (length>iAbbreviatedPathPos) + iAbbreviatedPath.Set(&fullName[0]+iAbbreviatedPathPos,length-iAbbreviatedPathPos); + else + iAbbreviatedPath.Set(_L("\\")); + } + + + + +EXPORT_C void CDirScan::NextL(CDir*& aDirEntries) +/** +Scans the next directory entry in the structure. + +The order in which the structure is scanned is determined by the scan +direction and the entry sort mask. These values are specified when setting up +the scan. The type of entries retrieved by this function is determined by the +entry attribute mask. This is also specified when setting up the scan. + +Notes: + +1. The function first sets aDirEntries to NULL, and then allocates memory for + it before appending entries to it. Therefore, aDirEntries should have no + memory allocated to it before this function is called, otherwise this + memory will become orphaned. + +2. The caller of this function is responsible for deleting aDirEntries after + the function has returned. + +@param aDirEntries On return, a pointer to an array containing filtered entries + from the next directory in the structure. NULL if there are + no more directories in the structure. +*/ + { + TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanNextL, MODULEUID, this); + + if (iScanDir==EScanUpTree) + ScanUpTreeL(aDirEntries); + else + ScanDownTreeL(aDirEntries); + + TRACE2(UTF::EBorder, UTraceModuleEfsrv::ECDirScanNextLReturn, MODULEUID, + KErrNone, aDirEntries ? (*aDirEntries).Count() : 0); + } + +void CDirScan::ScanUpTreeL(CDir*& aDirEntries) +// +// Get the next directory starting from the bottom of the tree +// eg: for deleting a directory structure +// + { + TInt r; + iFullPath.PopDir(); + CDirList* list=iStack->Peek(); + if (!list->MoreEntries()) + { + iStack->Pop(); + if (iStack->IsEmpty()) + { + aDirEntries=NULL; + return; + } + UpdateAbbreviatedPath(); + GetDirEntriesL(aDirEntries); + return; + } + + TFileName* next = new (ELeave) TFileName; + CleanupStack::PushL(next); + TFileName* current = new (ELeave) TFileName; + CleanupStack::PushL(current); + + FOREVER + { + TPtrC dirName=list->Next().iName; + r = iFullPath.AddDir(dirName); + if (r==KErrGeneral) // adding dirName would make iFullPath > 256 characters + { + current->Copy(iFullPath.DriveAndPath()); + next->Copy(dirName); + + r = ShrinkNames(Fs(), *current, *next, EFalse); + if(r == KErrNone) + { + r = iFullPath.Set(*current, NULL, NULL); + if(r == KErrNone) + { + r = iFullPath.AddDir(*next); + } + } + } + if (r != KErrNone) + { + TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanLeave, MODULEUID, r); + User::LeaveIfError(r); + } + + CDir* dirList; + // Start by searching for directories only from top to bottom + r = Fs().GetDir(iFullPath.DriveAndPath(), + KEntryAttDir|KEntryAttMatchExclusive|(iEntryAttMask&KEntryAttMatchMask), + iEntrySortMask, + dirList); + if (r == KErrPermissionDenied && !iScanning) + { + UpdateAbbreviatedPath(); + aDirEntries = CDirFactory::NewL(); + } + else if (r != KErrNone) + { + iScanning = EFalse; + TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanLeave, MODULEUID, r); + User::Leave(r); + } + + iScanning= EFalse; + + // Permission denied case. No entry + if(!dirList) + break; + + if (dirList->Count()==0)// No more directory entries - bottom of tree reached + { + delete dirList; + break; + } + iStack->PushL(*dirList); + list=iStack->Peek(); + } //END OF FOREVER + + CleanupStack::PopAndDestroy(2); // current and next pointers + + UpdateAbbreviatedPath(); + // Now get all valid entries for the lowest level directory encountered + + if(r!=KErrPermissionDenied ) + { + GetDirEntriesL(aDirEntries); + } + } + +void CDirScan::GetDirEntriesL(CDir*& aDirEntries) +// +// Call GetDir. +// + { + TInt r = Fs().GetDir(iFullPath.FullName(),iEntryAttMask,iEntrySortMask,aDirEntries); + if (r != KErrNone) + { + TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanLeave, MODULEUID, r); + User::Leave(r); + } + } + +void CDirScan::ScanDownTreeL(CDir*& aDirEntries) +// +// Get the next directory starting from the top of the tree +// eg: for copying a directory structure +// + { + CDir* dirEntries = NULL; + TInt r; + aDirEntries=NULL; + CDirList* list=iStack->Peek(); + while (!list->MoreEntries()) + { + iStack->Pop(); + if (iStack->IsEmpty()) + { + aDirEntries=NULL; + return; + } + iFullPath.PopDir(); + UpdateAbbreviatedPath(); + list=iStack->Peek(); + } + + TPtrC dirName=list->Next().iName; + r=iFullPath.AddDir(dirName); + if (r==KErrGeneral) // Adding dirName makes iFullPath>256 characters + { + TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanLeave, MODULEUID, KErrTooBig); + User::Leave(KErrTooBig); + } + + // Get all valid entries in this directory + + // coverity[alloc_arg] + TRAP(r, GetDirEntriesL(dirEntries)); + + if (r == KErrNone) + { + iScanning = EFalse; + CleanupStack::PushL(dirEntries); + // Get all directories within this directory - the next level down in the tree + CDir* dirList; + + // coverity[alloc_fn] + r = Fs().GetDir(iFullPath.DriveAndPath(), + KEntryAttDir|KEntryAttMatchExclusive|(iEntryAttMask&KEntryAttMatchMask), + iEntrySortMask,dirList); + if (r != KErrNone) + { + TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanLeave, MODULEUID, r); + User::Leave(r); + } + iStack->PushL(*dirList); + CleanupStack::Pop(); // dirEntries + UpdateAbbreviatedPath(); + aDirEntries=dirEntries; + } + else if (r == KErrPermissionDenied && !iScanning) + { + CDir* dirList = CDirFactory::NewL(); + iStack->PushL(*dirList); + aDirEntries = CDirFactory::NewL(); + } + else + { + iScanning = EFalse; + TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanLeave, MODULEUID, r); + User::Leave(r); + } + } + + + + +EXPORT_C TPtrC CDirScan::AbbreviatedPath() +/** +Gets the abbreviated path of the entry currently being scanned. + +The abbreviated path is the path relative to the top level directory +in the scan. + +@return A non modifiable pointer descriptor for the abbreviated path of + the entry currently being scanned. +*/ + { + + return iAbbreviatedPath; + } + + + + +EXPORT_C TPtrC CDirScan::FullPath() +/** +Gets the full path of the entry currently being scanned. + +The full path includes the drive letter. + +@return A non modifiable pointer descriptor for the full path of the entry + currently being scanned. +*/ + { + + return iFullPath.DriveAndPath(); + } + + + + +CDirStack* CDirStack::NewL() +// +// Create new directory stack +// + { + + return new(ELeave) CDirStack; + } + +CDirStack::CDirStack() +// +// Constructor +// + : iDirStack(KDirStackGranularity) + { + } + +CDirStack::~CDirStack() +// +// Destructor +// + { + + + iDirStack.ResetAndDestroy(); + } + +TInt CDirStack::IsEmpty() +// +// Return number of directories stacked +// + { + + return (iDirStack.Count()==0); + } + +void CDirStack::ResetL(const TDesC& aStartDir) +// +// Reset stack to containing only aStartDir +// + { + + iDirStack.ResetAndDestroy(); + CDir* dir=CDirFactory::NewL(aStartDir); + PushL(*dir); + } + +void CDirStack::PushL(CDir& aDirContents) +// +// Push a list of directories onto the stack +// + { + + CleanupStack::PushL(&aDirContents); + CDirList* nextLevel=CDirList::NewL(aDirContents); + CleanupStack::Pop(); // aDirContents now owned by CDirList + + TInt r=iDirStack.Append(nextLevel); + if (r!=KErrNone) + { + delete nextLevel; + TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanLeave, MODULEUID, r); + User::Leave(r); + } + } + +void CDirStack::Pop() +// +// Pop subdirectory list off the stack +// + { + + __ASSERT_DEBUG(iDirStack.Count(),Panic(EDirListError)); + TInt tos=iDirStack.Count()-1; + delete iDirStack[tos]; + iDirStack.Remove(tos); + } + +CDirList* CDirStack::Peek() +// +// Return current subdirectory +// + { + + __ASSERT_DEBUG(iDirStack.Count(),Panic(EDirListError)); + return iDirStack[iDirStack.Count()-1]; + } + +CDirList* CDirList::NewL(CDir& aDirList) +// +// Create a new directory list - takes ownership of aDirList +// + { + + CDirList* dirLevel=new(ELeave) CDirList; + dirLevel->iDirList=&aDirList; + return dirLevel; + } + +CDirList::CDirList() +// +// Construct directory list +// + { + } + +CDirList::~CDirList() +// +// Destroy directory list +// + { + + delete iDirList; + } + +const TEntry& CDirList::Next() +// +// Return next directory in list. +// + { + + __ASSERT_DEBUG(iCurrentPos>=0 && iCurrentPosCount(),Panic(EDirListError)); + const TEntry& entry=(*iDirList)[iCurrentPos]; + iCurrentPos++; + return entry; + } + +TBool CDirList::MoreEntries() const +// +// Return EFalse if the entire list has been read +// + { + + __ASSERT_DEBUG(iCurrentPos>=0 && iCurrentPos<=iDirList->Count(),Panic(EDirListError)); + return (iCurrentPos!=iDirList->Count()); + } + +CDir* CDirFactory::NewL(const TDesC& anEntryName) +// +// Create a CDir containing a single entry. Used to initialize the scanner +// + { + + CDirFactory* dir=(CDirFactory*)CDir::NewL(); + CleanupStack::PushL(dir); + TEntry entry; + entry.iName=anEntryName; + dir->AddL(entry); + CleanupStack::Pop(); + return dir; + } + +CDir* CDirFactory::NewL() +// +// Create a CDir with nothing in it +// + { + + CDirFactory* dir=(CDirFactory*)CDir::NewL(); + return dir; + } + + + + +EXPORT_C TOpenFileScan::TOpenFileScan(RFs& aFs) +/** +Constructs the object with the specified file server session. + +@param aFs The file server session. +*/ + : iFs(&aFs), iScanPos(0), iEntryListPos(0) + {} + + + + +EXPORT_C void TOpenFileScan::NextL(CFileList*& aFileList) +/** +Gets a list of entries for the open files in the file server session. + +@param aFileList On return, contains a list of entries for all open files + in the file server session. +*/ + { + + + aFileList=NULL; + if (iScanPos==KErrNotFound) + return; + TEntryArray* pArray=new(ELeave) TEntryArray; + CleanupStack::PushL(pArray); + TEntryArray& array=*pArray; + FOREVER + { + TThreadId theId; + TInt r = iFs->GetOpenFileList(iScanPos,iEntryListPos,theId,array); + if (r != KErrNone) + { + TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanLeave, MODULEUID, r); + User::Leave(r); + } + TInt count=array.Count(); + if (count==0) + { + if (aFileList==NULL) + iScanPos=KErrNotFound; + else + CleanupStack::Pop(); // aFileList + iEntryListPos=0; + CleanupStack::PopAndDestroy(); // pArray + return; + } + iThreadId = theId; + if (aFileList==NULL) + { + aFileList=CFileList::NewL(); + CleanupStack::PushL(aFileList); + } + TInt i=0; + while (iAddL(array[i++]); + } + } + + + + +EXPORT_C TThreadId TOpenFileScan::ThreadId() const +/** +Gets the ID of the thread that opened the files retrieved by NextL(). + +@return The ID of the thread that opened the files in the file list. +*/ + { + + return(iThreadId); + }