os/kernelhwsrv/userlibandfileserver/fileserver/srofs/dircache.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2001-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 //
    15 
    16 #include <e32std.h>
    17 #include <e32std_private.h>
    18 #include "sr_rofs.h"
    19 #include <rofs.h>
    20 
    21 
    22 CDirectoryCache::CDirectoryCache( CRofsMountCB& aMount, CProxyDrive& aLocalDrive, const TRofsHeader& aHeader )
    23 	: iMount( aMount ), iLocalDrive( aLocalDrive ), 
    24 	iTreeMediaOffset( aHeader.iDirTreeOffset ),
    25 	iTreeSize( aHeader.iDirTreeSize ),
    26 	iFilesMediaOffset( aHeader.iDirFileEntriesOffset ),
    27 	iFilesSize( aHeader.iDirFileEntriesSize )
    28 	{
    29 	}
    30 
    31 CDirectoryCache::~CDirectoryCache()
    32 	{
    33 	delete iTreeBuffer;
    34 	delete iFilesBuffer;
    35 	}
    36 	
    37 void CDirectoryCache::ConstructL()
    38 	{
    39 	iTreeBuffer = HBufC8::NewL( iTreeSize );
    40 	iFilesBuffer = HBufC8::NewL( iFilesSize );
    41 
    42 	TPtr8 ptr = iTreeBuffer->Des();
    43 	User::LeaveIfError( iLocalDrive.Read( iTreeMediaOffset, iTreeSize, ptr) );
    44 	TPtr8 ptr2 = iFilesBuffer->Des();
    45 	User::LeaveIfError( iLocalDrive.Read( iFilesMediaOffset, iFilesSize, ptr2) );
    46 	}
    47 
    48 
    49 void CDirectoryCache::FindLeafDirL(const TDesC& aName, const TRofsDir*& aDir) const
    50 //
    51 // Navigate the path to find the leaf directory, starting at aDir.
    52 //
    53 	{
    54 
    55 	TLex lex(aName);
    56 	TInt r;
    57 	FOREVER
    58 		{
    59 		lex.Inc(); // Skip the file separator
    60 		lex.Mark();
    61 		r=lex.Remainder().Locate(KPathDelimiter);
    62 		
    63 		if ( KErrNotFound == r )
    64 			{
    65 			r=lex.Remainder().Length();
    66 			}
    67 		if ( 0 == r ) // End of the path
    68 			{
    69 			break;
    70 			}
    71 
    72 		lex.Inc(r); // Set the token length
    73 		
    74 		const TRofsEntry* subDirEntry = NULL;
    75 		TInt r = DoBinaryFindSubDir(lex.MarkedToken(), KEntryAttDir|KEntryAttMatchExclusive, aDir, subDirEntry );
    76 		if( KErrNone != r )
    77 			{
    78 			User::Leave( KErrPathNotFound );
    79 			}
    80 		__ASSERT_DEBUG( 0 != (subDirEntry->iAtt & KEntryAttDir ), CRofs::Panic( CRofs::EPanicEntryNotDir ));
    81 		aDir = RofsDirFromSubDirEntry( subDirEntry );
    82 		}
    83 	}
    84 
    85 TInt CDirectoryCache::DoBinaryFindSubDir(const TDesC& aName, TUint aAtt, const TRofsDir* aDir, const TRofsEntry*& aSubDirEntry ) const
    86 	//
    87 	// Scan the directory aDir looking for subdirectory aName using binary search.
    88 	// aName cannot contain wildcards and aSubDirEntry should always be NULL.
    89 	// If a matching entry is found writes pointer to the entry into aSubDirEntry
    90 	// and returns KErrNone.
    91 	//
    92 	{
    93 
    94 	if (aSubDirEntry != NULL)
    95 		{
    96 		return DoFindSubDir(aName, aAtt, aDir, aSubDirEntry);
    97 		}
    98 
    99 	TInt numDirs=GetDirCount(aDir);
   100 	TInt topIndex=numDirs-1;
   101 	TInt bottomIndex=0;
   102 
   103 	TBool bFound=EFalse;
   104 	TInt retVal=KErrNotFound;
   105 	if(topIndex>=0)
   106 		{
   107 		TUint16* offsets = (TUint16*) ((TUint8*) aDir + aDir->iStructSize);
   108 		offsets += 2; //to skip file and dir counts
   109 
   110 		while((!bFound) && (topIndex>=bottomIndex))
   111 		{
   112 			TInt32 middleIndex;
   113 			const TRofsEntry* pCurrentEntry=NULL;
   114 			middleIndex=(topIndex+bottomIndex)>>1;
   115 
   116 			//Offsets for directories are relative to the start of the
   117 			//directory block
   118 			TUint8* ptr = (TUint8*) aDir + (offsets[middleIndex] << 2);
   119 			pCurrentEntry = (TRofsEntry*)  ptr;
   120 
   121 			TPtrC currName=TPtrC((const TText*)&pCurrentEntry->iName[0],pCurrentEntry->iNameLength);
   122 
   123 			TInt result=Compare(aName,currName);
   124 			if(result<0)
   125 				topIndex=middleIndex-1;
   126 			else if(result>0)
   127 				bottomIndex=middleIndex+1;
   128 			else
   129 				{
   130 				bFound=ETrue;	// exit loop
   131 				if (iMount.MatchEntryAtt(pCurrentEntry->iAtt, aAtt))
   132 					{
   133 					aSubDirEntry=pCurrentEntry;
   134 					retVal=KErrNone;
   135 					}
   136 				}
   137 			}
   138 		}
   139 	return retVal;
   140 	}
   141 
   142 TInt CDirectoryCache::DoFindSubDir(const TDesC& aName, TUint aAtt, const TRofsDir* aDir, const TRofsEntry*& aSubDirEntry ) const
   143 	//
   144 	// Scan the directory aDir looking for subdirectory aName. If aSubDirEntry is
   145 	// not NULL the search starts from the entry AFTER aSubDirEntry.
   146 	// If a matching entry is found writes pointer to the entry into aSubDirEntry
   147 	// and returns KErrNone.
   148 	//
   149 	{
   150 	const TRofsEntry* pEntry = aSubDirEntry;	// which entry
   151 	const TRofsEntry* const pEnd = (TRofsEntry*)EndOfDirPlusOne( aDir );
   152 
   153 	if( !pEntry )
   154 		{
   155 		pEntry = FirstSubDirEntryFromDir( aDir );
   156 		}
   157 	else
   158 		{
   159 		// move to next entry
   160 		__ASSERT_DEBUG( pEntry >= FirstSubDirEntryFromDir( aDir ), CRofs::Panic( CRofs::EPanicEntryBeforeDirectory ));
   161 		__ASSERT_DEBUG( pEntry < pEnd, CRofs::Panic( CRofs::EPanicEntryAfterDirectory ));
   162 		pEntry = NextEntry( pEntry );
   163 		}
   164 
   165 	while ( pEntry < pEnd )
   166 		{
   167 		TPtrC name( NameAddress( pEntry ), pEntry->iNameLength);
   168 		if ( KErrNotFound != name.MatchF(aName) && iMount.MatchEntryAtt(pEntry->iAtt, aAtt) )
   169 			{
   170 			aSubDirEntry = pEntry;
   171 			return KErrNone;
   172 			}
   173 		
   174 		pEntry = NextEntry( pEntry );
   175 		}
   176 	return KErrNotFound;
   177 	}
   178 
   179 TInt CDirectoryCache::GetDirCount(const TRofsDir* aDir) const
   180 //
   181 //Return the number of directory entries contained in aDir
   182 //
   183 	{
   184 	TUint16* dirCount = (TUint16*) ((TUint8*) aDir + aDir->iStructSize);
   185 	return *dirCount;
   186 	}
   187 
   188 TInt CDirectoryCache::GetFileCount(const TRofsDir* aDir) const
   189 //
   190 //Return the number of file entries contained in aDir
   191 //
   192 	{
   193 	TUint16* fileCount = (TUint16*) ((TUint8*) aDir + aDir->iStructSize);
   194 	fileCount++; //jump over the dir count
   195 	return *fileCount;
   196 	}
   197 
   198 TInt CDirectoryCache::Compare(const TDesC& aLeft, const TDesC& aRight) const
   199 //
   200 //Compares two filenames.  Folds ASCII characters to uppercase
   201 //
   202 	{
   203 
   204 	TInt len=Min(aLeft.Length(),aRight.Length());
   205 	const TText* leftString = aLeft.Ptr();
   206 	const TText* rightString = aRight.Ptr();
   207 	while (len--)
   208 		{
   209 		TText leftChar=*leftString++;
   210 		TText rightChar=*rightString++;
   211 		if (leftChar<='Z' && leftChar>='A')
   212 			leftChar +='a'-'A';     // covert to UPPERCASE
   213 		if (rightChar<='Z' && rightChar>='A')
   214 			rightChar +='a'-'A';    // covert to UPPERCASE
   215 		TInt result=leftChar-rightChar;
   216 		if (result != 0)
   217 			return result;
   218 		}
   219 		// match up to end of shorter string, now compare lengths
   220 		return aLeft.Length()-aRight.Length();
   221 	}
   222 
   223 TInt CDirectoryCache::ExtractMangleInfo(const TDesC& searchName, TUint8 &MountId, TUint8 &ReservedId) const
   224 {
   225 	#define HexToInt(x) ( x.IsDigit()? (TUint8)(x-(TUint)'0') : 0x0a+(TUint8)((x>='A' && x<='Z')? x-(TUint)'A':x-(TUint)'a') )
   226 	const TInt KOpenBraceRevPos = 7;
   227 	const TInt KHyphenRevPos = 4;
   228 	const TInt KCloseBraceRevPos = 1;
   229 
   230 	TInt openBraceRevPos = searchName.LocateReverse('[');
   231 	TInt closeBraceRevPos = searchName.LocateReverse(']');
   232 	TInt hyphenRevPos = searchName.LocateReverse('-');
   233 	TInt searchNameLen = searchName.Length();
   234 
   235 	if(openBraceRevPos==KErrNotFound || closeBraceRevPos==KErrNotFound || hyphenRevPos==KErrNotFound)
   236 		return KErrNotFound;
   237 
   238 	openBraceRevPos = searchNameLen - openBraceRevPos;
   239 	closeBraceRevPos = searchNameLen - closeBraceRevPos;
   240 	hyphenRevPos = searchNameLen - hyphenRevPos;
   241 	if(openBraceRevPos!=KOpenBraceRevPos || hyphenRevPos!=KHyphenRevPos || closeBraceRevPos!=KCloseBraceRevPos)
   242 		return KErrNotFound;
   243 
   244 	const TText* nameString = searchName.Ptr();
   245 	TInt MountIdPos = searchNameLen - KOpenBraceRevPos + 1;
   246 	TInt ReservedIdPos = searchNameLen - KHyphenRevPos + 1;
   247 
   248 	TChar MountIdHNibble = *(nameString+MountIdPos);
   249 	TChar MountIdLNibble = *(nameString+MountIdPos+1);
   250 
   251 	TChar ReservedIdHNibble = *(nameString+ReservedIdPos);
   252 	TChar ReservedIdLNibble = *(nameString+ReservedIdPos+1);
   253 
   254 	if(MountIdHNibble.IsHexDigit() && MountIdLNibble.IsHexDigit() &&
   255 			ReservedIdHNibble.IsHexDigit() && ReservedIdLNibble.IsHexDigit())
   256 	{
   257 		MountId = (TUint8)((HexToInt(MountIdHNibble) << 4) | HexToInt(MountIdLNibble));
   258 		ReservedId = (TUint8)((HexToInt(ReservedIdHNibble) << 4) | HexToInt(ReservedIdLNibble));
   259 		return KErrNone;
   260 	}
   261 	return KErrNotFound;
   262 }
   263 
   264 TInt CDirectoryCache::DoBinaryFindFile(const TDesC& aName, TUint aAtt, const TRofsDir* aDir, const TRofsEntry*& aEntry ) const
   265 //
   266 // Scan from aDir looking for file aName using binary search.
   267 // aName cannot contain wildcards and aEntry should always be NULL.
   268 // If found return the result in aEntry.
   269 //
   270 	{
   271 	if (aEntry != NULL)
   272 		{
   273 		return DoFindFile(aName, aAtt, aDir, aEntry);
   274 		}
   275 
   276 	TInt numFiles=GetFileCount(aDir);
   277 	TInt topIndex=numFiles-1;
   278 	TInt bottomIndex=0;
   279 	TInt result;
   280 	TBool doNameMangle = ETrue;
   281 	TBuf<KMaxFileName> searchName;
   282 
   283 	TBool bFound=EFalse;
   284 	TInt retVal=KErrNotFound;
   285 
   286 	searchName.Copy((const TText*)aName.Ptr(), aName.Length());
   287 
   288 	if(topIndex>=0)
   289 		{
   290 		TUint16* offsets = (TUint16*) ((TUint8*) aDir + aDir->iStructSize);
   291 		offsets += 2;                 //to skip file and dir counts
   292 		offsets += GetDirCount(aDir); //skip directory offsets
   293 
   294 		while((!bFound) && (topIndex>=bottomIndex))
   295 			{
   296 			TInt32 middleIndex;
   297 			const TRofsEntry* pCurrentEntry=NULL;
   298 			TBuf<KMaxFileName> currName;
   299 
   300 			middleIndex=(topIndex+bottomIndex)>>1;
   301 
   302 			//Offsets for files are relative to the start of the
   303 			//file block
   304 			TInt bufferOffset = (offsets[middleIndex]<<2) - iFilesMediaOffset + 4;
   305 			bufferOffset += aDir->iFileBlockAddress;
   306 
   307 			TUint8* ptr = (TUint8*) &iFilesBuffer[0];
   308 
   309 			pCurrentEntry=(TRofsEntry*) &ptr[bufferOffset];
   310 
   311 			currName.Copy(((const TText*)&pCurrentEntry->iName[0]), pCurrentEntry->iNameLength);
   312 
   313 			if(doNameMangle && ((~pCurrentEntry->iAttExtra & (KEntryAttUnique >> 23)) != 0))
   314 				currName.AppendFormat(_L("[%02x-00]"),iMount.iMountId);
   315 
   316 			result=Compare(searchName,currName);
   317 
   318 			if(result<0)
   319 				topIndex=middleIndex-1;
   320 			else if(result>0)
   321 				bottomIndex=middleIndex+1;
   322 			else
   323 				{
   324 				bFound=ETrue;	// exit loop
   325 				if (iMount.MatchEntryAtt(pCurrentEntry->iAtt, aAtt))
   326 					{
   327 					aEntry=pCurrentEntry;
   328 					retVal = (pCurrentEntry->iFileAddress == KFileHidden) ? KErrHidden : KErrNone;
   329 					}
   330 				/* If we have found a file and we are in second pass of binary search without nameMangle 
   331 					check whether it is unique file */
   332 				if(!doNameMangle)
   333 					{
   334 					/* If it is not a unique file then the file does not exist */
   335 					if((~pCurrentEntry->iAttExtra & (KEntryAttUnique >> 23)) == 0)
   336 						{
   337 						retVal = KErrNotFound;
   338 						aEntry = NULL;
   339 						}
   340 					}
   341 				}
   342 
   343 			/* If we are going to return and we are searching for the unique file,there is a possiblity
   344 			   that the binary search would have missed it (since the file entries were sorted without 
   345 			   namemangle).*/
   346 			if((!bFound) && (topIndex<bottomIndex) && doNameMangle)
   347 				{
   348 					TUint8 MountId;
   349 					TUint8 ReservedId;
   350 
   351 					if(ExtractMangleInfo(searchName,MountId,ReservedId) != KErrNone)
   352 						break;
   353 
   354 					if(MountId != iMount.iMountId || ReservedId != 0)
   355 						break;
   356 
   357 					/* If the aNameLength is equal to the mangle name length, we cant proceed our search 
   358 						with null strings */
   359 					if((TUint)(aName.Length()) == KRofsMangleNameLength)
   360 						break;
   361 
   362 					searchName.Copy((const TText*)aName.Ptr(), aName.Length()-KRofsMangleNameLength);
   363 
   364 					/* The next level of search is sufficient enough to start on the top portion of the list.
   365 						Thus resetting the bottomIndex to 0 is sufficient */
   366 					bottomIndex=0;
   367 					doNameMangle = EFalse;
   368 				}
   369 			}
   370 		}
   371 	return retVal;
   372 	}
   373 
   374 TInt CDirectoryCache::DoFindFile(const TDesC& aName, TUint aAtt, const TRofsDir* aDir, const TRofsEntry*& aEntry ) const
   375 //
   376 // Scan from aDir looking for file aName.
   377 // The search starts at the entry after aEntry, unless aEntry is NULL, in which
   378 // case the srach starts from the beginning of the file block.
   379 // If found return the result in aEntry.
   380 //
   381 	{
   382 	__ASSERT_DEBUG( aDir != NULL, CRofs::Panic( CRofs::EPanicNullSubDir ));
   383 	
   384 	if( aDir->iFileBlockAddress )
   385 		{
   386 		const TRofsEntry* pEntry;
   387 		if( !aEntry )
   388 			{
   389 			pEntry = FirstFileEntryFromDir( aDir );
   390 			}
   391 		else
   392 			{
   393 			pEntry = NextEntry( aEntry );
   394 			}
   395 		const TAny* const pEnd = EndOfFileBlockPlusOne( aDir );
   396 		
   397 		while ( pEntry < pEnd )
   398 			{
   399 			TBuf<KMaxFileName> fileName;
   400 
   401 			fileName.Copy(NameAddress( pEntry ), pEntry->iNameLength);
   402 			if((~pEntry->iAttExtra & (KEntryAttUnique >> 23)) != 0)
   403 				fileName.AppendFormat(_L("[%02x-00]"),iMount.iMountId);
   404 
   405 			if ( KErrNotFound != fileName.MatchF(aName) && iMount.MatchEntryAtt(pEntry->iAtt, aAtt)  )
   406 				{
   407 				aEntry = pEntry;
   408 				return(( pEntry->iFileAddress == KFileHidden ) ? KErrHidden : KErrNone);
   409 				}
   410 			
   411 			pEntry = NextEntry( pEntry );
   412 			}
   413 		}
   414 	return KErrNotFound;
   415 	}
   416 
   417 
   418 void CDirectoryCache::FindFileEntryL(const TDesC& aName, const TRofsEntry*& aEntry) const
   419 //
   420 // Locate an entry from its full path name.
   421 //
   422 	{
   423 	TInt namePos=aName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter
   424 	const TRofsDir* dir = RootDirectory();
   425 	FindLeafDirL(aName.Left(namePos), dir);
   426 
   427 	aEntry=0;
   428 	TInt r = DoBinaryFindFile(aName.Mid(namePos), KEntryAttDir|KEntryAttMatchExclude, dir, aEntry);
   429 	if (r!=KErrNone)
   430 		User::Leave(r);
   431 	}
   432 
   433 void CDirectoryCache::FindDirectoryEntryL(const TDesC& aName, const TRofsDir*& aDir) const
   434 //
   435 // Locate an entry from its full path name.
   436 //
   437 	{
   438 	aDir = RootDirectory();
   439 	FindLeafDirL(aName,aDir);
   440 	}
   441 
   442 
   443 void CDirectoryCache::GetNextMatchingL(const TDesC& aName, TUint aAtt, const TRofsDir*& aDir, const TRofsEntry*& aEntry, TInt aError, TBool bUseBinarySearch) const
   444 	//
   445 	// Retrieves the next directory or file entry from aDir that matches the pattern in aName
   446 	// (which should be the entry name only, not the full path)
   447 	// The search starts at the entry after aEntry
   448 	//
   449 	{
   450 	__ASSERT_DEBUG( aName.LocateReverse(KPathDelimiter) == KErrNotFound, CRofs::Panic( CRofs::EPanicBadMatchName ));
   451 
   452 	TInt r = KErrGeneral;
   453 	const TRofsEntry* entry = aEntry;
   454 	TBool searchFiles = EFalse;
   455 	if( entry && (entry < FirstSubDirEntryFromDir(aDir) || entry >= EndOfDirPlusOne(aDir)) )
   456 		{
   457 		searchFiles = ETrue;
   458 		}
   459 	else
   460 		{
   461 		// searching the directory list
   462 		if (!bUseBinarySearch)
   463 			{
   464 			r = DoFindSubDir( aName, aAtt, aDir, entry );
   465 			}
   466 		else
   467 			{
   468 			r = DoBinaryFindSubDir(aName, aAtt, aDir, entry);
   469 			}
   470 		if( KErrNotFound == r )
   471 			{
   472 			// start looking through the file list
   473 			entry = NULL;	// start at beginning of list
   474 			searchFiles = ETrue;
   475 			}
   476 		}
   477 
   478 
   479 	if( searchFiles )
   480 		{
   481 		if (!bUseBinarySearch)
   482 			{
   483 			r = DoFindFile( aName, aAtt, aDir, entry );
   484 			}
   485 		else
   486 			{
   487 			r = DoBinaryFindFile(aName, aAtt, aDir, entry);
   488 			}
   489 		}
   490 
   491 /*
   492 	if( aEntry >= FirstFileEntryFromDir( aDir ) 
   493 		&& aDir->iFileBlockAddress )
   494 		{
   495 		// we are searching the file list
   496 		r = DoFindFile( aName, aAtt, aDir, aEntry );
   497 		}
   498 	else
   499 		{
   500 		// searching the directory list
   501 		r = DoFindSubDir( aName, aAtt, aDir, aEntry );
   502 		if( KErrNotFound == r )
   503 			{
   504 			// start looking through the file list
   505 			TRofsEntry* entry = NULL;	// start at beginning of list
   506 			r = DoFindFile( aName, aAtt, aDir, entry );
   507 			if( KErrNone == r )
   508 				{
   509 				aEntry = entry;
   510 				}
   511 			}
   512 		}
   513 */
   514 
   515 	if( r == KErrNone || r == KErrHidden)
   516 		{
   517 		// Move onto the next entry (this is valid even for hidden entries so
   518 		// that we can move onto the next entry, which may not be hidden)
   519 		aEntry = entry;
   520 		if(r == KErrNone)
   521 			{
   522 			return;
   523 			}
   524 		}
   525 
   526 	User::Leave(r == KErrHidden ? r : aError);
   527 	}
   528 
   529 void CDirectoryCache::FindGeneralEntryL(const TDesC& aName, TUint aAtt, const TRofsDir*& aDir, const TRofsEntry*& aEntry ) const
   530 	{
   531 	TInt namePos=aName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter
   532 	aDir = RootDirectory();
   533 	FindLeafDirL(aName.Left(namePos), aDir);
   534 	GetNextMatchingL( aName.Mid(namePos), aAtt, aDir, aEntry, KErrNotFound, ETrue );
   535 	}
   536 
   537 TUint8 CDirectoryCache::GetMountId( void )
   538 	{
   539 	return (TUint8)(iMount.iMountId);
   540 	};