//***************************************************************************** // Open a metadata section for read //***************************************************************************** __checkReturn HRESULT CLiteWeightStgdbRW::OpenForRead( LPCWSTR szDatabase, // Name of database. void *pbData, // Data to open on top of, 0 default. ULONG cbData, // How big is the data. DWORD dwFlags) // Flags for the open. { LPCWSTR pNoFile=W(""); // Constant for empty file name. StgIO *pStgIO = NULL; // For file i/o. HRESULT hr; m_pImage = NULL; m_dwImageSize = 0; m_eFileType = FILETYPE_UNKNOWN; // szDatabase, and pbData are mutually exclusive. Only one may be // non-NULL. Having both NULL means empty stream creation. // _ASSERTE(!(szDatabase && (pbData))); _ASSERTE(!(pbData && (szDatabase))); // Open on memory needs there to be something to work with. if (pbData && cbData == 0) IfFailGo(CLDB_E_NO_DATA); // Make sure we have a path to work with. if (!szDatabase) szDatabase = pNoFile; // Sanity check the name lentgh. if (!IsValidFileNameLength(szDatabase)) { IfFailGo(E_INVALIDARG); } // If we have storage to work with, init it and get type. if (*szDatabase || pbData) { // Allocate a storage instance to use for i/o. if ((pStgIO = new (nothrow) StgIO) == 0) IfFailGo( E_OUTOFMEMORY ); DBPROPMODE dmOpenFlags = DBPROP_TMODEF_READ; // If we're taking ownership of this memory..... if (IsOfTakeOwnership(dwFlags)) { #ifdef FEATURE_METADATA_STANDALONE_WINRT_RO // Shared memory uses ole32.dll - we cannot depend on it in the standalone WinRT Read-Only DLL IfFailGo(E_INVALIDARG); #else dmOpenFlags = (DBPROPMODE)(dmOpenFlags | DBPROP_TMODEF_SHAREDMEM); #endif //!FEATURE_METADATA_STANDALONE_WINRT_RO } #ifdef FEATURE_METADATA_LOAD_TRUSTED_IMAGES if (IsOfTrustedImage(dwFlags)) dmOpenFlags = (DBPROPMODE)(dmOpenFlags | DBPROP_TMODEF_TRYLOADLIBRARY); #endif // Open the storage so we can read the signature if there is already data. IfFailGo( pStgIO->Open(szDatabase, dmOpenFlags, pbData, cbData, 0, // IStream* NULL) ); // Determine the type of file we are working with. IfFailGo( _GetFileTypeForPath(pStgIO, &m_eFileType) ); } // Check for default type. if (m_eFileType == FILETYPE_CLB) { // If user wanted us to make a local copy of the data, do that now. if (IsOfCopyMemory(dwFlags)) IfFailGo(pStgIO->LoadFileToMemory()); // Try the native .clb file. IfFailGo( InitFileForRead(pStgIO, IsOfRead(dwFlags)) ); } // PE/COFF executable/object format. This requires us to find the .clb // inside the binary before doing the Init. else if (m_eFileType == FILETYPE_NTPE || m_eFileType == FILETYPE_NTOBJ) { //<TODO>@FUTURE: Ideally the FindImageMetaData function //@FUTURE: would take the pStgIO and map only the part of the file where //@FUTURE: our data lives, leaving the rest alone. This would be smaller //@FUTURE: working set for us.</TODO> void *ptr; ULONG cbSize; // Map the entire binary for the FindImageMetaData function. IfFailGo( pStgIO->MapFileToMem(ptr, &cbSize) ); // Find the .clb inside of the content. if (m_eFileType == FILETYPE_NTPE) { m_pImage = ptr; m_dwImageSize = cbSize; hr = FindImageMetaData(ptr, cbSize, pStgIO->GetMemoryMappedType() == MTYPE_IMAGE, &ptr, &cbSize); } else { _ASSERTE(pStgIO->GetMemoryMappedType() != MTYPE_IMAGE); hr = FindObjMetaData(ptr, cbSize, &ptr, &cbSize); } // Was the metadata found inside the PE file? if (FAILED(hr)) { if (hr == E_OUTOFMEMORY) IfFailGo(E_OUTOFMEMORY); // No clb in the PE, assume it is a type library. m_eFileType = FILETYPE_TLB; // Let the caller deal with a TypeLib. IfFailGo(hr); } else { // Metadata was found inside the file. // Now reset the base of the stg object so that all memory accesses // are relative to the .clb content. // IfFailGo( pStgIO->SetBaseRange(ptr, cbSize) ); // If user wanted us to make a local copy of the data, do that now. if (IsOfCopyMemory(dwFlags)) { // Cache the PEKind, Machine. GetPEKind(pStgIO->GetMemoryMappedType(), NULL, NULL); // Copy the file into memory; releases the file. IfFailGo(pStgIO->LoadFileToMemory()); // No longer have the image. m_pImage = NULL; m_dwImageSize = 0; } // Defer to the normal lookup. IfFailGo( InitFileForRead(pStgIO, IsOfRead(dwFlags)) ); } } else if (m_eFileType == FILETYPE_TLB) { // Let the caller deal with a TypeLib. IfFailGo(CLDB_E_NO_DATA); } // This spells trouble, we need to handle all types we might find. else { _ASSERTE(!"Unknown file type."); IfFailGo( E_FAIL ); } // Save off everything. IfFailGo(SetFileName(szDatabase)); // If this was a file... if (pbData == NULL) { WIN32_FILE_ATTRIBUTE_DATA faData; if (!WszGetFileAttributesEx(szDatabase, GetFileExInfoStandard, &faData)) IfFailGo(E_FAIL); m_dwDatabaseLFS = faData.nFileSizeLow; m_dwDatabaseLFT = faData.ftLastWriteTime.dwLowDateTime; } ErrExit: if (SUCCEEDED(hr)) { m_pStgIO = pStgIO; } else { if (pStgIO != NULL) pStgIO->Release(); } return hr; }
//***************************************************************************** // Search the cached RegMetas for a given scope. //***************************************************************************** HRESULT LOADEDMODULES::FindCachedReadOnlyEntry( LPCWSTR szName, // Name of the desired file. DWORD dwOpenFlags, // Flags the new file is opened with. RegMeta ** ppMeta) // Put found RegMeta here. { RegMeta * pRegMeta = 0; BOOL bWillBeCopyMemory; // Will the opened file be copied to memory? DWORD dwLowFileSize; // Low bytes of this file's size DWORD dwLowFileTime; // Low butes of this file's last write time HRESULT hr; ULONG ixHash = 0; IfFailGo(InitializeStatics()); { LOCKREAD(); hr = S_FALSE; // We haven't found a match yet. // Avoid confusion. *ppMeta = NULL; bWillBeCopyMemory = IsOfCopyMemory(dwOpenFlags); // The cache is locked for read, so the list will not change. // Figure out the size and timestamp of this file WIN32_FILE_ATTRIBUTE_DATA faData; if (!WszGetFileAttributesEx(szName, GetFileExInfoStandard, &faData)) return E_FAIL; dwLowFileSize = faData.nFileSizeLow; dwLowFileTime = faData.ftLastWriteTime.dwLowDateTime; // Check the hash first. ixHash = HashFileName(szName); if ((pRegMeta = m_HashedModules[ixHash]) != NULL) { _ASSERTE(pRegMeta->IsReadOnly()); // Only match if the IsOfCopyMemory() bit is the same in both. This is because // when ofCopyMemory is set, the file is not locked on disk, and may become stale // in memory. // // Also, only match if the date and size are the same if (pRegMeta->IsCopyMemory() == bWillBeCopyMemory && pRegMeta->GetLowFileTimeOfDBFile() == dwLowFileTime && pRegMeta->GetLowFileSizeOfDBFile() == dwLowFileSize) { // If the name matches... LPCWSTR pszName = pRegMeta->GetNameOfDBFile(); #ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM if (wcscmp(szName, pszName) == 0) #else if (SString::_wcsicmp(szName, pszName) == 0) #endif { ULONG cRefs; // Found it. Add a reference, and return it. *ppMeta = pRegMeta; cRefs = pRegMeta->AddRef(); LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope found cached RegMeta in hash: %#8x, crefs: %d\n", pRegMeta, cRefs)); return S_OK; } } } // Not found in hash; loop through each loaded modules int count = s_pLoadedModules->Count(); for (int index = 0; index < count; index++) { pRegMeta = (*s_pLoadedModules)[index]; // If the module is read-only, and the CopyMemory bit matches, and the date // and size are the same.... if (pRegMeta->IsReadOnly() && pRegMeta->IsCopyMemory() == bWillBeCopyMemory && pRegMeta->GetLowFileTimeOfDBFile() == dwLowFileTime && pRegMeta->GetLowFileSizeOfDBFile() == dwLowFileSize) { // If the name matches... LPCWSTR pszName = pRegMeta->GetNameOfDBFile(); #ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM if (wcscmp(szName, pszName) == 0) #else if (SString::_wcsicmp(szName, pszName) == 0) #endif { ULONG cRefs; // Found it. Add a reference, and return it. *ppMeta = pRegMeta; cRefs = pRegMeta->AddRef(); // Update the hash. m_HashedModules[ixHash] = pRegMeta; LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope found cached RegMeta by search: %#8x, crefs: %d\n", pRegMeta, cRefs)); return S_OK; } } } } ErrExit: // Didn't find it. LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope did not find cached RegMeta\n")); _ASSERTE(hr != S_OK); return hr; } // LOADEDMODULES::FindCachedReadOnlyEntry