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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
17 #include <e32std_private.h>
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 )
31 CDirectoryCache::~CDirectoryCache()
37 void CDirectoryCache::ConstructL()
39 iTreeBuffer = HBufC8::NewL( iTreeSize );
40 iFilesBuffer = HBufC8::NewL( iFilesSize );
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) );
49 void CDirectoryCache::FindLeafDirL(const TDesC& aName, const TRofsDir*& aDir) const
51 // Navigate the path to find the leaf directory, starting at aDir.
59 lex.Inc(); // Skip the file separator
61 r=lex.Remainder().Locate(KPathDelimiter);
63 if ( KErrNotFound == r )
65 r=lex.Remainder().Length();
67 if ( 0 == r ) // End of the path
72 lex.Inc(r); // Set the token length
74 const TRofsEntry* subDirEntry = NULL;
75 TInt r = DoBinaryFindSubDir(lex.MarkedToken(), KEntryAttDir|KEntryAttMatchExclusive, aDir, subDirEntry );
78 User::Leave( KErrPathNotFound );
80 __ASSERT_DEBUG( 0 != (subDirEntry->iAtt & KEntryAttDir ), CRofs::Panic( CRofs::EPanicEntryNotDir ));
81 aDir = RofsDirFromSubDirEntry( subDirEntry );
85 TInt CDirectoryCache::DoBinaryFindSubDir(const TDesC& aName, TUint aAtt, const TRofsDir* aDir, const TRofsEntry*& aSubDirEntry ) const
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.
94 if (aSubDirEntry != NULL)
96 return DoFindSubDir(aName, aAtt, aDir, aSubDirEntry);
99 TInt numDirs=GetDirCount(aDir);
100 TInt topIndex=numDirs-1;
104 TInt retVal=KErrNotFound;
107 TUint16* offsets = (TUint16*) ((TUint8*) aDir + aDir->iStructSize);
108 offsets += 2; //to skip file and dir counts
110 while((!bFound) && (topIndex>=bottomIndex))
113 const TRofsEntry* pCurrentEntry=NULL;
114 middleIndex=(topIndex+bottomIndex)>>1;
116 //Offsets for directories are relative to the start of the
118 TUint8* ptr = (TUint8*) aDir + (offsets[middleIndex] << 2);
119 pCurrentEntry = (TRofsEntry*) ptr;
121 TPtrC currName=TPtrC((const TText*)&pCurrentEntry->iName[0],pCurrentEntry->iNameLength);
123 TInt result=Compare(aName,currName);
125 topIndex=middleIndex-1;
127 bottomIndex=middleIndex+1;
130 bFound=ETrue; // exit loop
131 if (iMount.MatchEntryAtt(pCurrentEntry->iAtt, aAtt))
133 aSubDirEntry=pCurrentEntry;
142 TInt CDirectoryCache::DoFindSubDir(const TDesC& aName, TUint aAtt, const TRofsDir* aDir, const TRofsEntry*& aSubDirEntry ) const
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.
150 const TRofsEntry* pEntry = aSubDirEntry; // which entry
151 const TRofsEntry* const pEnd = (TRofsEntry*)EndOfDirPlusOne( aDir );
155 pEntry = FirstSubDirEntryFromDir( aDir );
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 );
165 while ( pEntry < pEnd )
167 TPtrC name( NameAddress( pEntry ), pEntry->iNameLength);
168 if ( KErrNotFound != name.MatchF(aName) && iMount.MatchEntryAtt(pEntry->iAtt, aAtt) )
170 aSubDirEntry = pEntry;
174 pEntry = NextEntry( pEntry );
179 TInt CDirectoryCache::GetDirCount(const TRofsDir* aDir) const
181 //Return the number of directory entries contained in aDir
184 TUint16* dirCount = (TUint16*) ((TUint8*) aDir + aDir->iStructSize);
188 TInt CDirectoryCache::GetFileCount(const TRofsDir* aDir) const
190 //Return the number of file entries contained in aDir
193 TUint16* fileCount = (TUint16*) ((TUint8*) aDir + aDir->iStructSize);
194 fileCount++; //jump over the dir count
198 TInt CDirectoryCache::Compare(const TDesC& aLeft, const TDesC& aRight) const
200 //Compares two filenames. Folds ASCII characters to uppercase
204 TInt len=Min(aLeft.Length(),aRight.Length());
205 const TText* leftString = aLeft.Ptr();
206 const TText* rightString = aRight.Ptr();
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;
219 // match up to end of shorter string, now compare lengths
220 return aLeft.Length()-aRight.Length();
223 TInt CDirectoryCache::ExtractMangleInfo(const TDesC& searchName, TUint8 &MountId, TUint8 &ReservedId) const
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;
230 TInt openBraceRevPos = searchName.LocateReverse('[');
231 TInt closeBraceRevPos = searchName.LocateReverse(']');
232 TInt hyphenRevPos = searchName.LocateReverse('-');
233 TInt searchNameLen = searchName.Length();
235 if(openBraceRevPos==KErrNotFound || closeBraceRevPos==KErrNotFound || hyphenRevPos==KErrNotFound)
238 openBraceRevPos = searchNameLen - openBraceRevPos;
239 closeBraceRevPos = searchNameLen - closeBraceRevPos;
240 hyphenRevPos = searchNameLen - hyphenRevPos;
241 if(openBraceRevPos!=KOpenBraceRevPos || hyphenRevPos!=KHyphenRevPos || closeBraceRevPos!=KCloseBraceRevPos)
244 const TText* nameString = searchName.Ptr();
245 TInt MountIdPos = searchNameLen - KOpenBraceRevPos + 1;
246 TInt ReservedIdPos = searchNameLen - KHyphenRevPos + 1;
248 TChar MountIdHNibble = *(nameString+MountIdPos);
249 TChar MountIdLNibble = *(nameString+MountIdPos+1);
251 TChar ReservedIdHNibble = *(nameString+ReservedIdPos);
252 TChar ReservedIdLNibble = *(nameString+ReservedIdPos+1);
254 if(MountIdHNibble.IsHexDigit() && MountIdLNibble.IsHexDigit() &&
255 ReservedIdHNibble.IsHexDigit() && ReservedIdLNibble.IsHexDigit())
257 MountId = (TUint8)((HexToInt(MountIdHNibble) << 4) | HexToInt(MountIdLNibble));
258 ReservedId = (TUint8)((HexToInt(ReservedIdHNibble) << 4) | HexToInt(ReservedIdLNibble));
264 TInt CDirectoryCache::DoBinaryFindFile(const TDesC& aName, TUint aAtt, const TRofsDir* aDir, const TRofsEntry*& aEntry ) const
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.
273 return DoFindFile(aName, aAtt, aDir, aEntry);
276 TInt numFiles=GetFileCount(aDir);
277 TInt topIndex=numFiles-1;
280 TBool doNameMangle = ETrue;
281 TBuf<KMaxFileName> searchName;
284 TInt retVal=KErrNotFound;
286 searchName.Copy((const TText*)aName.Ptr(), aName.Length());
290 TUint16* offsets = (TUint16*) ((TUint8*) aDir + aDir->iStructSize);
291 offsets += 2; //to skip file and dir counts
292 offsets += GetDirCount(aDir); //skip directory offsets
294 while((!bFound) && (topIndex>=bottomIndex))
297 const TRofsEntry* pCurrentEntry=NULL;
298 TBuf<KMaxFileName> currName;
300 middleIndex=(topIndex+bottomIndex)>>1;
302 //Offsets for files are relative to the start of the
304 TInt bufferOffset = (offsets[middleIndex]<<2) - iFilesMediaOffset + 4;
305 bufferOffset += aDir->iFileBlockAddress;
307 TUint8* ptr = (TUint8*) &iFilesBuffer[0];
309 pCurrentEntry=(TRofsEntry*) &ptr[bufferOffset];
311 currName.Copy(((const TText*)&pCurrentEntry->iName[0]), pCurrentEntry->iNameLength);
313 if(doNameMangle && ((~pCurrentEntry->iAttExtra & (KEntryAttUnique >> 23)) != 0))
314 currName.AppendFormat(_L("[%02x-00]"),iMount.iMountId);
316 result=Compare(searchName,currName);
319 topIndex=middleIndex-1;
321 bottomIndex=middleIndex+1;
324 bFound=ETrue; // exit loop
325 if (iMount.MatchEntryAtt(pCurrentEntry->iAtt, aAtt))
327 aEntry=pCurrentEntry;
328 retVal = (pCurrentEntry->iFileAddress == KFileHidden) ? KErrHidden : KErrNone;
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 */
334 /* If it is not a unique file then the file does not exist */
335 if((~pCurrentEntry->iAttExtra & (KEntryAttUnique >> 23)) == 0)
337 retVal = KErrNotFound;
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
346 if((!bFound) && (topIndex<bottomIndex) && doNameMangle)
351 if(ExtractMangleInfo(searchName,MountId,ReservedId) != KErrNone)
354 if(MountId != iMount.iMountId || ReservedId != 0)
357 /* If the aNameLength is equal to the mangle name length, we cant proceed our search
359 if((TUint)(aName.Length()) == KRofsMangleNameLength)
362 searchName.Copy((const TText*)aName.Ptr(), aName.Length()-KRofsMangleNameLength);
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 */
367 doNameMangle = EFalse;
374 TInt CDirectoryCache::DoFindFile(const TDesC& aName, TUint aAtt, const TRofsDir* aDir, const TRofsEntry*& aEntry ) const
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.
382 __ASSERT_DEBUG( aDir != NULL, CRofs::Panic( CRofs::EPanicNullSubDir ));
384 if( aDir->iFileBlockAddress )
386 const TRofsEntry* pEntry;
389 pEntry = FirstFileEntryFromDir( aDir );
393 pEntry = NextEntry( aEntry );
395 const TAny* const pEnd = EndOfFileBlockPlusOne( aDir );
397 while ( pEntry < pEnd )
399 TBuf<KMaxFileName> fileName;
401 fileName.Copy(NameAddress( pEntry ), pEntry->iNameLength);
402 if((~pEntry->iAttExtra & (KEntryAttUnique >> 23)) != 0)
403 fileName.AppendFormat(_L("[%02x-00]"),iMount.iMountId);
405 if ( KErrNotFound != fileName.MatchF(aName) && iMount.MatchEntryAtt(pEntry->iAtt, aAtt) )
408 return(( pEntry->iFileAddress == KFileHidden ) ? KErrHidden : KErrNone);
411 pEntry = NextEntry( pEntry );
418 void CDirectoryCache::FindFileEntryL(const TDesC& aName, const TRofsEntry*& aEntry) const
420 // Locate an entry from its full path name.
423 TInt namePos=aName.LocateReverse(KPathDelimiter)+1; // There is always a path delimiter
424 const TRofsDir* dir = RootDirectory();
425 FindLeafDirL(aName.Left(namePos), dir);
428 TInt r = DoBinaryFindFile(aName.Mid(namePos), KEntryAttDir|KEntryAttMatchExclude, dir, aEntry);
433 void CDirectoryCache::FindDirectoryEntryL(const TDesC& aName, const TRofsDir*& aDir) const
435 // Locate an entry from its full path name.
438 aDir = RootDirectory();
439 FindLeafDirL(aName,aDir);
443 void CDirectoryCache::GetNextMatchingL(const TDesC& aName, TUint aAtt, const TRofsDir*& aDir, const TRofsEntry*& aEntry, TInt aError, TBool bUseBinarySearch) const
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
450 __ASSERT_DEBUG( aName.LocateReverse(KPathDelimiter) == KErrNotFound, CRofs::Panic( CRofs::EPanicBadMatchName ));
452 TInt r = KErrGeneral;
453 const TRofsEntry* entry = aEntry;
454 TBool searchFiles = EFalse;
455 if( entry && (entry < FirstSubDirEntryFromDir(aDir) || entry >= EndOfDirPlusOne(aDir)) )
461 // searching the directory list
462 if (!bUseBinarySearch)
464 r = DoFindSubDir( aName, aAtt, aDir, entry );
468 r = DoBinaryFindSubDir(aName, aAtt, aDir, entry);
470 if( KErrNotFound == r )
472 // start looking through the file list
473 entry = NULL; // start at beginning of list
481 if (!bUseBinarySearch)
483 r = DoFindFile( aName, aAtt, aDir, entry );
487 r = DoBinaryFindFile(aName, aAtt, aDir, entry);
492 if( aEntry >= FirstFileEntryFromDir( aDir )
493 && aDir->iFileBlockAddress )
495 // we are searching the file list
496 r = DoFindFile( aName, aAtt, aDir, aEntry );
500 // searching the directory list
501 r = DoFindSubDir( aName, aAtt, aDir, aEntry );
502 if( KErrNotFound == r )
504 // start looking through the file list
505 TRofsEntry* entry = NULL; // start at beginning of list
506 r = DoFindFile( aName, aAtt, aDir, entry );
515 if( r == KErrNone || r == KErrHidden)
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)
526 User::Leave(r == KErrHidden ? r : aError);
529 void CDirectoryCache::FindGeneralEntryL(const TDesC& aName, TUint aAtt, const TRofsDir*& aDir, const TRofsEntry*& aEntry ) const
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 );
537 TUint8 CDirectoryCache::GetMountId( void )
539 return (TUint8)(iMount.iMountId);