diff -r 000000000000 -r a41df078684a userlibandfileserver/fileserver/sfile/sf_ldr.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/userlibandfileserver/fileserver/sfile/sf_ldr.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,2297 @@ +// Copyright (c) 1995-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: +// f32\sfile\sf_ldr.cpp +// +// + +#include "sf_std.h" +#include +#include "sf_image.h" +#include "sf_cache.h" +#include "sf_ldr.h" +#include +#include + + +#ifdef _DEBUG +#define IF_DEBUG(x) x +TInt KernHeapFailCount=0; +TInt LdrHeapFailCount=0; +TInt HeapFailActive=0; +void SetupHeapFail(const RMessage2& aMsg); +void EndHeapFailCheck(TInt); +TInt RFsFailCount=0; +TInt RFsErrorCode=0; +TBool RFsFailActive=0; +void SetupRFsFail(const RMessage2& aMsg); +void EndRFsFailCheck(TInt); +TRequestStatus ProcessDestructStat; +TRequestStatus* ProcessDestructStatPtr=0; +TBool ProcessCreated=EFalse; +#else +#define IF_DEBUG(x) +#endif +TInt DoLoaderDebugFunction(const RMessage2& aMsg); + + +//#define __TRACE_LOADER_HEAP__ + +class RLoaderFs : public RFs + { +public: + inline TInt SendReceive(TInt aFunction, const TIpcArgs& aArgs) const + { return RSessionBase::SendReceive(aFunction, aArgs); } + }; + +static TInt CheckLibraryHash(RLdrReq& aReq); +const TInt KPriorityVeryHigh=14641; + +GLDEF_D RFs gTheLoaderFs; +GLDEF_D TAny* gExeCodeSeg; +GLDEF_D TUint32 gExeAttr; +GLDEF_D TAny* gKernelCodeSeg; +GLDEF_D TUint32 gKernelAttr; +GLDEF_D SSecurityInfo gKernelSecInfo; +GLDEF_D TBool gExecutesInSupervisorMode; +GLDEF_D TAny* gFileServerCodeSeg; +GLDEF_D TUint32 gFileServerAttr; +GLDEF_D SSecurityInfo gFileServerSecInfo; +GLDEF_D CActiveReaper* gActiveReaper=NULL; + +CSlottedChunkAllocator gFileDataAllocator; + + +GLREF_D TCodePageUtils TheCodePage; + + +_LIT(KDriveSystemRoot, "?:\\"); +_LIT(KLoaderThreadName, "LoaderThread"); +_LIT8(KFileExtensionExe,".EXE"); +_LIT8(KFileExtensionDll,".DLL"); +_LIT8(KFileExtensionLdd,".LDD"); +_LIT8(KFileExtensionPdd,".PDD"); +_LIT8(KFileExtensionFsy,".FSY"); +_LIT8(KFileExtensionFxt,".FXT"); +_LIT8(KFileExtensionPxt,".PXT"); +_LIT8(KFileExtensionPxy,".PXY"); +_LIT(KPathDel,"?:\\sys\\del\\"); +const TInt KPathDelLength = 11; +const TInt KExtensionLength=4; + +#if defined(__EPOC32__) && defined(__X86__) +TInt UseFloppy; +#endif + +/****************************************************************************** + * Loader top level stuff + ******************************************************************************/ + +TUint32 GetCodeSegAttr(TAny* aCodeSeg, SSecurityInfo* aS, TUint32* aVer) + { + TCodeSegCreateInfo info; + E32Loader::CodeSegInfo(aCodeSeg, info); + if (aS) + *aS = info.iS; + if (aVer) + *aVer = info.iModuleVersion; + return info.iAttr; + } + +#ifdef __EPOC32__ +extern void InitExecuteInSupervisorMode(); +#endif + +_LIT(KNullThreadName,"EKern*Null"); +void GetKernelInfo() + { + TFindThread ft(KNullThreadName); + TFullName fn; + TInt r = ft.Next(fn); + if (r==KErrNone) + { + RThread null; + r = null.Open(ft); + if (r==KErrNone) + { + gKernelCodeSeg = E32Loader::ThreadProcessCodeSeg(null.Handle()); + if (gKernelCodeSeg) + { + gKernelAttr = GetCodeSegAttr(gKernelCodeSeg, &gKernelSecInfo, NULL); + __IF_DEBUG(Printf("gKernelCodeSeg=%08x", gKernelCodeSeg)); + __IF_DEBUG(Printf("gKernelAttr=%08x", gKernelAttr)); + } + else + r=KErrGeneral; + null.Close(); + } + } + if (r==KErrNone) + { + gFileServerCodeSeg = E32Loader::ThreadProcessCodeSeg(KCurrentThreadHandle); + if (gFileServerCodeSeg) + { + gFileServerAttr = GetCodeSegAttr(gFileServerCodeSeg, &gFileServerSecInfo, NULL); + __IF_DEBUG(Printf("gFileServerCodeSeg=%08x", gFileServerCodeSeg)); + __IF_DEBUG(Printf("gFileServerAttr=%08x", gFileServerAttr)); + } + else + r=KErrGeneral; + } + +#ifdef __EPOC32__ + InitExecuteInSupervisorMode(); +#else + // When running on the emulator the loader can access all memory so effectively it is + // running in supervisor mode. + gExecutesInSupervisorMode = ETrue; +#endif + + __ASSERT_ALWAYS(r==KErrNone, Fault(ELdrGetKernelInfoFailed)); + } + + +#ifdef __TRACE_LOADER_HEAP__ +void InstallHeapTracer(); +#endif + + +#ifdef __LAZY_DLL_UNLOAD +const TInt KLoaderLazyDllDurationDefault=120; // 120 seconds default +TInt KLoaderLazyDllDuration=KLoaderLazyDllDurationDefault; +CLazyUnloadTimer* LazyUnloadTimer=NULL; + +void CLazyUnloadTimer::New() +// +// Create a new CLazyUnloadTimer. +// + { + + CLazyUnloadTimer* lazyUnloadTimer=new CLazyUnloadTimer; + if(lazyUnloadTimer) + { + TRAPD(err,lazyUnloadTimer->ConstructL()); + if(err==KErrNone) + { + lazyUnloadTimer->Start(); + } + else + { + delete lazyUnloadTimer; + } + } + } + +CLazyUnloadTimer::CLazyUnloadTimer() +// +// Constructor +// + : CTimer(EPriorityIdle) + { + Finish(); + LazyUnloadTimer = this; + if (KLoaderLazyDllDuration < 0) + KLoaderLazyDllDuration = KLoaderLazyDllDurationDefault; + } + +CLazyUnloadTimer::~CLazyUnloadTimer() + { + LazyUnloadTimer = NULL; + } + +void CLazyUnloadTimer::Start() + { + E32Loader::CodeSegDeferDeletes(); + CActiveScheduler::Add(this); + TTimeIntervalMicroSeconds32 timeout=KLoaderLazyDllDuration*1000000; + After(timeout); + } + +void CLazyUnloadTimer::RunL() +// +// The timer has completed. +// + { + E32Loader::CodeSegEndDeferDeletes(); + delete this; + } + +void CLazyUnloadTimer::Finish() + { + if(LazyUnloadTimer) + { + LazyUnloadTimer->Cancel(); + LazyUnloadTimer->RunL(); + } + } + +#endif + +/* ReaperCleanupTimer - Used to clear /sys/del/ shortly after boot. */ + +const TInt KLoaderReaperCleanupTimeDefault=60; // 60 seconds default +TInt KLoaderReaperCleanupTime=KLoaderReaperCleanupTimeDefault; +CReaperCleanupTimer* CReaperCleanupTimer::Timer=NULL; + +TInt CReaperCleanupTimer::New() +// +// Create a new CReaperCleanupTimer. +// + { + if (Timer) + return KErrInUse; + + CReaperCleanupTimer* timer=new CReaperCleanupTimer; + if(timer) + { + TRAPD(err,Timer->ConstructL()); + if(err==KErrNone) + { + Timer->Start(); + return KErrNone; + } + else + { + delete Timer; + return err; + } + } + return KErrNoMemory; + } + +CReaperCleanupTimer::CReaperCleanupTimer() + : CTimer(EPriorityIdle) + { + Timer=this; + } + +CReaperCleanupTimer::~CReaperCleanupTimer() + { + Timer = NULL; + } + +void CReaperCleanupTimer::Start() + { + CActiveScheduler::Add(this); + TTimeIntervalMicroSeconds32 timeout=KLoaderReaperCleanupTime*1000000; + After(timeout); + } + +void CReaperCleanupTimer::RunL() + { + if (gActiveReaper) + gActiveReaper->InitDelDir(); + delete this; + } + +void CReaperCleanupTimer::Complete() + { + if(Timer) + { + Timer->Cancel(); + Timer->RunL(); + } + } + +GLDEF_C TInt LoaderThread(TAny*) +// +// The loader thread. +// + { +#ifdef __TRACE_LOADER_HEAP__ + InstallHeapTracer(); +#endif + + TInt r; + __IF_DEBUG(Printf("LoaderThread")); + User::SetCritical(User::ESystemCritical); + GetKernelInfo(); + + CServerLoader* serverLoader; + CActiveSchedulerLoader* scheduler; + + CTrapCleanup* cleanup=CTrapCleanup::New(); + __ASSERT_ALWAYS(cleanup!=NULL, Fault(ELdrCleanupCreate)); + scheduler=CActiveSchedulerLoader::New(); + __ASSERT_ALWAYS(scheduler!=NULL, Fault(ELdrSchedulerCreate)); + serverLoader=CServerLoader::New(); + __ASSERT_ALWAYS(serverLoader!=NULL, Fault(ELdrServerCreate)); + + RThread::Rendezvous(KErrNone); + r=gTheLoaderFs.Connect(); + __ASSERT_ALWAYS(r==KErrNone, Fault(ELdrFsConnect)); + TBuf driveSystemRoot(KDriveSystemRoot); + driveSystemRoot[0] = (TUint8) RFs::GetSystemDriveChar(); + r=gTheLoaderFs.SetSessionPath(driveSystemRoot); + __ASSERT_ALWAYS(r==KErrNone, Fault(ELdrFsSetPath)); + +#ifdef __EPOC32__ + InitializeFileNameCache(); + + r=gFileDataAllocator.Construct(); + __ASSERT_ALWAYS(r==KErrNone, Fault(ELdrFileDataAllocInit)); +#endif + +#ifdef __LAZY_DLL_UNLOAD + CLazyUnloadTimer::New(); +#endif + + gActiveReaper = CActiveReaper::New(); + __ASSERT_ALWAYS(gActiveReaper!=NULL, Fault(ELdrReaperCreate)); + + r=CReaperCleanupTimer::New(); + __ASSERT_ALWAYS(r==KErrNone, Fault(ELdrReaperCleanupTimerCreate)); + + CActiveSchedulerLoader::Start(); + Fault(ELdrSchedulerStopped); + return 0; + } + +TInt InitLoader() + { + + TRequestStatus lts; + RThread loaderThread; + RHeap* h = (RHeap*)&User::Allocator(); + TInt maxsize = h->MaxLength(); // loader heap max size = file server heap max size + TInt r=loaderThread.Create(KLoaderThreadName,LoaderThread,KLoaderStackSize,KHeapMinSize,maxsize,NULL); + if (r!=KErrNone) + { + return r; + } + loaderThread.Rendezvous(lts); + loaderThread.Resume(); + User::WaitForRequest(lts); + loaderThread.Close(); + return lts.Int(); + } + +TInt CompareVersions(TUint32 aL, TUint32 aR) + { + if (aL>aR) + return 1; + if (aL> 16; + TUint32 c = aCandidate & 0x0000ffffu; + TUint32 R = aRequest >> 16; + TUint32 r = aRequest & 0x0000ffffu; + if (C==R) + { + if (c>r) + return EVersion_MinorBigger; + if (c==r) + return EVersion_Exact; + return EVersion_MinorSmaller; + } + if (C>R) + return EVersion_MajorBigger; + return EVersion_MajorSmaller; + } + +TInt DetailedCompareVersions(TUint32 aCandidate, TUint32 aRequest, TUint32 aCurrent, TBool aStrict) + { + TInt cvc = DetailedCompareVersions(aCandidate, aCurrent); + if (aRequest == KModuleVersionWild) + { + return (cvc == EVersion_MinorBigger || cvc == EVersion_MajorBigger) ? EAction_Replace : EAction_Skip; + } + TInt candidate_state = DetailedCompareVersions(aCandidate, aRequest); + if (aStrict) + { + if (candidate_state > EVersion_Exact) + return EAction_Skip; // no match + if (cvc == EVersion_MinorBigger) + return EAction_Replace; // later minor version so take it + return EAction_Skip; // same or earlier minor version + } + TInt current_state = DetailedCompareVersions(aCurrent, aRequest); + if (candidate_state < current_state) + { + // better match + if (candidate_state <= EVersion_Exact) + return EAction_Replace; + return (candidate_state == EVersion_MajorBigger) ? EAction_CheckImports : EAction_CheckLastImport; + } + if (candidate_state > current_state) + return EAction_Skip; // worse match + // match state same + // skip if (i) state=exact + // (ii) state=major smaller + // replace if (i) state=minor bigger and candidate minor > current minor + // (ii) state=minor smaller and candidate minor > current minor + // (iii) state=major bigger, candidate major=current major and candidate minor > current minor + // check if (i) state=major bigger and candidate major < current major + switch (candidate_state) + { + case EVersion_MinorBigger: + case EVersion_MinorSmaller: + return (cvc == EVersion_MinorBigger) ? EAction_Replace : EAction_Skip; + case EVersion_MajorBigger: + if (cvc == EVersion_MinorBigger) + return EAction_Replace; + return (cvc == EVersion_MajorSmaller) ? EAction_CheckImports : EAction_Skip; + default: + return EAction_Skip; + } + } + +TFileNameInfo::TFileNameInfo() + { + memclr(this, sizeof(TFileNameInfo)); + } + +TInt TFileNameInfo::Set(const TDesC8& aFileName, TUint aFlags) + { + __IF_DEBUG(Printf(">TFileNameInfo::Set %S %08x", &aFileName, aFlags)); + iUid = 0; + iVersion = 0; + iPathPos = 0; + iName = aFileName.Ptr(); + iLen = aFileName.Length(); + iExtPos = aFileName.LocateReverse('.'); + if (iExtPos<0) + iExtPos = iLen; + TInt osq = aFileName.LocateReverse('['); + TInt csq = aFileName.LocateReverse(']'); + if (!(aFlags & EAllowUid) && (osq>=0 || csq>=0)) + { + __IF_DEBUG(Printf("=iExtPos || csq>=iExtPos) + { + __IF_DEBUG(Printf("=10 && iName[p-1]==']' && iName[p-10]=='[') + { + TPtrC8 uidstr(iName + p - 9, 8); + TLex8 uidlex(uidstr); + TUint32 uid = 0; + TInt r = uidlex.Val(uid, EHex); + if (r==KErrNone && uidlex.Eos()) + iUid = uid, p -= 10; + } + iUidPos = p; + TInt ob = aFileName.LocateReverse('{'); + TInt cb = aFileName.LocateReverse('}'); + if (ob>=iUidPos || cb>=iUidPos) + { + __IF_DEBUG(Printf("=0 && cb>=0 && p-1==cb) + { + TPtrC8 p8(iName, p); + TInt d = p8.LocateReverse('.'); + TPtrC8 verstr(iName+ob+1, p-ob-2); + TLex8 verlex(verstr); + if (ob==p-10 && dob && p-1>d && (aFlags & EAllowDecimalVersion)) + { + TUint32 maj = 0; + TUint32 min = 0; + TInt r = verlex.Val(maj, EDecimal); + TUint c = (TUint)verlex.Get(); + TInt r2 = verlex.Val(min, EDecimal); + if (r==KErrNone && c=='.' && r2==KErrNone && verlex.Eos() && maj<32768 && min<32768) + iVersion = (maj << 16) | min, p = ob; + } + } + iVerPos = p; + if (iLen>=2 && iName[1]==':') + { + TUint c = iName[0]; + if (c!='?' || !(aFlags & EAllowPlaceholder)) + { + c |= 0x20; + if (c<'a' || c>'z') + { + __IF_DEBUG(Printf("=0 || pathp.Locate(']')>=0 || pathp.Locate('{')>=0 || pathp.Locate('}')>=0 || pathp.Locate(':')>=0) + { + __IF_DEBUG(Printf("Panic(KLitLoader,aPanic); + } + +TInt CheckedCollapse(TDes8& aDest, const TDesC16& aSrc) + { + TInt rl = aSrc.Length(); + aDest.SetLength(rl); + TText8* d = (TText8*)aDest.Ptr(); + const TText16* s = aSrc.Ptr(); + const TText16* sE = s + rl; + while (s=0x20u && *s<0x7fu) + *d++ = (TText8)*s++; + return (saMaxLen) + return KErrOverflow; + aBuf=HBufC8::New((l+aHeadroom)*sizeof(TText)); + if (!aBuf) + return KErrNoMemory; + TPtr8 bp8(aBuf->Des()); + TPtr16 bp16((TText*)bp8.Ptr(), 0, bp8.MaxLength()/sizeof(TText)); + TInt r = Read(aParam, bp16); + if (r == KErrNone) + { + TInt rl = bp16.Length(); + if (aReduce) + r = CheckedCollapse(bp8, bp16); + else + bp8.SetLength(rl*sizeof(TText)); + } + if (r!=KErrNone) + { + delete aBuf; + aBuf=NULL; + } + return r; + } + +TInt RLoaderMsg::GetLdrInfo(TLdrInfo& aInfo) const + { + TPckg infoPckg(aInfo); + return Read(0, infoPckg); + } + +TInt RLoaderMsg::UpdateLdrInfo(const TLdrInfo& aInfo) const + { + TPckgC infoPckg(aInfo); + return Write(0, infoPckg); + } + +TInt RLdrReq::AddFileExtension(const TDesC8& aExt) + { + if (iFileName->LocateReverse('.')==KErrNotFound) + { + if (iFileName->Length()+aExt.Length()>KMaxFileName) + return KErrBadName; + iFileName->Des().Append(aExt); + } + TInt r = iFileNameInfo.Set(*iFileName, TFileNameInfo::EAllowDecimalVersion); + if (r == KErrNone) + { + TInt l = iFileNameInfo.BaseLen() + iFileNameInfo.ExtLen(); + if (l > KMaxProcessName) + r = KErrBadName; + } + return r; + } + +TInt CheckSubstDrive(TDes8& aDest, const TDesC8& aSrc, TBool aIsPathOnly) + { + TInt r = KErrNone; + TInt l = aSrc.Length(); + TInt mdl = aDest.MaxLength(); + TInt pathStart = 0; + if (l>=3 && aSrc[1]==':') + { + // drive letter specified... + pathStart = 2; + TInt drive; + TDriveInfo dI; + r = RFs::CharToDrive((TChar)aSrc[0], drive); + if (r!=KErrNone) + { + return r; + } + r = gTheLoaderFs.Drive(dI, drive); + if (r!=KErrNone) + { + return r; + } + if (dI.iDriveAtt & KDriveAttSubsted) + { + TPtr16 ptr16(aDest.Expand()); + r = gTheLoaderFs.Subst(ptr16, drive); + if (r!=KErrNone) + { + return r; + } + aDest.SetLength(ptr16.Length()*sizeof(TText)); + aDest.Collapse(); + TInt srcm = (aSrc[2]=='\\') ? 3 : 2; + TPtrC8 rest(aSrc.Mid(srcm)); + if (rest.Length() + aDest.Length() > mdl) + return KErrBadName; + aDest.Append(rest); + r=1; + } + } + + if(!PlatSec::ConfigSetting(PlatSec::EPlatSecEnforceSysBin)) + return r; + + // make sure path starts with "\sys\bin\"... + + // get filename/path... + TPtrC8 ptr; + if(!r) + ptr.Set(aSrc); + else + ptr.Set(aDest); + + // set pathStart to first character of path (after any initial '\') + if(ptr.Length() && ptr[pathStart]=='\\') + ++pathStart; // drop initial '\' + + // set pathEnd to first character after path (the final '\' if present) + TInt pathEnd; + if(aIsPathOnly) + { + pathEnd = ptr.Length(); + if(pathEnd && ptr[pathEnd-1]==';') + --pathEnd; // drop trailing ';' + if(pathEnd && ptr[pathEnd-1]=='\\') + --pathEnd; // drop trailing '\' + } + else + { + pathEnd = ptr.LocateReverse('\\'); + if(pathEnd<0) + return r; // no path, so end + } + + // check if path starts with "sys\bin"... + const TUint8* fn = ptr.Ptr(); + _LIT8(KSysBin,"sys\\bin"); + const TInt KSysBinLength = 7; + if(pathStart+KSysBinLength <= pathEnd) + if(KSysBin().CompareF(TPtrC8(fn+pathStart,KSysBinLength))==0) + return r; // path already starts with "sys\bin", so end + + // replace path with "sys\bin"... + TBuf8 temp; + temp.Append(TPtrC8(fn,pathStart)); // add bits before path + temp.Append(KSysBin); // add "sys\bin" + TInt rootLen = ptr.Length()-pathEnd; + if(temp.Length()+rootLen>temp.MaxLength()) + return KErrBadName; // would overflow + temp.Append(TPtrC8(fn+pathEnd,rootLen)); // add bits after path + + // return modified string... + aDest = temp; + return 1; + } + + +TInt RLdrReq::CheckForSubstDriveInName() + { + TBuf8 temp; + TInt r = CheckSubstDrive(temp, *iFileName, EFalse); + if (r<0) + { + return r; + } + if (r>0) + { + TInt l=temp.Length(); + HBufC8* p = HBufC8::New(l+KExtensionLength); + if (!p) + return KErrNoMemory; + TPtr8 bp8(p->Des()); + bp8 = temp; + delete iFileName; + iFileName = p; + r = KErrNone; + } + return r; + } + + +TInt RLdrReq::CheckForSubstDrivesInPath() + { + if (!iPath) + return KErrNone; + TBuf8<(KMaxFileName+1)*sizeof(TText)> temp; + TInt ppos = 0; + TInt plen = iPath->Length(); + HBufC8* newpath = NULL; + while (ppos < plen) + { + TPtrC8 rmn(iPath->Mid(ppos)); + TInt term = rmn.Locate(';'); + TInt pel = (term<0) ? rmn.Length() : term+1; + TPtrC8 path_element(iPath->Mid(ppos, pel)); + ppos += pel; + temp.Zero(); + TInt r = CheckSubstDrive(temp, path_element, ETrue); + if (r<0) + { + delete newpath; + return r; + } + else if (r>0 || newpath) + { + if(!newpath) + { + // initialise 'newpath' to contain everything in path before the element just processed... + newpath = iPath->Left(ppos-pel).Alloc(); + if(!newpath) + return KErrNoMemory; + } + // grow 'newpath'... + TInt xl = (r>0) ? temp.Length() : pel; + HBufC8* np = newpath->ReAlloc(newpath->Length() + xl); + if(!np) + { + delete newpath; + return KErrNoMemory; + } + newpath = np; + // append modified path element to the 'newpath'... + newpath->Des().Append( (r>0) ? (const TDesC8&)temp : (const TDesC8&)path_element); + } + } + if(newpath) + { + delete iPath; + iPath = newpath; + } + return KErrNone; + } + +#ifdef __VC32__ +#pragma warning( disable : 4701 ) // disable warning C4701: local variable 'missingCaps' may be used without having been initialized +#endif + +TInt RLdrReq::CheckSecInfo(const SSecurityInfo& aCandidate) const +// +// Check that the security info of a candidate loadee is sufficient +// + { + if (iSecureId && iSecureId != aCandidate.iSecureId) + return KErrPermissionDenied; + + SCapabilitySet missingCaps; + TUint32 checkFail = 0; + for (TInt i=0; iiFileName,*iFileName,missingCaps); +#else //__REMOVE_PLATSEC_DIAGNOSTICS__ + return PlatSec::EmitDiagnostic(); +#endif //!__REMOVE_PLATSEC_DIAGNOSTICS__ + } + +#ifndef __REMOVE_PLATSEC_DIAGNOSTICS__ + return PlatSec::LoaderCapabilityViolation(iClientProcess,*iFileName,missingCaps); +#else //__REMOVE_PLATSEC_DIAGNOSTICS__ + return PlatSec::EmitDiagnostic(); +#endif //!__REMOVE_PLATSEC_DIAGNOSTICS__ + } + +#ifdef __VC32__ +#pragma warning( default : 4701 ) // enable warning C4701: local variable 'missingCaps' may be used without having been initialized +#endif + +void CSessionLoader::ServiceL(const RMessage2& aMessage) +// +// Handle messages for this server. +// + { + const RLoaderMsg& msg = (const RLoaderMsg&)aMessage; + TLoaderMsg mid=(TLoaderMsg)msg.Function(); + __IF_DEBUG(Printf("Loader: RX msg %d", mid)); + if (mid<1 || mid>=EMaxLoaderMsg) + { + aMessage.Complete(KErrNotSupported); + return; + } +#ifdef __EPOC32__ +#ifdef __X86__ + UseFloppy = -1; +#endif + TInt r=CheckLoaderCacheInit(); + if (r!=KErrNone) + { + aMessage.Complete(r); + return; + } +#else + TInt r = KErrNone; +#endif +#ifdef _DEBUG + if(mid==ELoaderDebugFunction) + { + msg.Complete(DoLoaderDebugFunction(msg)); + return; + } +#endif + if(mid==ELoaderCancelLazyDllUnload) + { +#ifdef __LAZY_DLL_UNLOAD + CLazyUnloadTimer::Finish(); +#endif + msg.Complete(KErrNone); + return; + } +#ifdef _DEBUG + gTheLoaderFs.ResourceCountMarkStart(); +#endif + if(mid==EGetInfoFromHeader) + { + r=GetInfoFromHeader(msg); +#ifdef _DEBUG + gTheLoaderFs.ResourceCountMarkEnd(); +#endif + msg.Complete(r); + return; + } + + if (mid == ELdrDelete) + { + // TCB and AllFiles are sufficient to ensure that write + // access to any part of the file system without having to + // check substitutions and access rights here. + if (! aMessage.HasCapability(ECapabilityTCB, ECapabilityAllFiles, __PLATSEC_DIAGNOSTIC_STRING("ELdrDelete,TCB+AllFiles"))) + { + r = KErrPermissionDenied; + } + // because this function is a general-purpose replacement for RFs::Delete, + // it doesn't use the transformed filename which would be put into ldrReq.iFileName, + // but the literal filename which was supplied, provided it is absolute. + else + { + TInt filenameLength = msg.GetDesLength(1); + if(filenameLength<0) + r = filenameLength; + else + { + HBufC* fnSupply = HBufC::New(filenameLength); + if(!fnSupply) + r = KErrNoMemory; + else + { + TPtr buf = fnSupply->Des(); + if ((r=msg.Read( 1, buf)) == KErrNone) + { + _LIT(KAbsolutePathPattern,"?:\\*"); + if (fnSupply->MatchF(KAbsolutePathPattern) != 0) + r = KErrBadName; + else + { + _LIT(KSysBin,"?:\\sys\\bin\\*"); + if (fnSupply->MatchF(KSysBin) == 0) + r = DeleteExecutable(*fnSupply); + else + r = gTheLoaderFs.Delete(*fnSupply); + } + } + delete fnSupply; + } + } + } // endif !aMessage.HasCapability + +#ifdef _DEBUG + gTheLoaderFs.ResourceCountMarkEnd(); +#endif + msg.Complete(r); + return; + } + + RLdrReq ldrReq; + ldrReq.iMsg=&msg; + r=msg.GetString(ldrReq.iFileName, 1, KMaxFileName, KExtensionLength, ETrue); + __IF_DEBUG(Printf("Filename: %S", ldrReq.iFileName)); + if (r==KErrNone) + r = ldrReq.CheckForSubstDriveInName(); + __IF_DEBUG(Printf("Post-subst filename: %S", ldrReq.iFileName)); + if (r!=KErrNone) + goto error; + + ldrReq.iPlatSecCaps = AllCapabilities; // secure default, require loaded executable to have all capabilities + +#ifndef __EPOC32__ + // On the emulator, temporarily disable CPU speed restrictions whilst loading executables... + TInt cpu; + HAL::Get(HALData::ECPUSpeed, cpu); + HAL::Set(HALData::ECPUSpeed, 0); +#endif + IF_DEBUG(SetupRFsFail(msg)); + IF_DEBUG(SetupHeapFail(msg)); + switch (mid) + { + //__DATA_CAGING__ + case EGetInfo: + { + r=ldrReq.AddFileExtension(KFileExtensionDll); + if (r==KErrNone) + r=msg.GetLdrInfo(ldrReq); + if (r==KErrNone) + r=GetModuleInfo(ldrReq); + break; + } + //__DATA_CAGING__ + case ELoadProcess: + { + r=ldrReq.AddFileExtension(KFileExtensionExe); + if (r==KErrNone) + r=msg.GetString(ldrReq.iCmd, 2, KMaxTInt, 0, EFalse); + if (r==KErrNone) + r=msg.GetLdrInfo(ldrReq); + if (r==KErrNone) + { + static const SCapabilitySet NoCapabilities={{0}}; + ldrReq.iPlatSecCaps=NoCapabilities; // We don't care what EXEs capabilities are + r=LoadProcess(ldrReq); + } + break; + } + case ELoadLibrary: + { + r=E32Loader::CheckClientState(msg.Handle()); + if (r!=KErrNone) + ldrReq.Panic(ELoadLibraryWithoutDllLock); + else + r=ldrReq.AddFileExtension(KFileExtensionDll); + if (r==KErrNone) + r=msg.GetString(ldrReq.iPath, 2, KMaxPath, 0, ETrue); + if (ldrReq.iPath) + { + __IF_DEBUG(Printf("Path: %S", ldrReq.iPath)); + } + if (r==KErrNone) + r = ldrReq.CheckForSubstDrivesInPath(); + if (ldrReq.iPath) + { + __IF_DEBUG(Printf("Post-subst Path: %S", ldrReq.iPath)); + } + if (r==KErrNone) + r=msg.GetLdrInfo(ldrReq); + if (r==KErrNone) + r=LoadLibrary(ldrReq); + break; + } + + case ECheckLibraryHash: + + r = ldrReq.AddFileExtension(KFileExtensionDll); + if (r==KErrNone) + { + r = CheckLibraryHash(ldrReq); + } + break; + + case ELoadLogicalDevice: + { + r=ldrReq.AddFileExtension(KFileExtensionLdd); + if (r==KErrNone) + r=LoadDeviceDriver(ldrReq, 0); + break; + } + case ELoadPhysicalDevice: + { + r=ldrReq.AddFileExtension(KFileExtensionPdd); + if (r==KErrNone) + r=LoadDeviceDriver(ldrReq, 1); + break; + } + case ELoadLocale: + { + r=ldrReq.AddFileExtension(KFileExtensionDll); + if (r==KErrNone) + { + ldrReq.iRequestedUids=TUidType(TUid::Uid(KDynamicLibraryUidValue),TUid::Uid(KLocaleDllUidValue)); + ldrReq.iOwnerType=EOwnerProcess; + ldrReq.iHandle=0; + ldrReq.iPlatSecCaps=AllCapabilities; + ldrReq.iMsg=NULL; // null msg -> client is self + TLibraryFunction functionList[KNumLocaleExports]; + r=LoadLocale(ldrReq, functionList); + if(r==KErrNone) + { + TInt size = KNumLocaleExports * sizeof(TLibraryFunction); + TPtr8 functionListBuf((TUint8*)&functionList[0], size, size); + TRAP(r, aMessage.WriteL(2, functionListBuf, 0)); + } + } + break; + } + case ELoadCodePage: + { + if (!KCapDiskAdmin.CheckPolicy(aMessage, __PLATSEC_DIAGNOSTIC_STRING("Loader : ELoadCodePage"))) + { + r = KErrPermissionDenied; + break; + } + r=ldrReq.AddFileExtension(KFileExtensionDll); + if (r==KErrNone) + { + ldrReq.iRequestedUids=TUidType(TUid::Uid(KDynamicLibraryUidValue),TUid::Uid(KLocaleDllUidValue)); + ldrReq.iOwnerType=EOwnerProcess; + ldrReq.iHandle=0; + ldrReq.iPlatSecCaps=gFileServerSecInfo.iCaps; + ldrReq.iMsg=NULL; // null msg -> client is self + r=LoadLibrary(ldrReq); + if (r==KErrNone) + { + // call file server to install code page dll + r = ((RLoaderFs*)&gTheLoaderFs)->SendReceive(EFsLoadCodePage, TIpcArgs(ldrReq.iHandle)); + } + } + if (r!=KErrNone) + { + RLibrary lib; + lib.SetHandle(ldrReq.iHandle); + lib.Close(); + } + break; + } + case ELoadFileSystem: + { + if (!KCapFsAddFileSystem.CheckPolicy(aMessage, __PLATSEC_DIAGNOSTIC_STRING("Add File System"))) + { + r = KErrPermissionDenied; + break; + } + r=ldrReq.AddFileExtension(KFileExtensionFsy); + if (r==KErrNone) + { + ldrReq.iRequestedUids=TUidType(TUid::Uid(KDynamicLibraryUidValue),TUid::Uid(KFileSystemUidValue)); + ldrReq.iOwnerType=EOwnerProcess; + ldrReq.iHandle=0; + ldrReq.iPlatSecCaps=gFileServerSecInfo.iCaps; + ldrReq.iMsg=NULL; // null msg -> client is self + r=LoadLibrary(ldrReq); + if (r==KErrNone) + { + // call file server to install file system + r = ((RLoaderFs*)&gTheLoaderFs)->SendReceive(EFsAddFileSystem, TIpcArgs(ldrReq.iHandle)); + } + } + if (r!=KErrNone) + { + RLibrary lib; + lib.SetHandle(ldrReq.iHandle); + lib.Close(); + } + break; + } + case ELoadFSExtension: + { + if (!KCapFsAddExtension.CheckPolicy(aMessage, __PLATSEC_DIAGNOSTIC_STRING("Add File Extension"))) + { + r = KErrPermissionDenied; + break; + } + r=ldrReq.AddFileExtension(KFileExtensionFxt); + if (r==KErrNone) + { + ldrReq.iRequestedUids=TUidType(TUid::Uid(KDynamicLibraryUidValue),TUid::Uid(KFileSystemUidValue)); + ldrReq.iOwnerType=EOwnerProcess; + ldrReq.iHandle=0; + ldrReq.iPlatSecCaps=gFileServerSecInfo.iCaps; + ldrReq.iMsg=NULL; // null msg -> client is self + r=LoadLibrary(ldrReq); + if (r==KErrNone) + { + // call file server to install file system + r = ((RLoaderFs*)&gTheLoaderFs)->SendReceive(EFsAddExtension, TIpcArgs(ldrReq.iHandle)); + } + } + if (r!=KErrNone) + { + RLibrary lib; + lib.SetHandle(ldrReq.iHandle); + lib.Close(); + } + break; + } + case ELoadFSProxyDrive: + { + if (!KCapFsAddProxyDrive.CheckPolicy(aMessage, __PLATSEC_DIAGNOSTIC_STRING("Add Proxy Drive"))) + { + r = KErrPermissionDenied; + break; + } + r=ldrReq.AddFileExtension(KFileExtensionPxy); + if (r==KErrNone) + { + ldrReq.iRequestedUids=TUidType(TUid::Uid(KDynamicLibraryUidValue),TUid::Uid(KFileSystemUidValue)); + ldrReq.iOwnerType=EOwnerProcess; + ldrReq.iHandle=0; + ldrReq.iPlatSecCaps=gFileServerSecInfo.iCaps; + ldrReq.iMsg=NULL; // null msg -> client is self + r=LoadLibrary(ldrReq); + if (r==KErrNone) + { + // call file server to install file system + r = ((RLoaderFs*)&gTheLoaderFs)->SendReceive(EFsAddProxyDrive, TIpcArgs(ldrReq.iHandle)); + } + } + if (r!=KErrNone) + { + RLibrary lib; + lib.SetHandle(ldrReq.iHandle); + lib.Close(); + } + break; + } + case ELoadFSPlugin: + { + r=ldrReq.AddFileExtension(KFileExtensionPxt); + if (r==KErrNone) + { + ldrReq.iRequestedUids=TUidType(TUid::Uid(KDynamicLibraryUidValue),TUid::Uid(KFileSystemUidValue)); + ldrReq.iOwnerType=EOwnerProcess; + ldrReq.iHandle=0; + ldrReq.iPlatSecCaps=gFileServerSecInfo.iCaps; + ldrReq.iMsg=NULL; // null msg -> client is self + r=LoadLibrary(ldrReq); + if (r==KErrNone) + { + // call file server to install file system + r = ((RLoaderFs*)&gTheLoaderFs)->SendReceive(EFsAddPlugin, TIpcArgs(ldrReq.iHandle)); + } + } + if (r!=KErrNone) + { + RLibrary lib; + lib.SetHandle(ldrReq.iHandle); + lib.Close(); + } + break; + } + + default: + r=KErrNotSupported; + break; + } + + ldrReq.Close(); + IF_DEBUG(EndRFsFailCheck(r)); + IF_DEBUG(EndHeapFailCheck(r)); +#ifndef __EPOC32__ + HAL::Set(HALData::ECPUSpeed, cpu); +#endif +error: +#ifdef _DEBUG + gTheLoaderFs.ResourceCountMarkEnd(); +#endif + if (!aMessage.IsNull()) + { + __IF_DEBUG(Printf("Loader: msg complete %d", r)); + aMessage.Complete(r); + } + } + +//----------------------------------------------------------------------------------- +#ifndef __WINS__ +/** + Helper function that reads a hash file from c:\\sys\\hash and compares it with the givem dll hash. + + @param aHashFile represents opened hash file in c:\\sys\\hash directory + @param aDllFileName full path to the dll file, which hash will be calculated and compared with aHashFile contents. + @leave on file operation error or if hashes differ. +*/ +static void DoCheckHashL(RFile& aHashFile, const TDesC& aDllFileName) + { + TBuf8 hashInstalled; //-- installed dll hash, from c:\\sys\\hash + User::LeaveIfError(aHashFile.Read(hashInstalled)); + + CSHA1* hasher=CSHA1::NewL(); + CleanupStack::PushL(hasher); + + RFile fileDll; + CleanupClosePushL(fileDll); + + //-- open dll file + User::LeaveIfError(fileDll.Open(gTheLoaderFs, aDllFileName, EFileRead|EFileReadDirectIO)); + + TInt fileSz; + User::LeaveIfError(fileDll.Size(fileSz)); + + //-- check if the file is on removable media + TInt drvNum; + TDriveInfo drvInfo; + User::LeaveIfError(fileDll.Drive(drvNum, drvInfo)); + if(!(drvInfo.iDriveAtt & KDriveAttRemovable)) + User::Leave(KErrNotSupported); + + TInt offset=0; + TInt readSize = KHashFileReadSize; + RBuf8 readBuf; + + CleanupClosePushL(readBuf); + readBuf.CreateMaxL(readSize); + + //-- calculate dll hash + do { + if((fileSz - offset) < readSize) + readSize = (fileSz - offset); + + User::LeaveIfError(fileDll.Read(offset, readBuf, readSize)); + hasher->Update(readBuf); + offset+=readSize; + } + while(offset < fileSz); + + TBuf8 hashCalculated; //-- calculated dll hash + hashCalculated=hasher->Final(); + + //-- compare hashes + if(hashCalculated.Compare(hashInstalled) !=0) + User::Leave(KErrCorrupt); + + CleanupStack::PopAndDestroy(3); //hasher, fileDll, readBuf + } +#endif //__WINS__ + +//----------------------------------------------------------------------------------- + +/** + Check if specified dll hash exists in \\sys\\hash on system drive and optionally validate it. + + + @param aReq loader request parameters + + @return System-wide error code, see RLoader::CheckLibraryHash() description + @return KErrNotSupported for the emulator version, because loading dlls from the emulated removable media is not supported +*/ +static TInt CheckLibraryHash(RLdrReq& aReq) + { +#ifdef __WINS__ + (void)aReq; + return KErrNotSupported; //-- loading dlls from removable media and dll hashing isn't supported for WINS +#else + + const TInt fNameLen=aReq.iFileName->Length(); + if(fNameLen <= 0 || fNameLen > KMaxFileName) + return KErrArgument; + + const TBool bValidateHash=aReq.iMsg->Int2(); + + //-- extract pure dll name + TInt posNameStart=aReq.iFileName->LocateReverse('\\'); + if(posNameStart <0) + posNameStart = 0; + else + posNameStart++; + + //-- compose hash file name \\sys\\hash\\xxx on system drive + TFileName hashFName; + hashFName.Copy(aReq.iFileName->Right(fNameLen-posNameStart)); + hashFName.Insert(0, KSysHash); + hashFName[0] = (TUint8) RFs::GetSystemDriveChar(); + + //-- try to locate hash file + TInt nRes=KErrNone; + RFile fileHash; + nRes = fileHash.Open(gTheLoaderFs, hashFName, EFileRead|EFileReadDirectIO); + + if(nRes != KErrNone) + { + nRes = KErrNotFound; //-- hash file couldn't be found + } + else if(bValidateHash) + {//-- request to validate the hash. + hashFName.Copy(aReq.iFileName->Left(fNameLen)); //-- expand file name to unicode + TRAP(nRes, DoCheckHashL(fileHash, hashFName)); + + if(nRes != KErrNone) + nRes=KErrCorrupt; + } + + fileHash.Close(); + + return nRes; + +#endif //__WINS__ + } + +// This safely deletes something that could be an executable (ie in /sys/bin) +// aName will be deleted either in, or sometime after this call +// (The descriptor and the file it represents) +TInt CSessionLoader::DeleteExecutable(const TDesC& aName) + { + __IF_DEBUG(Printf("DeleteExecutable %S", &aName)); + TInt r; + r = gTheLoaderFs.Delete(aName); + if (r!=KErrInUse) + { + return r; + } + RFile toDelete; + CReaperCleanupTimer::Complete(); + + HBufC* newName=NULL; + r = toDelete.Open(gTheLoaderFs,aName,EFileShareExclusive|EFileReadDirectIO); + if (r==KErrNone) + { + TInt64 startPos=0; + SBlockMapInfo blockmapInfo; + + // find drive number, and starting block + r = toDelete.BlockMap(blockmapInfo,startPos, 1, ETrue); + if (r == KErrCompletion) + { + TInt64 startBlock = blockmapInfo.iStartBlockAddress + + ((TBlockMapEntry *)(&(blockmapInfo.iMap[0])))->iStartBlock * + blockmapInfo.iBlockGranularity + + blockmapInfo.iBlockStartOffset; + TInt driveNumber = blockmapInfo.iLocalDriveNumber; + + newName = HBufC::New(KPathDelLength+2+16); // + 2 digits for drive and 16 for start block block + if(!newName) + r = KErrNoMemory; + else + { + // make unique name for file... + TPtr name = newName->Des(); + name.Copy(KPathDel); + name[0] = aName[0]; // copy drive letter + name.AppendNumFixedWidth(driveNumber, EHex, 2); + name.AppendNumFixedWidth(TUint32(startBlock>>32), EHex, 8); + name.AppendNumFixedWidth(TUint32(startBlock), EHex, 8); + + TLoaderDeletedList* tmpLink = new TLoaderDeletedList(); + if(tmpLink==NULL) + r = KErrNoMemory; + else + { + toDelete.Close(); + gTheLoaderFs.MkDirAll(*newName); // ignore error and let rename fail if path doesn't exists + r = gTheLoaderFs.Rename(aName, *newName); + __IF_DEBUG(Printf("DeleteExecutable rename to %S returns %d", &newName, r)); + if(r==KErrNone) + { + // add to pending deletion list + tmpLink->iStartBlock = startBlock; + tmpLink->iDriveNumber = driveNumber; + tmpLink->iFileName = newName; + gActiveReaper->AddDeleted(tmpLink); + return r; + } //endif rename + delete tmpLink; + } // alloc + delete newName; + } // alloc name + } //endif blockmap + else if (r == KErrNotSupported) + r = KErrInUse; + else if (r == KErrNone) + r = KErrGeneral; + toDelete.Close(); + } // endif open + return r; + } + + +GLDEF_C TInt LoadProcess(RLdrReq& aReq) + { + __LDRTRACE(aReq.Dump("LoadProcess:")); + TInt32* uid=(TInt32*)&aReq.iRequestedUids; + if (uid[0] && uid[0]!=KExecutableImageUidValue) + return KErrNotSupported; + uid[0]=KExecutableImageUidValue; + gExeCodeSeg=NULL; // new process doesn't load into another process + gExeAttr=0; + E32Image* e=new E32Image; + if (!e) + return KErrNoMemory; + e->iMain=e; + TInt r=e->LoadProcess(aReq); + if (r==KErrNone) + { + aReq.iHandle=e->iFinalHandle; + r=aReq.iMsg->UpdateLdrInfo(aReq); + if (r!=KErrNone) + aReq.Panic(KErrBadDescriptor); + } + if (r!=KErrNone && e->iProcessHandle) + { + RProcess p; + p.SetHandle(e->iProcessHandle); + p.Kill(0); + } + delete e; + return r; + } + + + +TInt LoadLibrary(RLdrReq& aReq) + { + __LDRTRACE(aReq.Dump("LoadLibrary:")); + TInt32* uid=(TInt32*)&aReq.iRequestedUids; + if (uid[0] && uid[0]!=KDynamicLibraryUidValue) + return KErrNotSupported; + uid[0]=KDynamicLibraryUidValue; + TInt r=KErrNone; + if (aReq.iMsg) + { + r = aReq.iMsg->Client(aReq.iClientThread); + if (r==KErrNone) + r = aReq.iClientThread.Process(aReq.iClientProcess); + if (r!=KErrNone) + { + return r; + } + } + else + { + aReq.iClientThread.SetHandle(KCurrentThreadHandle); + aReq.iClientProcess.SetHandle(KCurrentProcessHandle); + } + E32Loader::CodeSegDeferDeletes(); + gExeCodeSeg=E32Loader::ThreadProcessCodeSeg(aReq.iClientThread.Handle()); + SSecurityInfo si; + gExeAttr=GetCodeSegAttr(gExeCodeSeg, &si, NULL); + aReq.iPlatSecCaps=si.iCaps; + E32Loader::CodeSegEndDeferDeletes(); + E32Image* e=new E32Image; + if (!e) + return KErrNoMemory; + e->iMain=e; + e->iClientProcessHandle=aReq.iClientProcess.Handle(); + __IF_DEBUG(Printf("e->iClientProcessHandle = %08x", e->iClientProcessHandle)); + if (r==KErrNone) + r=e->LoadCodeSeg(aReq); + if (r==KErrNone) + { + TLibraryCreateInfo libInfo; + libInfo.iCodeSegHandle=e->iHandle; + libInfo.iClientHandle=aReq.iClientThread.Handle(); + libInfo.iLibraryHandle=0; + libInfo.iOwnerType=aReq.iOwnerType; + r=E32Loader::LibraryCreate(libInfo); + if (r==KErrNone) + { + aReq.iHandle=libInfo.iLibraryHandle; + if (aReq.iMsg) + { + r=aReq.iMsg->UpdateLdrInfo(aReq); + if (r!=KErrNone) + aReq.Panic(KErrBadDescriptor); + } + } + } + delete e; + return r; + } + +struct TFatUtilityFunctions; + +GLDEF_C TInt LoadLocale(RLdrReq& aReq, TLibraryFunction* aExportsList) + { + __LDRTRACE(aReq.Dump("LoadLocale:")); + TUint32* uid=(TUint32*)&aReq.iRequestedUids; + uid[2]=0; + gExeCodeSeg=NULL; + gExeAttr = gFileServerAttr; + E32Image* e=new E32Image; + if (!e) + return KErrNoMemory; + e->iMain=e; + e->iAttr=ECodeSegAttGlobal; + TInt r=e->LoadCodeSeg(aReq); + if (r==KErrNone) + { + r = E32Loader::LocaleExports(e->iHandle, aExportsList); +#ifdef SYMBIAN_DISTINCT_LOCALE_MODEL + _LIT8(KLocLan, "elocl_lan"); + _LIT8(KLoc, "elocl."); + if(aReq.iFileName->Find(KLocLan) != KErrNotFound) + { + TheCodePage.SetLocaleCodePage((TFatUtilityFunctions*)aExportsList[FnFatUtilityFunctionsV2]()); + } + if(aReq.iFileName->Find(KLoc) != KErrNotFound) + { + TheCodePage.SetLocaleCodePage((TFatUtilityFunctions*)aExportsList[FnFatUtilityFunctions]()); + } +#else + // The 'old' version of the locale DLL contained a set of code page conversion exports. + // This has now been superceeded by the use of a seperate code page DLL. + // - To ease migration both are currently supported. + // - If both locale and CP DLL functions are present, CP DLL's will take precedence + // - This functionality will eventually be deprecated. + TheCodePage.SetLocaleCodePage((TFatUtilityFunctions*)aExportsList[FnFatUtilityFunctions]()); +#endif + } + delete e; + return r; + } + +TInt LoadDeviceDriver(RLdrReq& aReq, TInt aDeviceType) + { + __IF_DEBUG(Printf("LoadDeviceDriver type %d", aDeviceType)); + __LDRTRACE(aReq.Dump("")); + TUint32* uid=(TUint32*)&aReq.iRequestedUids; + uid[0]=KDynamicLibraryUidValue; + uid[1]=aDeviceType ? KPhysicalDeviceDriverUidValue : KLogicalDeviceDriverUidValue; + uid[2]=0; + gExeCodeSeg=gKernelCodeSeg; + gExeAttr=gKernelAttr; + E32Image* e=new E32Image; + if (!e) + return KErrNoMemory; + e->iMain=e; + e->iAttr=ECodeSegAttKernel; + aReq.iOwnerType=EOwnerProcess; + aReq.iHandle=0; + aReq.iPlatSecCaps=gKernelSecInfo.iCaps; + TInt r=e->LoadCodeSeg(aReq); + if (r==KErrNone) + r=E32Loader::DeviceLoad(e->iHandle, aDeviceType); + delete e; + return r; + } + +CServerLoader* CServerLoader::New() +// +// Create a new CServerLoader. +// + { + CServerLoader* pS=new CServerLoader(EPriorityNormal); + if (pS==NULL) + return(NULL); + _LIT(KLoaderServerName,"!Loader"); + TInt r=pS->Start(KLoaderServerName); + if (r!=KErrNone) + return(NULL); + return(pS); + } + +CServerLoader::CServerLoader(TInt aPriority) +// +// Constructor. +// + : CServer2(aPriority) + { + } + +CSession2* CServerLoader::NewSessionL(const TVersion& aVersion, const RMessage2&) const +// +// Create a new client for this server. +// + { + + TVersion v(KLoaderMajorVersionNumber,KLoaderMinorVersionNumber,KF32BuildVersionNumber); + TBool r=User::QueryVersionSupported(v,aVersion); + if (!r) + User::Leave(KErrNotSupported); + return new (ELeave) CSessionLoader; + } + +TInt CServerLoader::RunError(TInt aError) +// +// Complete the request with the error code +// + { + Message().Complete(aError); + ReStart(); + return KErrNone; + } + +CActiveSchedulerLoader* CActiveSchedulerLoader::New() +// +// Create and install the active scheduler. +// + { + + CActiveSchedulerLoader* pA=new CActiveSchedulerLoader; + if (pA==NULL) + return(NULL); + CActiveScheduler::Install(pA); + return(pA); + } + +void CActiveSchedulerLoader::Error(TInt anError) const +// +// Called if any Run() method leaves. +// + { + _LIT(KPanicLoaderErr, "LOADER-ERR"); + User::Panic(KPanicLoaderErr,anError); + } + +/****************************************************************************** + * E32Image functions common to WINS and EPOC + ******************************************************************************/ + +TInt CheckUids(const TUidType& aUids, const TUidType& aRequestedUids) + { + const TUint32* uid=(const TUint32*)&aUids; + const TUint32* req=(const TUint32*)&aRequestedUids; + __IF_DEBUG(Printf("CheckUids %08x,%08x,%08x req %08x,%08x,%08x", uid[0],uid[1],uid[2], + req[0],req[1],req[2])); + return (CheckUid(uid[0],req[0]) && CheckUid(uid[1],req[1]) && CheckUid(uid[2],req[2])) + ? KErrNone : KErrNotSupported; + } + +E32Image::E32Image() + { + __IF_DEBUG(Printf("E32Image Constructor")); + Mem::FillZ(&iUids, sizeof(E32Image)-sizeof(iFileName)); + } + +E32Image::~E32Image() + { + + __IF_DEBUG(Printf("E32Image Destructor")); + Reset(); + } + +void E32Image::Reset() + { + __IF_DEBUG(Printf("E32Image::Reset")); + delete iHeader; + __IF_DEBUG(Printf("iHeader")); + + // demand paging fixup data + User::Free(iImportFixupTable); + __IF_DEBUG(Printf("iImportFixupTable")); + + // demand paging file data + __IF_DEBUG(Printf("iCodePageOffsets")); + delete[] iCodePageOffsets; + __IF_DEBUG(Printf("iCodeBlockMapEntries")); + User::Free(iCodeBlockMapEntries); + + __IF_DEBUG(Printf("iCodeRelocSection")); + User::Free(iCodeRelocTable); + __IF_DEBUG(Printf("iDataRelocSection")); + User::Free(iRestOfFileData); + __IF_DEBUG(Printf("iRestOfFileData")); + User::Free(iCurrentImportList); + __IF_DEBUG(Printf("iCurrentImportList")); + User::Free(iFixups); + __IF_DEBUG(Printf("iFixups")); + gFileDataAllocator.Free(iFileData); + iFileData = NULL; + __IF_DEBUG(Printf("iFileData")); + iFile.Close(); + __IF_DEBUG(Printf("iFile")); + User::Free(iCopyOfExportDir); + if (iProcessHandle) + { + RProcess p; + p.SetHandle(iProcessHandle); + p.Close(); + __IF_DEBUG(Printf("iProcessHandle")); + } + if (iCloseCodeSeg) + E32Loader::CodeSegClose(iCloseCodeSeg); + if (iMain==this) + E32Loader::CodeSegClose(NULL); + + // Unclamp file if load failed. Cannot handle error from RFs here. + __IF_DEBUG(Printf("iFileClamp,%ld,%ld", iFileClamp.iCookie[0], iFileClamp.iCookie[1])); + iFileClamp.Close(gTheLoaderFs); + + __IF_DEBUG(Printf("Reset done")); + } + + +TInt E32Image::OpenFile() + { + TBuf8 fnb; + if (iAttr & ECodeSegAttExpVer) + { + TFileNameInfo fi; + fi.Set(iFileName, 0); + fi.iVersion = iModuleVersion; + fi.GetName(fnb, TFileNameInfo::EIncludeDrivePathBaseExt|TFileNameInfo::EForceVer); + } + else + fnb = iFileName; + TPtr16 fn(fnb.Expand()); + __IF_DEBUG(Print(_L(">E32Image::OpenFile %S"),&fn)); + TInt r = iFile.Open(gTheLoaderFs, fn, EFileStream|EFileRead|EFileShareReadersOnly|EFileReadDirectIO); + __IF_DEBUG(Printf("E32Image::CheckAlreadyLoaded %S", &iFileName)); + __IF_DEBUG(Printf("UIDs %08x,%08x,%08x",iUids[0],iUids[1],iUids[2])); + __IF_DEBUG(Printf("VER %08x",iModuleVersion)); + __IF_DEBUG(Printf("CAPS %08x %08x SID %08x", iS.iSecureId, iS.iCaps[1], iS.iCaps[0])); + __IF_DEBUG(Printf("Client process handle %08x",iClientProcessHandle)); + + TFindCodeSeg find; + find.iUids = iUids; + find.iRomImgHdr = NULL; +#ifndef __WINS__ + // Make sure we check the code segment attributes (kernel or global) + // as part of the decision as to whether we are loaded or not. + find.iAttrMask = (ECodeSegAttKernel|ECodeSegAttGlobal); + find.iAttrVal = iAttr&(ECodeSegAttKernel|ECodeSegAttGlobal); +#else + // On the emulator, all DLLs are loaded into the same process, so we + // don't distinguish between instances of the same DLL loaded with + // different code segment attributes. + find.iAttrMask = 0; + find.iAttrVal = 0; +#endif + find.iProcess = iClientProcessHandle; + find.iS = iS; + find.iModuleVersion = iModuleVersion; + find.iName = RootName(); + __IF_DEBUG(Printf("Required root name %S", &find.iName)); + + E32Loader::CodeSegDeferDeletes(); + iHandle = NULL; + TAny* h = NULL; + TInt r = KErrNone; + E32Loader::CodeSegNext(h, find); + if(h) + { + // found... + iHandle = h; + __IF_DEBUG(Printf("Client process handle %08x",iClientProcessHandle)); + E32Loader::CodeSegInfo(h, *this); + __IF_DEBUG(Printf("Client process handle %08x",iClientProcessHandle)); + r = E32Loader::CodeSegOpen(h, iClientProcessHandle); + } + E32Loader::CodeSegEndDeferDeletes(); + + if(iHandle && r==KErrNone) + { + iAlreadyLoaded = ETrue; + TUint32 attrMask = (gExecutesInSupervisorMode)? + // The loader reads export directories in kernel mode so it can access + // kernel code export directories and global export directories. + ECodeSegAttKernel | ECodeSegAttGlobal : + // The loader reads export directories in user mode so it can't access + // kernel code export directories but can access global export directories. + ECodeSegAttGlobal; + + if(iAttr & attrMask) + {// The export directory is visible to loader so set iExportDirLoad to prevent + // the loader from invoking E32Loader::ReadExportDir() to copy the kernel's copy + // of the export directory to the loader's heap. + iExportDirLoad = iExportDir; + } + } + + __IF_DEBUG(Printf("0) + { + __KHEAP_SETFAIL(RHeap::EFailNext, KernHeapFailCount); + __KHEAP_MARK; + HeapFailActive|=1; + } + if (LdrHeapFailCount>0) + { + __UHEAP_SETFAIL(RHeap::EFailNext, LdrHeapFailCount); + __UHEAP_MARK; + HeapFailActive|=2; + } + ProcessCreated = EFalse; + ProcessDestructStat = KRequestPending; + ProcessDestructStatPtr = &ProcessDestructStat; + } + +void EndHeapFailCheck(TInt aError) + { + __IF_DEBUG(Printf("EndHeapFail: %d",aError)); + if (aError==KErrNone && ProcessCreated) + { + User::CancelMiscNotifier(ProcessDestructStat); + User::WaitForRequest(ProcessDestructStat); + } + if (aError!=KErrNone) + { + if (ProcessCreated) + // wait for any partially created process to die + User::WaitForRequest(ProcessDestructStat); + + // wait for reaper to run + TInt rr; + if (CActiveScheduler::RunIfReady(rr,KPriorityVeryHigh)) + User::WaitForAnyRequest(); + + // wait for any async cleanup in the supervisor to finish + UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0); + + if (HeapFailActive&1) + { + __KHEAP_MARKEND; + } + if (HeapFailActive&2) + { + __UHEAP_MARKEND; + } + } + if (HeapFailActive & 3) + { + __KHEAP_TOTAL_RESET; + __UHEAP_TOTAL_RESET; + } + HeapFailActive=0; + ProcessDestructStatPtr = 0; + ProcessCreated = EFalse; + } + +void SetupRFsFail(const RMessage2& /*aMsg*/) + { + __IF_DEBUG(Printf("SetupRFsFail: %d,%d", RFsErrorCode, RFsFailCount)); + if (RFsErrorCode!=KErrNone && RFsFailCount>0) + { + gTheLoaderFs.SetErrorCondition(RFsErrorCode, RFsFailCount); + RFsFailActive = ETrue; + } + } + +void EndRFsFailCheck(TInt /*aError*/) + { + if (RFsFailActive) + { + gTheLoaderFs.SetErrorCondition(KErrNone); + RFsFailActive = EFalse; + } + } + +#endif + +#if defined(_DEBUG) || defined(_DEBUG_RELEASE) +void RLdrReq::Dump(const char* aTitle) const + { + RDebug::Printf(aTitle); + if (iFileName) + RDebug::Printf("iFileName=%S", iFileName); + if (iPath) + RDebug::Printf("iPath=%S", iPath); + RDebug::Printf("SID %08x Caps %08x %08x", iSecureId, iPlatSecCaps[1], iPlatSecCaps[0]); + const TUint32* uid = (const TUint32*)&iRequestedUids; + RDebug::Printf("REQ UIDs %08x %08x %08x REQ VER %08x", uid[0], uid[1], uid[2], iRequestedVersion); + iFileNameInfo.Dump(); + } + +void TFileNameInfo::Dump() const + { + const TDesC8& d = Drive(); + const TDesC8& p = Path(); + const TDesC8& b = Base(); + const TDesC8& v = VerStr(); + const TDesC8& u = UidStr(); + const TDesC8& e = Ext(); + RDebug::Printf("D=%S P=%S B=%S V=%S U=%S E=%S", &d, &p, &b, &v, &u, &e); + } +#endif + +#ifdef __TRACE_LOADER_HEAP__ + +class RTraceHeap : public RAllocator + { +public: + virtual TAny* Alloc(TInt aSize); + virtual void Free(TAny* aPtr); + virtual TAny* ReAlloc(TAny* aPtr, TInt aSize, TInt aMode=0); + virtual TInt AllocLen(const TAny* aCell) const; + virtual TInt Compress(); + virtual void Reset(); + virtual TInt AllocSize(TInt& aTotalAllocSize) const; + virtual TInt Available(TInt& aBiggestBlock) const; + virtual TInt DebugFunction(TInt aFunc, TAny* a1=NULL, TAny* a2=NULL); +public: + RAllocator* iA; + }; + +void InstallHeapTracer() + { + RTraceHeap* p = new RTraceHeap; + __ASSERT_ALWAYS(p!=NULL, User::Invariant()); + p->iA = &User::Heap(); + User::SwitchHeap(p); + } + +TAny* RTraceHeap::Alloc(TInt aSize) + { + RDebug::Printf("TH:Alloc(%08x)", aSize); + TAny* p = iA->Alloc(aSize); + RDebug::Printf("TH:returns %08x", p); + return p; + } + +void RTraceHeap::Free(TAny* aPtr) + { + RDebug::Printf("TH:Free(%08x)", aPtr); + iA->Free(aPtr); + } + +TAny* RTraceHeap::ReAlloc(TAny* aPtr, TInt aSize, TInt aMode=0) + { + RDebug::Printf("TH:ReAlloc(%08x,%08x,%x)", aPtr, aSize, aMode); + TAny* p = iA->ReAlloc(aPtr,aSize,aMode); + RDebug::Printf("TH:returns %08x", p); + return p; + } + +TInt RTraceHeap::AllocLen(const TAny* aCell) const + { + RDebug::Printf("TH:AllocLen(%08x)", aCell); + TInt l = iA->AllocLen(aCell); + RDebug::Printf("TH:returns %08x", l); + return l; + } + +TInt RTraceHeap::Compress() + { + RDebug::Printf("TH:Compress()"); + TInt l = iA->Compress(); + RDebug::Printf("TH:returns %08x", l); + return l; + } + +void RTraceHeap::Reset() + { + RDebug::Printf("TH:Reset()"); + iA->Reset(); + } + +TInt RTraceHeap::AllocSize(TInt& aTotalAllocSize) const + { + RDebug::Printf("TH:AllocSize()"); + TInt s; + TInt r = iA->AllocSize(s); + RDebug::Printf("TH:returns %08x(%08x)", r, s); + aTotalAllocSize = s; + return r; + } + +TInt RTraceHeap::Available(TInt& aBiggestBlock) const + { + RDebug::Printf("TH:Available()"); + TInt s; + TInt r = iA->Available(s); + RDebug::Printf("TH:returns %08x(%08x)", r, s); + aBiggestBlock = s; + return r; + } + +TInt RTraceHeap::DebugFunction(TInt aFunc, TAny* a1=NULL, TAny* a2=NULL) + { + RDebug::Printf("TH:DebugFunction(%d,%08x,%08x)", aFunc, a1, a2); + TInt r = iA->DebugFunction(aFunc, a1, a2); + RDebug::Printf("TH:returns %08x", r); + return r; + } + +#endif + +/* The Reaper - Used to delete binarys in /sys/del/ after they are no longer needed by demand paging */ + +CActiveReaper::CActiveReaper() + : CActive(KPriorityVeryHigh) + { + iLoaderDeletedList=NULL; + } + +CActiveReaper* CActiveReaper::New() + { + CActiveReaper *self = new CActiveReaper(); + if (self!=NULL) + self->Construct(); + return self; + } + +void CActiveReaper::Construct() + { + iStatus=KRequestPending; + CActiveScheduler::Add(this); + E32Loader::NotifyIfCodeSegDestroyed(iStatus); + SetActive(); + } + +/* +Initialises the \sys\del\ directory, where files can be moved too, on deletion. +If the directory exists, then it is emptied. +*/ + +void CActiveReaper::InitDelDir() + { + TDriveList driveList; + TDriveInfo driveInfo; + CDir* dir=NULL; + TFileName fileName; + TInt i; + TBuf drivePath(KPathDel); + TInt r = gTheLoaderFs.DriveList(driveList); + if (r!=KErrNone) + return; + TChar ch; + for (TInt drvNum=0; drvNumCount()-1;i>=0;i--) + { + fileName = drivePath; + fileName.Append((*dir)[i].iName); + r = gTheLoaderFs.SetAtt(fileName,0,KEntryAttReadOnly|KEntryAttSystem); + r = gTheLoaderFs.Delete(fileName); + } + delete dir; + } + } + } + } + + +void CActiveReaper::RunL() + { + + TCodeSegLoaderCookie cookie; + TInt r; + + TLoaderDeletedList* link; + TLoaderDeletedList* prev; + + iStatus=KRequestPending; + E32Loader::NotifyIfCodeSegDestroyed(iStatus); + SetActive(); + FOREVER + { + r=E32Loader::GetDestroyedCodeSegInfo(cookie); + if (r!=KErrNone) + break; + r = cookie.iFileClamp.Close(gTheLoaderFs); + // See if its on our list. + if (r==KErrNone) + { + link = iLoaderDeletedList; + prev= (TLoaderDeletedList*) &iLoaderDeletedList; + + while (link!=NULL) + { + if ((link->iStartBlock==cookie.iStartAddress) && (link->iDriveNumber==cookie.iDriveNumber)) + { + gTheLoaderFs.Delete(*link->iFileName); + // Ignore error from file delete operation. If it does fail then the + // file will just have to sit around until it is cleaned up on the next reboot. + + // Remove from our list. + prev->iNext=link->iNext; + delete link; + link = prev->iNext; + } + else + { + prev = link; + link = link->iNext; + } + }// while + } // if unclamp ok + } //Forever + } + +void CActiveReaper::DoCancel(){}; + +CActiveReaper::~CActiveReaper() {} + +void CActiveReaper::AddDeleted(TLoaderDeletedList* aLink) + { + aLink->iNext=iLoaderDeletedList; + iLoaderDeletedList = aLink; + } + +/* Slotted allocator - used to store iFileData from hashchecked images */ + +TInt CSlottedChunkAllocator::Construct() + { + TInt r = iChunk.CreateDisconnectedLocal(0, 0, KSlotSize * KSlots); + if (r == KErrNone) + iBase = iChunk.Base(); + return r; + } + +TAny* CSlottedChunkAllocator::Alloc(TUint aSize) + { + if (aSize == 0 || aSize > KSlotSize) + return NULL; + + for (TInt i=0; i= 0 && slot < KSlots, Fault(ELdrFileDataAllocError)); +#ifdef _DEBUG + TInt r = +#endif + iChunk.Decommit(offset, iUsed[slot]); + __ASSERT_DEBUG(r==KErrNone, Fault(ELdrFileDataAllocError)); + iUsed[slot] = 0; + }