author | mikek |
Sun, 27 Jun 2010 21:43:55 +0100 | |
branch | GCC_SURGE |
changeset 181 | bd8f1e65581b |
parent 0 | a41df078684a |
permissions | -rw-r--r-- |
// 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); };