/*++ Copyright (C) 2000-2001 Microsoft Corporation --*/ #include #include #include #include #include "filecach.h" #include "creposit.h" // // assumes inside m_cs // long CFileCache::InnerInitialize(LPCWSTR wszBaseName) { long lRes; wcscpy(m_wszBaseName, wszBaseName); wcscat(m_wszBaseName, L"\\"); m_dwBaseNameLen = wcslen(m_wszBaseName); // // Read the maximum stage-file size from the registry // HKEY hKey; lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\WBEM\\CIMOM", 0, KEY_READ | KEY_WRITE, &hKey); if(lRes) return lRes; CRegCloseMe cm(hKey); DWORD dwLen = sizeof(DWORD); DWORD dwMaxLen; lRes = RegQueryValueExW(hKey, L"Max Stage File Size", NULL, NULL, (LPBYTE)&dwMaxLen, &dwLen); // // If not there, set to default and write the default into the registry // if(lRes != ERROR_SUCCESS) { dwMaxLen = 5000000; lRes = RegSetValueExW(hKey, L"Max Stage File Size", 0, REG_DWORD, (LPBYTE)&dwMaxLen, sizeof(DWORD)); } dwLen = sizeof(DWORD); DWORD dwAbortTransactionLen; lRes = RegQueryValueExW(hKey, L"Absolute Max Stage File Size", NULL, NULL, (LPBYTE)&dwAbortTransactionLen, &dwLen); // // If not there, set to default and write the default into the registry // if(lRes != ERROR_SUCCESS || dwAbortTransactionLen == dwMaxLen * 10) { dwAbortTransactionLen = 0x7FFFFFFF; lRes = RegSetValueExW(hKey, L"Absolute Max Stage File Size", 0, REG_DWORD, (LPBYTE)&dwAbortTransactionLen, sizeof(DWORD)); } if(dwMaxLen == 0) { // // Staged writes are disabled! // } else { // // Create the main staging area // CFileName wszStagingName; if (wszStagingName == NULL) return ERROR_OUTOFMEMORY; swprintf(wszStagingName, L"%s\\LowStage.dat", wszBaseName); lRes = m_AbstractSource.Create(wszStagingName, dwMaxLen, dwAbortTransactionLen); if(lRes != ERROR_SUCCESS) return lRes; } CFileName wszObjHeapName; if(wszObjHeapName == NULL) return ERROR_OUTOFMEMORY; swprintf(wszObjHeapName, L"%s\\ObjHeap", wszBaseName); lRes = m_ObjectHeap.Initialize(&m_AbstractSource, (WCHAR*)wszObjHeapName, (WCHAR*)wszBaseName, m_dwBaseNameLen); if(lRes != ERROR_SUCCESS) return lRes; lRes = m_AbstractSource.Start(); if(lRes != ERROR_SUCCESS) return lRes; return ERROR_SUCCESS; } // // assumes inside m_cs // long CFileCache::RepositoryExists(LPCWSTR wszBaseName) { CFileName wszStagingName; if (wszStagingName == NULL) return ERROR_OUTOFMEMORY; swprintf(wszStagingName, L"%s\\LowStage.dat", wszBaseName); DWORD dwAttributes = GetFileAttributesW(wszStagingName); if (dwAttributes == -1) return ERROR_FILE_NOT_FOUND; return ERROR_SUCCESS; } long CFileCache::Initialize(LPCWSTR wszBaseName) { long lRes; CInCritSec ics(&m_cs); if (m_bInit) return ERROR_SUCCESS; lRes = RepositoryExists(wszBaseName); if (ERROR_FILE_NOT_FOUND == lRes) { //If we have a database restore to do, go ahead and do it... lRes = DoAutoDatabaseRestore(); } // // Initialize file cache. It will read the registry itself to find out // its size limitations // if (SUCCEEDED(lRes)) { lRes = InnerInitialize(wszBaseName); if (ERROR_SUCCESS == lRes) { m_bInit = TRUE; } } return lRes; } CFileCache::CFileCache() : m_lRef(1), m_bInit(FALSE) { } CFileCache::~CFileCache() { } void CFileCache::Clear(DWORD dwShutDownFlags) { m_AbstractSource.Stop(dwShutDownFlags); m_ObjectHeap.Uninitialize(dwShutDownFlags); //for(int i = 0; i < m_apStages.GetSize(); i++) // m_apStages[i]->Stop(g_ShutDownFlags); //if (WMIDB_SHUTDOWN_MACHINE_DOWN != g_ShutDownFlags) //{ // m_apStages.RemoveAll(); //} } long CFileCache::Uninitialize(DWORD dwShutDownFlags) { CInCritSec ics(&m_cs); if (!m_bInit) return 0; Clear(dwShutDownFlags); m_bInit = FALSE; return 0; } bool CFileCache::IsFullyFlushed() { CInCritSec ics(&m_cs); if (!m_bInit) return false; //for(int i = 0; i < m_apStages.GetSize(); i++) //{ // if(!m_apStages[i]->IsFullyFlushed()) // return false; //} return true; } bool CFileCache::GetFlushFailure(long* plFlushStatus) { CInCritSec ics(&m_cs); *plFlushStatus = 0; //for(int i = 0; i < m_apStages.GetSize(); i++) //{ // if(m_apStages[i]->GetFailedBefore()) // { // *plFlushStatus = m_apStages[i]->GetStatus(); // return true; // } //} return false; } long CFileCache::WriteFile(LPCWSTR wszFileName, DWORD dwLen, BYTE* pBuffer) { CInCritSec ics(&m_cs); if (!m_bInit) return -1; // // Write the file into the main staging file // //if(GetMainStagingFile()) //{ // return GetMainStagingFile()->WriteFile(wszFileName + m_dwBaseNameLen, // dwLen, pBuffer); //} //else { return m_ObjectHeap.WriteFile(wszFileName, dwLen, pBuffer); } } long CFileCache::DeleteFile(LPCWSTR wszFileName) { CInCritSec ics(&m_cs); if (!m_bInit) return -1; // // Write the file into the main staging file // //if(GetMainStagingFile()) //{ // return GetMainStagingFile()->DeleteFile(wszFileName + m_dwBaseNameLen); //} //else { return m_ObjectHeap.DeleteFile(wszFileName); } } long CFileCache::RemoveDirectory(LPCWSTR wszFileName, bool bMustSucceed) { CInCritSec ics(&m_cs); if (!m_bInit) return -1; // // Write the file into the main staging file // //if(GetMainStagingFile()) //{ // return GetMainStagingFile()-> // RemoveDirectory(wszFileName + m_dwBaseNameLen); //} //else { // No need to remove "directories" in the index return ERROR_SUCCESS; } } HRESULT CFileCache::ReadFile(LPCWSTR wszFileName, DWORD* pdwLen, BYTE** ppBuffer, bool bMustBeThere) { CInCritSec ics(&m_cs); if (!m_bInit) return -1; long lRes; // // Search all staging files in order // //for(int i = 0; i < m_apStages.GetSize(); i++) //{ // lRes = m_apStages[i]->ReadFile(wszFileName + m_dwBaseNameLen, pdwLen, // ppBuffer, bMustBeThere); // if(lRes != ERROR_NO_INFORMATION) // { // if(lRes != ERROR_SUCCESS && lRes != ERROR_FILE_NOT_FOUND && // lRes != ERROR_PATH_NOT_FOUND) // { // ERRORTRACE((LOG_WBEMCORE, "Repository driver cannot read file " // "'%S' from the stage with error code %d\n", wszFileName, // lRes)); // } // return lRes; // } //} // // Not in the staging areas --- get from disk! // return m_ObjectHeap.ReadFile(wszFileName, pdwLen, ppBuffer); } long CFileCache::FindFirst(LPCWSTR wszFilePrefix, WIN32_FIND_DATAW* pfd, void** ppHandle) { CInCritSec ics(&m_cs); if (!m_bInit) return -1; // // Construct an enumerator // CFileEnumerator* pEnum = new CFileEnumerator(this, m_dwBaseNameLen); if (pEnum == NULL) return E_OUTOFMEMORY; long lRes = pEnum->GetFirst(wszFilePrefix, pfd, (ppHandle != NULL)); if(lRes != ERROR_SUCCESS) { delete pEnum; return lRes; } if(ppHandle) *ppHandle = (void*)pEnum; else delete pEnum; return ERROR_SUCCESS; } long CFileCache::FindNext(void* pHandle, WIN32_FIND_DATAW* pfd) { CInCritSec ics(&m_cs); if (!m_bInit) return -1; CFileEnumerator* pEnum = (CFileEnumerator*)pHandle; return pEnum->GetNext(pfd, true); } void CFileCache::FindClose(void* pHandle) { CInCritSec ics(&m_cs); // do not bail out if un-initialized // we always want to free memory via the scoped obejct delete (CFileEnumerator*)pHandle; } // // // this is a shortcut chain for going straight to the BtrIdx // /////////////////////////////////////////////////////////////////////// long CFileCache::FindFirstIdx(LPCWSTR wszFilePrefix, WIN32_FIND_DATAW* pfd, void** ppHandle) { return m_ObjectHeap.FindFirst(wszFilePrefix, pfd, ppHandle); } long CFileCache::FindNextIdx(void* pHandle, WIN32_FIND_DATAW* pfd) { return m_ObjectHeap.FindNext(pHandle, pfd); } void CFileCache::FindCloseIdx(void* pHandle) { m_ObjectHeap.FindClose(pHandle); } long CFileCache::BeginTransaction() { if (!m_bInit) return -1; //if(GetMainStagingFile()) // return GetMainStagingFile()->BeginTransaction(); //else return m_AbstractSource.Begin(NULL); } long CFileCache::CommitTransaction() { if (!m_bInit) return -1; A51TRACE(("Committing Transaction!\n")); //if(GetMainStagingFile()) // return GetMainStagingFile()->CommitTransaction(); //else return m_AbstractSource.Commit(0); } long CFileCache::AbortTransaction() { if (!m_bInit) return -1; A51TRACE(("Aborting Transaction!\n")); //if(GetMainStagingFile()) // return GetMainStagingFile()->AbortTransaction(NULL); //else { // // Actually rollback the staging file // bool bNonEmpty = false; long lRes = m_AbstractSource.Rollback(0, &bNonEmpty); if(lRes != ERROR_SUCCESS) return lRes; if(bNonEmpty) { // // We rolled back a non-empty transaction, which means that the // in-memory caches (which already took the transaction into // account) may no longer be valid. Invalidate all caches // m_ObjectHeap.InvalidateCache(); } return ERROR_SUCCESS; } } CFileCache::CFileEnumerator::~CFileEnumerator() { //if(m_pStageEnumerator) // m_pCache->GetStageFile(m_nCurrentStage)->FindClose(m_pStageEnumerator); if(m_hFileEnum) m_pCache->m_ObjectHeap.FindClose(m_hFileEnum); } long CFileCache::CFileEnumerator::GetFirst(LPCWSTR wszPrefix, WIN32_FIND_DATAW* pfd, bool bNeedToContinue) { long lRes; wcscpy(m_wszPrefix, wszPrefix); WCHAR* pwcLastSlash = wcsrchr(m_wszPrefix, L'\\'); if(pwcLastSlash == NULL) return E_OUTOFMEMORY; m_dwPrefixDirLen = pwcLastSlash - m_wszPrefix; // // We are going to start with the first staging area // m_nCurrentStage = 0; m_bUseFiles = false; // // Everything is set up to indicate that we are at the very beginning --- // GetNext will retrieve the first // lRes = GetNext(pfd, bNeedToContinue); // // One last thing --- absense of files is ERROR_NO_MORE_FILES for GetNext, // but ERROR_FILE_NOT_FOUND for GetFirst, so translate // if(lRes == ERROR_NO_MORE_FILES) lRes = ERROR_FILE_NOT_FOUND; return lRes; } long CFileCache::CFileEnumerator::GetFirstFile(WIN32_FIND_DATAW* pfd, bool bNeedToContinue) { long lRes; m_bUseFiles = true; if(bNeedToContinue) lRes = m_pCache->FindFirstIdx(m_wszPrefix, pfd, &m_hFileEnum); else lRes = m_pCache->FindFirstIdx(m_wszPrefix, pfd, NULL); A51TRACE(("Actual FindFirstFileW on %S returning %p %d\n", wszMask, (void*)m_hFileEnum, lRes)); if(lRes != ERROR_SUCCESS) { if(lRes == ERROR_PATH_NOT_FOUND) return ERROR_FILE_NOT_FOUND; else return lRes; } else return ERROR_SUCCESS; } void CFileCache::CFileEnumerator::ComputeCanonicalName(WIN32_FIND_DATAW* pfd, wchar_t *wszFilePath) { wcsncpy(wszFilePath, m_wszPrefix, m_dwPrefixDirLen+1); wbem_wcsupr(wszFilePath+m_dwPrefixDirLen+1, pfd->cFileName); } long CFileCache::CFileEnumerator::GetNext(WIN32_FIND_DATAW* pfd, bool bNeedToContinue) { // // Need-to-continue optimizations are not possible if staging is used at // this level because even though the caller is only asking for one object, // we may need to retrieve more than that from the store since some of the // objects in the store may be overriden by the stage file deletions // //if(m_pCache->GetNumStages() > 0) // bNeedToContinue = true; long lRes; // // Go through the files in the enumerator until we find a new and valid one // while((lRes = GetRawNext(pfd, bNeedToContinue)) == ERROR_SUCCESS) { // // Compute the full name // CFileName wszFullName; if (wszFullName == NULL) return ERROR_OUTOFMEMORY; ComputeCanonicalName(pfd, wszFullName); // // Check if it is already in our map of returned files // if(m_setSent.find((const wchar_t*)wszFullName) != m_setSent.end()) continue; // // Check if this file is deleted // bool bDeleted = false; /* for(int i = 0; i < m_nCurrentStage; i++) { long hres = m_pCache->GetStageFile(i)->IsDeleted(wszFullName + m_dwBaseNameLen); if (hres == S_OK) { bDeleted = true; break; } else if (FAILED(hres)) { return hres; } } */ if(bDeleted) continue; // // All clear! // if(!m_bUseFiles) m_setSent.insert((const wchar_t*)wszFullName); return ERROR_SUCCESS; } return lRes; } long CFileCache::CFileEnumerator::GetRawNext(WIN32_FIND_DATAW* pfd, bool bNeedToContinue) { long lRes; if(m_bUseFiles) { _ASSERT(bNeedToContinue, L"Continuing without need?"); // // Get the next file // lRes = m_pCache->FindNextIdx(m_hFileEnum, pfd); if(lRes != ERROR_SUCCESS) { m_pCache->FindCloseIdx(m_hFileEnum); m_hFileEnum = NULL; return lRes; } return ERROR_SUCCESS; } else { // // Check if we even have a stage enumerator // /* if(m_pStageEnumerator) { _ASSERT(bNeedToContinue, L"Continuing without need?"); // // Get the next file from the same stage // lRes = m_pCache->GetStageFile(m_nCurrentStage)-> FindNext(m_pStageEnumerator, pfd); if(lRes != ERROR_NO_MORE_FILES) return lRes; // // Advance to the next one // m_pCache->GetStageFile(m_nCurrentStage)-> FindClose(m_pStageEnumerator); m_pStageEnumerator = NULL; m_nCurrentStage++; } else { // // This is our first time --- we are all set up to pick up the first // file from the first stage // } */ while(1) { //if(m_nCurrentStage >= m_pCache->GetNumStages()) { // // Go to files // lRes = GetFirstFile(pfd, bNeedToContinue); if(lRes == ERROR_FILE_NOT_FOUND) return ERROR_NO_MORE_FILES; else return lRes; } /* else { _ASSERT(bNeedToContinue, L"Continuing without need?"); // // Initialize the next stage // lRes = m_pCache->GetStageFile(m_nCurrentStage)-> FindFirst(m_wszPrefix + m_dwBaseNameLen, pfd, &m_pStageEnumerator); if(lRes == ERROR_FILE_NOT_FOUND) { // // This stage has nothing to contribute --- move along // m_nCurrentStage++; continue; } else return lRes; } */ } } return 0; }