--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/srofs/dircache.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,540 @@
+// Copyright (c) 2001-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 <e32std.h>
+#include <e32std_private.h>
+#include "sr_rofs.h"
+#include <rofs.h>
+
+
+CDirectoryCache::CDirectoryCache( CRofsMountCB& aMount, CProxyDrive& aLocalDrive, const TRofsHeader& aHeader )
+ : iMount( aMount ), iLocalDrive( aLocalDrive ),
+ iTreeMediaOffset( aHeader.iDirTreeOffset ),
+ iTreeSize( aHeader.iDirTreeSize ),
+ iFilesMediaOffset( aHeader.iDirFileEntriesOffset ),
+ iFilesSize( aHeader.iDirFileEntriesSize )
+ {
+ }
+
+CDirectoryCache::~CDirectoryCache()
+ {
+ delete iTreeBuffer;
+ delete iFilesBuffer;
+ }
+
+void CDirectoryCache::ConstructL()
+ {
+ iTreeBuffer = HBufC8::NewL( iTreeSize );
+ iFilesBuffer = HBufC8::NewL( iFilesSize );
+
+ TPtr8 ptr = iTreeBuffer->Des();
+ User::LeaveIfError( iLocalDrive.Read( iTreeMediaOffset, iTreeSize, ptr) );
+ TPtr8 ptr2 = iFilesBuffer->Des();
+ User::LeaveIfError( iLocalDrive.Read( iFilesMediaOffset, iFilesSize, ptr2) );
+ }
+
+
+void CDirectoryCache::FindLeafDirL(const TDesC& aName, const TRofsDir*& aDir) const
+//
+// Navigate the path to find the leaf directory, starting at aDir.
+//
+ {
+
+ TLex lex(aName);
+ TInt r;
+ FOREVER
+ {
+ lex.Inc(); // Skip the file separator
+ lex.Mark();
+ r=lex.Remainder().Locate(KPathDelimiter);
+
+ if ( KErrNotFound == r )
+ {
+ r=lex.Remainder().Length();
+ }
+ if ( 0 == r ) // End of the path
+ {
+ break;
+ }
+
+ lex.Inc(r); // Set the token length
+
+ const TRofsEntry* subDirEntry = NULL;
+ TInt r = DoBinaryFindSubDir(lex.MarkedToken(), KEntryAttDir|KEntryAttMatchExclusive, aDir, subDirEntry );
+ if( KErrNone != r )
+ {
+ User::Leave( KErrPathNotFound );
+ }
+ __ASSERT_DEBUG( 0 != (subDirEntry->iAtt & KEntryAttDir ), CRofs::Panic( CRofs::EPanicEntryNotDir ));
+ aDir = RofsDirFromSubDirEntry( subDirEntry );
+ }
+ }
+
+TInt CDirectoryCache::DoBinaryFindSubDir(const TDesC& aName, TUint aAtt, const TRofsDir* aDir, const TRofsEntry*& aSubDirEntry ) const
+ //
+ // Scan the directory aDir looking for subdirectory aName using binary search.
+ // aName cannot contain wildcards and aSubDirEntry should always be NULL.
+ // If a matching entry is found writes pointer to the entry into aSubDirEntry
+ // and returns KErrNone.
+ //
+ {
+
+ if (aSubDirEntry != NULL)
+ {
+ return DoFindSubDir(aName, aAtt, aDir, aSubDirEntry);
+ }
+
+ TInt numDirs=GetDirCount(aDir);
+ TInt topIndex=numDirs-1;
+ TInt bottomIndex=0;
+
+ TBool bFound=EFalse;
+ TInt retVal=KErrNotFound;
+ if(topIndex>=0)
+ {
+ TUint16* offsets = (TUint16*) ((TUint8*) aDir + aDir->iStructSize);
+ offsets += 2; //to skip file and dir counts
+
+ while((!bFound) && (topIndex>=bottomIndex))
+ {
+ TInt32 middleIndex;
+ const TRofsEntry* pCurrentEntry=NULL;
+ middleIndex=(topIndex+bottomIndex)>>1;
+
+ //Offsets for directories are relative to the start of the
+ //directory block
+ TUint8* ptr = (TUint8*) aDir + (offsets[middleIndex] << 2);
+ pCurrentEntry = (TRofsEntry*) ptr;
+
+ TPtrC currName=TPtrC((const TText*)&pCurrentEntry->iName[0],pCurrentEntry->iNameLength);
+
+ TInt result=Compare(aName,currName);
+ if(result<0)
+ topIndex=middleIndex-1;
+ else if(result>0)
+ bottomIndex=middleIndex+1;
+ else
+ {
+ bFound=ETrue; // exit loop
+ if (iMount.MatchEntryAtt(pCurrentEntry->iAtt, aAtt))
+ {
+ aSubDirEntry=pCurrentEntry;
+ retVal=KErrNone;
+ }
+ }
+ }
+ }
+ return retVal;
+ }
+
+TInt CDirectoryCache::DoFindSubDir(const TDesC& aName, TUint aAtt, const TRofsDir* aDir, const TRofsEntry*& aSubDirEntry ) const
+ //
+ // Scan the directory aDir looking for subdirectory aName. If aSubDirEntry is
+ // not NULL the search starts from the entry AFTER aSubDirEntry.
+ // If a matching entry is found writes pointer to the entry into aSubDirEntry
+ // and returns KErrNone.
+ //
+ {
+ const TRofsEntry* pEntry = aSubDirEntry; // which entry
+ const TRofsEntry* const pEnd = (TRofsEntry*)EndOfDirPlusOne( aDir );
+
+ if( !pEntry )
+ {
+ pEntry = FirstSubDirEntryFromDir( aDir );
+ }
+ else
+ {
+ // move to next entry
+ __ASSERT_DEBUG( pEntry >= FirstSubDirEntryFromDir( aDir ), CRofs::Panic( CRofs::EPanicEntryBeforeDirectory ));
+ __ASSERT_DEBUG( pEntry < pEnd, CRofs::Panic( CRofs::EPanicEntryAfterDirectory ));
+ pEntry = NextEntry( pEntry );
+ }
+
+ while ( pEntry < pEnd )
+ {
+ TPtrC name( NameAddress( pEntry ), pEntry->iNameLength);
+ if ( KErrNotFound != name.MatchF(aName) && iMount.MatchEntryAtt(pEntry->iAtt, aAtt) )
+ {
+ aSubDirEntry = pEntry;
+ return KErrNone;
+ }
+
+ pEntry = NextEntry( pEntry );
+ }
+ return KErrNotFound;
+ }
+
+TInt CDirectoryCache::GetDirCount(const TRofsDir* aDir) const
+//
+//Return the number of directory entries contained in aDir
+//
+ {
+ TUint16* dirCount = (TUint16*) ((TUint8*) aDir + aDir->iStructSize);
+ return *dirCount;
+ }
+
+TInt CDirectoryCache::GetFileCount(const TRofsDir* aDir) const
+//
+//Return the number of file entries contained in aDir
+//
+ {
+ TUint16* fileCount = (TUint16*) ((TUint8*) aDir + aDir->iStructSize);
+ fileCount++; //jump over the dir count
+ return *fileCount;
+ }
+
+TInt CDirectoryCache::Compare(const TDesC& aLeft, const TDesC& aRight) const
+//
+//Compares two filenames. Folds ASCII characters to uppercase
+//
+ {
+
+ TInt len=Min(aLeft.Length(),aRight.Length());
+ const TText* leftString = aLeft.Ptr();
+ const TText* rightString = aRight.Ptr();
+ while (len--)
+ {
+ TText leftChar=*leftString++;
+ TText rightChar=*rightString++;
+ if (leftChar<='Z' && leftChar>='A')
+ leftChar +='a'-'A'; // covert to UPPERCASE
+ if (rightChar<='Z' && rightChar>='A')
+ rightChar +='a'-'A'; // covert to UPPERCASE
+ TInt result=leftChar-rightChar;
+ if (result != 0)
+ return result;
+ }
+ // match up to end of shorter string, now compare lengths
+ return aLeft.Length()-aRight.Length();
+ }
+
+TInt CDirectoryCache::ExtractMangleInfo(const TDesC& searchName, TUint8 &MountId, TUint8 &ReservedId) const
+{
+ #define HexToInt(x) ( x.IsDigit()? (TUint8)(x-(TUint)'0') : 0x0a+(TUint8)((x>='A' && x<='Z')? x-(TUint)'A':x-(TUint)'a') )
+ const TInt KOpenBraceRevPos = 7;
+ const TInt KHyphenRevPos = 4;
+ const TInt KCloseBraceRevPos = 1;
+
+ TInt openBraceRevPos = searchName.LocateReverse('[');
+ TInt closeBraceRevPos = searchName.LocateReverse(']');
+ TInt hyphenRevPos = searchName.LocateReverse('-');
+ TInt searchNameLen = searchName.Length();
+
+ if(openBraceRevPos==KErrNotFound || closeBraceRevPos==KErrNotFound || hyphenRevPos==KErrNotFound)
+ return KErrNotFound;
+
+ openBraceRevPos = searchNameLen - openBraceRevPos;
+ closeBraceRevPos = searchNameLen - closeBraceRevPos;
+ hyphenRevPos = searchNameLen - hyphenRevPos;
+ if(openBraceRevPos!=KOpenBraceRevPos || hyphenRevPos!=KHyphenRevPos || closeBraceRevPos!=KCloseBraceRevPos)
+ return KErrNotFound;
+
+ const TText* nameString = searchName.Ptr();
+ TInt MountIdPos = searchNameLen - KOpenBraceRevPos + 1;
+ TInt ReservedIdPos = searchNameLen - KHyphenRevPos + 1;
+
+ TChar MountIdHNibble = *(nameString+MountIdPos);
+ TChar MountIdLNibble = *(nameString+MountIdPos+1);
+
+ TChar ReservedIdHNibble = *(nameString+ReservedIdPos);
+ TChar ReservedIdLNibble = *(nameString+ReservedIdPos+1);
+
+ if(MountIdHNibble.IsHexDigit() && MountIdLNibble.IsHexDigit() &&
+ ReservedIdHNibble.IsHexDigit() && ReservedIdLNibble.IsHexDigit())
+ {
+ MountId = (TUint8)((HexToInt(MountIdHNibble) << 4) | HexToInt(MountIdLNibble));
+ ReservedId = (TUint8)((HexToInt(ReservedIdHNibble) << 4) | HexToInt(ReservedIdLNibble));
+ return KErrNone;
+ }
+ return KErrNotFound;
+}
+
+TInt CDirectoryCache::DoBinaryFindFile(const TDesC& aName, TUint aAtt, const TRofsDir* aDir, const TRofsEntry*& aEntry ) const
+//
+// Scan from aDir looking for file aName using binary search.
+// aName cannot contain wildcards and aEntry should always be NULL.
+// If found return the result in aEntry.
+//
+ {
+ if (aEntry != NULL)
+ {
+ return DoFindFile(aName, aAtt, aDir, aEntry);
+ }
+
+ TInt numFiles=GetFileCount(aDir);
+ TInt topIndex=numFiles-1;
+ TInt bottomIndex=0;
+ TInt result;
+ TBool doNameMangle = ETrue;
+ TBuf<KMaxFileName> searchName;
+
+ TBool bFound=EFalse;
+ TInt retVal=KErrNotFound;
+
+ searchName.Copy((const TText*)aName.Ptr(), aName.Length());
+
+ if(topIndex>=0)
+ {
+ TUint16* offsets = (TUint16*) ((TUint8*) aDir + aDir->iStructSize);
+ offsets += 2; //to skip file and dir counts
+ offsets += GetDirCount(aDir); //skip directory offsets
+
+ while((!bFound) && (topIndex>=bottomIndex))
+ {
+ TInt32 middleIndex;
+ const TRofsEntry* pCurrentEntry=NULL;
+ TBuf<KMaxFileName> currName;
+
+ middleIndex=(topIndex+bottomIndex)>>1;
+
+ //Offsets for files are relative to the start of the
+ //file block
+ TInt bufferOffset = (offsets[middleIndex]<<2) - iFilesMediaOffset + 4;
+ bufferOffset += aDir->iFileBlockAddress;
+
+ TUint8* ptr = (TUint8*) &iFilesBuffer[0];
+
+ pCurrentEntry=(TRofsEntry*) &ptr[bufferOffset];
+
+ currName.Copy(((const TText*)&pCurrentEntry->iName[0]), pCurrentEntry->iNameLength);
+
+ if(doNameMangle && ((~pCurrentEntry->iAttExtra & (KEntryAttUnique >> 23)) != 0))
+ currName.AppendFormat(_L("[%02x-00]"),iMount.iMountId);
+
+ result=Compare(searchName,currName);
+
+ if(result<0)
+ topIndex=middleIndex-1;
+ else if(result>0)
+ bottomIndex=middleIndex+1;
+ else
+ {
+ bFound=ETrue; // exit loop
+ if (iMount.MatchEntryAtt(pCurrentEntry->iAtt, aAtt))
+ {
+ aEntry=pCurrentEntry;
+ retVal = (pCurrentEntry->iFileAddress == KFileHidden) ? KErrHidden : KErrNone;
+ }
+ /* If we have found a file and we are in second pass of binary search without nameMangle
+ check whether it is unique file */
+ if(!doNameMangle)
+ {
+ /* If it is not a unique file then the file does not exist */
+ if((~pCurrentEntry->iAttExtra & (KEntryAttUnique >> 23)) == 0)
+ {
+ retVal = KErrNotFound;
+ aEntry = NULL;
+ }
+ }
+ }
+
+ /* If we are going to return and we are searching for the unique file,there is a possiblity
+ that the binary search would have missed it (since the file entries were sorted without
+ namemangle).*/
+ if((!bFound) && (topIndex<bottomIndex) && doNameMangle)
+ {
+ TUint8 MountId;
+ TUint8 ReservedId;
+
+ if(ExtractMangleInfo(searchName,MountId,ReservedId) != KErrNone)
+ break;
+
+ if(MountId != iMount.iMountId || ReservedId != 0)
+ break;
+
+ /* If the aNameLength is equal to the mangle name length, we cant proceed our search
+ with null strings */
+ if((TUint)(aName.Length()) == KRofsMangleNameLength)
+ break;
+
+ searchName.Copy((const TText*)aName.Ptr(), aName.Length()-KRofsMangleNameLength);
+
+ /* The next level of search is sufficient enough to start on the top portion of the list.
+ Thus resetting the bottomIndex to 0 is sufficient */
+ bottomIndex=0;
+ doNameMangle = EFalse;
+ }
+ }
+ }
+ return retVal;
+ }
+
+TInt CDirectoryCache::DoFindFile(const TDesC& aName, TUint aAtt, const TRofsDir* aDir, const TRofsEntry*& aEntry ) const
+//
+// Scan from aDir looking for file aName.
+// The search starts at the entry after aEntry, unless aEntry is NULL, in which
+// case the srach starts from the beginning of the file block.
+// If found return the result in aEntry.
+//
+ {
+ __ASSERT_DEBUG( aDir != NULL, CRofs::Panic( CRofs::EPanicNullSubDir ));
+
+ if( aDir->iFileBlockAddress )
+ {
+ const TRofsEntry* pEntry;
+ if( !aEntry )
+ {
+ pEntry = FirstFileEntryFromDir( aDir );
+ }
+ else
+ {
+ pEntry = NextEntry( aEntry );
+ }
+ const TAny* const pEnd = EndOfFileBlockPlusOne( aDir );
+
+ while ( pEntry < pEnd )
+ {
+ TBuf<KMaxFileName> fileName;
+
+ fileName.Copy(NameAddress( pEntry ), pEntry->iNameLength);
+ if((~pEntry->iAttExtra & (KEntryAttUnique >> 23)) != 0)
+ fileName.AppendFormat(_L("[%02x-00]"),iMount.iMountId);
+
+ if ( KErrNotFound != fileName.MatchF(aName) && iMount.MatchEntryAtt(pEntry->iAtt, aAtt) )
+ {
+ aEntry = pEntry;
+ return(( pEntry->iFileAddress == KFileHidden ) ? KErrHidden : KErrNone);
+ }
+
+ pEntry = NextEntry( pEntry );
+ }
+ }
+ return KErrNotFound;
+ }
+
+
+void CDirectoryCache::FindFileEntryL(const TDesC& aName, const TRofsEntry*& aEntry) const
+//
+// Locate an entry from its full path name.
+//
+ {
+ TInt namePos=aName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter
+ const TRofsDir* dir = RootDirectory();
+ FindLeafDirL(aName.Left(namePos), dir);
+
+ aEntry=0;
+ TInt r = DoBinaryFindFile(aName.Mid(namePos), KEntryAttDir|KEntryAttMatchExclude, dir, aEntry);
+ if (r!=KErrNone)
+ User::Leave(r);
+ }
+
+void CDirectoryCache::FindDirectoryEntryL(const TDesC& aName, const TRofsDir*& aDir) const
+//
+// Locate an entry from its full path name.
+//
+ {
+ aDir = RootDirectory();
+ FindLeafDirL(aName,aDir);
+ }
+
+
+void CDirectoryCache::GetNextMatchingL(const TDesC& aName, TUint aAtt, const TRofsDir*& aDir, const TRofsEntry*& aEntry, TInt aError, TBool bUseBinarySearch) const
+ //
+ // Retrieves the next directory or file entry from aDir that matches the pattern in aName
+ // (which should be the entry name only, not the full path)
+ // The search starts at the entry after aEntry
+ //
+ {
+ __ASSERT_DEBUG( aName.LocateReverse(KPathDelimiter) == KErrNotFound, CRofs::Panic( CRofs::EPanicBadMatchName ));
+
+ TInt r = KErrGeneral;
+ const TRofsEntry* entry = aEntry;
+ TBool searchFiles = EFalse;
+ if( entry && (entry < FirstSubDirEntryFromDir(aDir) || entry >= EndOfDirPlusOne(aDir)) )
+ {
+ searchFiles = ETrue;
+ }
+ else
+ {
+ // searching the directory list
+ if (!bUseBinarySearch)
+ {
+ r = DoFindSubDir( aName, aAtt, aDir, entry );
+ }
+ else
+ {
+ r = DoBinaryFindSubDir(aName, aAtt, aDir, entry);
+ }
+ if( KErrNotFound == r )
+ {
+ // start looking through the file list
+ entry = NULL; // start at beginning of list
+ searchFiles = ETrue;
+ }
+ }
+
+
+ if( searchFiles )
+ {
+ if (!bUseBinarySearch)
+ {
+ r = DoFindFile( aName, aAtt, aDir, entry );
+ }
+ else
+ {
+ r = DoBinaryFindFile(aName, aAtt, aDir, entry);
+ }
+ }
+
+/*
+ if( aEntry >= FirstFileEntryFromDir( aDir )
+ && aDir->iFileBlockAddress )
+ {
+ // we are searching the file list
+ r = DoFindFile( aName, aAtt, aDir, aEntry );
+ }
+ else
+ {
+ // searching the directory list
+ r = DoFindSubDir( aName, aAtt, aDir, aEntry );
+ if( KErrNotFound == r )
+ {
+ // start looking through the file list
+ TRofsEntry* entry = NULL; // start at beginning of list
+ r = DoFindFile( aName, aAtt, aDir, entry );
+ if( KErrNone == r )
+ {
+ aEntry = entry;
+ }
+ }
+ }
+*/
+
+ if( r == KErrNone || r == KErrHidden)
+ {
+ // Move onto the next entry (this is valid even for hidden entries so
+ // that we can move onto the next entry, which may not be hidden)
+ aEntry = entry;
+ if(r == KErrNone)
+ {
+ return;
+ }
+ }
+
+ User::Leave(r == KErrHidden ? r : aError);
+ }
+
+void CDirectoryCache::FindGeneralEntryL(const TDesC& aName, TUint aAtt, const TRofsDir*& aDir, const TRofsEntry*& aEntry ) const
+ {
+ TInt namePos=aName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter
+ aDir = RootDirectory();
+ FindLeafDirL(aName.Left(namePos), aDir);
+ GetNextMatchingL( aName.Mid(namePos), aAtt, aDir, aEntry, KErrNotFound, ETrue );
+ }
+
+TUint8 CDirectoryCache::GetMountId( void )
+ {
+ return (TUint8)(iMount.iMountId);
+ };