Update contrib.
1 // Copyright (c) 1997-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.
14 // f32\etshell\ts_deps.cpp
21 #include "sf_deflate.h"
24 //#define _DETAILED_CHECK // Select for detailed dependency check
26 #if defined(_DETAILED_CHECK) // Prints information to screen
27 #define __PRINT(t) {CShell::TheConsole->Printf(t);}
28 #define __PRINT1(t,a) {CShell::TheConsole->Printf(t,a);}
29 #define __PRINT2(t,a,b) {CShell::TheConsole->Printf(t,a,b);}
30 #define __PRINTWAIT(t){CShell::TheConsole->Printf(t);CShell::TheConsole->Getch();}
34 #define __PRINT2(t,a,b)
35 #define __PRINTWAIT(t)
40 CDllChecker::GetImportDataL(aFilename) reads the Image Header, Import Section
41 and all import data for aFilename. If aFilename is a ROM dll, and thus has no
42 import data, or if the file contains no import data for some other reason the
43 function leaves with KErrGeneral. If a file is compressed, function calls
44 appropriate decompression routine to inflate the import data.
45 The function then calls GetDllTableL function which
46 reads the first import block and enters a "for" loop. The Dll's name and Uid3 are obtained
47 from CDllChecker::GetFileNameAndUid(). If the Dll name does not occur in the
48 array of previously checked Dlls, CDllChecker::FindDll() is called. If the Dll
49 is found,the function then calls CDllChecker::GetImportDataL on the filename acquired by
50 GetFileNameAndUid()(recursive call).
52 If the Dll contains no import data or cannot be found, or if the Uid is invalid,
53 the next import is checked.
55 The Uid3 value is checked by calling CDllChecker::CheckUid. This compares the
56 Uid3 value found in the image header of the file, with that found by
57 GetFileNameAndUid(). If there are any discrepancies,these are noted.
59 Each potential import is added to the array by dllAppendL(TResultCheck) to
60 indicate its import status.
62 CDllChecker::ListArray() lists the contents of the array when all imports
67 CDllChecker::CDllChecker()
78 void CDllChecker::ConstructL()
80 // Creates an array to hold DLLs referenced by this executable
83 iDllArray = new(ELeave)CArrayFixFlat<SDllInfo>(4);
84 __PRINT(_L(" Successfully created iDllArray\n"));
88 CDllChecker::~CDllChecker()
97 GLDEF_C void Get16BitDllName(TDes8& aDllName,TDes& aFileName)
99 // Convert an 8 bit name to a 16 bit name - zero padded automatically
100 // No effect in 8 bit builds - just sets aFileName to aDllName
103 aFileName.SetLength(aDllName.Length());
104 aFileName.Copy(aDllName);
107 void FileCleanup(TAny* aPtr)
109 TFileInput* f=(TFileInput*)aPtr;
114 void CDllChecker::LoadFileInflateL(E32ImageHeaderComp* aHeader,TUint8* aRestOfFileData,TUint32 aRestOfFileSize)
116 TInt pos = aHeader->TotalSize();
117 User::LeaveIfError(iFile.Seek(ESeekStart,pos)); // Start at beginning of compressed data
119 TFileInput* file = new (ELeave) TFileInput(iFile);
120 CleanupStack::PushL(TCleanupItem(&FileCleanup,file));
121 CInflater* inflater=CInflater::NewLC(*file);
123 if (aHeader->iCodeSize)
125 TUint8* CodeData = (TUint8*)User::AllocLC(aHeader->iCodeSize );
126 TInt count=inflater->ReadL((TUint8*)CodeData ,aHeader->iCodeSize,&Mem::Move);
127 if(count!=aHeader->iCodeSize)
128 User::Leave(KErrCorrupt);
129 CleanupStack::PopAndDestroy(CodeData);
134 TUint32 count=inflater->ReadL(aRestOfFileData,aRestOfFileSize,&Mem::Move);
135 if(count!=aRestOfFileSize)
136 User::Leave(KErrCorrupt);
138 CleanupStack::PopAndDestroy(2,file);
141 void CDllChecker::LoadFileNoCompressL(E32ImageHeaderComp* aHeader,TUint8* aRestOfFileData,TUint32 aRestOfFileSize)
143 TInt pos = (aHeader->TotalSize()+aHeader->iCodeSize);
146 User::LeaveIfError(iFile.Seek(ESeekStart,pos)); // Start at beginning of import table
147 TPtr8 ptrToData((TText8*)(aRestOfFileData),aRestOfFileSize,aRestOfFileSize);
148 User::LeaveIfError(iFile.Read(ptrToData, (TInt)aRestOfFileSize));
151 //function loads file's import information calling decompression routine if needed
152 TInt CDllChecker::LoadFile(TUint32 aCompression,E32ImageHeaderComp* aHeader,TUint8* aRestOfFileData,TUint32 aRestOfFileSize)
155 if(aCompression==KFormatNotCompressed)
157 TRAP(r,LoadFileNoCompressL(aHeader,aRestOfFileData,aRestOfFileSize));
159 else if(aCompression==KUidCompressionDeflate)
161 TRAP(r,LoadFileInflateL(aHeader,aRestOfFileData,aRestOfFileSize));
169 //function iterates through the list of libraries the current executable depends on
170 //for each dependency in the list the function checks whether the .dll being checked is already added to the array of dependencies
171 //if not, the function adds dependency being checked to the array of dependencies and calls GetImportDataL function recursively
172 void CDllChecker::GetDllTableL(TUint8* aImportData, TInt aDllRefTableCount,TUint aFlags)
174 E32ImportBlock* block = (E32ImportBlock*)((TUint8*)aImportData+sizeof(E32ImportSection));
176 //*********Beginning of the loop*********
177 for (TInt i=0; i<aDllRefTableCount; i++)
181 TText8* dllName=(aImportData+block->iOffsetOfDllName);
182 TPtrC8 dllNamePtr(dllName, User::StringLength(dllName));
183 GetFileNameAndUid(dllInfo,dllNamePtr);//Gets name and Uid of dependency
184 TUid* pointer=&dllInfo.iUid;
185 __PRINT(_L(" Check Dll has not already been imported\n"));
186 TKeyArrayFix key(0,ECmpFolded);
188 TInt r=iDllArray->Find(dllInfo,key,pos);// Search array by Dll Name
189 if (r==KErrNone) // **********IT IS ALREADY IN THE ARRAY***********
191 __PRINT1(_L(" Dll %S has already been checked\n"),&dllInfo.iDllName);
193 //Check its Uid3 against that noted in the array
194 if (iDllArray->At(pos).iUid!=dllInfo.iUid)
196 // Uid3 is different to that of the same named Dll
197 // Add it to the array for comparative purposes
198 __PRINT2(_L(" Uid3 [%08x] for %S is different from that noted previously\n"),dllInfo.iUid, &dllInfo.iDllName);
199 dllInfo.iResult=EUidDifference;
201 // Add this entry to iDllArray
204 }// Run to the end of the "for" loop for this i value
205 else // **********THE FILE IS NOT YET IN THE ARRAY**********
207 __PRINT(_L(" Dll has not previously been checked\n"));
209 // Check through it and add the relevant information to the array
211 // Search for the DLL
212 TPath aPath=(TPath)CShell::currentPath;
217 Get16BitDllName(dllInfo.iDllName,dll16BitName);
219 dll16BitName=(dllInfo.iDllName);
221 r=FindDll(dll16BitName,fileName,aPath);
223 __PRINT1(_L("dll16BitName=%S\n"),&dll16BitName);
224 __PRINTWAIT(_L(" Press any key to continue\n"));
226 if (r==KErrNotFound) // Could not find Dll
228 dllInfo.iResult=ENotFound;
229 }// Run to the end of the "for" loop for this i value
231 else // File was located
233 // Go recursive. Call GetImportDataL on the new dll, if it imports anything.
234 // ROM dlls have no import data so this is never called for ROM dlls.
235 // This *will* terminate. It is only called on "new" dlls not in the array.
238 __PRINT(_L(" ****Go recursive****\n"));
239 __PRINTWAIT(_L(" Press any key to continue\n"));
243 TRAP(r,GetImportDataL(fileName, pointer));
244 // Pass in (parsed) fileName and Uid3 (from file header)
247 case(KErrGeneral): // No import data
249 dllInfo.iResult=ENoImportData;
251 // Run to the end of the for loop for this i value
253 case(EUidNotSupported):
255 dllInfo.iResult=EUidNotSupported;
258 case(KErrNone): // Import data was read
260 dllInfo.iResult=EFileFoundAndUidSupported;
262 // Run to the end of the for loop for this i value
266 __PRINT2(_L(" File %S is already open\n"),&fileName,r);
267 dllInfo.iResult=EAlreadyOpen;
272 __PRINT2(_L(" File %S has unexpected format\n"),&fileName,r);
273 dllInfo.iResult=EAlreadyOpen;
278 __PRINT1(_L(" File %S could not be opened \n"),&fileName);
279 dllInfo.iResult=ECouldNotOpenFile;
282 // Run to the end of the for loop for this i value
286 // Add the information about the dependency to iDllArray
289 // Runs to here when all import data has been read for this i value
291 __PRINT(_L(" Go to next dll to be imported...\n"));
292 __PRINTWAIT(_L(" Press any key to continue\n"));
294 block = (E32ImportBlock*)block->NextBlock(E32ImageHeader::ImpFmtFromFlags(aFlags));
296 }// The end of the loop. Every DLL has been located
301 void CDllChecker::GetImportDataL(const TDesC& aFileName, TUid* aPointer)
304 // Check that the file is not a ROM dll. These have no import data
305 if (ShellFunction::TheShell->TheFs.IsFileInRom(aFileName))
307 User::Leave(KErrGeneral);
310 //open file for reading and push it to autoclose stack
311 TAutoClose<RFile> autoFile;
312 User::LeaveIfError(autoFile.iObj.Open(CShell::TheFs,aFileName,EFileStream));
317 //Create a pointer to an Image Header
318 //reserve enough memory for compressed file header because we don't know whether the file is compressed or not
319 E32ImageHeaderComp* imageHeader=new(ELeave)E32ImageHeaderComp;
320 CleanupStack::PushL(imageHeader);
324 TPtr8 ptrToImageHeader((TText8*)(imageHeader),sizeof(E32ImageHeaderComp),sizeof(E32ImageHeaderComp));
325 User::LeaveIfError(iFile.Read(ptrToImageHeader,sizeof(E32ImageHeaderComp)));
327 if (imageHeader->iImportOffset==0)// File contains no import data
329 User::Leave(KErrGeneral);
332 TUint32 compression = imageHeader->CompressionType();
333 TInt restOfFileSize=0;
334 TUint8* restOfFileData=NULL;
335 //detect the size of import information
336 if (compression != KFormatNotCompressed)
338 // Compressed executable
339 // iCodeOffset = header size for format V or above
340 // = sizeof(E32ImageHeader) for format J
341 restOfFileSize = imageHeader->UncompressedFileSize() - imageHeader->iCodeOffset;
346 iFile.Size(FileSize);
347 restOfFileSize = FileSize-imageHeader->TotalSize();
349 restOfFileSize -= imageHeader->iCodeSize; // the size of the exe less header & code
351 //allocate memory for import information
352 if (restOfFileSize >0)
354 restOfFileData = (TUint8*)User::AllocLC(restOfFileSize );
358 User::LeaveIfError(LoadFile(compression,imageHeader,restOfFileData,restOfFileSize)); // Read import information in
360 TInt32 uid3=imageHeader->iUid3;
361 if(iCalls!=0) // Only check Uid3 of dependencies (ie only after first
362 { // call of recursive function)
363 TInt r=CheckUid3(uid3,*aPointer);
365 if (r!=KErrNone) // Dll's Uid3 is not valid
366 User::Leave(EUidNotSupported);
369 TInt bufferOffset=imageHeader->iImportOffset-(imageHeader->iCodeOffset + imageHeader->iCodeSize);
370 if( TInt(bufferOffset+sizeof(E32ImportSection))>restOfFileSize)
371 User::Leave(KErrCorrupt);
372 //get the table of dependencies
373 GetDllTableL(restOfFileData+bufferOffset,imageHeader->iDllRefTableCount,imageHeader->iFlags);
375 CleanupStack::PopAndDestroy(cleanupCount);
379 TUint8* CDllChecker::NextBlock(TUint8* aBlock)
381 E32ImportBlock* block;
382 // Advance the pointer to the next block
383 block=(E32ImportBlock*)aBlock;
384 aBlock=(aBlock+sizeof(E32ImportBlock)+((block->iNumberOfImports)*sizeof(TUint)));
389 TFileNameInfo::TFileNameInfo()
391 memclr(this, sizeof(TFileNameInfo));
394 TInt TFileNameInfo::Set(const TDesC8& aFileName, TUint aFlags)
399 iName = aFileName.Ptr();
400 iLen = aFileName.Length();
401 iExtPos = aFileName.LocateReverse('.');
404 TInt osq = aFileName.LocateReverse('[');
405 TInt csq = aFileName.LocateReverse(']');
406 if (!(aFlags & EAllowUid) && (osq>=0 || csq>=0))
410 if (osq>=iExtPos || csq>=iExtPos)
415 if ((aFlags & EAllowUid) && p>=10 && iName[p-1]==']' && iName[p-10]=='[')
417 TPtrC8 uidstr(iName + p - 9, 8);
418 TLex8 uidlex(uidstr);
420 TInt r = uidlex.Val(uid, EHex);
421 if (r==KErrNone && uidlex.Eos())
425 TInt ob = aFileName.LocateReverse('{');
426 TInt cb = aFileName.LocateReverse('}');
427 if (ob>=iUidPos || cb>=iUidPos)
431 if (ob>=0 && cb>=0 && p-1==cb)
434 TInt d = p8.LocateReverse('.');
435 TPtrC8 verstr(iName+ob+1, p-ob-2);
436 TLex8 verlex(verstr);
437 if (ob==p-10 && d<ob)
440 TInt r = verlex.Val(ver, EHex);
441 if (r==KErrNone && verlex.Eos())
442 iVersion = ver, p = ob;
444 else if (d>ob && p-1>d && (aFlags & EAllowDecimalVersion))
448 TInt r = verlex.Val(maj, EDecimal);
449 TUint c = (TUint)verlex.Get();
450 TInt r2 = verlex.Val(min, EDecimal);
451 if (r==KErrNone && c=='.' && r2==KErrNone && verlex.Eos() && maj<32768 && min<32768)
452 iVersion = (maj << 16) | min, p = ob;
456 if (iLen>=2 && iName[1]==':')
459 if (c!='?' || !(aFlags & EAllowPlaceholder))
469 TPtrC8 pathp(iName+iPathPos, iVerPos-iPathPos);
470 if (pathp.Locate('[')>=0 || pathp.Locate(']')>=0 || pathp.Locate('{')>=0 || pathp.Locate('}')>=0 || pathp.Locate(':')>=0)
474 iBasePos = pathp.LocateReverse('\\') + 1 + iPathPos;
478 void TFileNameInfo::GetName(TDes8& aName, TUint aFlags) const
480 if (aFlags & EIncludeDrive)
481 aName.Append(Drive());
482 if (aFlags & EIncludePath)
484 if (PathLen() && iName[iPathPos]!='\\')
486 aName.Append(Path());
488 if (aFlags & EIncludeBase)
489 aName.Append(Base());
490 if ((aFlags & EForceVer) || ((aFlags & EIncludeVer) && VerLen()) )
493 aName.AppendNumFixedWidth(iVersion, EHex, 8);
496 if ((aFlags & EForceUid) || ((aFlags & EIncludeUid) && UidLen()) )
499 aName.AppendNumFixedWidth(iUid, EHex, 8);
502 if (aFlags & EIncludeExt)
507 void CDllChecker::GetFileNameAndUid(SDllInfo &aDllInfo, const TDesC8 &aExportName)
509 // Gets filename and UID
512 TFileNameInfo filename;
513 filename.Set(aExportName,TFileNameInfo::EAllowUid|TFileNameInfo::EAllowDecimalVersion);
514 filename.GetName(aDllInfo.iDllName,TFileNameInfo::EIncludeBaseExt);
515 aDllInfo.iUid=TUid::Uid(filename.Uid());
519 TInt CDllChecker::CheckUid3(TInt32 aUid3,TUid aUid)
521 // Check that Uid3 is the same in the iDllName and as noted by the Image Header
522 // aUid3 is the value found by the image header
523 // aUid is the value found by parsing the result of block->dllname
524 // using GetFileNameAndUid()
527 if ((aUid.iUid)==aUid3)
530 __PRINT(_L(" Uid3 is valid\n"));
537 __PRINT(_L(" Uid3 value is not supported\n"));
539 return (EUidNotSupported);
545 TInt CDllChecker::FindDll(TDes& aDllName,TFileName& aFileName, TPath& aPath)
547 // Search for a dll in the following sequence ...
548 // 1. Supplied path parameter
549 // 2. System directories on all drives
552 TFindFile findFile(CShell::TheFs);
553 TInt r=findFile.FindByPath(aDllName,&aPath);
556 aFileName=findFile.File();
558 __PRINT1(_L(" Dependency %S was found (supplied path)\n"),&aFileName);
563 r=findFile.FindByDir(aDllName,_L("\\Sys\\Bin\\"));
566 aFileName=findFile.File();
568 __PRINT1(_L(" Dependency %S was found (system directory)\n"),&aFileName);
573 if(!PlatSec::ConfigSetting(PlatSec::EPlatSecEnforceSysBin))
575 r=findFile.FindByDir(aDllName,_L("\\System\\Bin\\"));
578 aFileName=findFile.File();
580 __PRINT1(_L(" Dependency %S was found (system directory)\n"),&aFileName);
586 __PRINT1(_L(" Dependency %S was not found\n"),&aDllName);
588 return(KErrNotFound);
594 void CDllChecker::DllAppendL(const SDllInfo& aDllInfo)
596 TInt leaveCode=KErrNone;
597 TRAP(leaveCode,iDllArray->AppendL(aDllInfo)); // Add it to iDllArray
599 if (leaveCode!=KErrNone)
601 __PRINT(_L(" Could not add Dll to the array\n"));
602 __PRINTWAIT(_L(" Press any key to continue\n"));
604 User::Leave(leaveCode);
608 __PRINT(_L(" Added this information to the array\n"));
609 __PRINT1(_L(" Number of elements in array=%d\n"),iDllArray->Count());
616 void CDllChecker::ListArray()
618 TInt elements=iDllArray->Count();
620 CShell::TheConsole->Printf(_L(" Number of dependencies checked = %d\n"),elements);
622 for (TInt i=0;i<elements; i++)
624 // Prints filename and result of CDllChecker::GetImportDataL for
625 // each element in iDllArray
626 #if defined (UNICODE)
628 Get16BitDllName(iDllArray->At(i).iDllName,filename);
629 CShell::TheConsole->Printf(_L(" %d: %-15S Uid3: [%08x] "),(i+1),&(filename),(iDllArray->At(i).iUid));
631 CShell::TheConsole->Printf(_L(" %d: %-15S Uid3: [%08x] "),(i+1),&(iDllArray->At(i).iDllName),(iDllArray->At(i).iUid));
633 switch(iDllArray->At(i).iResult)
636 CShell::TheConsole->Printf(_L("--- No import data\n"));
639 case(EUidNotSupported):
640 CShell::TheConsole->Printf(_L("--- Uid3 is not supported\n"));
644 CShell::TheConsole->Printf(_L("--- File was not found\n"));
647 case(ECouldNotOpenFile):
648 CShell::TheConsole->Printf(_L("--- File could not be opened\n"));
651 case(EUidDifference):
652 CShell::TheConsole->Printf(_L("--- File already noted with different Uid\n"));
656 CShell::TheConsole->Printf(_L("--- File already open\n"));
659 case(EFileFoundAndUidSupported):
660 CShell::TheConsole->Printf(_L("--- File was found, Uid3 is supported\n"));
662 default: // Will never reach here
663 CShell::TheConsole->Printf(_L("--- Undefined\n"));