os/kernelhwsrv/userlibandfileserver/fileserver/sfat/sl_leafdir_cache.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2008-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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // f32\sfat\sl_leafdir_cache.cpp
    15 // 
    16 //
    17 
    18 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    19 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    20 //!!
    21 //!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
    22 //!!
    23 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    24 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    25 
    26 
    27 #include "sl_std.h"
    28 #include "sl_leafdir_cache.h"
    29 
    30 
    31 
    32 
    33 /**
    34 Get the lru list count
    35 
    36 @return the count of lru list
    37 */
    38 TInt CLeafDirTree::LruCount() const 
    39     {
    40     return iLruList.Count();
    41     }
    42 
    43 /**
    44 Count currently cached items
    45 
    46 @return the number of currently cached items
    47 */
    48 TInt CLeafDirCache::CacheCount() const 
    49     {
    50     return iTree->LruCount();
    51     }
    52 
    53 //---------------------------------------------------------------------------------------------------------------------------------
    54 /**
    55 Default constructor of TDirPosition, a data structure that represents a location of directory
    56 */
    57 TLeafDirData::TLeafDirData()
    58              :iClusterNum(0),iMRUPos(0,0)
    59     {
    60     }
    61 
    62 /**
    63 Constructor of TDirPosition, a data structure that represents a location of directory
    64 
    65 @param  aClusterNum     the cluster number of the directory stores   
    66 */
    67 TLeafDirData::TLeafDirData(TUint aClusterNum)
    68              :iClusterNum(aClusterNum),iMRUPos(0,0)
    69     {
    70     }
    71 
    72 /**
    73 Constructor of TDirPosition, a data structure that represents a location of directory
    74 
    75 @param  aClusterNum     the cluster number of the directory stores   
    76 */
    77 TLeafDirData::TLeafDirData(TUint aClusterNum, const TEntryPos& aMRUPos)
    78              :iClusterNum(aClusterNum),iMRUPos(aMRUPos.Cluster(), aMRUPos.Pos())
    79     {
    80     }
    81 
    82 
    83 
    84 /**
    85 Factory fucntion of tree nodes
    86 
    87 @param  aOwnerTree  a pointer of the tree that owns this node   
    88 @param  aPathName   the directory path this node represents
    89 @param  aDirPos     the location of the directory this node represents   
    90 @param  aType       the type of the node   
    91 */
    92 CLeafDirTreeNode* CLeafDirTreeNode::NewL(CLeafDirTree* aOwnerTree, const TDesC& aPathName, const TLeafDirData& aDirPos, TLeafDirTreeNodeType aType)
    93     {
    94     CLeafDirTreeNode* self = new(ELeave) CLeafDirTreeNode(aDirPos, aType);
    95     CleanupStack::PushL(self);
    96     self->ConstructL(aOwnerTree, aPathName);
    97     CleanupStack::Pop();
    98     return self;
    99     }
   100 
   101 /**
   102 Constructor of tree nodes
   103 
   104 @param  aDirPos     the location of the directory this node represents   
   105 @param  aType       the type of the node   
   106 */
   107 CLeafDirTreeNode::CLeafDirTreeNode(const TLeafDirData& aDirPos, TLeafDirTreeNodeType aType)
   108                   :iParent(NULL), iLeafDirData(aDirPos), iNodeType(aType)
   109     {
   110     }
   111 
   112 /**
   113 2nd phase constructor of tree nodes
   114 
   115 @param  aOwnerTree  a pointer of the tree that owns this node   
   116 @param  aPathName   the directory path this node represents
   117 */
   118 void CLeafDirTreeNode::ConstructL(CLeafDirTree* aOwnerTree, const TDesC& aPath)
   119     {
   120     if (aOwnerTree == NULL)
   121         {
   122         ASSERT(0);
   123         User::Leave(KErrArgument);
   124         }
   125     iOwnerTree = aOwnerTree;
   126     iPath.CreateL(aPath);
   127 #ifdef _DEBUG
   128     iOwnerTree->AddToObjectContainerL(this);
   129 #endif //_DEBUG
   130     }
   131 
   132 /**
   133 Destructor of tree nodes
   134 
   135 @pre    The node should already be removed from its parent before being deleted
   136 */
   137 CLeafDirTreeNode::~CLeafDirTreeNode()
   138     {
   139 #ifdef _DEBUG
   140     TRAPD(err, iOwnerTree->RemoveFromObjectContainerL(this));
   141     ASSERT(err == KErrNone);
   142 #endif // _DEBUG
   143     iPath.Close();
   144     iChildren.Close();
   145     }
   146 
   147 /**
   148 Set type of the node
   149 
   150 @param  aType   the type to be set
   151 */
   152 void CLeafDirTreeNode::SetType(const CLeafDirTreeNode::TLeafDirTreeNodeType aType)
   153     {
   154     // Root node can not be reset type
   155     if (iNodeType == CLeafDirTreeNode::ERoot)
   156         return;
   157     iNodeType = aType;
   158     }
   159 
   160 /**
   161 Set path of the directory the node represents
   162 
   163 @param  aPath   the path to be set   
   164 */
   165 void CLeafDirTreeNode::SetPathL(const TDesC& aPath)
   166     {
   167     ASSERT(aPath.Length() > 0);
   168     if (iPath.Length() < aPath.Length())
   169         {
   170         TInt err = iPath.ReAlloc(aPath.Length());
   171         ASSERT(err==KErrNone);
   172         User::LeaveIfError(err);
   173         }
   174     iPath = aPath;
   175     }
   176 
   177 /**
   178 Removes from the children list, sets aNode's parent NULL, does not delete aNode
   179 
   180 @param  aNode   the node to be removed   
   181 */
   182 TInt CLeafDirTreeNode::RemoveChild(CLeafDirTreeNode* aNode)
   183     {
   184     ASSERT(aNode);
   185     if (aNode->IsRoot())
   186         {
   187         ASSERT(0);
   188         return KErrArgument;
   189         }
   190     
   191     if (iChildren.Count() > 0)
   192         {
   193         for (TInt i = iChildren.Count() - 1; i >= 0; i--)
   194             {
   195             if (iChildren[i] == aNode)
   196                 {
   197                 iChildren.Remove(i);
   198                 aNode->SetParent(NULL);
   199                 return KErrNone;
   200                 }
   201             }
   202         }
   203     return KErrNotFound;
   204     }
   205 
   206 /**
   207 Add a new child node to self
   208 
   209 @pre    aNode should have been removed from its original parent
   210 @param  aNode   the node to be added   
   211 */
   212 void CLeafDirTreeNode::MakeItChildL(CLeafDirTreeNode* aNode)
   213     {
   214     ASSERT(aNode->Parent() == NULL);
   215     if (aNode->IsRoot())
   216         {
   217         ASSERT(0);
   218         User::Leave(KErrArgument);
   219         }
   220     iChildren.AppendL(aNode);
   221     aNode->SetParent(this);
   222     }
   223 
   224 
   225 /**
   226 Factory function of CLeafDirTree
   227 
   228 @param  aLimit  the maximum number of 'leaf' nodes allowed of the tree   
   229 */
   230 CLeafDirTree* CLeafDirTree::NewL(TUint32 aSize)
   231     {
   232     CLeafDirTree* self = new(ELeave) CLeafDirTree(aSize);
   233     CleanupStack::PushL(self);
   234     self->ConstructL();
   235     CleanupStack::Pop();
   236     return self;
   237     }
   238 
   239 /**
   240 Constructor of CLeafDirTree
   241 
   242 @param  aLimit  the maximum number of 'leaf' nodes allowed of the tree   
   243 */
   244 CLeafDirTree::CLeafDirTree(TUint32 aSize)
   245 :iSize(aSize)
   246     {
   247     }
   248 
   249 _LIT(KRootDirPath, "\\");
   250 /**
   251 2nd phase constructor of CLeafDirTree
   252 */
   253 void CLeafDirTree::ConstructL()
   254     {
   255     TLeafDirData rootDirPos(0);
   256     CLeafDirTreeNode* root = CLeafDirTreeNode::NewL(this, KRootDirPath, rootDirPos, CLeafDirTreeNode::ERoot);
   257     iRoot = root;
   258     iRoot->SetType(CLeafDirTreeNode::ERoot);
   259     }
   260 
   261 /**
   262 Destructor of CLeafDirTree
   263 */
   264 CLeafDirTree::~CLeafDirTree()
   265     {
   266     Reset();
   267     delete iRoot;
   268     iLruList.Close();
   269 
   270 #ifdef _DEBUG
   271     iContainer.Close();
   272 #endif //_DEBUG
   273     }
   274 
   275 /**
   276 Free all the nodes from the tree except root node
   277 */
   278 void CLeafDirTree::Reset()
   279     {
   280     TInt err = KErrNone;
   281     TRAP(err, DeleteSubTreeL(iRoot));
   282     ASSERT(err == KErrNone);
   283     }
   284 
   285 /**
   286 Search for a node by directory path
   287 
   288 @param  aPath       the path as the key to search in the tree
   289 @param  aNodeFound  in return, the node found 
   290 @param  aDirPos     the location of the directory
   291 @return KErrNone    if a node found
   292         KErrNotFound if no node is found
   293 */
   294 TInt CLeafDirTree::Search(const TDesC& aPath, CLeafDirTreeNode*& aNodeFound, TLeafDirData& aDirPos)
   295     {
   296     return (DoSearch(aPath, iRoot, aNodeFound, aDirPos));
   297     }
   298 
   299 /**
   300 Search for a node by directory path, start from children of aNodeToStart but do not include aNodeToStart.
   301 
   302 @param  aPath           the path as the key to search in the tree
   303 @param  aNodeToStart    the node whose children to start with 
   304 @param  aNodeFound      in return, the node found 
   305 @param  aDirPos         the location of the directory
   306 @return KErrNone        if a node found
   307         KErrNotFound    if no node is found
   308 */
   309 TInt CLeafDirTree::DoSearch(const TDesC& aPath, CLeafDirTreeNode* aNodeToStart, CLeafDirTreeNode*& aNodeFound, TLeafDirData& aLeafDirData)
   310     {
   311     RPointerArray<CLeafDirTreeNode> currentLevel = aNodeToStart->Children();
   312     TInt currentPos = currentLevel.Count() - 1;
   313     // Current path in search
   314     TPtrC currentPath;
   315     currentPath.Set(aPath);
   316     while (currentLevel.Count() > 0 && currentPos >= 0)
   317         {
   318         CLeafDirTreeNode* currentNode = currentLevel[currentPos];
   319         TPtrC currentNodePath;
   320         currentNodePath.Set(currentNode->Path());
   321         TInt foundPos = currentPath.FindF(currentNodePath);
   322         // If current child's path is part of the searching path, 
   323         //  go to next level
   324         //  E.g.: current child's path = "1\2\3\", searching path = "1\2\3\5\".
   325         if (foundPos == 0 && currentNodePath.Length() < currentPath.Length())
   326             {
   327             currentPath.Set(currentPath.Mid(currentNodePath.Length()));
   328             currentLevel = currentNode->Children();
   329             currentPos = currentLevel.Count() - 1;
   330             continue;
   331             }
   332         // If current child's path matches current searching path,
   333         //  check the node type.
   334         else if (foundPos == 0 && currentNodePath.Length() == currentPath.Length())
   335             {
   336             if (currentNode->IsPureIntermediary())
   337             // If found is 'pure intermediary', it is not cached. 
   338                 {
   339                 return KErrNotFound;
   340                 }
   341             // Otherwise, we have got a cache hit!
   342             MakeMostRecentlyUsed(currentNode);
   343             aNodeFound = currentNode;
   344             aLeafDirData = currentNode->LeafDirData();
   345             return KErrNone;
   346             }
   347         // else, go through current level
   348         currentPos--;
   349         }
   350     // If there is no child or we have not found any matching node,
   351     //  return KErrNotFound
   352     return KErrNotFound;
   353     }
   354 
   355 /**
   356 Find the longest common 'path' between two paths.
   357 Note: not the longest common 'string'.
   358 
   359 @param  aPathA  path A
   360 @param  aPathB  path B 
   361 @return     the length of the longest common path found
   362             KErrNotFound    if no node is found
   363 */
   364 TInt FindLongestCommonPath(const TDesC& aPathA, const TDesC& aPathB)
   365     {
   366     const TInt compareLength = Min(aPathA.Length(), aPathB.Length());
   367     if (compareLength <= 0)
   368         {
   369         return KErrArgument;
   370         }
   371     TInt i = 0;
   372     TInt lastPathDelimiterPos = KErrNotFound;
   373     while (i < compareLength && aPathA[i] == aPathB[i])
   374         {
   375         if (aPathA[i] == '\\')
   376             {
   377             lastPathDelimiterPos = i;
   378             }
   379         i++;
   380         }
   381     
   382     if (i == 0)
   383         {
   384         return KErrNotFound;
   385         }
   386     return lastPathDelimiterPos;
   387     }
   388 
   389 /**
   390 Insert a new node to the tree according to the path 
   391 
   392 @param  aPath           the path of the new node to be inserted
   393 @param  aDirPos         the position of the new node to be inserted
   394 @param  aNodeInserted   in return, the node that has been successfully inserted
   395 */
   396 void CLeafDirTree::InsertL(const TDesC& aPath, const TLeafDirData& aLeafDirData, CLeafDirTreeNode*& aNodeInserted)
   397     {
   398     ASSERT(aPath.Length() > 0);
   399     // aPath should always start and end with a '\\'.
   400     if (aPath[0] == '\\' && aPath[aPath.Length() - 1] =='\\')
   401         {
   402         if (aPath.Length() > 1)
   403             {
   404             TPtrC path;
   405             path.Set(aPath.Mid(1));
   406             DoInsertL(iRoot, path, aLeafDirData, aNodeInserted);
   407             }
   408         }
   409     else
   410         {
   411         ASSERT(0);
   412         User::Leave(KErrBadName);
   413         }
   414     }
   415 
   416 /**
   417 Implementation of the insertion algorithm 
   418 
   419 @param  aNodeToStart    the node whose children to start with
   420 @param  aPath           the path of the new node to be inserted
   421 @param  aDirPos         the position of the new node to be inserted
   422 @param  aNodeInserted   in return, the node that has been successfully inserted
   423 */
   424 void CLeafDirTree::DoInsertL(CLeafDirTreeNode* aNodeToStart, const TDesC& aPath, const TLeafDirData& aLeafDirData, CLeafDirTreeNode*& aNodeInserted)
   425     {
   426     CLeafDirTreeNode* currentParent = aNodeToStart;
   427     TInt foundPos = 0;
   428     RPointerArray<CLeafDirTreeNode> currentLevel = aNodeToStart->Children();
   429     TInt currentPos = currentLevel.Count() - 1;
   430     TPtrC currentPath;
   431     currentPath.Set(aPath);
   432     while (currentLevel.Count() > 0 && currentPos >= 0)
   433         {
   434         CLeafDirTreeNode* currentNode = currentLevel[currentPos];
   435         TPtrC currentNodePath;
   436         currentNodePath.Set(currentNode->Path());
   437 
   438         // If current node is contained by aPath.
   439         //  E.g.: current node = "1\2\3\", currentPath = "1\2\3\5\"
   440         //  In this case, we need to go to next level,
   441         //  discard logged position (currentPos) in this level as we don't need to come back.
   442         foundPos = currentPath.FindF(currentNodePath);
   443         if (foundPos == 0 && currentNodePath.Length() < currentPath.Length())
   444             {
   445             currentParent = currentNode;
   446             currentLevel = currentNode->Children();
   447             currentPos = currentLevel.Count() - 1;
   448             currentPath.Set(currentPath.Mid(currentNodePath.Length()));
   449             continue;
   450             }
   451 
   452         // If current node's path contains aPath 
   453         //  E.g.: current node = "1\2\3\4\", currentPath = "1\2\3\"
   454         //  We need to split current node to two nodes and return.
   455         foundPos = currentNodePath.FindF(currentPath);
   456         if (foundPos == 0 && currentNodePath.Length() > currentPath.Length())
   457             {
   458             CLeafDirTreeNode* newNode = CLeafDirTreeNode::NewL(this, currentPath, aLeafDirData, CLeafDirTreeNode::ELeafIntermediary);
   459             currentParent->MakeItChildL(newNode);
   460             
   461             TPtrC restPath;
   462             restPath.Set(currentNodePath.Mid(currentPath.Length()));
   463             currentNode->SetPathL(restPath);
   464             currentParent->RemoveChild(currentNode);
   465             
   466             newNode->MakeItChildL(currentNode);
   467             AddOntoLruL(newNode);
   468             aNodeInserted = newNode;
   469             return;
   470             }
   471 
   472         // If current node's path equals aPath,
   473         //  change the node type if it is necessary
   474         if (foundPos == 0 && currentNodePath.Length() == currentPath.Length())
   475             {
   476             // Check node type, if already cached, update Lru list and return.
   477             if (currentNode->IsLeaf() || currentNode->IsLeafIntermediary())
   478                 {
   479                 currentNode->SetLeafDirData(aLeafDirData);
   480                 aNodeInserted = currentNode;
   481                 MakeMostRecentlyUsed(currentNode);
   482                 return;
   483                 }
   484             // If it has not been cached yet, i.e., it is a 'pure intermediary' node,
   485             //  cache the node and put it onto Lru list
   486             else if(currentNode->IsPureIntermediary())
   487                 {
   488                 currentNode->SetLeafDirData(aLeafDirData);
   489                 currentNode->SetType(CLeafDirTreeNode::ELeafIntermediary);
   490                 AddOntoLruL(currentNode);
   491                 aNodeInserted = currentNode;
   492                 return;
   493                 }
   494             }
   495         
   496         // If none of above is the case (i.e. haven't found exact match or paths 
   497         //  are not contained by each other), we need to find the first common part 
   498         //  between each child and aPath to share path data.
   499         foundPos = FindLongestCommonPath(currentNodePath, currentPath);
   500         // If a common part of path is found, we need to create a pure intermediary node to share
   501         //  the common part of path data, and create a new leaf node for the target path.
   502         if (foundPos > 0)
   503             {
   504             TPtrC commonPath;
   505             commonPath.Set(currentNodePath.Left(foundPos + 1));
   506 
   507             currentNodePath.Set(currentNodePath.Mid(foundPos + 1));
   508             TPtrC newLeafPath;
   509             newLeafPath.Set(currentPath.Mid(foundPos + 1));
   510 
   511             // Add new pureintermediary node, set it as child of current parent
   512             TLeafDirData dummyPos(0);
   513             CLeafDirTreeNode* newPureIntermediaryNode = CLeafDirTreeNode::NewL(this, commonPath, dummyPos, CLeafDirTreeNode::EPureIntermediary);
   514             currentParent->MakeItChildL(newPureIntermediaryNode);
   515 
   516             // Remove current child from aNodeToStart, do not need to change
   517             //  node type of aNodeToStart
   518             currentParent->RemoveChild(currentNode);
   519 
   520             // Modify current pathData, make it child of new node
   521             newPureIntermediaryNode->MakeItChildL(currentNode);
   522             currentNode->SetPathL(currentNodePath);
   523 
   524             // Add new leaf node as a child of the new pure intermediary node
   525             CLeafDirTreeNode* newLeafNode = CLeafDirTreeNode::NewL(this, newLeafPath, aLeafDirData, CLeafDirTreeNode::ELeaf);
   526             newPureIntermediaryNode->MakeItChildL(newLeafNode);
   527             aNodeInserted = newLeafNode;
   528             AddOntoLruL(newLeafNode);
   529             return;
   530             }
   531 
   532         // Otherwise, move on within this level.
   533         currentPos--;
   534         }
   535     
   536     // No match case found, add a new node straight on at current level
   537     CLeafDirTreeNode* newNode = CLeafDirTreeNode::NewL(this, currentPath, aLeafDirData, CLeafDirTreeNode::ELeaf);
   538 
   539     if (currentParent->IsLeaf())        // might be the root node
   540         {
   541         currentParent->SetType(CLeafDirTreeNode::ELeafIntermediary);
   542         }
   543     currentParent->MakeItChildL(newNode);
   544     aNodeInserted = newNode;
   545     AddOntoLruL(newNode);
   546     }
   547 
   548 /**
   549 Remove nodes with a specific position from the tree  
   550 Note: multiple nodes may have the same position value, as directories can be accessed
   551     by both long names and short names:
   552 E.g.:   "\\LongDirName01\\LongDirName02\\LongDirName03\\"
   553         "\\LongDirName01\\LongDirName02\\LONGDI~1\\"
   554         "\\LongDirName01\\LONGDI~1\\LongDirName03\\"
   555         "\\LONGDI~1\\LongDirName02\\LongDirName03\\"
   556 
   557 @param  aDirPos     the position of the nodes to be removed
   558 */
   559 void CLeafDirTree::RemoveDirL(const TLeafDirData& aDirPos)
   560     {
   561     // remove alias nodes in cache
   562     for (TInt i = iLruList.Count() - 1; i >= 0; i--)
   563         {
   564         if (iLruList[i]->StartClusterNum() == aDirPos.iClusterNum)
   565             {
   566             RemoveFromCacheL(iLruList[i]);
   567             }
   568         }
   569     }
   570 
   571 
   572 /**
   573 Update the MRU entry position of the tree nodes.
   574 @param  aLeafDirData    contains the index of the cache node and the new MRU entry position 
   575 */
   576 void CLeafDirTree::UpdateMRUPos(const TLeafDirData& aLeafDirData)
   577     {
   578     // update alias nodes in cache
   579     for (TInt i = iLruList.Count() - 1; i >= 0; i--)
   580         {
   581         if (iLruList[i]->StartClusterNum() == aLeafDirData.iClusterNum)
   582             {
   583             iLruList[i]->SetLeafDirData(aLeafDirData);
   584             }
   585         }
   586     }
   587 
   588 /**
   589 Remove a 'leaf' node, i.e. a leaf node or leaf intermediary node.
   590 
   591 @param  aNodeTodelete the node to be removed
   592 */
   593 void CLeafDirTree::RemoveFromCacheL(CLeafDirTreeNode* aNodeToDelete)
   594     {
   595     ASSERT(aNodeToDelete->IsLeaf() || aNodeToDelete->IsLeafIntermediary());
   596     CLeafDirTreeNode* parent = aNodeToDelete->Parent(); 
   597     // Deleting 'leaf intermediary' nodes:
   598     if (aNodeToDelete->IsLeafIntermediary())
   599         {
   600         // If there is no child, error! The 'tree' is corrupted.
   601         if (aNodeToDelete->Children().Count() == 0)
   602             {
   603             ASSERT(0);
   604             User::Leave(KErrCorrupt);
   605             }
   606         // If there is only one child, 'promote' the child, delete self
   607         else if (aNodeToDelete->Children().Count() == 1)
   608             {
   609             CLeafDirTreeNode* child = (aNodeToDelete->Children())[0];
   610             TFileName newPath = aNodeToDelete->Path();
   611             newPath.Append(child->Path());
   612             child->SetPathL(newPath);
   613             aNodeToDelete->RemoveChild(child);
   614             parent->MakeItChildL(child);
   615 
   616             parent->RemoveChild(aNodeToDelete);
   617             RemoveFromLru(aNodeToDelete);
   618             delete aNodeToDelete;
   619             return;
   620             }
   621         // If there are more than one child, just change node type to 'pure intermediary',
   622         //  but remove self from Lru list.
   623         else
   624             {
   625             aNodeToDelete->SetType(CLeafDirTreeNode::EPureIntermediary);
   626             RemoveFromLru(aNodeToDelete);
   627             return;
   628             }
   629         }
   630     // Deleting 'leaf' nodes:
   631     else
   632         {
   633         // If 'parent' is a 'leaf intermediary' node
   634         if (parent->IsLeafIntermediary())
   635             {
   636             // If there is no other sibling, change parent's node type to 'leaf',
   637             //  otherwise, leave parent's type as 'leaf intermediary' 
   638             if (parent->Children().Count() == 1)
   639                 {
   640                 parent->SetType(CLeafDirTreeNode::ELeaf);
   641                 }
   642             parent->RemoveChild(aNodeToDelete);
   643             RemoveFromLru(aNodeToDelete);
   644             delete aNodeToDelete;
   645             return;
   646             }
   647         // If 'parent' is 'pure intermediary'
   648         else if (parent->IsPureIntermediary())
   649             {
   650             // If there is no sibling nodes, the tree is corrupted,
   651             //  as 'pure intermediary' node should always have more than one child.
   652             if (parent->Children().Count() <= 1)
   653                 {
   654                 ASSERT(0);
   655                 User::Leave(KErrCorrupt);
   656                 }
   657             // If there is only one sibling node, we need to merge the sibling node
   658             //  to 'parent'.
   659             else if (parent->Children().Count() == 2)
   660                 {
   661                 // Promote the sibling node, delete both parent and self
   662                 CLeafDirTreeNode* sibling = (parent->Children())[0] ;
   663                 if (sibling == aNodeToDelete)
   664                     {
   665                     sibling = (parent->Children())[1];
   666                     }
   667                 TFileName newPath = aNodeToDelete->Parent()->Path();
   668                 newPath.Append(sibling->Path());
   669                 sibling->SetPathL(newPath);
   670                 parent->RemoveChild(sibling);
   671                 parent->Parent()->MakeItChildL(sibling);
   672                 
   673                 parent->RemoveChild(aNodeToDelete);
   674                 RemoveFromLru(aNodeToDelete);
   675                 delete aNodeToDelete;
   676                 aNodeToDelete = NULL;
   677 
   678                 parent->Parent()->RemoveChild(parent);
   679                 delete parent;
   680                 return;
   681                 }
   682             // Else if there are more than 2 sibling nodes, simply delete self.
   683             else
   684                 {
   685                 parent->RemoveChild(aNodeToDelete);
   686                 RemoveFromLru(aNodeToDelete);
   687                 delete aNodeToDelete;
   688                 aNodeToDelete = NULL;
   689                 return;
   690                 }
   691             }
   692         // If 'parent' is root node, delete self straightaway
   693         else if (aNodeToDelete->Parent()->IsRoot())
   694             {
   695             aNodeToDelete->Parent()->RemoveChild(aNodeToDelete);
   696             RemoveFromLru(aNodeToDelete);
   697             delete aNodeToDelete;
   698             aNodeToDelete = NULL;
   699             return;
   700             }
   701         // If 'parent' is 'leaf', the tree is corrupted. 
   702         else if (aNodeToDelete->Parent()->IsLeaf())
   703             {
   704             ASSERT(0);
   705             User::Leave(KErrCorrupt);
   706             }
   707         }
   708     }
   709 
   710 /**
   711 Find the leftest node
   712 Note: the leftest node must be a 'leaf' node
   713 
   714 @param  aNodeToStart    a node whose children to start with
   715 @return the leftest node
   716 */
   717 CLeafDirTreeNode* CLeafDirTree::FindLeftestLeafNode(CLeafDirTreeNode* aNodeToStart) const
   718     {
   719     CLeafDirTreeNode* current = aNodeToStart;
   720     while (current->Children().Count() > 0)
   721         {
   722         current = (current->Children())[0];
   723         }
   724     return current;
   725     }
   726 
   727 /**
   728 Delete all nodes derived from aNodeToStart, except itself.
   729 
   730 @param  aNodeToStart    a node whose children to start with
   731 */
   732 void CLeafDirTree::DeleteSubTreeL(CLeafDirTreeNode* aNodeToStart)
   733     {
   734     while(aNodeToStart->Children().Count() > 0)
   735         {
   736         CLeafDirTreeNode* aLeafNode = FindLeftestLeafNode(aNodeToStart);
   737         RemoveFromCacheL(aLeafNode);
   738         }
   739     }
   740 
   741 /**
   742 Make the a node most recent used in LRU list
   743 
   744 @param  aNodeUsed   the node to be made MRU
   745 */
   746 TInt CLeafDirTree::MakeMostRecentlyUsed(CLeafDirTreeNode* aNodeUsed)
   747     {
   748     for(TInt i = 0; i < iLruList.Count(); i++)
   749         {
   750         if (aNodeUsed == iLruList[i])
   751             {
   752             if (i == 0)
   753                 {
   754                 return KErrNone;
   755                 }
   756             else
   757                 {
   758                 iLruList.Remove(i);
   759                 iLruList.Insert(aNodeUsed, 0);
   760                 return KErrNone;
   761                 }
   762             }
   763         }
   764     return KErrNotFound;
   765     }
   766 
   767 /**
   768 Check cache limit, remove least-used cached item when necessary.
   769 */
   770 void CLeafDirTree::CheckLimitL()
   771     {
   772     const TInt cacheSize = iSize;
   773     while (iLruList.Count() > cacheSize)
   774         {
   775         CLeafDirTreeNode* lruNode = LruNode();
   776         RemoveFromCacheL(lruNode);
   777         }
   778     return;
   779     }
   780 
   781 /**
   782 Add new node onto cache list
   783 
   784 @param  aNodeToAdd  the new node to be added onto cache list
   785 */
   786 void CLeafDirTree::AddOntoLruL(CLeafDirTreeNode* aNodeToAdd)
   787     {
   788     if (aNodeToAdd == NULL)
   789         {
   790         ASSERT(0);
   791         User::Leave(KErrArgument);
   792         }
   793     
   794     TInt r = iLruList.Insert(aNodeToAdd, 0);
   795     if (r != KErrNone)
   796         {
   797         ASSERT(0);
   798         User::Leave(KErrArgument);
   799         }
   800     CheckLimitL();
   801     }
   802 
   803 /**
   804 Remove a node from cached list.
   805 
   806 @param  aNodeToRemove   the node to be removed from the cache list
   807 */
   808 TInt CLeafDirTree::RemoveFromLru(CLeafDirTreeNode* aNodeToRemove)
   809     {
   810     for (TInt i = 0; i < iLruList.Count(); i++)
   811         {
   812         if (aNodeToRemove == iLruList[i])
   813             {
   814             iLruList.Remove(i);
   815             return KErrNone;
   816             }
   817         }
   818     return KErrNotFound;
   819     }
   820 
   821 /**
   822 Return the least-recent-used node.
   823 
   824 @return the least recent used node on cache
   825 */
   826 CLeafDirTreeNode* CLeafDirTree::LruNode()
   827     {
   828     if (iLruList.Count() > 0)
   829         {
   830         return iLruList[iLruList.Count() - 1];
   831         }
   832     return NULL;
   833     }
   834 
   835 /*
   836 Factory function of CLeafDirCache
   837 
   838 @param  aLimit  the cache size 
   839 */
   840 CLeafDirCache* CLeafDirCache::NewL(TUint32 aLimit)
   841     {
   842     CLeafDirCache* self = new(ELeave) CLeafDirCache(aLimit);
   843     CleanupStack::PushL(self);
   844     self->ConstructL();
   845     CleanupStack::Pop(self);
   846     return self;
   847     }
   848 
   849 /*
   850 2nd phase constructor of CLeafDirCache
   851 */
   852 void CLeafDirCache::ConstructL()
   853     {
   854     CLeafDirTree* tree = CLeafDirTree::NewL(iSize);
   855     iTree = tree;
   856     }
   857 
   858 /*
   859 Destructor of CLeafDirCache
   860 */
   861 CLeafDirCache::~CLeafDirCache()
   862     {
   863     delete iTree;
   864     }
   865 
   866 /*
   867 Constructor of CLeafDirCache
   868 
   869 @param aLimit the cache size
   870 */
   871 CLeafDirCache::CLeafDirCache(TUint32 aSize)
   872               :iSize(aSize)
   873     {
   874     }
   875 
   876 /*
   877 Reset cache, delete all memory allocated
   878 */
   879 void CLeafDirCache::Reset()
   880     {
   881     iTree->Reset();
   882     }
   883 
   884 /*
   885 Cache interface for searching operations.
   886 
   887 @param  aPath   the path of the directory to search for
   888 @param  aDirPos the location of the direcotry found
   889 @return KErrNone if a cached direcotry is found,
   890         KErrBadName if the path is incorrect, otherwise 
   891         other system wide error code
   892 */
   893 TInt CLeafDirCache::FindInCache(const TDesC& aPath, TLeafDirData& aLeafDirData) const 
   894     {
   895     if (aPath[0] == '\\')
   896         {
   897         TPtrC path;
   898         path.Set(aPath.Mid(1));
   899         CLeafDirTreeNode* dummy = NULL;
   900         return (iTree->Search(path, dummy, aLeafDirData));
   901         }
   902     else
   903         {
   904         return KErrBadName;
   905         }
   906     }
   907 
   908 /*
   909 Cache interface for insertion operations.
   910 
   911 @param  aPath   the path of the directory to be added
   912 @param  aDirPos the location of the direcotry to be added
   913 */
   914 void CLeafDirCache::AddToCacheL(const TDesC& aPath, const TLeafDirData& aDirPos)
   915     {
   916     if (aPath.Length() == 1 && aPath[0] == '\\')
   917         return;
   918 
   919     CLeafDirTreeNode* dummy = NULL;
   920     iTree->InsertL(aPath, aDirPos, dummy);
   921     }
   922 
   923 /*
   924 Cache interface for deletion oeprations.
   925 Remove all the cached directories with the same specfied position
   926 
   927 @param  aDirPos the location of the direcotry to be removed
   928 */
   929 void CLeafDirCache::RemoveDirL(const TLeafDirData& aDirPos)
   930     {
   931     iTree->RemoveDirL(aDirPos);
   932     }
   933 
   934 /**
   935 Update the MRU entry position of the cached leaf dir.
   936 @param  aLeafDirData    contains a cluster number as the index of the leaf dir and the new MRU entry position 
   937 */
   938 void CLeafDirCache::UpdateMRUPos(const TLeafDirData& aLeafDirData)
   939     {
   940     iTree->UpdateMRUPos(aLeafDirData);
   941     }
   942 /*
   943  * Helper functions of CLeafDirTree for debugging & testing use
   944  */
   945 #ifdef _DEBUG
   946 /*
   947 All node created will be added to the container of its owner tree, so that we can calculate
   948     the number of objects created.
   949 
   950 @param  aNodeToAdd  the newly created node to be add to object container 
   951 */
   952 void CLeafDirTree::AddToObjectContainerL(CLeafDirTreeNode* aNodeToAdd)
   953     {
   954     iContainer.AppendL(aNodeToAdd);
   955     }
   956 
   957 /*
   958 A node is removed from object container if it is deleted.
   959 
   960 @param  aNodeToRemove   the node to be deleted 
   961 */
   962 void CLeafDirTree::RemoveFromObjectContainerL(CLeafDirTreeNode* aNodeToRemove)
   963     {
   964     for (TInt i = 0; i < iContainer.Count(); i++)
   965         {
   966         if (aNodeToRemove == iContainer[i])
   967             {
   968             iContainer.Remove(i);
   969             return;
   970             }
   971         }
   972     ASSERT(0);
   973     User::Leave(KErrNotFound);
   974     }
   975 
   976 /*
   977 Print out current tree content
   978 */
   979 void CLeafDirTree::DumpTreeContentL() const
   980     {
   981     RPointerArray<CLeafDirTreeNode>* nodeStack = new(ELeave) RPointerArray<CLeafDirTreeNode>(4);
   982     RFs fs;
   983     fs.Connect();
   984     const TUint32 debugRegister = DebugRegister();
   985     fs.SetDebugRegister(debugRegister|KFSYS);
   986     if (iRoot != NULL)
   987         {
   988         nodeStack->Insert(iRoot, 0);
   989         while(nodeStack->Count() > 0)
   990             {
   991             CLeafDirTreeNode* current = (*nodeStack)[0];
   992             if (current->Parent() != NULL)
   993                 {
   994                 __PRINT3(_L("(\"%S\") -> \"%S\" : (%d)\n"), &current->Parent()->Path(), &current->Path(), current->StartClusterNum());
   995                 }
   996             else
   997                 {
   998                 __PRINT2(_L("\"%S\" : (%d)\n"), &current->Path(), current->StartClusterNum());              
   999                 }
  1000 
  1001             nodeStack->Remove(0);
  1002             
  1003             TInt currentCount = current->Children().Count();
  1004             if (currentCount > 0)
  1005                 {
  1006                 RPointerArray<CLeafDirTreeNode> children = current->Children();
  1007                 for (TInt i = 0; i < currentCount; i++)
  1008                     {
  1009                     nodeStack->Insert(children[i], 0);
  1010                     }
  1011                 }
  1012             }
  1013         }
  1014 
  1015     fs.SetDebugRegister(debugRegister);
  1016     fs.Close();
  1017     nodeStack->Close();
  1018     delete nodeStack;
  1019     }
  1020 
  1021 /*
  1022 Print out current cache content
  1023 */
  1024 void CLeafDirCache::DumpCacheContentL() const
  1025     {
  1026     iTree->DumpTreeContentL();
  1027     }
  1028 
  1029 /*
  1030 Count of all the nodes
  1031 */
  1032 TInt CLeafDirCache::NodeCount() const
  1033     {
  1034     return iTree->ObjectCount();
  1035     }
  1036 #endif // _DEBUG
  1037