//***************************************************************************** // Save the data to a stream. A TiggerStorage sub-allocates streams within // the stream. //***************************************************************************** __checkReturn HRESULT CLiteWeightStgdbRW::SaveToStream( IStream *pIStream, MetaDataReorderingOptions reorderingOptions, CorProfileData *pProfileData) { HRESULT hr = S_OK; // A result. StgIO *pStgIO = 0; TiggerStorage *pStorage = 0; // Allocate a storage subsystem and backing store. IfNullGo(pStgIO = new (nothrow) StgIO); IfNullGo(pStorage = new (nothrow) TiggerStorage); // Open around this stream for write. IfFailGo(pStgIO->Open(W(""), DBPROP_TMODEF_DFTWRITEMASK, 0, 0, // pbData, cbData pIStream, 0)); // LPSecurityAttributes OptionValue ov; IfFailGo(m_MiniMd.GetOption(&ov)); IfFailGo(pStorage->Init(pStgIO, ov.m_RuntimeVersion)); // Save worker will do tables, pools. IfFailGo(SaveToStorage(pStorage, reorderingOptions, pProfileData)); ErrExit: if (pStgIO != NULL) pStgIO->Release(); if (pStorage != NULL) delete pStorage; return hr; } // CLiteWeightStgdbRW::SaveToStream
//***************************************************************************** // Save the metadata to a file. //***************************************************************************** HRESULT CLiteWeightStgdbRW::Save( // S_OK or error. LPCWSTR szDatabase, // Name of file to which to save. DWORD dwSaveFlags) // Flags for the save. { TiggerStorage *pStorage=0; // IStorage object. StgIO *pStgIO=0; // Backing storage. HRESULT hr = S_OK; if (!*m_rcDatabase) { if (!szDatabase) { // Make sure that a NULL is not passed in the first time around. _ASSERTE(!"Not allowed to pass a NULL for filename on the first call to Save."); return (E_INVALIDARG); } else { // Save the file name. wcscpy(m_rcDatabase, szDatabase); } } else if (szDatabase && _wcsicmp(szDatabase, m_rcDatabase) != 0) { // Allow for same name, case of multiple saves during session. // Changing the name on a scope which is already opened is not allowed. // Save the file name. wcscpy(m_rcDatabase, szDatabase); } // Sanity check the name. if (lstrlenW(m_rcDatabase) >= _MAX_PATH) IfFailGo(E_INVALIDARG); m_eFileType = FILETYPE_CLB; // Allocate a new storage object. IfNullGo(pStgIO = new StgIO); // Create the output file. IfFailGo(pStgIO->Open(m_rcDatabase, DBPROP_TMODEF_DFTWRITEMASK)); // Allocate an IStorage object to use. IfNullGo(pStorage = new TiggerStorage); // Init the storage object on the i/o system. OptionValue ov; m_MiniMd.GetOption(&ov); IfFailGo( pStorage->Init(pStgIO, ov.m_RuntimeVersion) ); // Save the data. IfFailGo(SaveToStorage(pStorage)); ErrExit: if (pStgIO) pStgIO->Release(); if (pStorage) delete pStorage; return (hr); } // HRESULT CLiteWeightStgdbRW::Save()
//***************************************************************************** // Save the data to a stream. A TiggerStorage sub-allocates streams within // the stream. //***************************************************************************** HRESULT CLiteWeightStgdbRW::SaveToStream( IStream *pIStream) { HRESULT hr = S_OK; // A result. StgIO *pStgIO = 0; TiggerStorage *pStorage = 0; // Allocate a storage subsystem and backing store. IfNullGo(pStgIO = new StgIO); IfNullGo(pStorage = new TiggerStorage); // Open around this stream for write. IfFailGo(pStgIO->Open(L"", DBPROP_TMODEF_DFTWRITEMASK, 0, 0, pIStream)); OptionValue ov; m_MiniMd.GetOption(&ov); IfFailGo( pStorage->Init(pStgIO, ov.m_RuntimeVersion) ); // Save worker will do tables, pools. IfFailGo(SaveToStorage(pStorage)); ErrExit: if (pStgIO) pStgIO->Release(); if (pStorage) delete pStorage; return hr; } // HRESULT CLiteWeightStgdbRW::PersistToStream()
HRESULT RegMeta::OpenExistingMD( IMDCustomDataSource* pDataSource, // Name of database. ULONG dwOpenFlags) // Flags to control open. { HRESULT hr = NOERROR; m_OpenFlags = dwOpenFlags; if (!IsOfReOpen(dwOpenFlags)) { // Allocate our m_pStgdb, if we should. _ASSERTE(m_pStgdb == NULL); IfNullGo(m_pStgdb = new (nothrow)CLiteWeightStgdbRW); } IfFailGo(m_pStgdb->OpenForRead( pDataSource, m_OpenFlags)); if (m_pStgdb->m_MiniMd.m_Schema.m_major == METAMODEL_MAJOR_VER_V1_0 && m_pStgdb->m_MiniMd.m_Schema.m_minor == METAMODEL_MINOR_VER_V1_0) m_OptionValue.m_MetadataVersion = MDVersion1; else m_OptionValue.m_MetadataVersion = MDVersion2; IfFailGo(m_pStgdb->m_MiniMd.SetOption(&m_OptionValue)); if (IsThreadSafetyOn()) { m_pSemReadWrite = new (nothrow)UTSemReadWrite(); IfNullGo(m_pSemReadWrite); IfFailGo(m_pSemReadWrite->Init()); m_fOwnSem = true; INDEBUG(m_pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);) } if (!IsOfReOpen(dwOpenFlags)) { #ifdef FEATURE_METADATA_EMIT_ALL // initialize the embedded merger m_newMerger.Init(this); #endif //FEATURE_METADATA_EMIT_ALL // There must always be a Global Module class and its the first entry in // the TypeDef table. m_tdModule = TokenFromRid(1, mdtTypeDef); } ErrExit: return hr; } //RegMeta::OpenExistingMD
//***************************************************************************** // call stgdb InitNew //***************************************************************************** __checkReturn HRESULT RegMeta::CreateNewMD() { HRESULT hr = NOERROR; m_OpenFlags = ofWrite; // Allocate our m_pStgdb. _ASSERTE(m_pStgdb == NULL); IfNullGo(m_pStgdb = new (nothrow) CLiteWeightStgdbRW); // Initialize the new, empty database. // First tell the new database what sort of metadata to create m_pStgdb->m_MiniMd.m_OptionValue.m_MetadataVersion = m_OptionValue.m_MetadataVersion; m_pStgdb->m_MiniMd.m_OptionValue.m_InitialSize = m_OptionValue.m_InitialSize; IfFailGo(m_pStgdb->InitNew()); // Set up the Module record. ULONG iRecord; ModuleRec *pModule; GUID mvid; IfFailGo(m_pStgdb->m_MiniMd.AddModuleRecord(&pModule, &iRecord)); IfFailGo(CoCreateGuid(&mvid)); IfFailGo(m_pStgdb->m_MiniMd.PutGuid(TBL_Module, ModuleRec::COL_Mvid, pModule, mvid)); // Add the dummy module typedef which we are using to parent global items. TypeDefRec *pRecord; IfFailGo(m_pStgdb->m_MiniMd.AddTypeDefRecord(&pRecord, &iRecord)); m_tdModule = TokenFromRid(iRecord, mdtTypeDef); IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_TypeDef, TypeDefRec::COL_Name, pRecord, COR_WMODULE_CLASS)); IfFailGo(m_pStgdb->m_MiniMd.SetOption(&m_OptionValue)); if (IsThreadSafetyOn()) { m_pSemReadWrite = new (nothrow) UTSemReadWrite(); IfNullGo(m_pSemReadWrite); IfFailGo(m_pSemReadWrite->Init()); m_fOwnSem = true; INDEBUG(m_pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);) } #ifdef FEATURE_METADATA_EMIT_ALL // initialize the embedded merger m_newMerger.Init(this); #endif //FEATURE_METADATA_EMIT_ALL ErrExit: return hr; } // RegMeta::CreateNewMD
//======================================================================================= // // Set file name of this database (makes copy of the file name). // // Return value: S_OK or E_OUTOFMEMORY // __checkReturn HRESULT CLiteWeightStgdbRW::SetFileName( const WCHAR * wszFileName) { HRESULT hr = S_OK; if (m_wszFileName != NULL) { delete [] m_wszFileName; m_wszFileName = NULL; } if ((wszFileName == NULL) || (*wszFileName == 0)) { // The new file name is empty _ASSERTE(m_wszFileName == NULL); // No need to allocate anything, NULL means empty name hr = S_OK; goto ErrExit; } // Size of the file name incl. null terminator size_t cchFileName; cchFileName = wcslen(wszFileName) + 1; // Allocate and copy the file name m_wszFileName = new (nothrow) WCHAR[cchFileName]; IfNullGo(m_wszFileName); wcscpy_s(m_wszFileName, cchFileName, wszFileName); ErrExit: return hr; } // CLiteWeightStgdbRW::SetFileName
STDMETHODIMP CCeeGen::AllocateMethodBuffer(ULONG cchBuffer, UCHAR **lpBuffer, ULONG *RVA) { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; ULONG methodOffset = 0; if (! cchBuffer) IfFailGo(E_INVALIDARG); if (! lpBuffer || ! RVA) IfFailGo(E_POINTER); *lpBuffer = (UCHAR*) getIlSection().getBlock(cchBuffer, 4); // Dword align IfNullGo(*lpBuffer); // have to compute the method offset after getting the block, not // before (since alignment might shift it up // for in-memory, just return address and will calc later methodOffset = getIlSection().dataLen() - cchBuffer; *RVA = methodOffset; ErrExit: END_ENTRYPOINT_NOTHROW; return hr; }
HRESULT CConnectProxy::FinalConstruct() { HRESULT hr = S_OK; IUnknown* pUnkThis = NULL; // Instantiate the CLR-loader object. m_pCLRLoader = new (std::nothrow) CCLRLoader(); IfNullGo( m_pCLRLoader ); IfFailGo( this->QueryInterface(IID_IUnknown, (LPVOID*)&pUnkThis) ); // Load the CLR, create an AppDomain, and instantiate the target add-in // and the inner aggregated object of the shim. IfFailGo( m_pCLRLoader->CreateAggregatedAddIn( pUnkThis, szAddInAssemblyName, szConnectClassName, szAssemblyConfigName) ); // Extract the IDTExtensibility2 interface pointer from the target add-in. IfFailGo( m_pUnknownInner->QueryInterface( __uuidof(IDTExtensibility2), (LPVOID*)&this->m_pConnect) ); Error: if (pUnkThis != NULL) pUnkThis->Release(); return hr; }
//***************************************************************************** // Add a RegMeta pointer to the loaded module list //***************************************************************************** HRESULT LOADEDMODULES::AddModuleToLoadedList(RegMeta * pRegMeta) { HRESULT hr = NOERROR; RegMeta ** ppRegMeta; IfFailGo(InitializeStatics()); { LOCKWRITE(); ppRegMeta = s_pLoadedModules->Append(); IfNullGo(ppRegMeta); // The cache holds a copy of the pointer, but no ref-count. There is no // point to the ref-count, because it just changes comparisons against 0 // to comparisons against 1. *ppRegMeta = pRegMeta; // If the module is read-only, hash it. if (pRegMeta->IsReadOnly()) { ULONG ixHash = HashFileName(pRegMeta->GetNameOfDBFile()); m_HashedModules[ixHash] = pRegMeta; } } ErrExit: return hr; } // LOADEDMODULES::AddModuleToLoadedList
//***************************************************************************** // Called by the meta data engine when a token is remapped to a new location. // This value is recorded in the m_rgMap array based on type and rid of the // from token value. //***************************************************************************** HRESULT STDMETHODCALLTYPE CeeGenTokenMapper::Map( mdToken tkFrom, mdToken tkTo) { HRESULT hr = S_OK; mdToken *pToken = NULL; ULONG ridFrom = 0; TOKENMAP *pMap = NULL; BEGIN_ENTRYPOINT_NOTHROW; if ( IndexForType(tkFrom) == -1 ) { // It is a type that we are not tracking, such as mdtProperty or mdtEvent, // just return S_OK. goto ErrExit; } _ASSERTE(IndexForType(tkFrom) < GetMaxMapSize()); _ASSERTE(IndexForType(tkTo) != -1 && IndexForType(tkTo) < GetMaxMapSize()); // If there is another token mapper that the user wants called, go // ahead and call it now. if (m_pIMapToken) m_pIMapToken->Map(tkFrom, tkTo); ridFrom = RidFromToken(tkFrom); pMap = &m_rgMap[IndexForType(tkFrom)]; // If there isn't enough entries, fill out array up to the count // and mark the token to nil so we know there is no valid data yet. if ((ULONG) pMap->Count() <= ridFrom) { for (int i=ridFrom - pMap->Count() + 1; i; i--) { pToken = pMap->Append(); if (!pToken) break; *pToken = mdTokenNil; } _ASSERTE(!pToken || pMap->Get(ridFrom) == pToken); } else pToken = pMap->Get(ridFrom); IfNullGo(pToken); *pToken = tkTo; ErrExit: END_ENTRYPOINT_NOTHROW; return hr; }
//***************************************************************************** // Add a RegMeta pointer to the loaded module list //***************************************************************************** HRESULT LOADEDMODULES::AddModuleToLoadedList(RegMeta *pRegMeta) { HRESULT hr = NOERROR; RegMeta **ppRegMeta; LOCKWRITE(); // create the dynamic array if it is not created yet. if (g_LoadedModules == NULL) { g_LoadedModules = new LOADEDMODULES; IfNullGo(g_LoadedModules); } ppRegMeta = g_LoadedModules->Append(); IfNullGo(ppRegMeta); *ppRegMeta = pRegMeta; ErrExit: return hr; } // LOADEDMODULES::AddModuleToLoadedList
//***************************************************************************** // Apply a delta record to a table, generically. //***************************************************************************** __checkReturn HRESULT CMiniMdRW::ApplyTableDelta( CMiniMdRW &mdDelta, // Interface to MD with the ENC delta. ULONG ixTbl, // Table index to update. RID iRid, // RID of the changed item. int fc) // Function code of update. { HRESULT hr = S_OK; void *pRec; // Record in existing MetaData. void *pDeltaRec; // Record if Delta MetaData. RID newRid; // Rid of new record. // Get the delta record. IfFailGo(mdDelta.GetDeltaRecord(ixTbl, iRid, &pDeltaRec)); // Get the record from the base metadata. if (iRid > m_Schema.m_cRecs[ixTbl]) { // Added record. Each addition is the next one. _ASSERTE(iRid == m_Schema.m_cRecs[ixTbl] + 1); switch (ixTbl) { case TBL_TypeDef: IfFailGo(AddTypeDefRecord(reinterpret_cast<TypeDefRec **>(&pRec), &newRid)); break; case TBL_Method: IfFailGo(AddMethodRecord(reinterpret_cast<MethodRec **>(&pRec), &newRid)); break; case TBL_EventMap: IfFailGo(AddEventMapRecord(reinterpret_cast<EventMapRec **>(&pRec), &newRid)); break; case TBL_PropertyMap: IfFailGo(AddPropertyMapRecord(reinterpret_cast<PropertyMapRec **>(&pRec), &newRid)); break; default: IfFailGo(AddRecord(ixTbl, &pRec, &newRid)); break; } IfNullGo(pRec); _ASSERTE(iRid == newRid); } else { // Updated record. IfFailGo(getRow(ixTbl, iRid, &pRec)); } // Copy the record info. IfFailGo(ApplyRecordDelta(mdDelta, ixTbl, pDeltaRec, pRec)); ErrExit: return hr; } // CMiniMdRW::ApplyTableDelta
//***************************************************************************** // Determine what the size of the saved data will be. //***************************************************************************** HRESULT CLiteWeightStgdbRW::GetSaveSize(// S_OK or error. CorSaveSize fSave, // Quick or accurate? ULONG *pulSaveSize) // Put the size here. { HRESULT hr = S_OK; // A result. ULONG cbTotal = 0; // The total size. ULONG cbSize = 0; // Size of a component. m_cbSaveSize = 0; // Allocate stream list if not already done. if (!m_pStreamList) IfNullGo(m_pStreamList = new STORAGESTREAMLST); else m_pStreamList->Clear(); // Query the MiniMd for its size. IfFailGo(GetTablesSaveSize(fSave, &cbSize)); cbTotal += cbSize; // Get the pools' sizes. IfFailGo(GetPoolSaveSize(STRING_POOL_STREAM, MDPoolStrings, &cbSize)); cbTotal += cbSize; IfFailGo(GetPoolSaveSize(US_BLOB_POOL_STREAM, MDPoolUSBlobs, &cbSize)); cbTotal += cbSize; IfFailGo(GetPoolSaveSize(GUID_POOL_STREAM, MDPoolGuids, &cbSize)); cbTotal += cbSize; IfFailGo(GetPoolSaveSize(BLOB_POOL_STREAM, MDPoolBlobs, &cbSize)); cbTotal += cbSize; // Finally, ask the storage system to add fixed overhead it needs for the // file format. The overhead of each stream has already be calculated as // part of GetStreamSaveSize. What's left is the signature and header // fixed size overhead. IfFailGo(TiggerStorage::GetStorageSaveSize(&cbTotal, 0)); // Log the size info. LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize total is %d.\n", cbTotal)); // The list of streams that will be saved are now in the stream save list. // Next step is to walk that list and fill out the correct offsets. This is // done here so that the data can be streamed without fixing up the header. TiggerStorage::CalcOffsets(m_pStreamList, 0); if (pulSaveSize) *pulSaveSize = cbTotal; m_cbSaveSize = cbTotal; ErrExit: return hr; } // HRESULT CLiteWeightStgdbRW::GetSaveSize()
//--------------------------------------------------------------------------------------- // // Initialize the static instance and lock. // HRESULT LOADEDMODULES::InitializeStatics() { HRESULT hr = S_OK; if (VolatileLoad(&s_pLoadedModules) == NULL) { // Initialize global read-write lock { NewHolder<UTSemReadWrite> pSemReadWrite = new (nothrow) UTSemReadWrite(); IfNullGo(pSemReadWrite); IfFailGo(pSemReadWrite->Init()); if (InterlockedCompareExchangeT<UTSemReadWrite *>(&m_pSemReadWrite, pSemReadWrite, NULL) == NULL) { // We won the initialization race pSemReadWrite.SuppressRelease(); } } // Initialize the global instance { NewHolder<LOADEDMODULES> pLoadedModules = new (nothrow) LOADEDMODULES(); IfNullGo(pLoadedModules); { LOCKWRITE(); if (VolatileLoad(&s_pLoadedModules) == NULL) { VolatileStore(&s_pLoadedModules, pLoadedModules.Extract()); } } } } ErrExit: return hr; } // LOADEDMODULES::InitializeStatics
//***************************************************************************** //***************************************************************************** __checkReturn HRESULT CMiniMdRW::StartENCMap() // S_OK or error. { HRESULT hr = S_OK; ULONG iENC; // Loop control. ULONG ixTbl; // A table. int ixTblPrev = -1; // Table previously seen. _ASSERTE(m_rENCRecs == 0); if (m_Schema.m_cRecs[TBL_ENCMap] == 0) return S_OK; // Build an array of pointers into the ENCMap table for fast access to the ENCMap // for each table. m_rENCRecs = new (nothrow) ULONGARRAY; IfNullGo(m_rENCRecs); if (!m_rENCRecs->AllocateBlock(TBL_COUNT)) IfFailGo(E_OUTOFMEMORY); for (iENC = 1; iENC <= m_Schema.m_cRecs[TBL_ENCMap]; ++iENC) { ENCMapRec *pMap; IfFailGo(GetENCMapRecord(iENC, &pMap)); ixTbl = TblFromRecId(pMap->GetToken()); _ASSERTE((int)ixTbl >= ixTblPrev); _ASSERTE(ixTbl < TBL_COUNT); _ASSERTE(ixTbl != TBL_ENCMap); _ASSERTE(ixTbl != TBL_ENCLog); if ((int)ixTbl == ixTblPrev) continue; // Catch up on any skipped tables. while (ixTblPrev < (int)ixTbl) { (*m_rENCRecs)[++ixTblPrev] = iENC; } } while (ixTblPrev < TBL_COUNT-1) { (*m_rENCRecs)[++ixTblPrev] = iENC; } ErrExit: return hr; } // CMiniMdRW::StartENCMap
//***************************************************************************** // Add a stream, and its size, to the list of streams to be saved. //***************************************************************************** HRESULT CLiteWeightStgdbRW::AddStreamToList( ULONG cbSize, LPCWSTR szName) { HRESULT hr = S_OK; PSTORAGESTREAM pItem; // New item to allocate & fill. // Add a new item to the end of the list. IfNullGo(pItem = m_pStreamList->Append()); // Fill out the data. pItem->SetOffset(0); pItem->SetSize(cbSize); pItem->SetName(szName); ErrExit: return hr; }
//************************************************************* // // Open the file with anme wzModule and check to see if there is a type // with namespace/class of wzNamespace/wzType. If so, return the RegMeta // corresponding to the file and the mdTypeDef of the typedef // //************************************************************* HRESULT CORPATHService::FindTypeDef( __in __in_z LPWSTR wzModule, // name of the module that we are going to open mdTypeRef tr, // TypeRef to resolve. IMetaModelCommon * pCommon, // Scope in which the TypeRef is defined. REFIID riid, IUnknown ** ppIScope, mdTypeDef * ptd) // [OUT] the type that we resolve to { HRESULT hr = NOERROR; NewHolder<Disp> pDisp; ReleaseHolder<IMetaDataImport2> pImport = NULL; CQuickArray<mdTypeRef> cqaNesters; CQuickArray<LPCUTF8> cqaNesterNamespaces; CQuickArray<LPCUTF8> cqaNesterNames; RegMeta * pRegMeta; _ASSERTE((ppIScope != NULL) && (ptd != NULL)); *ppIScope = NULL; pDisp = new (nothrow) Disp; IfNullGo(pDisp); IfFailGo(pDisp->OpenScope(wzModule, 0, IID_IMetaDataImport2, (IUnknown **)&pImport)); pRegMeta = static_cast<RegMeta *>(pImport.GetValue()); // Get the Nesting hierarchy. IfFailGo(ImportHelper::GetNesterHierarchy(pCommon, tr, cqaNesters, cqaNesterNamespaces, cqaNesterNames)); hr = ImportHelper::FindNestedTypeDef( pRegMeta->GetMiniMd(), cqaNesterNamespaces, cqaNesterNames, mdTokenNil, ptd); if (SUCCEEDED(hr)) { *ppIScope = pImport.Extract(); } ErrExit: return hr; } // CORPATHService::FindTypeDef
//***************************************************************************** // Called to read the data into allocated memory and release the backing store. // Only available on read-only data. //***************************************************************************** HRESULT StgIO::LoadFileToMemory() { HRESULT hr; void *pData; // Allocated buffer for file. ULONG cbData; // Size of the data. ULONG cbRead = 0; // Data actually read. // Make sure it is a read-only file. if (m_fFlags & DBPROP_TMODEF_WRITE) return E_INVALIDARG; // Try to allocate the buffer. cbData = m_cbData; pData = AllocateMemory(cbData); IfNullGo(pData); // Try to read the file into the buffer. IfFailGo(Read(pData, cbData, &cbRead)); if (cbData != cbRead) { _ASSERTE_MSG(FALSE, "Read didn't succeed."); IfFailGo(CLDB_E_FILE_CORRUPT); } // Done with the old data. Close(); // Open with new data. hr = Open(NULL /* szName */, STGIO_READ, pData, cbData, NULL /* IStream* */, NULL /* lpSecurityAttributes */); _ASSERTE(SUCCEEDED(hr)); // should not be a failure code path with open on buffer. // Mark the new memory so that it will be freed later. m_pBaseData = m_pData; m_bFreeMem = true; ErrExit: if (FAILED(hr) && pData) FreeMemory(pData); return hr; } // StgIO::LoadFileToMemory
//***************************************************************************** // Add a stream, and its size, to the list of streams to be saved. //***************************************************************************** HRESULT CLiteWeightStgdbRW::AddStreamToList( ULONG cbSize, LPCWSTR szName) { HRESULT hr = S_OK; STORAGESTREAM *pItem; // New item to allocate & fill. int size; // Add a new item to the end of the list. IfNullGo(pItem = m_pStreamList->Append()); // Fill out the data. pItem->SetOffset(0); pItem->SetSize(cbSize); size = WszWideCharToMultiByte(CP_ACP, 0, szName, -1, pItem->rcName, MAXSTREAMNAME, 0, 0); _ASSERTE(size > 0); ErrExit: return hr; }
//***************************************************************************** // Driver for the delta process. //***************************************************************************** __checkReturn HRESULT CMiniMdRW::ApplyDelta( CMiniMdRW &mdDelta) // Interface to MD with the ENC delta. { HRESULT hr = S_OK; ULONG iENC; // Loop control. ULONG iRid; // RID of some record. ULONG iNew; // RID of a new record. int i; // Loop control. ULONG ixTbl; // A table. #ifdef _DEBUG if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_ApplyDeltaBreak)) { _ASSERTE(!"CMiniMDRW::ApplyDelta()"); } #endif // _DEBUG // Init the suppressed column table. We know this one isn't zero... if (m_SuppressedDeltaColumns[TBL_TypeDef] == 0) { m_SuppressedDeltaColumns[TBL_EventMap] = (1 << EventMapRec::COL_EventList); m_SuppressedDeltaColumns[TBL_PropertyMap] = (1 << PropertyMapRec::COL_PropertyList); m_SuppressedDeltaColumns[TBL_EventMap] = (1 << EventMapRec::COL_EventList); m_SuppressedDeltaColumns[TBL_Method] = (1 << MethodRec::COL_ParamList); m_SuppressedDeltaColumns[TBL_TypeDef] = (1 << TypeDefRec::COL_FieldList)|(1<<TypeDefRec::COL_MethodList); } // Verify the version of the MD. if (m_Schema.m_major != mdDelta.m_Schema.m_major || m_Schema.m_minor != mdDelta.m_Schema.m_minor) { _ASSERTE(!"Version of Delta MetaData is a incompatible with current MetaData."); //<TODO>@FUTURE: unique error in the future since we are not shipping ENC.</TODO> return E_INVALIDARG; } // verify MVIDs. ModuleRec *pModDelta; ModuleRec *pModBase; IfFailGo(mdDelta.GetModuleRecord(1, &pModDelta)); IfFailGo(GetModuleRecord(1, &pModBase)); GUID GuidDelta; GUID GuidBase; IfFailGo(mdDelta.getMvidOfModule(pModDelta, &GuidDelta)); IfFailGo(getMvidOfModule(pModBase, &GuidBase)); if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_DeltaCheck) && (GuidDelta != GuidBase)) { _ASSERTE(!"Delta MetaData has different base than current MetaData."); return E_INVALIDARG; } #ifndef FEATURE_CORECLR // Verify that the delta is based on the base. IfFailGo(mdDelta.getEncBaseIdOfModule(pModDelta, &GuidDelta)); IfFailGo(getEncBaseIdOfModule(pModBase,&GuidBase)); if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_DeltaCheck) && CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_UseMinimalDeltas) && (GuidDelta != GuidBase)) { _ASSERTE(!"The Delta MetaData is based on a different generation than the current MetaData."); return E_INVALIDARG; } #endif //!FEATURE_CORECLR // Let the other md prepare for sparse records. IfFailGo(mdDelta.StartENCMap()); // Fix the heaps. IfFailGo(ApplyHeapDeltas(mdDelta)); // Truncate some tables in preparation to copy in new ENCLog data. for (i = 0; (ixTbl = m_TruncatedEncTables[i]) != (ULONG)-1; ++i) { m_Tables[ixTbl].Delete(); IfFailGo(m_Tables[ixTbl].InitializeEmpty_WithRecordCount( m_TableDefs[ixTbl].m_cbRec, mdDelta.m_Schema.m_cRecs[ixTbl] COMMA_INDEBUG_MD(TRUE))); // fIsReadWrite INDEBUG_MD(m_Tables[ixTbl].Debug_SetTableInfo(NULL, ixTbl)); m_Schema.m_cRecs[ixTbl] = 0; } // For each record in the ENC log... for (iENC = 1; iENC <= mdDelta.m_Schema.m_cRecs[TBL_ENCLog]; ++iENC) { // Get the record, and the updated token. ENCLogRec *pENC; IfFailGo(mdDelta.GetENCLogRecord(iENC, &pENC)); ENCLogRec *pENC2; IfFailGo(AddENCLogRecord(&pENC2, &iNew)); IfNullGo(pENC2); ENCLogRec *pENC3; _ASSERTE(iNew == iENC); ULONG func = pENC->GetFuncCode(); pENC2->SetFuncCode(pENC->GetFuncCode()); pENC2->SetToken(pENC->GetToken()); // What kind of record is this? if (IsRecId(pENC->GetToken())) { // Non-token table iRid = RidFromRecId(pENC->GetToken()); ixTbl = TblFromRecId(pENC->GetToken()); } else { // Token table. iRid = RidFromToken(pENC->GetToken()); ixTbl = GetTableForToken(pENC->GetToken()); } RID rid_Ignore; // Switch based on the function code. switch (func) { case eDeltaMethodCreate: // Next ENC record will define the new Method. MethodRec *pMethodRecord; IfFailGo(AddMethodRecord(&pMethodRecord, &rid_Ignore)); IfFailGo(AddMethodToTypeDef(iRid, m_Schema.m_cRecs[TBL_Method])); break; case eDeltaParamCreate: // Next ENC record will define the new Param. This record is // tricky because params will be re-ordered based on their sequence, // but the sequence isn't set until the NEXT record is applied. // So, for ParamCreate only, apply the param record delta before // adding the parent-child linkage. ParamRec *pParamRecord; IfFailGo(AddParamRecord(&pParamRecord, &rid_Ignore)); // Should have recorded a Param delta after the Param add. _ASSERTE(iENC<mdDelta.m_Schema.m_cRecs[TBL_ENCLog]); IfFailGo(mdDelta.GetENCLogRecord(iENC+1, &pENC3)); _ASSERTE(pENC3->GetFuncCode() == 0); _ASSERTE(GetTableForToken(pENC3->GetToken()) == TBL_Param); IfFailGo(ApplyTableDelta(mdDelta, TBL_Param, RidFromToken(pENC3->GetToken()), eDeltaFuncDefault)); // Now that Param record is OK, set up linkage. IfFailGo(AddParamToMethod(iRid, m_Schema.m_cRecs[TBL_Param])); break; case eDeltaFieldCreate: // Next ENC record will define the new Field. FieldRec *pFieldRecord; IfFailGo(AddFieldRecord(&pFieldRecord, &rid_Ignore)); IfFailGo(AddFieldToTypeDef(iRid, m_Schema.m_cRecs[TBL_Field])); break; case eDeltaPropertyCreate: // Next ENC record will define the new Property. PropertyRec *pPropertyRecord; IfFailGo(AddPropertyRecord(&pPropertyRecord, &rid_Ignore)); IfFailGo(AddPropertyToPropertyMap(iRid, m_Schema.m_cRecs[TBL_Property])); break; case eDeltaEventCreate: // Next ENC record will define the new Event. EventRec *pEventRecord; IfFailGo(AddEventRecord(&pEventRecord, &rid_Ignore)); IfFailGo(AddEventToEventMap(iRid, m_Schema.m_cRecs[TBL_Event])); break; case eDeltaFuncDefault: IfFailGo(ApplyTableDelta(mdDelta, ixTbl, iRid, func)); break; default: _ASSERTE(!"Unexpected function in ApplyDelta"); IfFailGo(E_UNEXPECTED); break; } } m_Schema.m_cRecs[TBL_ENCLog] = mdDelta.m_Schema.m_cRecs[TBL_ENCLog]; ErrExit: // Store the result for returning (IfFailRet will modify hr) HRESULT hrReturn = hr; IfFailRet(mdDelta.EndENCMap()); #ifndef FEATURE_CORECLR if (SUCCEEDED(hrReturn) && CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_DeltaCheck) && CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_UseMinimalDeltas)) { GUID GuidNewBase; // We'll use the delta's 'delta guid' for our new base guid IfFailRet(mdDelta.getEncIdOfModule(pModDelta, &GuidNewBase)); IfFailRet(PutGuid(TBL_Module, ModuleRec::COL_EncBaseId, pModBase, GuidNewBase)); } #endif //!FEATURE_CORECLR return hrReturn; } // CMiniMdRW::ApplyDelta
//***************************************************************************** // Determine what the size of the saved data will be. //***************************************************************************** HRESULT CLiteWeightStgdbRW::GetSaveSize(// S_OK or error. CorSaveSize fSave, // Quick or accurate? ULONG *pulSaveSize, // Put the size here. CorProfileData *profileData) // Profile data for working set optimization { HRESULT hr = S_OK; // A result. ULONG cbTotal = 0; // The total size. ULONG cbSize = 0; // Size of a component. m_cbSaveSize = 0; // Allocate stream list if not already done. if (!m_pStreamList) IfNullGo(m_pStreamList = new (nothrow) STORAGESTREAMLST); else m_pStreamList->Clear(); // Make sure the user string pool is not empty. An empty user string pool causes // problems with edit and continue if(m_MiniMd.m_USBlobs.IsEmpty()) { if(!(IsENCDelta(m_MiniMd.m_OptionValue.m_UpdateMode)||m_MiniMd.IsMinimalDelta())) { BYTE pbData[] = {' ', 0, 0}; ULONG ulOffset; m_MiniMd.PutUserString(pbData,sizeof(pbData),&ulOffset); } } // If we're saving a delta metadata, figure out how much space it will take to // save the minimal metadata stream (used only to identify that we have a delta // metadata... nothing should be in that stream. if ((m_MiniMd.m_OptionValue.m_UpdateMode & MDUpdateMask) == MDUpdateDelta) { IfFailGo(AddStreamToList(0, MINIMAL_MD_STREAM)); // Ask the storage system to add stream fixed overhead. IfFailGo(TiggerStorage::GetStreamSaveSize(MINIMAL_MD_STREAM, 0, &cbSize)); cbTotal += cbSize; } // Query the MiniMd for its size. IfFailGo(GetTablesSaveSize(fSave, &cbSize, profileData)); cbTotal += cbSize; // Get the pools' sizes. IfFailGo(GetPoolSaveSize(STRING_POOL_STREAM, MDPoolStrings, &cbSize)); cbTotal += cbSize; IfFailGo(GetPoolSaveSize(US_BLOB_POOL_STREAM, MDPoolUSBlobs, &cbSize)); cbTotal += cbSize; IfFailGo(GetPoolSaveSize(GUID_POOL_STREAM, MDPoolGuids, &cbSize)); cbTotal += cbSize; IfFailGo(GetPoolSaveSize(BLOB_POOL_STREAM, MDPoolBlobs, &cbSize)); cbTotal += cbSize; // Finally, ask the storage system to add fixed overhead it needs for the // file format. The overhead of each stream has already be calculated as // part of GetStreamSaveSize. What's left is the signature and header // fixed size overhead. IfFailGo(TiggerStorage::GetStorageSaveSize(&cbTotal, 0, m_MiniMd.m_OptionValue.m_RuntimeVersion)); // Log the size info. LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize total is %d.\n", cbTotal)); // The list of streams that will be saved are now in the stream save list. // Next step is to walk that list and fill out the correct offsets. This is // done here so that the data can be streamed without fixing up the header. TiggerStorage::CalcOffsets(m_pStreamList, 0, m_MiniMd.m_OptionValue.m_RuntimeVersion); if (pulSaveSize) *pulSaveSize = cbTotal; // Don't cache the value for the EnC case if (!IsENCDelta(m_MiniMd.m_OptionValue.m_UpdateMode)) m_cbSaveSize = cbTotal; ErrExit: return hr; } // HRESULT CLiteWeightStgdbRW::GetSaveSize()
//***************************************************************************** // Save the metadata to a file. //***************************************************************************** __checkReturn HRESULT CLiteWeightStgdbRW::Save( LPCWSTR szDatabase, // Name of file to which to save. DWORD dwSaveFlags) // Flags for the save. { TiggerStorage * pStorage = NULL; // IStorage object. StgIO * pStgIO = NULL; // Backing storage. HRESULT hr = S_OK; if (m_wszFileName == NULL) { if (szDatabase == NULL) { // Make sure that a NULL is not passed in the first time around. _ASSERTE(!"Not allowed to pass a NULL for filename on the first call to Save."); return E_INVALIDARG; } else { // Save the file name. IfFailGo(SetFileName(szDatabase)); } } else if ((szDatabase != NULL) && (SString::_wcsicmp(szDatabase, m_wszFileName) != 0)) { // Save the file name. IfFailGo(SetFileName(szDatabase)); } // Sanity check the name. if (!IsValidFileNameLength(m_wszFileName)) { IfFailGo(E_INVALIDARG); } m_eFileType = FILETYPE_CLB; // Allocate a new storage object. IfNullGo(pStgIO = new (nothrow) StgIO); // Create the output file. IfFailGo(pStgIO->Open(m_wszFileName, DBPROP_TMODEF_DFTWRITEMASK, 0,0, // pbData, cbData 0, // IStream* 0)); // LPSecurityAttributes // Allocate an IStorage object to use. IfNullGo(pStorage = new (nothrow) TiggerStorage); // Init the storage object on the i/o system. OptionValue ov; IfFailGo(m_MiniMd.GetOption(&ov)); IfFailGo(pStorage->Init(pStgIO, ov.m_RuntimeVersion)); // Save the data. IfFailGo(SaveToStorage(pStorage)); ErrExit: if (pStgIO != NULL) pStgIO->Release(); if (pStorage != NULL) delete pStorage; return hr; } // CLiteWeightStgdbRW::Save
//***************************************************************************** // Determine what the size of the saved data will be. //***************************************************************************** __checkReturn HRESULT CLiteWeightStgdbRW::GetSaveSize(// S_OK or error. CorSaveSize fSave, // Quick or accurate? UINT32 *pcbSaveSize, // Put the size here. MetaDataReorderingOptions reorderingOptions, CorProfileData *pProfileData) // Profile data for working set optimization { HRESULT hr = S_OK; // A result. UINT32 cbTotal = 0; // The total size. UINT32 cbSize = 0; // Size of a component. m_cbSaveSize = 0; // Allocate stream list if not already done. if (m_pStreamList == NULL) { IfNullGo(m_pStreamList = new (nothrow) STORAGESTREAMLST); } else { m_pStreamList->Clear(); } // Make sure the user string pool is not empty. An empty user string pool causes // problems with edit and continue if (m_MiniMd.m_UserStringHeap.GetUnalignedSize() <= 1) { if (!IsENCDelta(m_MiniMd.m_OptionValue.m_UpdateMode) && !m_MiniMd.IsMinimalDelta()) { BYTE rgData[] = {' ', 0, 0}; UINT32 nIndex_Ignore; IfFailGo(m_MiniMd.PutUserString( MetaData::DataBlob(rgData, sizeof(rgData)), &nIndex_Ignore)); } } // If we're saving a delta metadata, figure out how much space it will take to // save the minimal metadata stream (used only to identify that we have a delta // metadata... nothing should be in that stream. if ((m_MiniMd.m_OptionValue.m_UpdateMode & MDUpdateMask) == MDUpdateDelta) { IfFailGo(AddStreamToList(0, MINIMAL_MD_STREAM)); // Ask the storage system to add stream fixed overhead. IfFailGo(TiggerStorage::GetStreamSaveSize(MINIMAL_MD_STREAM, 0, &cbSize)); cbTotal += cbSize; } if (reorderingOptions & ReArrangeStringPool) { if (pProfileData != NULL) { UINT32 cbHotSize = 0; // Size of pool data. UINT32 cbStream; // Size of just the stream. DWORD bCompressed; // Will the stream be compressed data? // Ask the metadata to size its hot data. IfFailGo(m_MiniMd.GetSaveSize(fSave, &cbHotSize, &bCompressed, reorderingOptions, pProfileData)); cbStream = cbHotSize; m_bSaveCompressed = bCompressed; if (cbHotSize != 0) { // Add this item to the save list. IfFailGo(AddStreamToList(cbHotSize, HOT_MODEL_STREAM)); // Ask the storage system to add stream fixed overhead. IfFailGo(TiggerStorage::GetStreamSaveSize(HOT_MODEL_STREAM, cbHotSize, &cbHotSize)); // Log the size info. LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize for %ls: %d data, %d total.\n", HOT_MODEL_STREAM, cbStream, cbHotSize)); cbTotal += cbHotSize; } } // get string pool save size IfFailGo(GetPoolSaveSize(STRING_POOL_STREAM, MDPoolStrings, &cbSize)); cbTotal += cbSize; } // Query the MiniMd for its size. IfFailGo(GetTablesSaveSize(fSave, &cbSize, reorderingOptions, pProfileData)); cbTotal += cbSize; // Get the pools' sizes. if( !(reorderingOptions & ReArrangeStringPool) ) { IfFailGo(GetPoolSaveSize(STRING_POOL_STREAM, MDPoolStrings, &cbSize)); cbTotal += cbSize; } IfFailGo(GetPoolSaveSize(US_BLOB_POOL_STREAM, MDPoolUSBlobs, &cbSize)); cbTotal += cbSize; IfFailGo(GetPoolSaveSize(GUID_POOL_STREAM, MDPoolGuids, &cbSize)); cbTotal += cbSize; IfFailGo(GetPoolSaveSize(BLOB_POOL_STREAM, MDPoolBlobs, &cbSize)); cbTotal += cbSize; // Finally, ask the storage system to add fixed overhead it needs for the // file format. The overhead of each stream has already be calculated as // part of GetStreamSaveSize. What's left is the signature and header // fixed size overhead. IfFailGo(TiggerStorage::GetStorageSaveSize((ULONG *)&cbTotal, 0, m_MiniMd.m_OptionValue.m_RuntimeVersion)); // Log the size info. LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize total is %d.\n", cbTotal)); // The list of streams that will be saved are now in the stream save list. // Next step is to walk that list and fill out the correct offsets. This is // done here so that the data can be streamed without fixing up the header. TiggerStorage::CalcOffsets(m_pStreamList, 0, m_MiniMd.m_OptionValue.m_RuntimeVersion); if (pcbSaveSize != NULL) { *pcbSaveSize = cbTotal; } // Don't cache the value for the EnC case if (!IsENCDelta(m_MiniMd.m_OptionValue.m_UpdateMode)) m_cbSaveSize = cbTotal; ErrExit: return hr; } // CLiteWeightStgdbRW::GetSaveSize
//***************************************************************************** // Given an StgIO, opens compressed streams and do proper initialization. // This is a helper for other Init functions. //***************************************************************************** __checkReturn HRESULT CLiteWeightStgdbRW::InitFileForRead( StgIO * pStgIO, // For file i/o. int bReadOnly) // If read-only open. { TiggerStorage * pStorage = NULL; void * pvData; ULONG cbData; HRESULT hr = NOERROR; // Allocate a new storage object which has IStorage on it. pStorage = new (nothrow) TiggerStorage(); IfNullGo(pStorage); // Init the storage object on the backing storage. OptionValue ov; IfFailGo(m_MiniMd.GetOption(&ov)); IfFailGo(pStorage->Init(pStgIO, ov.m_RuntimeVersion)); // Save pointers to header structure for version string. _ASSERTE((m_pvMd == NULL) && (m_cbMd == 0)); IfFailGo(pStorage->GetHeaderPointer(&m_pvMd, &m_cbMd)); // Check to see if this is a minimal metadata if (SUCCEEDED(pStorage->OpenStream(MINIMAL_MD_STREAM, &cbData, &pvData))) { m_MiniMd.m_fMinimalDelta = TRUE; } // Load the string pool. if (SUCCEEDED(hr = pStorage->OpenStream(STRING_POOL_STREAM, &cbData, &pvData))) { // String pool has to end with a null-terminator, therefore we don't have to check string pool // content on access. // Shrink size of the pool to the last null-terminator found. while (cbData != 0) { if (((LPBYTE)pvData)[cbData - 1] == 0) { // We have found last null terminator break; } // Shrink size of the pool cbData--; Debug_ReportError("String heap/pool does not end with null-terminator ... shrinking the heap."); } IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolStrings, pvData, cbData, bReadOnly)); } else { if (hr != STG_E_FILENOTFOUND) { IfFailGo(hr); } IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolStrings, NULL, 0, bReadOnly)); } // Load the user string blob pool. if (SUCCEEDED(hr = pStorage->OpenStream(US_BLOB_POOL_STREAM, &cbData, &pvData))) { IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolUSBlobs, pvData, cbData, bReadOnly)); } else { if (hr != STG_E_FILENOTFOUND) { IfFailGo(hr); } IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolUSBlobs, NULL, 0, bReadOnly)); } // Load the guid pool. if (SUCCEEDED(hr = pStorage->OpenStream(GUID_POOL_STREAM, &cbData, &pvData))) { IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolGuids, pvData, cbData, bReadOnly)); } else { if (hr != STG_E_FILENOTFOUND) { IfFailGo(hr); } IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolGuids, NULL, 0, bReadOnly)); } // Load the blob pool. if (SUCCEEDED(hr = pStorage->OpenStream(BLOB_POOL_STREAM, &cbData, &pvData))) { IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolBlobs, pvData, cbData, bReadOnly)); } else { if (hr != STG_E_FILENOTFOUND) { IfFailGo(hr); } IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolBlobs, NULL, 0, bReadOnly)); } // Open the metadata. hr = pStorage->OpenStream(COMPRESSED_MODEL_STREAM, &cbData, &pvData); if (hr == STG_E_FILENOTFOUND) { IfFailGo(pStorage->OpenStream(ENC_MODEL_STREAM, &cbData, &pvData)); } IfFailGo(m_MiniMd.InitOnMem(pvData, cbData, bReadOnly)); IfFailGo(m_MiniMd.PostInit(0)); ErrExit: if (pStorage != NULL) { delete pStorage; } return hr; } // CLiteWeightStgdbRW::InitFileForRead
//***************************************************************************** // IGetIMDInternalImport methods //***************************************************************************** HRESULT RegMeta::GetIMDInternalImport( IMDInternalImport ** ppIMDInternalImport // [OUT] Buffer to receive IMDInternalImport* ) { HRESULT hr = S_OK; MDInternalRW *pInternalRW = NULL; bool isLockedForWrite = false; IUnknown *pIUnkInternal = NULL; IUnknown *pThis = (IMetaDataImport2*)this; pIUnkInternal = this->GetCachedInternalInterface(TRUE); if (pIUnkInternal) { // there is already a cached Internal interface. GetCachedInternalInterface does add ref the // returned interface IfFailGo(pIUnkInternal->QueryInterface(IID_IMDInternalImport, (void**)ppIMDInternalImport)); goto ErrExit; } if (this->IsThreadSafetyOn()) { _ASSERTE( this->GetReaderWriterLock() ); IfFailGo(this->GetReaderWriterLock()->LockWrite()); isLockedForWrite = true; } // check again. Maybe someone else beat us to setting the internal interface while we are waiting // for the write lock. Don't need to grab the read lock since we already have the write lock. pIUnkInternal = this->GetCachedInternalInterface(FALSE); if (pIUnkInternal) { // there is already a cached Internal interface. GetCachedInternalInterface does add ref the // returned interface IfFailGo(pIUnkInternal->QueryInterface(IID_IMDInternalImport, (void**)ppIMDInternalImport)); goto ErrExit; } // now create the compressed object IfNullGo( pInternalRW = new (nothrow) MDInternalRW ); IfFailGo( pInternalRW->InitWithStgdb(pThis, this->GetMiniStgdb() ) ); // make the public object and the internal object point to each other. _ASSERTE( pInternalRW->GetReaderWriterLock() == NULL && (! this->IsThreadSafetyOn() || this->GetReaderWriterLock() != NULL )); IfFailGo( this->SetCachedInternalInterface(static_cast<IMDInternalImportENC*>(pInternalRW)) ); IfFailGo( pInternalRW->SetCachedPublicInterface(pThis)); IfFailGo( pInternalRW->SetReaderWriterLock(this->GetReaderWriterLock() )); IfFailGo( pInternalRW->QueryInterface(IID_IMDInternalImport, (void**)ppIMDInternalImport)); ErrExit: if (isLockedForWrite == true) this->GetReaderWriterLock()->UnlockWrite(); if (pIUnkInternal) pIUnkInternal->Release(); if (pInternalRW) pInternalRW->Release(); if (FAILED(hr)) { if (ppIMDInternalImport) *ppIMDInternalImport = 0; } return hr; }
//***************************************************************************** // GetMDInternalInterface. // This function will check the metadata section and determine if it should // return an interface which implements ReadOnly or ReadWrite. //***************************************************************************** STDAPI GetMDInternalInterface( LPVOID pData, ULONG cbData, DWORD flags, // [IN] ofRead or ofWrite. REFIID riid, // [in] The interface desired. void **ppIUnk) // [out] Return interface on success. { HRESULT hr = NOERROR; MDInternalRO *pInternalRO = NULL; IMDCommon *pInternalROMDCommon = NULL; MDFileFormat format; BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW); if (ppIUnk == NULL) IfFailGo(E_INVALIDARG); // Determine the file format we're trying to read. IfFailGo( CheckFileFormat(pData, cbData, &format) ); // Found a fully-compressed, read-only format. if ( format == MDFormat_ReadOnly ) { pInternalRO = new (nothrow) MDInternalRO; IfNullGo( pInternalRO ); IfFailGo( pInternalRO->Init(const_cast<void*>(pData), cbData) ); #ifdef FEATURE_COMINTEROP IfFailGo(pInternalRO->QueryInterface(IID_IMDCommon, (void**)&pInternalROMDCommon)); IfFailGo( (flags & ofNoTransform) ? S_FALSE : CheckIfWinMDAdapterNeeded(pInternalROMDCommon)); if (hr == S_OK) { IfFailGo(CreateWinMDInternalImportRO(pInternalROMDCommon, riid, (void**)ppIUnk)); } else #endif // FEATURE_COMINTEROP { IfFailGo(pInternalRO->QueryInterface(riid, ppIUnk)); } } else { // Found a not-fully-compressed, ENC format. _ASSERTE( format == MDFormat_ReadWrite ); IfFailGo( GetInternalWithRWFormat( pData, cbData, flags, riid, ppIUnk ) ); } ErrExit: // clean up if ( pInternalRO ) pInternalRO->Release(); if ( pInternalROMDCommon ) pInternalROMDCommon->Release(); END_SO_INTOLERANT_CODE; return hr; } // GetMDInternalInterface
//***************************************************************************** // Using the existing RegMeta and reopen with another chuck of memory. Make sure that all stgdb // is still kept alive. //***************************************************************************** HRESULT RegMeta::ReOpenWithMemory( LPCVOID pData, // [in] Location of scope data. ULONG cbData, // [in] Size of the data pointed to by pData. DWORD dwReOpenFlags) // [in] ReOpen flags { HRESULT hr = NOERROR; // Only allow the ofCopyMemory and ofTakeOwnership flags if (dwReOpenFlags != 0 && ((dwReOpenFlags & (~(ofCopyMemory|ofTakeOwnership))) > 0)) return E_INVALIDARG; LOCKWRITE(); // put the current m_pStgdb to the free list m_pStgdb->m_pNextStgdb = m_pStgdbFreeList; m_pStgdbFreeList = m_pStgdb; m_pStgdb = new (nothrow) CLiteWeightStgdbRW; IfNullGo( m_pStgdb ); IfFailGo( OpenExistingMD(0 /* szFileName */, const_cast<void*>(pData), cbData, ofReOpen|dwReOpenFlags /* flags */) ); #ifdef FEATURE_METADATA_INTERNAL_APIS // We've created a new Stgdb, but may still have an Internal Importer hanging around accessing the old Stgdb. // The free list ensures we don't have a dangling pointer, but the // If we have a corresponding InternalInterface, need to clear it because it's now using stale data. // Others will need to update their Internal interface to get the new data. { HRESULT hrIgnore = SetCachedInternalInterface(NULL); (void)hrIgnore; //prevent "unused variable" error from GCC _ASSERTE(hrIgnore == NOERROR); // clearing the cached interface should always succeed. } #endif //FEATURE_METADATA_INTERNAL_APIS // we are done! ErrExit: if (FAILED(hr)) { // recover to the old state if (m_pStgdb) delete m_pStgdb; m_pStgdb = m_pStgdbFreeList; m_pStgdbFreeList = m_pStgdbFreeList->m_pNextStgdb; } #ifdef FEATURE_METADATA_RELEASE_MEMORY_ON_REOPEN else { if( !(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_MD_PreserveDebuggerMetadataMemory)) && IsSafeToDeleteStgdb()) { // now that success is assured, delete the old block of memory // This isn't normally a safe operation because we would have given out // internal pointers to the memory. However when this feature is enabled // we track calls that might have given out internal pointers. If none // of the APIs were ever called then we can safely delete. CLiteWeightStgdbRW* pStgdb = m_pStgdbFreeList; m_pStgdbFreeList = m_pStgdbFreeList->m_pNextStgdb; delete pStgdb; } MarkSafeToDeleteStgdb(); // As of right now, no APIs have given out internal pointers // to the newly allocated stgdb } #endif return hr; } // RegMeta::ReOpenWithMemory