First public contribution.
1 // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
19 const TInt KDirStackGranularity=8;
21 /** Replace long names in path and filename with their sohrter version (if exists). Optionally appends
22 filename to path name creating fully qualified file name.
23 @param aFs (connected) File system session
24 @param aCurrentPath on input contains current full path name,
25 upon return contains the shortest version (using either shor or long names) of the same path
26 @param aItem on input contains item with long name in the current path,
27 upon return contains shorter name of either long or short name
28 @param aAppend if ETrue aItem will be appended to aCurrentPath before successful return
29 @return KErrNone if successful, otherwise one of the other system-wide error codes.
31 TInt ShrinkNames(RFs& aFs, TFileName& aCurrentPath, TFileName& aItem, TBool aAppend)
34 TBuf<8+1+3> shortname;
35 TFileName* current = NULL;
36 TRAPD(r,current = new (ELeave) TFileName);
41 TInt lastslash = KErrNotFound;
42 TInt lastnewslash = KErrNotFound;
43 while(ret == KErrNone && pos < aCurrentPath.Length())
45 if(aCurrentPath[pos] == KPathDelimiter)
47 if(lastslash != KErrNotFound)
49 ret = aFs.GetShortName(*current, shortname);
50 if(ret == KErrNone && pos-lastslash > shortname.Length())
52 current->SetLength(lastnewslash);
53 current->Append(shortname);
57 lastnewslash = current->Length()+1;
59 current->Append(aCurrentPath[pos++]);
61 if(ret == KErrNone && current->Length() + aItem.Length() <= KMaxFileName)
63 aCurrentPath = *current;
64 TInt lenBefore = aCurrentPath.Length();
65 aCurrentPath.Append(aItem);
66 ret = aFs.GetShortName(aCurrentPath, shortname);
67 aCurrentPath.SetLength(lenBefore);
69 if(ret == KErrNone && aItem.Length() > shortname.Length())
74 if(aAppend && ret == KErrNone && aCurrentPath.Length() + aItem.Length() <= KMaxFileName)
76 aCurrentPath.Append(aItem);
82 LOCAL_C TPtrC LeafDir(const TDesC& aPath)
84 // Returns the leaf directory of a path
88 TInt end=aPath.LocateReverse('\\');
89 __ASSERT_DEBUG(end!=KErrNotFound,Panic(EDirListError));
90 TPtrC ret(aPath.Ptr(),end);
91 TInt start=ret.LocateReverse('\\');
92 if (start==KErrNotFound)
94 return ret.Right(end-start-1);
97 CDirScan::CDirScan(RFs& aFs)
108 EXPORT_C CDirScan* CDirScan::NewLC(RFs& aFs)
110 Constructs and allocates memory for a new CDirScan object, putting a pointer
111 to the object onto the cleanup stack.
113 @param aFs The file server session.
115 @return A pointer to the new directory scan object.
118 TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanNewLC, MODULEUID, aFs.Handle());
120 CDirScan* scan=new(ELeave) CDirScan(aFs);
121 CleanupStack::PushL(scan);
122 scan->iStack=CDirStack::NewL();
124 TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanNewLCReturn, MODULEUID, scan);
131 EXPORT_C CDirScan* CDirScan::NewL(RFs& aFs)
133 Constructs and allocates memory for a new CDirScan object.
135 @param aFs The file server session.
137 @return A pointer to the new directory scan object.
140 TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanNewL, MODULEUID, aFs.Handle());
142 CDirScan* scan=CDirScan::NewLC(aFs);
145 TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanNewLReturn, MODULEUID, scan);
152 EXPORT_C CDirScan::~CDirScan()
156 Frees all resources owned by the object, prior to its destruction.
159 TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanDestructor, MODULEUID, this);
163 TRACE0(UTF::EBorder, UTraceModuleEfsrv::ECDirScanDestructorReturn, MODULEUID);
169 EXPORT_C void CDirScan::SetScanDataL(const TDesC& aMatchName,TUint anEntryAttMask,TUint anEntrySortKey,TScanDirection aScanDir)
171 Initialises the scan.
173 This involves specifying:
175 1. the directory at the top of the structure to be scanned
177 2. a filter for the entry types of interest
179 3. the order in which the entries in each directory in the structure are to be sorted
181 4. the scan direction.
183 Whether the scan direction is upwards or downwards, the directories that are
184 scanned are those in the part of the hierarchy below the directory
185 specified in aMatchName. By default, the scan direction is downwards.
186 If the scan direction is set to CDirScan::EScanUpTree, then all branches of
187 the tree are explored starting at the lowest level directory in
188 the tree below aMatchName, and ending at aMatchName.
189 This option is provided for deleting a directory structure.
191 @param aMatchName The top level directory for the scan. Any path components
192 that are not specified here are taken from the session path.
193 Note that the trailing backslash is required to specify the directory.
194 I.e. path x:\\dir1\\dir2\\ means that the scan will start from dir2, while
195 path x:\\dir1\\dir2 assumes scan starting from x:\\dir1\\
197 @param anEntryAttMask A bit mask that filters the entry types which should be returned by
198 NextL(). The mask works as follows:
199 To match files only, specify KEntryAttNormal.
200 To match both files and directories,
201 specify KEntryAttDir.
202 To match directories only,
203 specify KEntryAttDir|KEntryAttMatchExclusive.
204 To match files with a specific attribute,
205 then OR the attribute involved with
206 KEntryAttMatchExclusive.
207 For example, to match read-only files,
208 specify KEntryAttReadOnly|KEntryAttMatchExclusive.
209 For more information,
210 see KEntryAttNormal or
211 the other file/directory attributes.
212 @param anEntrySortKey The order in which the directories are scanned by
213 NextL(). This flag is defined in TEntryKey.
214 @param aScanDir The direction of the scan. The default is downwards.
217 TRACEMULT5(UTF::EBorder, UTraceModuleEfsrv::ECDirScanSetScanDataL, MODULEUID, (TUint)
218 this, aMatchName, anEntryAttMask, anEntrySortKey, (TUint) aScanDir);
220 TInt r = Fs().Parse(aMatchName,iFullPath);
223 TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanSetScanDataLReturn, MODULEUID, r);
228 iEntryAttMask=anEntryAttMask;
229 iEntrySortMask=anEntrySortKey;
230 iStack->ResetL(LeafDir(iFullPath.FullName()));
231 iAbbreviatedPathPos=iFullPath.DriveAndPath().Length()-1;
232 iAbbreviatedPath.Set(_L("\\"));
234 if (aScanDir==EScanDownTree)
237 TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanSetScanDataLReturn, MODULEUID, KErrNone);
240 void CDirScan::UpdateAbbreviatedPath()
242 // Set the abbreviated path based on the full path
246 TInt length=iFullPath.DriveAndPath().Length();
247 TPtrC fullName=iFullPath.FullName();
248 if (length>iAbbreviatedPathPos)
249 iAbbreviatedPath.Set(&fullName[0]+iAbbreviatedPathPos,length-iAbbreviatedPathPos);
251 iAbbreviatedPath.Set(_L("\\"));
257 EXPORT_C void CDirScan::NextL(CDir*& aDirEntries)
259 Scans the next directory entry in the structure.
261 The order in which the structure is scanned is determined by the scan
262 direction and the entry sort mask. These values are specified when setting up
263 the scan. The type of entries retrieved by this function is determined by the
264 entry attribute mask. This is also specified when setting up the scan.
268 1. The function first sets aDirEntries to NULL, and then allocates memory for
269 it before appending entries to it. Therefore, aDirEntries should have no
270 memory allocated to it before this function is called, otherwise this
271 memory will become orphaned.
273 2. The caller of this function is responsible for deleting aDirEntries after
274 the function has returned.
276 @param aDirEntries On return, a pointer to an array containing filtered entries
277 from the next directory in the structure. NULL if there are
278 no more directories in the structure.
281 TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanNextL, MODULEUID, this);
283 if (iScanDir==EScanUpTree)
284 ScanUpTreeL(aDirEntries);
286 ScanDownTreeL(aDirEntries);
288 TRACE2(UTF::EBorder, UTraceModuleEfsrv::ECDirScanNextLReturn, MODULEUID,
289 KErrNone, aDirEntries ? (*aDirEntries).Count() : 0);
292 void CDirScan::ScanUpTreeL(CDir*& aDirEntries)
294 // Get the next directory starting from the bottom of the tree
295 // eg: for deleting a directory structure
300 CDirList* list=iStack->Peek();
301 if (!list->MoreEntries())
304 if (iStack->IsEmpty())
309 UpdateAbbreviatedPath();
310 GetDirEntriesL(aDirEntries);
314 TFileName* next = new (ELeave) TFileName;
315 CleanupStack::PushL(next);
316 TFileName* current = new (ELeave) TFileName;
317 CleanupStack::PushL(current);
321 TPtrC dirName=list->Next().iName;
322 r = iFullPath.AddDir(dirName);
323 if (r==KErrGeneral) // adding dirName would make iFullPath > 256 characters
325 current->Copy(iFullPath.DriveAndPath());
328 r = ShrinkNames(Fs(), *current, *next, EFalse);
331 r = iFullPath.Set(*current, NULL, NULL);
334 r = iFullPath.AddDir(*next);
340 TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanLeave, MODULEUID, r);
341 User::LeaveIfError(r);
345 // Start by searching for directories only from top to bottom
346 r = Fs().GetDir(iFullPath.DriveAndPath(),
347 KEntryAttDir|KEntryAttMatchExclusive|(iEntryAttMask&KEntryAttMatchMask),
350 if (r == KErrPermissionDenied && !iScanning)
352 UpdateAbbreviatedPath();
353 aDirEntries = CDirFactory::NewL();
355 else if (r != KErrNone)
358 TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanLeave, MODULEUID, r);
364 // Permission denied case. No entry
368 if (dirList->Count()==0)// No more directory entries - bottom of tree reached
373 iStack->PushL(*dirList);
377 CleanupStack::PopAndDestroy(2); // current and next pointers
379 UpdateAbbreviatedPath();
380 // Now get all valid entries for the lowest level directory encountered
382 if(r!=KErrPermissionDenied )
384 GetDirEntriesL(aDirEntries);
388 void CDirScan::GetDirEntriesL(CDir*& aDirEntries)
393 TInt r = Fs().GetDir(iFullPath.FullName(),iEntryAttMask,iEntrySortMask,aDirEntries);
396 TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanLeave, MODULEUID, r);
401 void CDirScan::ScanDownTreeL(CDir*& aDirEntries)
403 // Get the next directory starting from the top of the tree
404 // eg: for copying a directory structure
407 CDir* dirEntries = NULL;
410 CDirList* list=iStack->Peek();
411 while (!list->MoreEntries())
414 if (iStack->IsEmpty())
420 UpdateAbbreviatedPath();
424 TPtrC dirName=list->Next().iName;
425 r=iFullPath.AddDir(dirName);
426 if (r==KErrGeneral) // Adding dirName makes iFullPath>256 characters
428 TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanLeave, MODULEUID, KErrTooBig);
429 User::Leave(KErrTooBig);
432 // Get all valid entries in this directory
434 // coverity[alloc_arg]
435 TRAP(r, GetDirEntriesL(dirEntries));
440 CleanupStack::PushL(dirEntries);
441 // Get all directories within this directory - the next level down in the tree
444 // coverity[alloc_fn]
445 r = Fs().GetDir(iFullPath.DriveAndPath(),
446 KEntryAttDir|KEntryAttMatchExclusive|(iEntryAttMask&KEntryAttMatchMask),
447 iEntrySortMask,dirList);
450 TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanLeave, MODULEUID, r);
453 iStack->PushL(*dirList);
454 CleanupStack::Pop(); // dirEntries
455 UpdateAbbreviatedPath();
456 aDirEntries=dirEntries;
458 else if (r == KErrPermissionDenied && !iScanning)
460 CDir* dirList = CDirFactory::NewL();
461 iStack->PushL(*dirList);
462 aDirEntries = CDirFactory::NewL();
467 TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanLeave, MODULEUID, r);
475 EXPORT_C TPtrC CDirScan::AbbreviatedPath()
477 Gets the abbreviated path of the entry currently being scanned.
479 The abbreviated path is the path relative to the top level directory
482 @return A non modifiable pointer descriptor for the abbreviated path of
483 the entry currently being scanned.
487 return iAbbreviatedPath;
493 EXPORT_C TPtrC CDirScan::FullPath()
495 Gets the full path of the entry currently being scanned.
497 The full path includes the drive letter.
499 @return A non modifiable pointer descriptor for the full path of the entry
500 currently being scanned.
504 return iFullPath.DriveAndPath();
510 CDirStack* CDirStack::NewL()
512 // Create new directory stack
516 return new(ELeave) CDirStack;
519 CDirStack::CDirStack()
523 : iDirStack(KDirStackGranularity)
527 CDirStack::~CDirStack()
534 iDirStack.ResetAndDestroy();
537 TInt CDirStack::IsEmpty()
539 // Return number of directories stacked
543 return (iDirStack.Count()==0);
546 void CDirStack::ResetL(const TDesC& aStartDir)
548 // Reset stack to containing only aStartDir
552 iDirStack.ResetAndDestroy();
553 CDir* dir=CDirFactory::NewL(aStartDir);
557 void CDirStack::PushL(CDir& aDirContents)
559 // Push a list of directories onto the stack
563 CleanupStack::PushL(&aDirContents);
564 CDirList* nextLevel=CDirList::NewL(aDirContents);
565 CleanupStack::Pop(); // aDirContents now owned by CDirList
567 TInt r=iDirStack.Append(nextLevel);
571 TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanLeave, MODULEUID, r);
576 void CDirStack::Pop()
578 // Pop subdirectory list off the stack
582 __ASSERT_DEBUG(iDirStack.Count(),Panic(EDirListError));
583 TInt tos=iDirStack.Count()-1;
584 delete iDirStack[tos];
585 iDirStack.Remove(tos);
588 CDirList* CDirStack::Peek()
590 // Return current subdirectory
594 __ASSERT_DEBUG(iDirStack.Count(),Panic(EDirListError));
595 return iDirStack[iDirStack.Count()-1];
598 CDirList* CDirList::NewL(CDir& aDirList)
600 // Create a new directory list - takes ownership of aDirList
604 CDirList* dirLevel=new(ELeave) CDirList;
605 dirLevel->iDirList=&aDirList;
611 // Construct directory list
616 CDirList::~CDirList()
618 // Destroy directory list
625 const TEntry& CDirList::Next()
627 // Return next directory in list.
631 __ASSERT_DEBUG(iCurrentPos>=0 && iCurrentPos<iDirList->Count(),Panic(EDirListError));
632 const TEntry& entry=(*iDirList)[iCurrentPos];
637 TBool CDirList::MoreEntries() const
639 // Return EFalse if the entire list has been read
643 __ASSERT_DEBUG(iCurrentPos>=0 && iCurrentPos<=iDirList->Count(),Panic(EDirListError));
644 return (iCurrentPos!=iDirList->Count());
647 CDir* CDirFactory::NewL(const TDesC& anEntryName)
649 // Create a CDir containing a single entry. Used to initialize the scanner
653 CDirFactory* dir=(CDirFactory*)CDir::NewL();
654 CleanupStack::PushL(dir);
656 entry.iName=anEntryName;
662 CDir* CDirFactory::NewL()
664 // Create a CDir with nothing in it
668 CDirFactory* dir=(CDirFactory*)CDir::NewL();
675 EXPORT_C TOpenFileScan::TOpenFileScan(RFs& aFs)
677 Constructs the object with the specified file server session.
679 @param aFs The file server session.
681 : iFs(&aFs), iScanPos(0), iEntryListPos(0)
687 EXPORT_C void TOpenFileScan::NextL(CFileList*& aFileList)
689 Gets a list of entries for the open files in the file server session.
691 @param aFileList On return, contains a list of entries for all open files
692 in the file server session.
698 if (iScanPos==KErrNotFound)
700 TEntryArray* pArray=new(ELeave) TEntryArray;
701 CleanupStack::PushL(pArray);
702 TEntryArray& array=*pArray;
706 TInt r = iFs->GetOpenFileList(iScanPos,iEntryListPos,theId,array);
709 TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECDirScanLeave, MODULEUID, r);
712 TInt count=array.Count();
716 iScanPos=KErrNotFound;
718 CleanupStack::Pop(); // aFileList
720 CleanupStack::PopAndDestroy(); // pArray
726 aFileList=CFileList::NewL();
727 CleanupStack::PushL(aFileList);
731 aFileList->AddL(array[i++]);
738 EXPORT_C TThreadId TOpenFileScan::ThreadId() const
740 Gets the ID of the thread that opened the files retrieved by NextL().
742 @return The ID of the thread that opened the files in the file list.