text:
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

/*============================================================
**
** Header:  AssemblyNative.cpp
**
** Purpose: Implements AssemblyNative (loader domain) architecture
**
**

**
===========================================================*/

#include "common.h"

#include <shlwapi.h>
#include <stdlib.h>
#ifdef FEATURE_FUSION
#include "actasm.h"
#include "appctx.h"
#include "asm.h"
#endif
#include "assemblynative.hpp"
#include "dllimport.h"
#include "field.h"
#include "assemblyname.hpp"
#include "eeconfig.h"
#include "security.h"
#include "strongname.h"
#include "interoputil.h"
#include "frames.h"
#include "typeparse.h"
#ifdef FEATURE_REMOTING
#include "appdomainhelper.h"
#endif
#include "stackprobe.h"
#ifdef FEATURE_FUSION
#include "dbglog.h"
#include "bindinglog.hpp"
#include "policy.h"
#endif

#ifdef FEATURE_CORECLR
#include "appdomainnative.hpp"
#include "../binder/inc/clrprivbindercoreclr.h"
#endif // FEATURE_CORECLR

#ifndef FEATURE_CORECLR
#include "assemblynativeresource.h"
#endif // !FEATURE_CORECLR

#if !defined(FEATURE_CORECLR)
#include "clrprivbinderloadfile.h"
#endif

#ifdef FEATURE_FUSION
//----------------------------------------------------------------------------------------------------
// Allows managed code in mscorlib to find out whether an assembly name corresponds to mscorlib,
// a .NET Framework assembly found in the unification list (see fxretarget.h), or a portable assembly (see portabilityPolicy.cpp)
// See Fusion::Util::IsAnyFrameworkAssembly for more details.
// The NGEN task uses this function (via System.Reflection.RuntimeAssembly.IsFrameworkAssembly)
FCIMPL1(FC_BOOL_RET, AssemblyNative::IsFrameworkAssembly, AssemblyNameBaseObject* refAssemblyNameUNSAFE)
{
    FCALL_CONTRACT;

    struct _gc
    {
        ASSEMBLYNAMEREF assemblyName;
    } gc;
    gc.assemblyName = (ASSEMBLYNAMEREF) refAssemblyNameUNSAFE;

    BOOL bIsFxAssembly = FALSE;

    HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
    AssemblySpec spec;

    Thread *pThread = GetThread();
    CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease

    spec.InitializeSpec(&(pThread->m_MarshalAlloc),
                        &gc.assemblyName,
                        FALSE, /*fIsStringized*/
                        FALSE /*fForIntrospection*/
                       );
    ReleaseHolder<IAssemblyName> pIAssemblyName;
    IfFailThrow(spec.CreateFusionName(&pIAssemblyName,FALSE));

    bIsFxAssembly = (IfFailThrow(Fusion::Util::IsAnyFrameworkAssembly(pIAssemblyName)) == S_OK);
    HELPER_METHOD_FRAME_END();

    FC_RETURN_BOOL(bIsFxAssembly);
}
FCIMPLEND
#endif // FEATURE_FUSION

#ifdef FEATURE_FUSION
//----------------------------------------------------------------------------------------------------
FCIMPL1(FC_BOOL_RET, AssemblyNative::IsNewPortableAssembly, AssemblyNameBaseObject* refAssemblyNameUNSAFE)
{
    FCALL_CONTRACT;

    struct _gc
    {
        ASSEMBLYNAMEREF assemblyName;
    } gc;
    gc.assemblyName = (ASSEMBLYNAMEREF) refAssemblyNameUNSAFE;

    BOOL fIsPortable = FALSE;

    HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);

    AssemblySpec spec;

    Thread *pThread = GetThread();
    CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease

    {
        GCX_COOP();
        spec.InitializeSpec(&(pThread->m_MarshalAlloc),
                            &gc.assemblyName,
                            FALSE, /*fIsStringized*/
                            FALSE /*fForIntrospection*/);
    }

    ReleaseHolder<IAssemblyName> pIAssemblyName;
    IfFailThrow(spec.CreateFusionName(&pIAssemblyName,FALSE));

    fIsPortable = (IfFailThrow(Fusion::Util::IsNewPortableAssembly(pIAssemblyName)) == S_OK);
    HELPER_METHOD_FRAME_END();

    FC_RETURN_BOOL(fIsPortable);
}
FCIMPLEND
#endif // FEATURE_FUSION

FCIMPL10(Object*, AssemblyNative::Load, AssemblyNameBaseObject* assemblyNameUNSAFE,
        StringObject* codeBaseUNSAFE,
        Object* securityUNSAFE,
        AssemblyBaseObject* requestingAssemblyUNSAFE,
        StackCrawlMark* stackMark,
        ICLRPrivBinder * pPrivHostBinder,
        CLR_BOOL fThrowOnFileNotFound,
        CLR_BOOL fForIntrospection,
        CLR_BOOL fSuppressSecurityChecks,
        INT_PTR ptrLoadContextBinder)
{
    FCALL_CONTRACT;

    struct _gc
    {
        ASSEMBLYNAMEREF assemblyName;
        STRINGREF       codeBase;
        ASSEMBLYREF     requestingAssembly;
        OBJECTREF       security;
        ASSEMBLYREF     rv;
    } gc;

    gc.assemblyName    = (ASSEMBLYNAMEREF) assemblyNameUNSAFE;
    gc.codeBase        = (STRINGREF)       codeBaseUNSAFE;
    gc.requestingAssembly    = (ASSEMBLYREF)     requestingAssemblyUNSAFE;
    gc.security        = (OBJECTREF)       securityUNSAFE;
    gc.rv              = NULL;

    HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);

    if (gc.assemblyName == NULL)
        COMPlusThrow(kArgumentNullException, W("ArgumentNull_AssemblyName"));

    if (fForIntrospection)
    {
        if (!GetThread()->GetDomain()->IsVerificationDomain())
            GetThread()->GetDomain()->SetIllegalVerificationDomain();
    }

    Thread * pThread = GetThread();
    CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease

    DomainAssembly * pParentAssembly = NULL;
    Assembly * pRefAssembly = NULL;

    if(gc.assemblyName->GetSimpleName() == NULL)
    {
        if (gc.codeBase == NULL)
            COMPlusThrow(kArgumentException, W("Format_StringZeroLength"));
        if ((!fForIntrospection) && CorHost2::IsLoadFromBlocked())
            COMPlusThrow(kFileLoadException, FUSION_E_LOADFROM_BLOCKED);
    }
    else if (!fForIntrospection)
    {
        // name specified, if immersive ignore the codebase
        if (GetThread()->GetDomain()->HasLoadContextHostBinder())
            gc.codeBase = NULL;

        // Compute parent assembly
        if (gc.requestingAssembly == NULL)
        {
            pRefAssembly = SystemDomain::GetCallersAssembly(stackMark);

            // Cross-appdomain callers aren't allowed as the parent
            if (pRefAssembly &&
                (pRefAssembly->GetDomain() != pThread->GetDomain()))
            {
                pRefAssembly = NULL;
            }
        }
        else
            pRefAssembly = gc.requestingAssembly->GetAssembly();

        // Shared or collectible assemblies should not be used for the parent in the
        // late-bound case.
        if (pRefAssembly && (!pRefAssembly->IsDomainNeutral()) && (!pRefAssembly->IsCollectible()))
        {
            pParentAssembly= pRefAssembly->GetDomainAssembly();
        }

    }

    // Initialize spec
    AssemblySpec spec;
    spec.InitializeSpec(&(pThread->m_MarshalAlloc),
                        &gc.assemblyName,
                        FALSE,
                        fForIntrospection);

    if (!spec.HasUniqueIdentity())
    {   // Insuficient assembly name for binding (e.g. ContentType=WindowsRuntime cannot bind by assembly name)
        EEFileLoadException::Throw(&spec, COR_E_NOTSUPPORTED);
    }

    if (pPrivHostBinder != NULL)
    {
        pParentAssembly = NULL;
        spec.SetHostBinder(pPrivHostBinder);
    }

    if (gc.codeBase != NULL)
        spec.SetCodeBase(&(pThread->m_MarshalAlloc), &gc.codeBase);

    if (pParentAssembly != NULL)
        spec.SetParentAssembly(pParentAssembly);

#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
    // Have we been passed the reference to the binder against which this load should be triggered?
    // If so, then use it to set the fallback load context binder.
    if (ptrLoadContextBinder != NULL)
    {
        spec.SetFallbackLoadContextBinderForRequestingAssembly(reinterpret_cast<ICLRPrivBinder *>(ptrLoadContextBinder));
        spec.SetPreferFallbackLoadContextBinder();
    }
    else if (pRefAssembly != NULL)
    {
        // If the requesting assembly has Fallback LoadContext binder available,
        // then set it up in the AssemblySpec.
        PEFile *pRefAssemblyManifestFile = pRefAssembly->GetManifestFile();
        spec.SetFallbackLoadContextBinderForRequestingAssembly(pRefAssemblyManifestFile->GetFallbackLoadContextBinder());
    }
#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER)

    AssemblyLoadSecurity loadSecurity;
    loadSecurity.m_pAdditionalEvidence = &gc.security;
    loadSecurity.m_fCheckLoadFromRemoteSource = !!(gc.codeBase != NULL);
    loadSecurity.m_fSuppressSecurityChecks = !!fSuppressSecurityChecks;

    // If we're in an APPX domain, then all loads from the application will find themselves within the APPX package
    // graph or from a trusted location.   However, assemblies within the package may have been marked by Windows as
    // not being from the MyComputer zone, which can trip the LoadFromRemoteSources check.  Since we do not need to
    // defend against accidental loads from HTTP for APPX applications, we simply suppress the remote load check.
    if (AppX::IsAppXProcess())
    {
        loadSecurity.m_fCheckLoadFromRemoteSource = false;
    }

    Assembly *pAssembly;

    {
        GCX_PREEMP();
        pAssembly = spec.LoadAssembly(FILE_LOADED, &loadSecurity, fThrowOnFileNotFound, FALSE /*fRaisePrebindEvents*/, stackMark);
    }

    if (pAssembly != NULL)
        gc.rv = (ASSEMBLYREF) pAssembly->GetExposedObject();

    HELPER_METHOD_FRAME_END();

    return OBJECTREFToObject(gc.rv);
}
FCIMPLEND

Assembly* AssemblyNative::LoadFromBuffer(BOOL fForIntrospection, const BYTE* pAssemblyData,  UINT64 uAssemblyLength, const BYTE* pPDBData,  UINT64 uPDBLength, StackCrawlMark* stackMark, Object * securityUNSAFE, SecurityContextSource securityContextSource)
{
    CONTRACTL
    {
        GC_TRIGGERS;
        THROWS;
        MODE_ANY;
    }
    CONTRACTL_END;

    Assembly *pAssembly;

    struct _gc {
        OBJECTREF orefSecurity;
        OBJECTREF granted;
        OBJECTREF denied;
    } gc;

    ZeroMemory(&gc, sizeof(gc));

    GCPROTECT_BEGIN(gc);

    gc.orefSecurity = (OBJECTREF) securityUNSAFE;

    if((!fForIntrospection) && CorHost2::IsLoadFromBlocked())
        COMPlusThrow(kFileLoadException, FUSION_E_LOADFROM_BLOCKED);

    if (pAssemblyData == NULL)
        COMPlusThrow(kArgumentNullException, W("ArgumentNull_Array"));

#ifndef FEATURE_CORECLR
    // Event Tracing for Windows is used to log data for performance and functional testing purposes.
    // The events in this function are used to help measure the performance of assembly loading as a whole when loading from a buffer.
     FireEtwLoaderPhaseStart(GetAppDomain() ? GetAppDomain()->GetId().m_dwId : ETWAppDomainIdNotAvailable, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderDynamicLoad, NULL, NULL, GetClrInstanceId());
#endif // FEATURE_CORECLR

    if (fForIntrospection) {
        if (!GetThread()->GetDomain()->IsVerificationDomain())
            GetThread()->GetDomain()->SetIllegalVerificationDomain();
    }

    // Get caller's assembly so we can extract their codebase and propagate it
    // into the new assembly (which obviously doesn't have one of its own).

    AppDomain *pCallersDomain = NULL;
    MethodDesc* pCallerMD = SystemDomain::GetCallersMethod (stackMark, &pCallersDomain);
    Assembly *pCallersAssembly = (pCallerMD ? pCallerMD->GetAssembly() : NULL);
    BOOL fPropagateIdentity = ((!fForIntrospection) && (gc.orefSecurity == NULL));

    // Callers assembly can be null if caller is interop
    // @todo: we really don't want to call this assembly "mscorlib" to anyone who asks
    // for its code base.  But the required effect here is that it recieves full trust
    // as far as its codebase goes so this should be OK.  We really need to allow a
    // "no code base" condition to avoid confusion
    if (pCallersAssembly == NULL) {
        pCallersAssembly = SystemDomain::System()->SystemAssembly();
    } else {
#ifdef FEATURE_CAS_POLICY
        // If no evidence was provided to the Assembly.Load(byte[]) call,
        // we want to inherit the evidence from the security context source
        if (fPropagateIdentity) {
            ISecurityDescriptor *pSecDesc = NULL;
            if (securityContextSource == kCurrentAppDomain) {
                pSecDesc = pCallersDomain->GetSecurityDescriptor();
            }
            else {
                _ASSERTE(securityContextSource == kCurrentAssembly);
                pSecDesc = pCallersAssembly->GetSecurityDescriptor(pCallersDomain);
            }

            ENTER_DOMAIN_PTR(pSecDesc->GetDomain(),ADV_RUNNINGIN)
            {
                gc.orefSecurity = pSecDesc->GetEvidence();
            }
            END_DOMAIN_TRANSITION;

            // Caller may be in another appdomain context, in which case we'll
            // need to marshal/unmarshal the evidence across.
#ifdef FEATURE_REMOTING   // should not happenwithout remoting
            if (pCallersDomain != GetAppDomain())
                gc.orefSecurity = AppDomainHelper::CrossContextCopyFrom(pCallersDomain->GetId(), &gc.orefSecurity);
#else
            _ASSERTE(pCallersDomain == GetAppDomain());
#endif
        }
#endif // FEATURE_CAS_POLICY
    }

    if ((COUNT_T)uAssemblyLength !=uAssemblyLength)  // overflow
        ThrowOutOfMemory();

    PEAssemblyHolder pFile;

    {
        GCX_PREEMP();

        CLRPrivBinderLoadFile* pBinderToUse = NULL;

#if !defined(FEATURE_CORECLR)
        if (GetAppDomain()->HasLoadContextHostBinder())
        {
            pBinderToUse = CLRPrivBinderLoadFile::GetOrCreateBinder();
        }
#endif // !FEATURE_CORECLR

        pFile = PEAssembly::OpenMemory(pCallersAssembly->GetManifestFile(),
                                                  pAssemblyData, (COUNT_T)uAssemblyLength,
                                                  fForIntrospection,
                                                  pBinderToUse);
    }

    fPropagateIdentity = (fPropagateIdentity && pCallersDomain && pCallersAssembly);

    AssemblyLoadSecurity loadSecurity;
    loadSecurity.m_pEvidence = &gc.orefSecurity;
    if (fPropagateIdentity)
    {
        DWORD dwSpecialFlags = 0;

#ifdef FEATURE_CAS_POLICY
        if (securityContextSource == kCurrentAssembly)
        {
            IAssemblySecurityDescriptor *pCallersSecDesc = pCallersAssembly->GetSecurityDescriptor(pCallersDomain);
            gc.granted = pCallersSecDesc->GetGrantedPermissionSet( &(gc.denied));
            dwSpecialFlags = pCallersSecDesc->GetSpecialFlags();

            // If we're going to inherit the grant set of an anonymously hosted dynamic method, it will be
            // full trust/transparent. In that case, we should demand full trust.
            if(pCallersAssembly != NULL && pCallersDomain != NULL && pCallersAssembly->GetDomainAssembly(pCallersDomain) == pCallersDomain->GetAnonymouslyHostedDynamicMethodsAssembly())
            {
                loadSecurity.m_fPropagatingAnonymouslyHostedDynamicMethodGrant = true;
            }
        }
        else
#endif // FEATURE_CAS_POLICY
        {
            IApplicationSecurityDescriptor *pDomainSecDesc = pCallersDomain->GetSecurityDescriptor();

#ifdef FEATURE_CAS_POLICY
            // We only want to propigate the identity of homogenous domains, since heterogenous domains tend
            // to be fully trusted even if they are housing partially trusted code - which could lead to an
            // elevation of privilege if we allow the grant set to be pushed to assemblies partially trusted
            // code is loading.
            if (!pDomainSecDesc->IsHomogeneous())
            {
                COMPlusThrow(kNotSupportedException, W("NotSupported_SecurityContextSourceAppDomainInHeterogenous"));
            }
#endif // FEATURE_CAS_POLICY

            gc.granted = pDomainSecDesc->GetGrantedPermissionSet();
            dwSpecialFlags = pDomainSecDesc->GetSpecialFlags();
        }

#ifdef FEATURE_REMOTING
        // Caller may be in another appdomain context, in which case we'll need to marshal/unmarshal the grant
        // and deny sets across.
        if (pCallersDomain != GetAppDomain())
        {
            gc.granted = AppDomainHelper::CrossContextCopyFrom(pCallersDomain->GetId(), &(gc.granted));
            if (gc.denied != NULL)
            {
                gc.denied = AppDomainHelper::CrossContextCopyFrom(pCallersDomain->GetId(), &(gc.denied));
            }
        }
#endif // FEATURE_REMOTING

        // Instead of resolving policy, the loader should use an inherited grant set
        loadSecurity.m_pGrantSet = &gc.granted;
        loadSecurity.m_pRefusedSet = &gc.denied;
        loadSecurity.m_dwSpecialFlags = dwSpecialFlags;

        // if the caller is from another appdomain we wil not be able to get the ssembly's security descriptor
        // but that is ok, since getting a pointer to our AppDomain required full trust
        if (!pCallersDomain->GetSecurityDescriptor()->IsFullyTrusted() ||
            ( pCallersAssembly->FindDomainAssembly(::GetAppDomain()) != NULL && !pCallersAssembly->GetSecurityDescriptor()->IsFullyTrusted())   )
            pFile->VerifyStrongName();
    }
    pAssembly = GetPostPolicyAssembly(pFile, fForIntrospection, &loadSecurity, TRUE);

    // perform necessary Transparency checks for this Load(byte[]) call (based on the calling method).
    if (pCallerMD)
    {
        Security::PerformTransparencyChecksForLoadByteArray(pCallerMD, pAssembly->GetSecurityDescriptor());
    }

    // In order to assign the PDB image (if present),
    // the resulting assembly's image needs to be exactly the one
    // we created above. We need pointer comparison instead of pe image equivalence
    // to avoid mixed binaries/PDB pairs of other images.
    // This applies to both Desktop CLR and CoreCLR, with or without fusion.
    BOOL fIsSameAssembly = (pAssembly->GetManifestFile()->GetILimage() == pFile->GetILimage());

#ifdef FEATURE_REFLECTION_ONLY_LOAD
    if (fForIntrospection)
    {
        IAssemblyName * pIAssemblyName = pAssembly->GetFusionAssemblyName();

        AppDomain::AssemblyIterator i = GetAppDomain()->IterateAssembliesEx(
            (AssemblyIterationFlags)(kIncludeLoaded | kIncludeIntrospection));
        CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;

        while (i.Next(pDomainAssembly.This()))
        {
            Assembly * pCachedAssembly = pDomainAssembly->GetAssembly();
            IAssemblyName * pCachedAssemblyName = pCachedAssembly->GetFusionAssemblyName();
            if ((pAssembly != pCachedAssembly) && (S_OK == pCachedAssemblyName->IsEqual(pIAssemblyName, ASM_CMPF_IL_ALL)))
            {
                COMPlusThrow(kFileLoadException, IDS_EE_REFLECTIONONLY_LOADFROM, W("")); //@todo: need to fill in assemblyname
            }
        }
    }
#endif // FEATURE_REFLECTION_ONLY_LOAD

#ifndef FEATURE_CORECLR
    FireEtwLoaderPhaseEnd(GetAppDomain() ? GetAppDomain()->GetId().m_dwId : ETWAppDomainIdNotAvailable, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderDynamicLoad, NULL, NULL, GetClrInstanceId());
#endif // FEATURE_CORECLR
    LOG((LF_CLASSLOADER,
         LL_INFO100,
         "\tLoaded in-memory module\n"));

    // Setting the PDB info is only applicable for our original assembly.
    // This applies to both Desktop CLR and CoreCLR, with or without fusion.
    if (fIsSameAssembly)
    {
#ifdef DEBUGGING_SUPPORTED
        // If we were given symbols, save a copy of them.
                // the debugger, load them now).
        if (pPDBData != NULL)
        {
            GCX_PREEMP();
            if ((DWORD)uPDBLength != uPDBLength) // overflow
                ThrowOutOfMemory();
            pAssembly->GetManifestModule()->SetSymbolBytes(pPDBData, (DWORD)uPDBLength);
        }
#endif // DEBUGGING_SUPPORTED
    }

    GCPROTECT_END();

    return pAssembly;
}

FCIMPL6(Object*, AssemblyNative::LoadImage, U1Array* PEByteArrayUNSAFE,
        U1Array* SymByteArrayUNSAFE, Object* securityUNSAFE,
        StackCrawlMark* stackMark, CLR_BOOL fForIntrospection, SecurityContextSource securityContextSource)
{
    FCALL_CONTRACT;

    struct _gc
    {
        U1ARRAYREF PEByteArray;
        U1ARRAYREF SymByteArray;
        OBJECTREF  security;
        OBJECTREF Throwable;
        OBJECTREF refRetVal;
    } gc;

    gc.PEByteArray  = (U1ARRAYREF) PEByteArrayUNSAFE;
    gc.SymByteArray = (U1ARRAYREF) SymByteArrayUNSAFE;
    gc.security     = (OBJECTREF)  securityUNSAFE;
    gc.Throwable = NULL;
    gc.refRetVal = NULL;

    HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);

    if (gc.PEByteArray == NULL)
        COMPlusThrow(kArgumentNullException, W("ArgumentNull_Array"));

    NewArrayHolder<BYTE> pbSyms;
    DWORD cbSyms = 0;

#ifdef DEBUGGING_SUPPORTED
    // If we were given symbols, save a copy of them.
            // the debugger, load them now).
    if (gc.SymByteArray != NULL)
    {
        Security::CopyByteArrayToEncoding(&gc.SymByteArray,
                                                    &pbSyms, &cbSyms);

    }
#endif // DEBUGGING_SUPPORTED

    Assembly* pAssembly = NULL;
    // Pin byte array for loading
    {
        Wrapper<OBJECTHANDLE, DoNothing, DestroyPinningHandle> handle(
            GetAppDomain()->CreatePinningHandle(gc.PEByteArray));

        const BYTE *pbImage = gc.PEByteArray->GetDirectConstPointerToNonObjectElements();
        DWORD cbImage = gc.PEByteArray->GetNumComponents();
        pAssembly = LoadFromBuffer(fForIntrospection, pbImage, cbImage, pbSyms, cbSyms, stackMark, OBJECTREFToObject(gc.security), securityContextSource);
    }

#ifdef FEATURE_FUSION
    if (!fForIntrospection && IsLoggingNeeded())
    {
        BinderLogging::BindingLog::LogLoadByteArray(GetAppDomain()->GetFusionContext(), pAssembly);
    }
#endif

    if (pAssembly != NULL)
        gc.refRetVal = pAssembly->GetExposedObject();

    HELPER_METHOD_FRAME_END();

    return OBJECTREFToObject(gc.refRetVal);
}
FCIMPLEND

FCIMPL2(Object*, AssemblyNative::LoadFile, StringObject* pathUNSAFE, Object* securityUNSAFE)
{
    FCALL_CONTRACT;

    struct _gc {
        OBJECTREF refRetVal;
        OBJECTREF refSecurity;
        STRINGREF strPath;
    } gc;

    gc.refRetVal = NULL;
    gc.refSecurity = ObjectToOBJECTREF(securityUNSAFE);
    gc.strPath = ObjectToSTRINGREF(pathUNSAFE);

    HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);

    if(CorHost2::IsLoadFromBlocked())
        COMPlusThrow(kFileLoadException, FUSION_E_LOADFROM_BLOCKED);

    if (pathUNSAFE == NULL)
        COMPlusThrow(kArgumentNullException, W("ArgumentNull_Path"));

    StackSString path;
    gc.strPath->GetSString(path);

#ifdef FEATURE_FUSION // use BindResult for abstraction
    // Event Tracing for Windows is used to log data for performance and functional testing purposes.
    // The events in this function are used to help measure the performance of assembly loading as a whole when loading directly from a file,
    // of binding to an assembly, as well as of lookup scenarios such as from a host store.
    FireEtwLoaderPhaseStart(ETWAppDomainIdNotAvailable, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderDynamicLoad, path, NULL, GetClrInstanceId());
    SafeComHolder<IAssembly> pFusionAssembly;
    SafeComHolder<IBindResult> pNativeFusionAssembly;
    SafeComHolder<IFusionBindLog> pFusionLog;

    PEAssemblyHolder pFile;
    FireEtwBindingPhaseStart(GetAppDomain() ? GetAppDomain()->GetId().m_dwId : ETWAppDomainIdNotAvailable, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderLoadTypeNotAvailable, path, NULL, GetClrInstanceId());

    if(GetAppDomain()->HasLoadContextHostBinder())
    {
        GCX_PREEMP();
        CLRPrivBinderLoadFile* pLFBinder =  CLRPrivBinderLoadFile::GetOrCreateBinder();
        ReleaseHolder<PEImage> pImage(PEImage::OpenImage(path));
        ReleaseHolder<ICLRPrivAssembly> pAsm;
        ReleaseHolder<IAssemblyName> pAssemblyName;
        IfFailThrow(pLFBinder->BindAssemblyExplicit(pImage, &pAssemblyName, &pAsm));
        IfFailThrow(GetAppDomain()->BindHostedPrivAssembly(nullptr, pAsm, pAssemblyName, &pFile));
        _ASSERTE(pFile);
    }
    else
    {
        GCX_PREEMP();
        IfFailThrow(ExplicitBind(path, GetAppDomain()->GetFusionContext(),
                                 EXPLICITBIND_FLAGS_NON_BINDABLE,
                                 NULL, &pFusionAssembly, &pNativeFusionAssembly, &pFusionLog));
        pFile.Assign(PEAssembly::Open(pFusionAssembly, pNativeFusionAssembly, pFusionLog, FALSE, FALSE));
    }

    FireEtwBindingLookupAndProbingPhaseEnd(GetAppDomain() ? GetAppDomain()->GetId().m_dwId : ETWAppDomainIdNotAvailable, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderLoadTypeNotAvailable, path, NULL, GetClrInstanceId());

    FireEtwBindingPhaseEnd(GetAppDomain() ? GetAppDomain()->GetId().m_dwId : ETWAppDomainIdNotAvailable, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderLoadTypeNotAvailable, path, NULL, GetClrInstanceId());

    AssemblyLoadSecurity loadSecurity;
    loadSecurity.m_pAdditionalEvidence = &gc.refSecurity;
    loadSecurity.m_fCheckLoadFromRemoteSource = true;

    // If we're in an APPX domain, then all loads from the application will find themselves within the APPX package
    // graph or from a trusted location.   However, assemblies within the package may have been marked by Windows as
    // not being from the MyComputer zone, which can trip the LoadFromRemoteSources check.  Since we do not need to
    // defend against accidental loads from HTTP for APPX applications, we simply suppress the remote load check.
    if (AppX::IsAppXProcess())
    {
        loadSecurity.m_fCheckLoadFromRemoteSource = false;
    }

    Assembly *pAssembly = GetPostPolicyAssembly(pFile, FALSE, &loadSecurity);

    FireEtwLoaderPhaseEnd(ETWAppDomainIdNotAvailable, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderDynamicLoad, path, NULL, GetClrInstanceId());

    if (IsLoggingNeeded())
    {
        BinderLogging::BindingLog::LogLoadFile(GetAppDomain()->GetFusionContext(), path, pAssembly);
    }

#else // FEATURE_FUSION
    Assembly *pAssembly = AssemblySpec::LoadAssembly(path);
#endif // FEATURE_FUSION

    LOG((LF_CLASSLOADER,
         LL_INFO100,
         "\tLoaded assembly from a file\n"));

    if (pAssembly != NULL)
        gc.refRetVal = (ASSEMBLYREF) pAssembly->GetExposedObject();

    HELPER_METHOD_FRAME_END();

    return OBJECTREFToObject(gc.refRetVal);
}
FCIMPLEND

#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)

/* static */
Assembly* AssemblyNative::LoadFromPEImage(ICLRPrivBinder* pBinderContext, PEImage *pILImage, PEImage *pNIImage)
{
    CONTRACT(Assembly*)
    {
        STANDARD_VM_CHECK;
        PRECONDITION(CheckPointer(pBinderContext));
        POSTCONDITION(CheckPointer(RETVAL));
    }
    CONTRACT_END;

    Assembly *pLoadedAssembly = NULL;

    ReleaseHolder<ICLRPrivAssembly> pAssembly;

    // Get the correct PEImage to work with.
    BOOL fIsNativeImage = TRUE;
    PEImage *pImage = pNIImage;
    if (pNIImage == NULL)
    {
        // Since we do not have a NI image, we are working with IL assembly
        pImage = pILImage;
        fIsNativeImage = FALSE;
    }
    _ASSERTE(pImage != NULL);

    BOOL fHadLoadFailure = FALSE;

    // Force the image to be loaded and mapped so that subsequent loads do not
    // map a duplicate copy.
    if (pImage->IsFile())
    {
        pImage->Load();
    }
    else
    {
        pImage->LoadNoFile();
    }

    DWORD dwMessageID = IDS_EE_FILELOAD_ERROR_GENERIC;

    // Set the caller's assembly to be mscorlib
    DomainAssembly *pCallersAssembly = SystemDomain::System()->SystemAssembly()->GetDomainAssembly();
    PEAssembly *pParentAssembly = pCallersAssembly->GetFile();

    // Initialize the AssemblySpec
    AssemblySpec spec;
    spec.InitializeSpec(TokenFromRid(1, mdtAssembly), pImage->GetMDImport(), pCallersAssembly);
    spec.SetBindingContext(pBinderContext);

    HRESULT hr = S_OK;
    PTR_AppDomain pCurDomain = GetAppDomain();
    CLRPrivBinderCoreCLR *pTPABinder = pCurDomain->GetTPABinderContext();
    if (!AreSameBinderInstance(pTPABinder, pBinderContext))
    {
        // We are working with custom Assembly Load Context so bind the assembly using it.
        CLRPrivBinderAssemblyLoadContext *pBinder = reinterpret_cast<CLRPrivBinderAssemblyLoadContext *>(pBinderContext);
        hr = pBinder->BindUsingPEImage(pImage, fIsNativeImage, &pAssembly);
    }
    else
    {
        // Bind the assembly using TPA binder
        hr = pTPABinder->BindUsingPEImage(pImage, fIsNativeImage, &pAssembly);
    }

    if (hr != S_OK)
    {
        // Give a more specific message for the case when we found the assembly with the same name already loaded.
        if (hr == COR_E_FILELOAD)
        {
            dwMessageID = IDS_HOST_ASSEMBLY_RESOLVER_ASSEMBLY_ALREADY_LOADED_IN_CONTEXT;
        }

        StackSString name;
        spec.GetFileOrDisplayName(0, name);
        COMPlusThrowHR(COR_E_FILELOAD, dwMessageID, name);
    }

    PEAssemblyHolder pPEAssembly(PEAssembly::Open(pParentAssembly, pILImage, pNIImage, pAssembly, FALSE));

    GCX_COOP();

    IApplicationSecurityDescriptor *pDomainSecDesc = pCurDomain->GetSecurityDescriptor();

    OBJECTREF refGrantedPermissionSet = NULL;
    AssemblyLoadSecurity loadSecurity;
    DomainAssembly *pDomainAssembly = NULL;

    // Setup the AssemblyLoadSecurity to perform the assembly load
    GCPROTECT_BEGIN(refGrantedPermissionSet);

    loadSecurity.m_dwSpecialFlags = pDomainSecDesc->GetSpecialFlags();
    refGrantedPermissionSet = pDomainSecDesc->GetGrantedPermissionSet();
    loadSecurity.m_pGrantSet = &refGrantedPermissionSet;

    pDomainAssembly = pCurDomain->LoadDomainAssembly(&spec, pPEAssembly, FILE_LOADED, &loadSecurity);
    pLoadedAssembly = pDomainAssembly->GetAssembly();

    GCPROTECT_END();

    RETURN pLoadedAssembly;
}

/* static */
void QCALLTYPE AssemblyNative::LoadFromPath(INT_PTR ptrNativeAssemblyLoadContext, LPCWSTR pwzILPath, LPCWSTR pwzNIPath, QCall::ObjectHandleOnStack retLoadedAssembly)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    PTR_AppDomain pCurDomain = GetAppDomain();

    // Get the binder context in which the assembly will be loaded.
    ICLRPrivBinder *pBinderContext = reinterpret_cast<ICLRPrivBinder*>(ptrNativeAssemblyLoadContext);
    _ASSERTE(pBinderContext != NULL);

    // Form the PEImage for the ILAssembly. Incase of an exception, the holders will ensure
    // the release of the image.
    PEImageHolder pILImage, pNIImage;

    if (pwzILPath != NULL)
    {
        pILImage = PEImage::OpenImage(pwzILPath);

        // Need to verify that this is a valid CLR assembly.
        if (!pILImage->CheckILFormat())
            ThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL);
    }

    // Form the PEImage for the NI assembly, if specified
    if (pwzNIPath != NULL)
    {
        pNIImage = PEImage::OpenImage(pwzNIPath, MDInternalImport_TrustedNativeImage);

        if (pNIImage->HasReadyToRunHeader())
        {
            // ReadyToRun images are treated as IL images by the rest of the system
            if (!pNIImage->CheckILFormat())
                ThrowHR(COR_E_BADIMAGEFORMAT);

            pILImage = pNIImage.Extract();
            pNIImage = NULL;
        }
        else
        {
            if (!pNIImage->CheckNativeFormat())
                ThrowHR(COR_E_BADIMAGEFORMAT);
        }
    }

    Assembly *pLoadedAssembly = AssemblyNative::LoadFromPEImage(pBinderContext, pILImage, pNIImage);

    {
        GCX_COOP();
        retLoadedAssembly.Set(pLoadedAssembly->GetExposedObject());
    }

    LOG((LF_CLASSLOADER,
            LL_INFO100,
            "\tLoaded assembly from a file\n"));

    END_QCALL;
}

// static
INT_PTR QCALLTYPE AssemblyNative::InternalLoadUnmanagedDllFromPath(LPCWSTR unmanagedLibraryPath)
{
    QCALL_CONTRACT;

    HMODULE moduleHandle = nullptr;

    BEGIN_QCALL;

    moduleHandle = NDirect::LoadLibraryFromPath(unmanagedLibraryPath);

    END_QCALL;

    return reinterpret_cast<INT_PTR>(moduleHandle);
}

/*static */
void QCALLTYPE AssemblyNative::LoadFromStream(INT_PTR ptrNativeAssemblyLoadContext, INT_PTR ptrAssemblyArray,
                                              INT32 cbAssemblyArrayLength, INT_PTR ptrSymbolArray, INT32 cbSymbolArrayLength,
                                              QCall::ObjectHandleOnStack retLoadedAssembly)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    // Ensure that the invariants are in place
    _ASSERTE(ptrNativeAssemblyLoadContext != NULL);
    _ASSERTE((ptrAssemblyArray != NULL) && (cbAssemblyArrayLength > 0));
    _ASSERTE((ptrSymbolArray == NULL) || (cbSymbolArrayLength > 0));

    // We must have a flat image stashed away since we need a private
    // copy of the data which we can verify before doing the mapping.
    PVOID pAssemblyArray = reinterpret_cast<PVOID>(ptrAssemblyArray);

    PEImageHolder pILImage(PEImage::LoadFlat(pAssemblyArray, (COUNT_T)cbAssemblyArrayLength));

    // Need to verify that this is a valid CLR assembly.
    if (!pILImage->CheckILFormat())
        ThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL);

    // Get the binder context in which the assembly will be loaded
    ICLRPrivBinder *pBinderContext = reinterpret_cast<ICLRPrivBinder*>(ptrNativeAssemblyLoadContext);

    // Pass the stream based assembly as IL and NI in an attempt to bind and load it
    Assembly* pLoadedAssembly = AssemblyNative::LoadFromPEImage(pBinderContext, pILImage, NULL);
    {
        GCX_COOP();
        retLoadedAssembly.Set(pLoadedAssembly->GetExposedObject());
    }

    LOG((LF_CLASSLOADER,
            LL_INFO100,
            "\tLoaded assembly from a file\n"));

    // In order to assign the PDB image (if present),
    // the resulting assembly's image needs to be exactly the one
    // we created above. We need pointer comparison instead of pe image equivalence
    // to avoid mixed binaries/PDB pairs of other images.
    // This applies to both Desktop CLR and CoreCLR, with or without fusion.
    BOOL fIsSameAssembly = (pLoadedAssembly->GetManifestFile()->GetILimage() == pILImage);

    // Setting the PDB info is only applicable for our original assembly.
    // This applies to both Desktop CLR and CoreCLR, with or without fusion.
    if (fIsSameAssembly)
    {
#ifdef DEBUGGING_SUPPORTED
        // If we were given symbols, save a copy of them.
        if (ptrSymbolArray != NULL)
        {
            PBYTE pSymbolArray = reinterpret_cast<PBYTE>(ptrSymbolArray);
            pLoadedAssembly->GetManifestModule()->SetSymbolBytes(pSymbolArray, (DWORD)cbSymbolArrayLength);
        }
#endif // DEBUGGING_SUPPORTED
    }

    END_QCALL;
}

#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER)

/* static */
Assembly* AssemblyNative::GetPostPolicyAssembly(PEAssembly *pFile,
                                                BOOL fForIntrospection,
                                                AssemblyLoadSecurity *pLoadSecurity,
                                                BOOL fIsLoadByteArray /* = FALSE */)
{
    CONTRACT(Assembly*)
    {
        MODE_ANY;
        THROWS;
        GC_TRIGGERS;
        PRECONDITION(CheckPointer(pFile));
        PRECONDITION(CheckPointer(pLoadSecurity));
        POSTCONDITION(CheckPointer(RETVAL));
    }
    CONTRACT_END;

    GCX_PREEMP();

#ifdef FEATURE_FUSION
    if (!fForIntrospection && !GetAppDomain()->HasLoadContextHostBinder()) {
        DWORD   dwSize = 0;
        // if strongly named and not an exempt
        BOOL bOptionallyRetargetable;

        IfFailThrow(IsOptionallyRetargetableAssembly(pFile->GetFusionAssemblyName(), &bOptionallyRetargetable));
        if ( !bOptionallyRetargetable && pFile->GetFusionAssemblyName()->GetProperty(ASM_NAME_PUBLIC_KEY_TOKEN, NULL, &dwSize) == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {

            SafeComHolder<IAssemblyName> pPostPolicyName(NULL);
            HRESULT hr = PreBindAssembly(GetAppDomain()->GetFusionContext(),
                                         pFile->GetFusionAssemblyName(),
                                         NULL,  // pAsmParent
                                         &pPostPolicyName,
                                         NULL); // pvReserved
            if (FAILED(hr)) {
                if (hr == FUSION_E_REF_DEF_MISMATCH) {
                    // Policy redirects to another version
                    AssemblySpec spec;
                    spec.InitializeSpec(pPostPolicyName, FALSE);
                    RETURN spec.LoadAssembly(FILE_LOADED, pLoadSecurity);
                }
                else
                    ThrowHR(hr);
            }
            else {
                ReleaseHolder<IAssembly> pAsm;

                SafeComHolder<IAssemblyCache> pIAsmCache (NULL);
                IfFailThrow(CreateAssemblyCache(&pIAsmCache, 0));

                DWORD dwFlags = ASM_DISPLAYF_FULL;

                if (pFile->IsMarkedAsNoPlatform()) { // No Platform implies that the assembly is not tied to a specific machine architecture, which means we need to do full GAC probing.
                    hr = CreateAssemblyFromCacheLookup(GetAppDomain()->GetFusionContext(), pFile->GetFusionAssemblyName(), TRUE, &pAsm, NULL);
                }
                else {
                    SString sourceDisplay;
                    FusionBind::GetAssemblyNameDisplayName(pFile->GetFusionAssemblyName(), sourceDisplay, dwFlags);
                    hr = pIAsmCache->QueryAssemblyInfo(0, sourceDisplay, NULL);
                }

                if (SUCCEEDED(hr)) {
                    // It's in the GAC
                    AssemblySpec spec;
                    spec.InitializeSpec(pFile->GetFusionAssemblyName(), FALSE);
                    RETURN spec.LoadAssembly(FILE_LOADED, pLoadSecurity);
                }
                else if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
                    ThrowHR(hr);
            }
        }
    }
#else // FEATURE_FUSION
    if (fIsLoadByteArray)
    {
        PEImage *pPEImage = pFile->GetILimage();
        HRESULT hr = S_OK;
        PTR_AppDomain pCurDomain = GetAppDomain();
        CLRPrivBinderCoreCLR *pTPABinder = pCurDomain->GetTPABinderContext();

        _ASSERTE(pCurDomain->GetFusionContext() == pTPABinder);
        hr = pTPABinder->PreBindByteArray(pPEImage, fForIntrospection);
        if (hr == S_OK)
        {
            AssemblySpec spec;
            spec.InitializeSpec(pFile);

            // Set the binder associated with the AssemblySpec
            spec.SetBindingContext(pTPABinder);
            RETURN spec.LoadAssembly(FILE_LOADED, pLoadSecurity);
        }
        else
        {
            _ASSERTE(hr != S_FALSE);
            ThrowHR(hr);
        }
    }
#endif // FEATURE_FUSION

    RETURN GetAppDomain()->LoadAssembly(NULL, pFile, FILE_LOADED, pLoadSecurity);
}

#ifdef FEATURE_MULTIMODULE_ASSEMBLIES
void QCALLTYPE AssemblyNative::LoadModule(QCall::AssemblyHandle pAssembly,
                                                         LPCWSTR wszModuleName,
                                                         LPCBYTE pRawModule, INT32 cbModule,
                                                         LPCBYTE pRawSymbolStore, INT32 cbSymbolStore,
                                                         QCall::ObjectHandleOnStack retModule)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    Module * pModule = NULL;

    if(CorHost2::IsLoadFromBlocked())
        COMPlusThrow(kFileLoadException, FUSION_E_LOADFROM_BLOCKED);

    if (wszModuleName == NULL)
        COMPlusThrow(kArgumentNullException, W("ArgumentNull_FileName"));

    if (pRawModule == NULL)
        COMPlusThrow(kArgumentNullException, W("ArgumentNull_Array"));

    if (*wszModuleName == '\0')
        COMPlusThrow(kArgumentException, W("Argument_EmptyFileName"));

    CQuickBytes qbLC;

    MAKE_UTF8PTR_FROMWIDE(pName, wszModuleName);
    LPCSTR psModuleName = pName;

    // Need to perform case insensitive lookup.
    {
        UTF8_TO_LOWER_CASE(psModuleName, qbLC);
        psModuleName = (LPUTF8) qbLC.Ptr();
    }

    HashDatum datum;
    mdFile kFile = NULL;
    // m_pAllowedFiles only grows - entries are never deleted from it. So we do not take
    // a lock around GetValue. If the code is modified such that we delete entries from m_pAllowedFiles,
    // reconsider whether we should take the m_crstAllowedFiles lock here (see the uses of kFile below).
    if (pAssembly->GetAssembly()->m_pAllowedFiles->GetValue(psModuleName, &datum))
        kFile = (mdFile)(size_t)datum;

    // If the name doesn't match one of the File def names, don't load this module.
    // If this name matches the manifest file (datum was NULL), don't load either.
    if (!kFile)
        COMPlusThrow(kArgumentException, W("Arg_InvalidFileName"));

    PEModuleHolder pFile(PEModule::OpenMemory(pAssembly->GetFile(), kFile,
                                              pRawModule, cbModule));

    DomainModule *pDomainModule = GetAppDomain()->LoadDomainModule(pAssembly->GetDomainAssembly(),
                                                                   pFile, FILE_LOADED);
    pModule = pDomainModule->GetModule();

    if (!pFile->Equals(pModule->GetFile()))
        COMPlusThrow(kArgumentException, W("Argument_ModuleAlreadyLoaded"));

    LOG((LF_CLASSLOADER,
         LL_INFO100,
         "\tLoaded in-memory module\n"));

#ifdef DEBUGGING_SUPPORTED
    if (!pModule->IsResource())
    {
        // If we were given symbols, hold onto a copy
        if (pRawSymbolStore != NULL)
        {
            pModule->SetSymbolBytes(pRawSymbolStore, cbSymbolStore);
        }
    }
#endif // DEBUGGING_SUPPORTED

    if (pModule != NULL)
    {
        GCX_COOP();
        retModule.Set(pModule->GetExposedObject());
    }

    END_QCALL;

    return;
}
#endif // FEATURE_MULTIMODULE_ASSEMBLIES

void QCALLTYPE AssemblyNative::GetLocation(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

#ifndef FEATURE_CORECLR
    // workaround - lie about where mscorlib is. Mscorlib is now loaded out of the GAC,
    // but some apps query its location to find the system directory. (Notably system.web)
    if (pAssembly->IsSystem())
    {
        retString.Set(SystemDomain::System()->BaseLibrary());
    }
    else
#endif // !FEATURE_CORECLR
    {
        retString.Set(pAssembly->GetFile()->GetPath());
    }

    END_QCALL;
}

FCIMPL1(FC_BOOL_RET, AssemblyNative::IsReflectionOnly, AssemblyBaseObject *pAssemblyUNSAFE)
{
    FCALL_CONTRACT;

    ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);

    if (refAssembly == NULL)
        FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));

    FC_RETURN_BOOL(refAssembly->GetDomainAssembly()->IsIntrospectionOnly());
}
FCIMPLEND

void QCALLTYPE AssemblyNative::GetType(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType, QCall::ObjectHandleOnStack keepAlive)
{
    CONTRACTL
    {
        QCALL_CHECK;
        PRECONDITION(CheckPointer(wszName));
    }
    CONTRACTL_END;

    TypeHandle retTypeHandle;

    BEGIN_QCALL;

    if (!wszName)
        COMPlusThrowArgumentNull(W("name"), W("ArgumentNull_String"));

    BOOL prohibitAsmQualifiedName = TRUE;

    // Load the class from this assembly (fail if it is in a different one).
    retTypeHandle = TypeName::GetTypeManaged(wszName, pAssembly, bThrowOnError, bIgnoreCase, pAssembly->IsIntrospectionOnly(), prohibitAsmQualifiedName, NULL, FALSE, (OBJECTREF*)keepAlive.m_ppObject);

    if (!retTypeHandle.IsNull())
    {
         GCX_COOP();
         retType.Set(retTypeHandle.GetManagedClassObject());
    }

    END_QCALL;

    return;
}

FCIMPL1(FC_BOOL_RET, AssemblyNative::IsDynamic, AssemblyBaseObject* pAssemblyUNSAFE)
{
    FCALL_CONTRACT;

    ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);

    if (refAssembly == NULL)
        FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));

    FC_RETURN_BOOL(refAssembly->GetDomainAssembly()->GetFile()->IsDynamic());
}
FCIMPLEND

void QCALLTYPE AssemblyNative::GetVersion(QCall::AssemblyHandle pAssembly, INT32* pMajorVersion, INT32* pMinorVersion, INT32*pBuildNumber, INT32* pRevisionNumber)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    UINT16 major=0xffff, minor=0xffff, build=0xffff, revision=0xffff;

    pAssembly->GetFile()->GetVersion(&major, &minor, &build, &revision);

    *pMajorVersion = major;
    *pMinorVersion = minor;
    *pBuildNumber = build;
    *pRevisionNumber = revision;

    END_QCALL;
}

void QCALLTYPE AssemblyNative::GetPublicKey(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retPublicKey)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    DWORD cbPublicKey = 0;
    const void *pbPublicKey = pAssembly->GetFile()->GetPublicKey(&cbPublicKey);
    retPublicKey.SetByteArray((BYTE *)pbPublicKey, cbPublicKey);

    END_QCALL;
}

#if !FEATURE_CORECLR

BYTE QCALLTYPE AssemblyNative::GetSecurityRuleSet(QCall::AssemblyHandle pAssembly)
{
    QCALL_CONTRACT;

    SecurityRuleSet ruleSet = SecurityRuleSet_Default;

    BEGIN_QCALL;

    ModuleSecurityDescriptor *pMSD = ModuleSecurityDescriptor::GetModuleSecurityDescriptor(pAssembly->GetAssembly());
    ruleSet = pMSD->GetSecurityRuleSet();

    END_QCALL;

    return static_cast<BYTE>(ruleSet);
}

#endif // !FEATURE_CORECLR

void QCALLTYPE AssemblyNative::GetSimpleName(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retSimpleName)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;
    retSimpleName.Set(pAssembly->GetSimpleName());
    END_QCALL;
}

void QCALLTYPE AssemblyNative::GetLocale(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    LPCUTF8 pLocale = pAssembly->GetFile()->GetLocale();
    if(pLocale)
    {
        retString.Set(pLocale);
    }

    END_QCALL;
}

void QCALLTYPE AssemblyNative::GetCodeBase(QCall::AssemblyHandle pAssembly, BOOL fCopiedName, QCall::StringHandleOnStack retString)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    StackSString codebase;

#ifndef FEATURE_CORECLR
    if (pAssembly->IsSystem()) {
        // workaround: lie about the location of mscorlib.  Some callers assume it is in the install dir.
        codebase.Set(SystemDomain::System()->BaseLibrary());
        PEAssembly::PathToUrl(codebase);
    }
    else
#endif // !FEATURE_CORECLR
    {
        pAssembly->GetFile()->GetCodeBase(codebase);
    }

    retString.Set(codebase);

    END_QCALL;
}

INT32 QCALLTYPE AssemblyNative::GetHashAlgorithm(QCall::AssemblyHandle pAssembly)
{
    QCALL_CONTRACT;

    INT32 retVal=0;
    BEGIN_QCALL;
    retVal = pAssembly->GetFile()->GetHashAlgId();
    END_QCALL;
    return retVal;
}

INT32 QCALLTYPE AssemblyNative::GetFlags(QCall::AssemblyHandle pAssembly)
{
    QCALL_CONTRACT;

    INT32 retVal=0;
    BEGIN_QCALL;
    retVal = pAssembly->GetFile()->GetFlags();
    END_QCALL;
    return retVal;
}

BYTE * QCALLTYPE AssemblyNative::GetResource(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, UINT64 * length, QCall::StackCrawlMarkHandle stackMark, BOOL skipSecurityCheck)
{
    QCALL_CONTRACT;

    PBYTE       pbInMemoryResource  = NULL;

    BEGIN_QCALL;

    if (wszName == NULL)
        COMPlusThrow(kArgumentNullException, W("ArgumentNull_String"));

    // Get the name in UTF8
    SString name(SString::Literal, wszName);

    StackScratchBuffer scratch;
    LPCUTF8 pNameUTF8 = name.GetUTF8(scratch);

    if (*pNameUTF8 == '\0')
        COMPlusThrow(kArgumentException, W("Format_StringZeroLength"));

    DWORD  cbResource;
    if (pAssembly->GetResource(pNameUTF8, &cbResource,
                               &pbInMemoryResource, NULL, NULL,
                               NULL, stackMark, skipSecurityCheck, FALSE))
    {
        *length = cbResource;
    }

    END_QCALL;

    // Can return null if resource file is zero-length
    return pbInMemoryResource;
}

#ifndef FEATURE_CORECLR

BOOL QCALLTYPE AssemblyNative::UseRelativeBindForSatellites()
{
    QCALL_CONTRACT;

    BOOL retVal = TRUE;

    BEGIN_QCALL;
    retVal  = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_RelativeBindForResources);
    END_QCALL;

    return retVal;

}
#endif // !FEATURE_CORECLR

INT32 QCALLTYPE AssemblyNative::GetManifestResourceInfo(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, QCall::ObjectHandleOnStack retAssembly, QCall::StringHandleOnStack retFileName, QCall::StackCrawlMarkHandle stackMark)
{
    QCALL_CONTRACT;

    INT32 rv = -1;

    BEGIN_QCALL;

    if (wszName == NULL)
        COMPlusThrow(kArgumentNullException, W("ArgumentNull_String"));

    // Get the name in UTF8
    SString name(SString::Literal, wszName);

    StackScratchBuffer scratch;
    LPCUTF8 pNameUTF8 = name.GetUTF8(scratch);

    if (*pNameUTF8 == '\0')
        COMPlusThrow(kArgumentException, W("Format_StringZeroLength"));

    DomainAssembly * pReferencedAssembly = NULL;
    LPCSTR pFileName = NULL;
    DWORD dwLocation = 0;

    if (pAssembly->GetResource(pNameUTF8, NULL, NULL, &pReferencedAssembly, &pFileName,
                              &dwLocation, stackMark, FALSE, FALSE))
    {
        if (pFileName)
            retFileName.Set(pFileName);

        GCX_COOP();

        if (pReferencedAssembly)
            retAssembly.Set(pReferencedAssembly->GetExposedAssemblyObject());

        rv = dwLocation;
    }

    END_QCALL;

    return rv;
}

void QCALLTYPE AssemblyNative::GetModules(QCall::AssemblyHandle pAssembly, BOOL fLoadIfNotFound, BOOL fGetResourceModules, QCall::ObjectHandleOnStack retModules)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    HENUMInternalHolder phEnum(pAssembly->GetMDImport());
    phEnum.EnumInit(mdtFile, mdTokenNil);

    InlineSArray<DomainFile *, 8> modules;

    modules.Append(pAssembly);

    ReflectionModule *pOnDiskManifest = NULL;
    if (pAssembly->GetAssembly()->NeedsToHideManifestForEmit())
        pOnDiskManifest = pAssembly->GetAssembly()->GetOnDiskManifestModule();

    mdFile mdFile;
    while (pAssembly->GetMDImport()->EnumNext(&phEnum, &mdFile))
    {
        DomainFile *pModule = pAssembly->GetModule()->LoadModule(GetAppDomain(), mdFile, fGetResourceModules, !fLoadIfNotFound);

        if (pModule && pModule->GetModule() != pOnDiskManifest) {
            modules.Append(pModule);
        }
    }

    {
        GCX_COOP();

        PTRARRAYREF orModules = NULL;

        GCPROTECT_BEGIN(orModules);

        // Return the modules
        orModules = (PTRARRAYREF)AllocateObjectArray(modules.GetCount(), MscorlibBinder::GetClass(CLASS__MODULE));

        for(COUNT_T i = 0; i < modules.GetCount(); i++)
        {
            DomainFile * pModule = modules[i];

            OBJECTREF o = pModule->GetExposedModuleObject();
            orModules->SetAt(i, o);
        }

        retModules.Set(orModules);

        GCPROTECT_END();
    }

    END_QCALL;
}

BOOL QCALLTYPE AssemblyNative::GetNeutralResourcesLanguageAttribute(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack cultureName, INT16& outFallbackLocation)
{
    CONTRACTL {
        QCALL_CHECK;
    } CONTRACTL_END;

    BOOL retVal = FALSE;
    BEGIN_QCALL;

    _ASSERTE(pAssembly);
    Assembly * pAsm = pAssembly->GetAssembly();
    _ASSERTE(pAsm);
    Module * pModule = pAsm->GetManifestModule();
    _ASSERTE(pModule);

    LPCUTF8 pszCultureName = NULL;
    ULONG cultureNameLength = 0;
    INT16 fallbackLocation = 0;

    // find the attribute if it exists
    if (pModule->GetNeutralResourcesLanguage(&pszCultureName, &cultureNameLength, &fallbackLocation, FALSE)) {
        StackSString culture(SString::Utf8, pszCultureName, cultureNameLength);
        cultureName.Set(culture);
        outFallbackLocation = fallbackLocation;
        retVal = TRUE;
    }

    END_QCALL;

    return retVal;
}

void QCALLTYPE AssemblyNative::GetModule(QCall::AssemblyHandle pAssembly, LPCWSTR wszFileName, QCall::ObjectHandleOnStack retModule)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    Module * pModule = NULL;

    CQuickBytes qbLC;

    if (wszFileName == NULL)
        COMPlusThrow(kArgumentNullException, W("ArgumentNull_FileName"));
    if (wszFileName[0] == W('\0'))
        COMPlusThrow(kArgumentException, W("Argument_EmptyFileName"));

    MAKE_UTF8PTR_FROMWIDE(szModuleName, wszFileName);

#ifdef FEATURE_MULTIMODULE_ASSEMBLIES
    // Need to perform case insensitive lookup.
    {
        UTF8_TO_LOWER_CASE(szModuleName, qbLC);
        szModuleName = (LPUTF8) qbLC.Ptr();
    }

    HashDatum datum = NULL;

    // m_pAllowedFiles only grows - entries are never deleted from it. So we do not take
    // a lock around GetValue. If the code is modified such that we delete entries from m_pAllowedFiles,
    // reconsider whether we should take the m_crstAllowedFiles lock here (see the uses of datum below).
    if (pAssembly->GetAssembly()->m_pAllowedFiles->GetValue(szModuleName, &datum))
    {
        if (datum)
        {
            // internal module
            mdFile  tokFile = (mdFile)(UINT_PTR)datum;

            pModule = pAssembly->GetModule()->LoadModule(GetAppDomain(), tokFile)->GetModule();
        }
        else
        { // manifest module
            pModule = pAssembly->GetDomainAssembly()->GetModule();
        }
    }
#else

    LPCUTF8 pModuleName = NULL;

    if SUCCEEDED(pAssembly->GetDomainAssembly()->GetModule()->GetScopeName(&pModuleName))
    {
        if (::SString::_stricmp(pModuleName, szModuleName) == 0)
            pModule = pAssembly->GetDomainAssembly()->GetModule();
    }

#endif

    if (pModule != NULL)
    {
        GCX_COOP();
        retModule.Set(pModule->GetExposedObject());
    }

    END_QCALL;

    return;
}

void QCALLTYPE AssemblyNative::GetExportedTypes(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retTypes)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    InlineSArray<TypeHandle, 20> types;

    Assembly * pAsm = pAssembly->GetAssembly();

    IMDInternalImport *pImport = pAsm->GetManifestImport();

    {
        HENUMTypeDefInternalHolder phTDEnum(pImport);
        phTDEnum.EnumTypeDefInit();

        mdTypeDef mdTD;
        while(pImport->EnumNext(&phTDEnum, &mdTD))
        {
            DWORD dwFlags;
            IfFailThrow(pImport->GetTypeDefProps(
                mdTD,
                &dwFlags,
                NULL));

            // nested type
            mdTypeDef mdEncloser = mdTD;
            while (SUCCEEDED(pImport->GetNestedClassProps(mdEncloser, &mdEncloser)) &&
                   IsTdNestedPublic(dwFlags))
            {
                IfFailThrow(pImport->GetTypeDefProps(
                    mdEncloser,
                    &dwFlags,
                    NULL));
            }

            if (IsTdPublic(dwFlags))
            {
                TypeHandle typeHnd = ClassLoader::LoadTypeDefThrowing(pAsm->GetManifestModule(), mdTD,
                                                                      ClassLoader::ThrowIfNotFound,
                                                                      ClassLoader::PermitUninstDefOrRef);
                types.Append(typeHnd);
            }
        }
    }

    {
        HENUMInternalHolder phCTEnum(pImport);
        phCTEnum.EnumInit(mdtExportedType, mdTokenNil);

        // Now get the ExportedTypes that don't have TD's in the manifest file
        mdExportedType mdCT;
        while(pImport->EnumNext(&phCTEnum, &mdCT))
        {
            mdToken mdImpl;
            LPCSTR pszNameSpace;
            LPCSTR pszClassName;
            DWORD dwFlags;

            IfFailThrow(pImport->GetExportedTypeProps(
                mdCT,
                &pszNameSpace,
                &pszClassName,
                &mdImpl,
                NULL,           //binding
                &dwFlags));

            // nested type
            while ((TypeFromToken(mdImpl) == mdtExportedType) &&
                   (mdImpl != mdExportedTypeNil) &&
                   IsTdNestedPublic(dwFlags))
            {
                IfFailThrow(pImport->GetExportedTypeProps(
                    mdImpl,
                    NULL,       //namespace
                    NULL,       //name
                    &mdImpl,
                    NULL,       //binding
                    &dwFlags));
            }

            if ((TypeFromToken(mdImpl) == mdtFile) &&
                (mdImpl != mdFileNil) &&
                IsTdPublic(dwFlags))
            {
                NameHandle typeName(pszNameSpace, pszClassName);
                typeName.SetTypeToken(pAsm->GetManifestModule(), mdCT);
                TypeHandle typeHnd = pAsm->GetLoader()->LoadTypeHandleThrowIfFailed(&typeName);

                types.Append(typeHnd);
            }
        }
    }

    {
        GCX_COOP();

        PTRARRAYREF orTypes = NULL;

        GCPROTECT_BEGIN(orTypes);

        // Return the types
        orTypes = (PTRARRAYREF)AllocateObjectArray(types.GetCount(), MscorlibBinder::GetClass(CLASS__TYPE));

        for(COUNT_T i = 0; i < types.GetCount(); i++)
        {
            TypeHandle typeHnd = types[i];

            OBJECTREF o = typeHnd.GetManagedClassObject();
            orTypes->SetAt(i, o);
        }

        retTypes.Set(orTypes);

        GCPROTECT_END();
    }

    END_QCALL;
}

void QCALLTYPE AssemblyNative::GetForwardedTypes(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retTypes)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    InlineSArray<TypeHandle, 8> types;

    Assembly * pAsm = pAssembly->GetAssembly();

    IMDInternalImport *pImport = pAsm->GetManifestImport();

    // enumerate the ExportedTypes table
    {
        HENUMInternalHolder phCTEnum(pImport);
        phCTEnum.EnumInit(mdtExportedType, mdTokenNil);

        // Now get the ExportedTypes that don't have TD's in the manifest file
        mdExportedType mdCT;
        while(pImport->EnumNext(&phCTEnum, &mdCT))
        {
            mdToken mdImpl;
            LPCSTR pszNameSpace;
            LPCSTR pszClassName;
            DWORD dwFlags;

            IfFailThrow(pImport->GetExportedTypeProps(mdCT,
                &pszNameSpace,
                &pszClassName,
                &mdImpl,
                NULL, //binding
                &dwFlags));

            if ((TypeFromToken(mdImpl) == mdtAssemblyRef) && (mdImpl != mdAssemblyRefNil))
            {
                NameHandle typeName(pszNameSpace, pszClassName);
                typeName.SetTypeToken(pAsm->GetManifestModule(), mdCT);
                TypeHandle typeHnd = pAsm->GetLoader()->LoadTypeHandleThrowIfFailed(&typeName);

                types.Append(typeHnd);
            }
        }
    }

    // Populate retTypes
    {
        GCX_COOP();

        PTRARRAYREF orTypes = NULL;

        GCPROTECT_BEGIN(orTypes);

        // Return the types
        orTypes = (PTRARRAYREF)AllocateObjectArray(types.GetCount(), MscorlibBinder::GetClass(CLASS__TYPE));

        for(COUNT_T i = 0; i < types.GetCount(); i++)
        {
            TypeHandle typeHnd = types[i];

            OBJECTREF o = typeHnd.GetManagedClassObject();
            orTypes->SetAt(i, o);
        }

        retTypes.Set(orTypes);

        GCPROTECT_END();
    }

    END_QCALL;
}

FCIMPL1(Object*, AssemblyNative::GetManifestResourceNames, AssemblyBaseObject * pAssemblyUNSAFE)
{
    FCALL_CONTRACT;

    ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);

    if (refAssembly == NULL)
        FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));

    DomainAssembly *pAssembly = refAssembly->GetDomainAssembly();
    PTRARRAYREF rv = NULL;

    HELPER_METHOD_FRAME_BEGIN_RET_2(rv, refAssembly);

    IMDInternalImport *pImport = pAssembly->GetMDImport();

    HENUMInternalHolder phEnum(pImport);
    DWORD dwCount;

    phEnum.EnumInit(mdtManifestResource, mdTokenNil);
        dwCount = pImport->EnumGetCount(&phEnum);

    PTRARRAYREF ItemArray = (PTRARRAYREF) AllocateObjectArray(dwCount, g_pStringClass);

    mdManifestResource mdResource;

    GCPROTECT_BEGIN(ItemArray);
    for(DWORD i = 0;  i < dwCount; i++) {
        pImport->EnumNext(&phEnum, &mdResource);
        LPCSTR pszName = NULL;

        IfFailThrow(pImport->GetManifestResourceProps(
            mdResource,
            &pszName,   // name
            NULL,       // linkref
            NULL,       // offset
            NULL));     //flags

        OBJECTREF o = (OBJECTREF) StringObject::NewString(pszName);
        ItemArray->SetAt(i, o);
    }

    rv = ItemArray;
    GCPROTECT_END();

    HELPER_METHOD_FRAME_END();

    return OBJECTREFToObject(rv);
}
FCIMPLEND

FCIMPL1(Object*, AssemblyNative::GetReferencedAssemblies, AssemblyBaseObject * pAssemblyUNSAFE)
{
    FCALL_CONTRACT;

    struct _gc {
        PTRARRAYREF ItemArray;
        ASSEMBLYNAMEREF pObj;
        ASSEMBLYREF refAssembly;
    } gc;
    ZeroMemory(&gc, sizeof(gc));

    gc.refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);

    if (gc.refAssembly == NULL)
        FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));

    DomainAssembly *pAssembly = gc.refAssembly->GetDomainAssembly();

    HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);

    IMDInternalImport *pImport = pAssembly->GetAssembly()->GetManifestImport();

    MethodTable* pAsmNameClass = MscorlibBinder::GetClass(CLASS__ASSEMBLY_NAME);

    HENUMInternalHolder phEnum(pImport);
    DWORD dwCount = 0;

    phEnum.EnumInit(mdtAssemblyRef, mdTokenNil);

    dwCount = pImport->EnumGetCount(&phEnum);

    mdAssemblyRef mdAssemblyRef;

    gc.ItemArray = (PTRARRAYREF) AllocateObjectArray(dwCount, pAsmNameClass);

    for(DWORD i = 0; i < dwCount; i++)
    {
        pImport->EnumNext(&phEnum, &mdAssemblyRef);

        AssemblySpec spec;
        spec.InitializeSpec(mdAssemblyRef, pImport);

        gc.pObj = (ASSEMBLYNAMEREF) AllocateObject(pAsmNameClass);
        spec.AssemblyNameInit(&gc.pObj,NULL);

        gc.ItemArray->SetAt(i, (OBJECTREF) gc.pObj);
    }

    HELPER_METHOD_FRAME_END();

    return OBJECTREFToObject(gc.ItemArray);
}
FCIMPLEND

void QCALLTYPE AssemblyNative::GetEntryPoint(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retMethod)
{
    QCALL_CONTRACT;

    MethodDesc* pMeth = NULL;

    BEGIN_QCALL;

    pMeth = pAssembly->GetAssembly()->GetEntryPoint();
    if (pMeth != NULL)
    {
        GCX_COOP();
        retMethod.Set(pMeth->GetStubMethodInfo());
    }

    END_QCALL;

    return;
}

#ifndef FEATURE_CORECLR
// prepare saving manifest to disk
void QCALLTYPE AssemblyNative::PrepareForSavingManifestToDisk(QCall::AssemblyHandle pAssembly, QCall::ModuleHandle pAssemblyModule)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    pAssembly->GetAssembly()->PrepareSavingManifest((ReflectionModule *)(Module *)pAssemblyModule);

    END_QCALL;
}

#endif

#ifndef FEATURE_CORECLR
// add a file name to the file list of this assembly. On disk only.
mdFile QCALLTYPE AssemblyNative::AddFile(QCall::AssemblyHandle pAssembly, LPCWSTR wszFileName)
{
    QCALL_CONTRACT;

    mdFile      retVal = 0;

    BEGIN_QCALL;

    retVal = pAssembly->GetAssembly()->AddFile(wszFileName);

    END_QCALL;

    return retVal;
}
#endif //FEATURE_CORECLR

#ifndef FEATURE_CORECLR
// set the hash value on a file.
void QCALLTYPE AssemblyNative::SetFileHashValue(QCall::AssemblyHandle pAssembly, INT32 tkFile, LPCWSTR wszFullFileName)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    pAssembly->GetAssembly()->SetFileHashValue(tkFile, wszFullFileName);

    END_QCALL;
}
#endif //FEATURE_CORECLR

#ifndef FEATURE_CORECLR
// Add a Type name to the ExportedType table in the on-disk assembly manifest.
mdExportedType QCALLTYPE AssemblyNative::AddExportedTypeOnDisk(QCall::AssemblyHandle pAssembly, LPCWSTR wszCOMTypeName, INT32 tkImpl, INT32 tkTypeDef, INT32 flags)
{
    QCALL_CONTRACT;

    mdExportedType  retVal = 0;

    BEGIN_QCALL;

    retVal = pAssembly->GetAssembly()->AddExportedTypeOnDisk(wszCOMTypeName, tkImpl, tkTypeDef, (CorTypeAttr)flags);

    END_QCALL;

    return retVal;
}

// Add a Type name to the ExportedType table in the in-memory assembly manifest.
mdExportedType QCALLTYPE AssemblyNative::AddExportedTypeInMemory(QCall::AssemblyHandle pAssembly, LPCWSTR wszCOMTypeName, INT32 tkImpl, INT32 tkTypeDef, INT32 flags)
{
    QCALL_CONTRACT;

    mdExportedType  retVal = 0;

    BEGIN_QCALL;

    retVal = pAssembly->GetAssembly()->AddExportedTypeInMemory(wszCOMTypeName, tkImpl, tkTypeDef, (CorTypeAttr)flags);

    END_QCALL;

    return retVal;
}
#endif //FEATURE_CORECLR

#ifndef FEATURE_CORECLR
// add a Stand alone resource to ManifestResource table
void QCALLTYPE AssemblyNative::AddStandAloneResource(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, LPCWSTR wszFileName, LPCWSTR wszFullFileName, INT32 iAttribute)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    pAssembly->GetAssembly()->AddStandAloneResource(
        wszName,
        NULL,
        NULL,
        wszFileName,
        wszFullFileName,
        iAttribute);

    END_QCALL;
}
#endif //FEATURE_CORECLR

#ifndef FEATURE_CORECLR
// Save security permission requests.
void QCALLTYPE AssemblyNative::AddDeclarativeSecurity(QCall::AssemblyHandle pAssembly, INT32 action, PVOID blob, INT32 length)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    pAssembly->GetAssembly()->AddDeclarativeSecurity(action, blob, length);

    END_QCALL;
}
#endif //FEATURE_CORECLR

//---------------------------------------------------------------------------------------
//
// Get the raw bytes making up this assembly
//
// Arguments:
//    pAssembly   - Assembly to get the data of
//    retRawBytes - [out] raw bytes of the assembly
//

// static
void QCALLTYPE AssemblyNative::GetRawBytes(QCall::AssemblyHandle pAssembly,
                                           QCall::ObjectHandleOnStack retRawBytes)
{
    QCALL_CONTRACT;
    BEGIN_QCALL;

    PEFile *pPEFile = pAssembly->GetFile();
    if (pPEFile != NULL)
    {
        PEImage *pPEImage = pPEFile->GetILimage();

        if (pPEImage != NULL)
        {
            SBuffer dataBuffer;
            pPEImage->GetImageBits(PEImageLayout::LAYOUT_FLAT, dataBuffer);

            if (dataBuffer.GetSize() > 0)
            {
                retRawBytes.SetByteArray(dataBuffer, dataBuffer.GetSize());
            }
        }
    }

    END_QCALL;
}

//---------------------------------------------------------------------------------------
//
// Release QCALL for System.SafePEFileHandle
//
//

// static
void QCALLTYPE AssemblyNative::ReleaseSafePEFileHandle(PEFile *pPEFile)
{
    CONTRACTL
    {
        QCALL_CHECK;
        PRECONDITION(CheckPointer(pPEFile));
    }
    CONTRACTL_END;

    BEGIN_QCALL;

    pPEFile->Release();

    END_QCALL;
}

// save the manifest to disk!
extern void ManagedBitnessFlagsToUnmanagedBitnessFlags(
    INT32 portableExecutableKind, INT32 imageFileMachine,
    DWORD* pPeFlags, DWORD* pCorhFlags);

#ifndef FEATURE_CORECLR
void QCALLTYPE AssemblyNative::SaveManifestToDisk(QCall::AssemblyHandle pAssembly,
                                                  LPCWSTR wszManifestFileName,
                                                  INT32 entrypoint,
                                                  INT32 fileKind,
                                                  INT32 portableExecutableKind,
                                                  INT32 imageFileMachine)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    DWORD peFlags = 0, corhFlags = 0;
    ManagedBitnessFlagsToUnmanagedBitnessFlags(portableExecutableKind, imageFileMachine, &peFlags, &corhFlags);

    pAssembly->GetAssembly()->SaveManifestToDisk(wszManifestFileName, entrypoint, fileKind, corhFlags, peFlags);

    END_QCALL;
}
#endif // !FEATURE_CORECLR

void QCALLTYPE AssemblyNative::GetFullName(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    StackSString name;
    pAssembly->GetFile()->GetDisplayName(name);
    retString.Set(name);

    END_QCALL;
}

void QCALLTYPE AssemblyNative::GetExecutingAssembly(QCall::StackCrawlMarkHandle stackMark, QCall::ObjectHandleOnStack retAssembly)
{
    QCALL_CONTRACT;

    DomainAssembly * pExecutingAssembly = NULL;

    BEGIN_QCALL;

    Assembly* pAssembly = SystemDomain::GetCallersAssembly(stackMark);
    if(pAssembly)
    {
        pExecutingAssembly = pAssembly->GetDomainAssembly();
        GCX_COOP();
        retAssembly.Set(pExecutingAssembly->GetExposedAssemblyObject());
    }

    END_QCALL;
    return;
}

void QCALLTYPE AssemblyNative::GetEntryAssembly(QCall::ObjectHandleOnStack retAssembly)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    DomainAssembly * pRootAssembly = NULL;
    Assembly * pAssembly = GetAppDomain()->m_pRootAssembly;

    if (pAssembly)
    {
        pRootAssembly = pAssembly->GetDomainAssembly();
        GCX_COOP();
        retAssembly.Set(pRootAssembly->GetExposedAssemblyObject());
    }

    END_QCALL;

    return;
}

void QCALLTYPE AssemblyNative::GetGrantSet(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retGranted, QCall::ObjectHandleOnStack retDenied)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    IAssemblySecurityDescriptor *pSecDesc = pAssembly->GetSecurityDescriptor();

    {
        GCX_COOP();

        pSecDesc->Resolve();

        OBJECTREF granted, denied;

        granted = pSecDesc->GetGrantedPermissionSet(&denied);

        retGranted.Set(granted);
        retDenied.Set(denied);
    }

    END_QCALL;
}

//
// QCalls to determine if everything introduced by the assembly is either security critical or safe critical
//

// static
BOOL QCALLTYPE AssemblyNative::IsAllSecurityCritical(QCall::AssemblyHandle pAssembly)
{
    QCALL_CONTRACT;

    BOOL fIsCritical = FALSE;

    BEGIN_QCALL;

    fIsCritical = pAssembly->GetSecurityDescriptor()->IsAllCritical();

    END_QCALL;

    return fIsCritical;
}

// static
BOOL QCALLTYPE AssemblyNative::IsAllSecuritySafeCritical(QCall::AssemblyHandle pAssembly)
{
    QCALL_CONTRACT;

    BOOL fIsSafeCritical = FALSE;

    BEGIN_QCALL;

    fIsSafeCritical = pAssembly->GetSecurityDescriptor()->IsAllSafeCritical();

    END_QCALL;

    return fIsSafeCritical;
}

// static
BOOL QCALLTYPE AssemblyNative::IsAllPublicAreaSecuritySafeCritical(QCall::AssemblyHandle pAssembly)
{
    QCALL_CONTRACT;

    BOOL fIsAllPublicAreaSafeCritical = FALSE;

    BEGIN_QCALL;

    fIsAllPublicAreaSafeCritical = pAssembly->GetSecurityDescriptor()->IsAllPublicAreaSafeCritical();

    END_QCALL;

    return fIsAllPublicAreaSafeCritical;
}

// static
BOOL QCALLTYPE AssemblyNative::IsAllSecurityTransparent(QCall::AssemblyHandle pAssembly)
{
    QCALL_CONTRACT;

    BOOL fIsTransparent = FALSE;

    BEGIN_QCALL;

    fIsTransparent = pAssembly->GetSecurityDescriptor()->IsAllTransparent();

    END_QCALL;

    return fIsTransparent;
}

// return the on disk assembly module for reflection emit. This only works for dynamic assembly.
FCIMPL1(ReflectModuleBaseObject *, AssemblyNative::GetOnDiskAssemblyModule, AssemblyBaseObject* pAssemblyUNSAFE)
{
    FCALL_CONTRACT;

    ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);

    if (refAssembly == NULL)
        FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));

    DomainAssembly *pAssembly = refAssembly->GetDomainAssembly();

    FC_RETURN_MODULE_OBJECT(pAssembly->GetCurrentAssembly()->GetOnDiskManifestModule(), refAssembly);
}
FCIMPLEND

// return the in memory assembly module for reflection emit. This only works for dynamic assembly.
FCIMPL1(ReflectModuleBaseObject *, AssemblyNative::GetInMemoryAssemblyModule, AssemblyBaseObject* pAssemblyUNSAFE)
{
    FCALL_CONTRACT;

    ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);

    if (refAssembly == NULL)
        FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));

    DomainAssembly *pAssembly = refAssembly->GetDomainAssembly();

    FC_RETURN_MODULE_OBJECT(pAssembly->GetCurrentModule(), refAssembly);
}
FCIMPLEND

#ifndef FEATURE_CORECLR
// Create a stand-alone resource file for version resource.
void QCALLTYPE AssemblyNative::CreateVersionInfoResource(LPCWSTR    pwzFilename,
                                                         LPCWSTR    pwzTitle,
                                                         LPCWSTR    pwzIconFilename,
                                                         LPCWSTR    pwzDescription,
                                                         LPCWSTR    pwzCopyright,
                                                         LPCWSTR    pwzTrademark,
                                                         LPCWSTR    pwzCompany,
                                                         LPCWSTR    pwzProduct,
                                                         LPCWSTR    pwzProductVersion,
                                                         LPCWSTR    pwzFileVersion,
                                                         INT32 lcid,
                                                         BOOL       fIsDll,
                                                         QCall::StringHandleOnStack retFileName)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    Win32Res    res;                    // Resource helper object.
    const void  *pvData=0;              // Pointer to the resource.
    ULONG       cbData;                 // Size of the resource data.
    ULONG       cbWritten;
    PathString       szFile;     // File name for resource file.
    PathString       szPath;     // Path name for resource file.
    HandleHolder hFile;

    res.SetInfo(pwzFilename,
                pwzTitle,
                pwzIconFilename,
                pwzDescription,
                pwzCopyright,
                pwzTrademark,
                pwzCompany,
                pwzProduct,
                pwzProductVersion,
                pwzFileVersion,
                lcid,
                fIsDll);

    res.MakeResFile(&pvData, &cbData);

    //<TODO>Change the COMPlusThrowWin32's to exceptions with
    // messages including the path/file name</TODO>

    // Persist to a file.
    if (!WszGetTempPath(szPath))
        COMPlusThrowWin32();
    if (!WszGetTempFileName(szPath.GetUnicode(), W("RES"), 0, szFile))
        COMPlusThrowWin32();

    hFile = WszCreateFile(szFile, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        COMPlusThrowWin32();

    if (!WriteFile(hFile, pvData, cbData, &cbWritten, NULL))
        COMPlusThrowWin32();

    retFileName.Set(szFile);

    END_QCALL;
}
#endif // !FEATURE_CORECLR

#ifndef FEATURE_CORECLR
FCIMPL1(FC_BOOL_RET, AssemblyNative::IsGlobalAssemblyCache, AssemblyBaseObject* pAssemblyUNSAFE)
{
    FCALL_CONTRACT;

    ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);

    if (refAssembly == NULL)
        FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));

    DomainAssembly *pAssembly = refAssembly->GetDomainAssembly();

    FC_RETURN_BOOL(pAssembly->GetFile()->IsSourceGAC());
}
FCIMPLEND
#endif // !FEATURE_CORECLR

void QCALLTYPE AssemblyNative::GetImageRuntimeVersion(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    // Retrieve the PEFile from the assembly.
    PEFile* pPEFile = pAssembly->GetFile();
    PREFIX_ASSUME(pPEFile!=NULL);

    LPCSTR pszVersion = NULL;
    IfFailThrow(pPEFile->GetMDImport()->GetVersionString(&pszVersion));

    SString version(SString::Utf8, pszVersion);
 #ifndef FEATURE_CORECLR
    AdjustImageRuntimeVersion(&version);
#endif // FEATURE_CORECLR

    // Allocate a managed string that contains the version and return it.
    retString.Set(version);

    END_QCALL;
}

#ifdef FEATURE_FUSION
INT64 QCALLTYPE AssemblyNative::GetHostContext(QCall::AssemblyHandle pAssembly)
{
    QCALL_CONTRACT;

    UINT64 Context = 0;

    BEGIN_QCALL;

    IHostAssembly *pIHostAssembly = pAssembly->GetFile()->GetIHostAssembly();
    if (pIHostAssembly != NULL)
    {
        IfFailThrow(pIHostAssembly->GetAssemblyContext(&Context));
    }

    END_QCALL;

    return Context;
}
#endif // FEATURE_FUSION

#ifdef FEATURE_CAS_POLICY
BOOL QCALLTYPE AssemblyNative::IsStrongNameVerified(QCall::AssemblyHandle pAssembly)
{
    QCALL_CONTRACT;

    BOOL fStrongNameVerified = FALSE;

    BEGIN_QCALL;

    PEFile *pPEFile = pAssembly->GetFile();
    fStrongNameVerified = pPEFile->IsStrongNameVerified();

    END_QCALL;

    return fStrongNameVerified;
}
#endif // FEATURE_CAS_POLICY

#ifdef FEATURE_APPX
/*static*/
BOOL QCALLTYPE AssemblyNative::IsDesignerBindingContext(QCall::AssemblyHandle pAssembly)
{
    QCALL_CONTRACT;

    BOOL fRet = FALSE;

    BEGIN_QCALL;

    PEFile *pPEFile = pAssembly->GetFile();
    fRet = pPEFile->IsDesignerBindingContext();

    END_QCALL;

    return fRet;
}
#endif // FEATURE_APPX

#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
/*static*/
INT_PTR QCALLTYPE AssemblyNative::InitializeAssemblyLoadContext(INT_PTR ptrManagedAssemblyLoadContext, BOOL fRepresentsTPALoadContext)
{
    QCALL_CONTRACT;

    INT_PTR ptrNativeAssemblyLoadContext = NULL;

    BEGIN_QCALL;

    // We do not need to take a lock since this method is invoked from the ctor of AssemblyLoadContext managed type and
    // only one thread is ever executing a ctor for a given instance.
    //

    // Initialize the assembly binder instance in the VM
    PTR_AppDomain pCurDomain = AppDomain::GetCurrentDomain();
    CLRPrivBinderCoreCLR *pTPABinderContext = pCurDomain->GetTPABinderContext();
    if (!fRepresentsTPALoadContext)
    {
        // Initialize a custom Assembly Load Context
        CLRPrivBinderAssemblyLoadContext *pBindContext = NULL;
        IfFailThrow(CLRPrivBinderAssemblyLoadContext::SetupContext(pCurDomain->GetId().m_dwId, pTPABinderContext, ptrManagedAssemblyLoadContext, &pBindContext));
        ptrNativeAssemblyLoadContext = reinterpret_cast<INT_PTR>(pBindContext);
    }
    else
    {
        // We are initializing the managed instance of Assembly Load Context that would represent the TPA binder.
        // First, confirm we do not have an existing managed ALC attached to the TPA binder.
        INT_PTR ptrTPAAssemblyLoadContext = pTPABinderContext->GetManagedAssemblyLoadContext();
        if ((ptrTPAAssemblyLoadContext != NULL) && (ptrTPAAssemblyLoadContext != ptrManagedAssemblyLoadContext))
        {
            COMPlusThrow(kInvalidOperationException, IDS_HOST_ASSEMBLY_RESOLVER_INCOMPATIBLE_TPA_BINDING_CONTEXT);
        }

        // Attach the managed TPA binding context with the native one.
        pTPABinderContext->SetManagedAssemblyLoadContext(ptrManagedAssemblyLoadContext);
        ptrNativeAssemblyLoadContext = reinterpret_cast<INT_PTR>(pTPABinderContext);
    }

    END_QCALL;

    return ptrNativeAssemblyLoadContext;
}

/*static*/
BOOL QCALLTYPE AssemblyNative::OverrideDefaultAssemblyLoadContextForCurrentDomain(INT_PTR ptrNativeAssemblyLoadContext)
{
    QCALL_CONTRACT;

    BOOL fOverrodeDefaultLoadContext = FALSE;

    BEGIN_QCALL;

    AppDomain *pCurDomain = AppDomain::GetCurrentDomain();

    if (pCurDomain->LockBindingModel())
    {
        // Only one thread will ever enter here - it will be the ones that actually locked the binding model
        //
        // AssemblyLoadContext should have a binder associated with it
        IUnknown *pOverrideBinder = reinterpret_cast<IUnknown *>(ptrNativeAssemblyLoadContext);
        _ASSERTE(pOverrideBinder != NULL);

        // Get reference to the current default context binder

        IUnknown * pCurrentDefaultContextBinder = pCurDomain->GetFusionContext();

        // The default context binder can never be null since the runtime always sets one up
        _ASSERTE(pCurrentDefaultContextBinder != NULL);

        // The default context should also be the same as TPABinder context
        _ASSERTE(pCurrentDefaultContextBinder == pCurDomain->GetTPABinderContext());

        // Override the default context binder in the VM
        pCurDomain->OverrideDefaultContextBinder(pOverrideBinder);

        fOverrodeDefaultLoadContext = TRUE;
    }

    END_QCALL;

    return fOverrodeDefaultLoadContext;
}

BOOL QCALLTYPE AssemblyNative::CanUseAppPathAssemblyLoadContextInCurrentDomain()
{
    QCALL_CONTRACT;

    BOOL fCanUseAppPathAssemblyLoadContext = FALSE;

    BEGIN_QCALL;

    AppDomain *pCurDomain = AppDomain::GetCurrentDomain();

    pCurDomain->LockBindingModel();

    fCanUseAppPathAssemblyLoadContext = !pCurDomain->IsHostAssemblyResolverInUse();

    END_QCALL;

    return fCanUseAppPathAssemblyLoadContext;
}

/*static*/
INT_PTR QCALLTYPE AssemblyNative::GetLoadContextForAssembly(QCall::AssemblyHandle pAssembly)
{
    QCALL_CONTRACT;

    INT_PTR ptrManagedAssemblyLoadContext = NULL;

    BEGIN_QCALL;

    // Get the PEAssembly for the RuntimeAssembly
    PEFile *pPEFile = pAssembly->GetFile();
    PTR_PEAssembly pPEAssembly = pPEFile->AsAssembly();
    _ASSERTE(pAssembly != NULL);

    // Platform assemblies are semantically bound against the "Default" binder which could be the TPA Binder or
    // the overridden binder. In either case, the reference to the same will be returned when this QCall returns.
    if (!pPEAssembly->IsProfileAssembly())
    {
        // Get the binding context for the assembly.
        //
        ICLRPrivBinder *pOpaqueBinder = nullptr;
        AppDomain *pCurDomain = AppDomain::GetCurrentDomain();
        CLRPrivBinderCoreCLR *pTPABinder = pCurDomain->GetTPABinderContext();

        // GetBindingContext returns a ICLRPrivAssembly which can be used to get access to the
        // actual ICLRPrivBinder instance in which the assembly was loaded.
        PTR_ICLRPrivBinder pBindingContext = pPEAssembly->GetBindingContext();
        UINT_PTR assemblyBinderID = 0;
        IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID));

        // If the assembly was bound using the TPA binder,
        // then we will return the reference to "Default" binder from the managed implementation when this QCall returns.
        //
        // See earlier comment about "Default" binder for additional context.
        pOpaqueBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID);

        // We should have a load context binder at this point.
        _ASSERTE(pOpaqueBinder != nullptr);

        if (!AreSameBinderInstance(pTPABinder, pOpaqueBinder))
        {
            // Only CLRPrivBinderAssemblyLoadContext instance contains the reference to its
            // corresponding managed instance.
            CLRPrivBinderAssemblyLoadContext *pBinder = (CLRPrivBinderAssemblyLoadContext *)(pOpaqueBinder);

            // Fetch the managed binder reference from the native binder instance
            ptrManagedAssemblyLoadContext = pBinder->GetManagedAssemblyLoadContext();
            _ASSERTE(ptrManagedAssemblyLoadContext != NULL);
        }
    }

    END_QCALL;

    return ptrManagedAssemblyLoadContext;
}
#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER)

// static
BOOL QCALLTYPE AssemblyNative::InternalTryGetRawMetadata(
    QCall::AssemblyHandle assembly,
    UINT8 **blobRef,
    INT32 *lengthRef)
{
    QCALL_CONTRACT;

    PTR_CVOID metadata = nullptr;

    BEGIN_QCALL;

    _ASSERTE(assembly != nullptr);
    _ASSERTE(blobRef != nullptr);
    _ASSERTE(lengthRef != nullptr);

    static_assert_no_msg(sizeof(*lengthRef) == sizeof(COUNT_T));
    metadata = assembly->GetFile()->GetLoadedMetadata(reinterpret_cast<COUNT_T *>(lengthRef));
    *blobRef = reinterpret_cast<UINT8 *>(const_cast<PTR_VOID>(metadata));
    _ASSERTE(*lengthRef >= 0);

    END_QCALL;

    return metadata != nullptr;
}


text:
import os
import tempfile

import mock
import six

from cinder import exception
from cinder import test
from cinder.volume import configuration as conf
from cinder.volume.drivers.hitachi import hnas_nfs as nfs
from cinder.volume import volume_types

SHARESCONF = """172.17.39.132:/cinder
172.17.39.133:/cinder"""

HNASCONF = """<?xml version="1.0" encoding="UTF-8" ?>
<config>
  <hnas_cmd>ssc</hnas_cmd>
  <mgmt_ip0>172.17.44.15</mgmt_ip0>
  <username>supervisor</username>
  <password>supervisor</password>
  <svc_0>
    <volume_type>default</volume_type>
    <hdp>172.17.39.132:/cinder</hdp>
  </svc_0>
  <svc_1>
    <volume_type>silver</volume_type>
    <hdp>172.17.39.133:/cinder</hdp>
  </svc_1>
</config>
"""

HNAS_WRONG_CONF1 = """<?xml version="1.0" encoding="UTF-8" ?>
<config>
  <hnas_cmd>ssc</hnas_cmd>
  <mgmt_ip0>172.17.44.15</mgmt_ip0>
  <username>supervisor</username>
  <password>supervisor</password>
    <volume_type>default</volume_type>
    <hdp>172.17.39.132:/cinder</hdp>
  </svc_0>
</config>
"""

HNAS_WRONG_CONF2 = """<?xml version="1.0" encoding="UTF-8" ?>
<config>
  <hnas_cmd>ssc</hnas_cmd>
  <mgmt_ip0>172.17.44.15</mgmt_ip0>
  <username>supervisor</username>
  <password>supervisor</password>
  <svc_0>
    <volume_type>default</volume_type>
  </svc_0>
  <svc_1>
    <volume_type>silver</volume_type>
  </svc_1>
</config>
"""

# The following information is passed on to tests, when creating a volume
_SERVICE = ('Test_hdp', 'Test_path', 'Test_label')
_SHARE = '172.17.39.132:/cinder'
_SHARE2 = '172.17.39.133:/cinder'
_EXPORT = '/cinder'
_VOLUME = {'name': 'volume-bcc48c61-9691-4e5f-897c-793686093190',
           'volume_id': 'bcc48c61-9691-4e5f-897c-793686093190',
           'size': 128,
           'volume_type': 'silver',
           'volume_type_id': 'test',
           'metadata': [{'key': 'type',
                         'service_label': 'silver'}],
           'provider_location': None,
           'id': 'bcc48c61-9691-4e5f-897c-793686093190',
           'status': 'available',
           'host': 'host1@hnas-iscsi-backend#silver'}
_SNAPVOLUME = {'name': 'snapshot-51dd4-8d8a-4aa9-9176-086c9d89e7fc',
               'id': '51dd4-8d8a-4aa9-9176-086c9d89e7fc',
               'size': 128,
               'volume_type': None,
               'provider_location': None,
               'volume_size': 128,
               'volume_name': 'volume-bcc48c61-9691-4e5f-897c-793686093190',
               'volume_id': 'bcc48c61-9691-4e5f-897c-793686093191',
               'host': 'host1@hnas-iscsi-backend#silver'}

GET_ID_VOL = {
    ("bcc48c61-9691-4e5f-897c-793686093190"): [_VOLUME],
    ("bcc48c61-9691-4e5f-897c-793686093191"): [_SNAPVOLUME]
}

def id_to_vol(arg):
    return GET_ID_VOL.get(arg)

class SimulatedHnasBackend(object):
    """Simulation Back end. Talks to HNAS."""

    # these attributes are shared across object instances
    start_lun = 0

    def __init__(self):
        self.type = 'HNAS'
        self.out = ''

    def file_clone(self, cmd, ip0, user, pw, fslabel, source_path,
                   target_path):
        return ""

    def get_version(self, ver, cmd, ip0, user, pw):
        self.out = "Array_ID: 18-48-A5-A1-80-13 (3080-G2) " \
                   "version: 11.2.3319.09 LU: 256 " \
                   "RG: 0 RG_LU: 0 Utility_version: 11.1.3225.01"
        return self.out

    def get_hdp_info(self, ip0, user, pw):
        self.out = "HDP: 1024  272384 MB    33792 MB  12 %  LUs:   70 " \
                   "Normal  fs1\n" \
                   "HDP: 1025  546816 MB    73728 MB  13 %  LUs:  194 " \
                   "Normal  fs2"
        return self.out

    def get_nfs_info(self, cmd, ip0, user, pw):
        self.out = "Export: /cinder Path: /volumes HDP: fs1 FSID: 1024 " \
                   "EVS: 1 IPS: 172.17.39.132\n" \
                   "Export: /cinder Path: /volumes HDP: fs2 FSID: 1025 " \
                   "EVS: 1 IPS: 172.17.39.133"
        return self.out

class HDSNFSDriverTest(test.TestCase):
    """Test HNAS NFS volume driver."""

    def __init__(self, *args, **kwargs):
        super(HDSNFSDriverTest, self).__init__(*args, **kwargs)

    @mock.patch.object(nfs, 'factory_bend')
    def setUp(self, m_factory_bend):
        super(HDSNFSDriverTest, self).setUp()

        self.backend = SimulatedHnasBackend()
        m_factory_bend.return_value = self.backend

        (handle, self.config_file) = tempfile.mkstemp('.xml')
        os.write(handle, HNASCONF)
        os.close(handle)
        (handle, self.shares_file) = tempfile.mkstemp('')
        os.write(handle, SHARESCONF)
        os.close(handle)

        self.configuration = mock.Mock(spec=conf.Configuration)
        self.configuration.hds_hnas_nfs_config_file = self.config_file
        self.configuration.nfs_shares_config = self.shares_file
        self.configuration.nfs_mount_point_base = '/opt/stack/cinder/mnt'
        self.configuration.nfs_mount_options = None
        self.configuration.nas_ip = None
        self.configuration.nas_share_path = None
        self.configuration.nas_mount_options = None

        self.driver = nfs.HDSNFSDriver(configuration=self.configuration)
        self.driver.do_setup("")
        self.addCleanup(self._clean)

    def _clean(self):
        os.remove(self.config_file)
        os.remove(self.shares_file)

    @mock.patch('__builtin__.open')
    @mock.patch.object(os, 'access')
    def test_read_config(self, m_access, m_open):
        # Test exception when file is not found
        m_access.return_value = False
        m_open.return_value = six.StringIO(HNASCONF)
        self.assertRaises(exception.NotFound, nfs._read_config, '')

        # Test exception when config file has parsing errors
        # due to missing <svc> tag
        m_access.return_value = True
        m_open.return_value = six.StringIO(HNAS_WRONG_CONF1)
        self.assertRaises(exception.ConfigNotFound, nfs._read_config, '')

        # Test exception when config file has parsing errors
        # due to missing <hdp> tag
        m_open.return_value = six.StringIO(HNAS_WRONG_CONF2)
        self.configuration.hds_hnas_iscsi_config_file = ''
        self.assertRaises(exception.ParameterNotFound, nfs._read_config, '')

    @mock.patch.object(nfs.HDSNFSDriver, '_id_to_vol')
    @mock.patch.object(nfs.HDSNFSDriver, '_get_provider_location')
    @mock.patch.object(nfs.HDSNFSDriver, '_get_export_path')
    @mock.patch.object(nfs.HDSNFSDriver, '_get_volume_location')
    def test_create_snapshot(self, m_get_volume_location, m_get_export_path,
                             m_get_provider_location, m_id_to_vol):
        svol = _SNAPVOLUME.copy()
        m_id_to_vol.return_value = svol

        m_get_provider_location.return_value = _SHARE
        m_get_volume_location.return_value = _SHARE
        m_get_export_path.return_value = _EXPORT

        loc = self.driver.create_snapshot(svol)
        out = "{'provider_location': \'" + _SHARE + "'}"
        self.assertEqual(str(loc), out)

    @mock.patch.object(nfs.HDSNFSDriver, '_get_service')
    @mock.patch.object(nfs.HDSNFSDriver, '_id_to_vol', side_effect=id_to_vol)
    @mock.patch.object(nfs.HDSNFSDriver, '_get_provider_location')
    @mock.patch.object(nfs.HDSNFSDriver, '_get_volume_location')
    def test_create_cloned_volume(self, m_get_volume_location,
                                  m_get_provider_location, m_id_to_vol,
                                  m_get_service):
        vol = _VOLUME.copy()
        svol = _SNAPVOLUME.copy()

        m_get_service.return_value = _SERVICE
        m_get_provider_location.return_value = _SHARE
        m_get_volume_location.return_value = _SHARE

        loc = self.driver.create_cloned_volume(vol, svol)

        out = "{'provider_location': \'" + _SHARE + "'}"
        self.assertEqual(str(loc), out)

    @mock.patch.object(nfs.HDSNFSDriver, '_ensure_shares_mounted')
    @mock.patch.object(nfs.HDSNFSDriver, '_do_create_volume')
    @mock.patch.object(nfs.HDSNFSDriver, '_id_to_vol', side_effect=id_to_vol)
    @mock.patch.object(nfs.HDSNFSDriver, '_get_provider_location')
    @mock.patch.object(nfs.HDSNFSDriver, '_get_volume_location')
    def test_create_volume(self, m_get_volume_location,
                           m_get_provider_location, m_id_to_vol,
                           m_do_create_volume, m_ensure_shares_mounted):

        vol = _VOLUME.copy()

        m_get_provider_location.return_value = _SHARE2
        m_get_volume_location.return_value = _SHARE2

        loc = self.driver.create_volume(vol)

        out = "{'provider_location': \'" + _SHARE2 + "'}"
        self.assertEqual(str(loc), out)

    @mock.patch.object(nfs.HDSNFSDriver, '_id_to_vol')
    @mock.patch.object(nfs.HDSNFSDriver, '_get_provider_location')
    @mock.patch.object(nfs.HDSNFSDriver, '_volume_not_present')
    def test_delete_snapshot(self, m_volume_not_present,
                             m_get_provider_location, m_id_to_vol):
        svol = _SNAPVOLUME.copy()

        m_id_to_vol.return_value = svol
        m_get_provider_location.return_value = _SHARE

        m_volume_not_present.return_value = True

        self.driver.delete_snapshot(svol)
        self.assertEqual(svol['provider_location'], None)

    @mock.patch.object(nfs.HDSNFSDriver, '_get_service')
    @mock.patch.object(nfs.HDSNFSDriver, '_id_to_vol', side_effect=id_to_vol)
    @mock.patch.object(nfs.HDSNFSDriver, '_get_provider_location')
    @mock.patch.object(nfs.HDSNFSDriver, '_get_export_path')
    @mock.patch.object(nfs.HDSNFSDriver, '_get_volume_location')
    def test_create_volume_from_snapshot(self, m_get_volume_location,
                                         m_get_export_path,
                                         m_get_provider_location, m_id_to_vol,
                                         m_get_service):
        vol = _VOLUME.copy()
        svol = _SNAPVOLUME.copy()

        m_get_service.return_value = _SERVICE
        m_get_provider_location.return_value = _SHARE
        m_get_export_path.return_value = _EXPORT
        m_get_volume_location.return_value = _SHARE

        loc = self.driver.create_volume_from_snapshot(vol, svol)
        out = "{'provider_location': \'" + _SHARE + "'}"
        self.assertEqual(str(loc), out)

    @mock.patch.object(volume_types, 'get_volume_type_extra_specs',
                       return_value={'key': 'type', 'service_label': 'silver'})
    def test_get_pool(self, m_ext_spec):
        vol = _VOLUME.copy()

        self.assertEqual(self.driver.get_pool(vol), 'silver')

redpajama_set_name: RedPajamaGithub


text:
<tool id="data_manager_manual" name="Manual Data Manager" version="0.0.1" tool_type="manage_data">
    <options sanitize="False" />
    <description>Entry Builder</description>
    <command detect_errors="exit_code"><![CDATA[
        python '$__tool_directory__/data_manager_manual.py'
        '${out_file}'
        --galaxy_data_manager_data_path '${__app__.config.galaxy_data_manager_data_path}'
    ]]></command>
    <inputs>
        <repeat name="data_tables" title="Data Table to define" min="1">
            <param name="data_table_name" type="select" multiple="False" optional="False" label="Choose Desired Data Table"
                dynamic_options="galaxy_code_get_available_data_tables( __trans__ )" refresh_on_change="True"/>
        <repeat name="columns" title="Table Columns" min="1">
            <param name="data_table_column_name" type="select" multiple="False" optional="False" label="Column Name"
                dynamic_options="galaxy_code_get_available_data_table_columns( __trans__, data_table_name )" />
            <!-- <param name="data_table_column_name" type="text" label="Column Name"/> -->
            <param name="data_table_column_value" type="text" label="Value to use for data table column"/>
            <conditional name="is_path">
                <param name="is_path_selector" type="select" label="Value is a path">
                    <option value="yes">Yes</option>
                    <option value="no" selected="True">No</option>
                </param>
                <when value="yes">
                    <param name="abspath" type="boolean" label="Apply abspath" checked="True" truevalue="abspath" falsevalue="" />
                </when>
                <when value="no"/>
            </conditional>
        </repeat>
        </repeat>
        <repeat name="directory_content" title="Directory Content">
            <param name="subdir" type="text" label="Place in Subdirectory" value=""/>
            <conditional name="file_source">
                <param name="file_source_selector" type="select" label="File Content Source">
                    <option value="history">History Item</option>
                    <option value="URL" selected="True">URL</option>
                </param>
                <when value="history">
                    <param name="file_history" type="data" multiple="false" optional="false" format="data" label="File from history" />
                </when>
                <when value="URL">
                    <param name="file_URL" type="text" label="Fetch from URL" value=""/>
                </when>
            </conditional>
            <conditional name="file_action">
                <param name="file_action_selector" type="select" label="File Actions">
                    <option value="unpack">Extract Archive</option>
                    <option value="None" selected="True">None</option>
                </param>
                <when value="None">
                    <param name="filename_override" type="text" label="Override with Filename" value=""/>
                </when>
                <when value="unpack">
                </when>
            </conditional>
        </repeat>
    </inputs>
    <outputs>
        <data name="out_file" format="data_manager_json" dbkey="dbkey"/>
    </outputs>
    <tests>
    </tests>
    <help>
**What it does**

This tool allows manually specifying data table entries and optionally providing filesystem contents.

    </help>
    <code file="data_manager_manual.py" />
</tool>


text:
var winston = require('winston');
var util = require('util');
var extend = require('node.extend');
var config = require('./config').get('logger');

function capitalize (str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
}

var DEFAULT_CONFIG = {
    timestamp: function () {
        return new Date().toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, '$1');
    }
};

var logger = new winston.Logger({
    transports: Object.keys(config).map(function (key) {
        return new winston.transports[capitalize(key)](extend(true, {}, DEFAULT_CONFIG, config[key]));
    })
});

[
    'silly',
    'input',
    'verbose',
    'prompt',
    'info',
    'data',
    'help',
    'warn',
    'debug',
    'error'
].forEach(function (level) {
    exports[level] = function () {
        logger.log(level, util.format.apply(util, arguments));
    };
});


text:
#pragma once

#include <odp.h>
#include "typedefs.h"

/**
 * @brief Neighbor Solicitation.
 * @param  pkt     the packet
 * @param  thr     the thread-local struct
 */
void fstn_nd6_neighbor_solicitation_receive(odp_packet_t pkt, thr_s* thr);

/**
 * @brief Neighbor Advertisemnt.
 * @param  pkt     the packet
 * @param  thr     the thread-local struct
 */
void fstn_nd6_neighbor_advertisement_receive(odp_packet_t pkt, thr_s* thr);

/**
 * @brief Router Advertisemnt.
 * @param  pkt     the packet
 * @param  thr     the thread-local struct
 */
void fstn_nd6_router_advertisement_receive(odp_packet_t pkt, thr_s* thr);

/**
 * @brief Redirect.
 * @param  pkt     the packet
 * @param  thr     the thread-local struct
 */
void fstn_nd6_redirect_receive(odp_packet_t pkt, thr_s* thr);