/*++ Copyright (c) 2001 Microsoft Corporation Module Name : datasetcache.cxx Abstract: A URL->data_set_number cache Author: Bilal Alam (balam) 8-12-2001 Environment: Win32 - User Mode Project: ULW3.DLL --*/ #include "precomp.hxx" DWORD DATA_SET_CACHE::sm_cMaxCacheEntries = 50; HRESULT DATA_SET_CACHE_ENTRY::Create( WCHAR * pszSubPath, DWORD dwMatchDataSetNumber, DWORD dwPrefixDataSetNumber ) /*++ Routine Description: Initialize a data set cache entry Arguments: pszSubPath - Sub path (based off site root) dwMatchDataSetNumber - Data set number for this entry dwPrefixDataSetNumber - Data set number for paths prefixed by this entry Return Value: HRESULT --*/ { HRESULT hr; _dwMatchDataSetNumber = dwMatchDataSetNumber; _dwPrefixDataSetNumber = dwPrefixDataSetNumber; hr = _strSubPath.Copy( pszSubPath ); if ( FAILED( hr ) ) { return hr; } if ( _strSubPath.QueryCCH() != 0 && _strSubPath.QueryStr()[ _strSubPath.QueryCCH() - 1 ] != L'/' ) { hr = _strSubPath.Append( L"/" ); if ( FAILED( hr ) ) { return hr; } } return NO_ERROR; } //static HRESULT DATA_SET_CACHE::Initialize( VOID ) /*++ Routine Description: Initialize some data set cache globals Arguments: None Return Value: HRESULT --*/ { DWORD dwError; DWORD dwType; DWORD dwValue; DWORD cbData; HKEY hKey = NULL; // // Read max DataSetCache size // dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Services\\inetinfo\\Parameters", 0, KEY_READ, &hKey ); if ( dwError == ERROR_SUCCESS ) { DBG_ASSERT( hKey != NULL ); // // Should we be file caching at all? // cbData = sizeof( DWORD ); dwError = RegQueryValueEx( hKey, L"DataSetCacheSize", NULL, &dwType, (LPBYTE) &dwValue, &cbData ); if ( dwError == ERROR_SUCCESS && dwType == REG_DWORD ) { sm_cMaxCacheEntries = dwValue; } RegCloseKey( hKey ); } return NO_ERROR; } HRESULT DATA_SET_CACHE::Create( STRU & strSiteRoot ) /*++ Routine Description: Initialize a data set number cache for the given site root path Arguments: strSiteRoot - Site root path (like /LM/W3SVC//Root) Return Value: HRESULT --*/ { MB mb( g_pW3Server->QueryMDObject() ); MB mb2( g_pW3Server->QueryMDObject() ); BOOL fRet; HRESULT hr = NO_ERROR; WCHAR achSubRoot[ METADATA_MAX_NAME_LEN ]; WCHAR achNextLevel[ METADATA_MAX_NAME_LEN ]; STACK_STRU( strFullPath, 256 ); DWORD i = 0; DWORD dwMatchDataSetNumber; DWORD dwPrefixDataSetNumber; DATA_SET_CACHE_ENTRY * pDataSetCacheEntry; BOOL fCanUseRoot = TRUE; hr = _strSiteRoot.Copy( strSiteRoot ); if ( FAILED( hr ) ) { goto Finished; } fRet = mb.Open( strSiteRoot.QueryStr() ); if ( !fRet ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } // // If there are more than sm_cMaxCacheEntries paths, then we should // not even bother with the cache // if ( mb.EnumObjects( NULL, achSubRoot, sm_cMaxCacheEntries ) ) { return NO_ERROR; } // // Do a first level enumeration (we'll only handle one level for now) // while ( TRUE ) { if ( !mb.EnumObjects( NULL, achSubRoot, i++ ) ) { // // We've reached the end of the sub paths. If we can use the // root, then add it now (it will be the last entry) // if ( fCanUseRoot ) { achSubRoot[ 0 ] = L'\0'; } else { break; } } else { // // Only add an entry to data set cache if there are no sublevels // if ( mb.EnumObjects( achSubRoot, achNextLevel, 0 ) ) { // // If there is a multi-level root, we cannot use the root in // getting data set number. Remember that. // fCanUseRoot = FALSE; continue; } } // // Cool. Get the data set numbers (we need to full path :-( ) // hr = strFullPath.Copy( strSiteRoot ); if ( FAILED( hr ) ) { goto Finished; } hr = strFullPath.Append( achSubRoot ); if ( FAILED( hr ) ) { goto Finished; } if ( strFullPath.QueryStr()[ strFullPath.QueryCCH() - 1 ] != L'/' ) { hr = strFullPath.Append( L"/" ); if ( FAILED( hr ) ) { goto Finished; } } // // We need two data set numbers. // // 1) One for the exact path // 2) One for the prefixed path. For this one, we'll just append // a bogus suffix and retrieve the data set number // if ( !mb2.GetDataSetNumber( strFullPath.QueryStr(), &dwMatchDataSetNumber ) ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } hr = strFullPath.Append( L"foo" ); if ( FAILED( hr ) ) { goto Finished; } if ( !mb2.GetDataSetNumber( strFullPath.QueryStr(), &dwPrefixDataSetNumber ) ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } // // Create an entry for this guy // pDataSetCacheEntry = new DATA_SET_CACHE_ENTRY; if ( pDataSetCacheEntry == NULL ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } _wcsupr( achSubRoot ); hr = pDataSetCacheEntry->Create( achSubRoot, dwMatchDataSetNumber, dwPrefixDataSetNumber ); if ( FAILED( hr ) ) { goto Finished; } // // Add to the array // if ( !_bufEntries.Resize( sizeof( DATA_SET_CACHE_ENTRY* ) * ( _cEntries + 1 ) ) ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } QueryEntries()[ _cEntries ] = pDataSetCacheEntry; _cEntries++; // // If we've just added the root, we're done // if ( achSubRoot[ 0 ] == L'\0' ) { break; } } Finished: return hr; } HRESULT DATA_SET_CACHE::GetDataSetNumber( STRU & strMetabasePath, DWORD * pdwDataSetNumber ) /*++ Routine Description: Get data set number from the cache Arguments: strMetabasePath - Metabase path to get data set number for (duh) pdwDataSetNumber - Filled with data set number (duh^2) Return Value: HRESULT --*/ { DWORD i; DATA_SET_CACHE_ENTRY * pDataSetCacheEntry; STACK_STRU( strUpperPath, 256 ); HRESULT hr; HANDLE hToken = NULL; if ( pdwDataSetNumber == NULL ) { DBG_ASSERT( FALSE ); return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } hr = strUpperPath.Copy( strMetabasePath.QueryStr() + _strSiteRoot.QueryCCH() ); if ( FAILED( hr ) ) { return hr; } _wcsupr( strUpperPath.QueryStr() ); // // Add a trailing / if needed (since the entries are / suffixed) // if ( strUpperPath.QueryCCH() && strUpperPath.QueryStr()[ strUpperPath.QueryCCH() - 1 ] != L'/' ) { hr = strUpperPath.Append( L"/" ); if ( FAILED( hr ) ) { return hr; } } // // First check the data set number entries // for ( i = 0; i < _cEntries; i++ ) { pDataSetCacheEntry = QueryEntries()[ i ]; DBG_ASSERT( pDataSetCacheEntry != NULL ); if ( pDataSetCacheEntry->QueryDoesMatch( strUpperPath, pdwDataSetNumber ) ) { return NO_ERROR; } } // // If we're here, then we didn't find a match. Call into the metabase // MB mb( g_pW3Server->QueryMDObject() ); // // If the caller is coming from an ISAPI, then the thread may // be impersonating. Temporarily discard the impersonation // token until we get the metadata. // if ( OpenThreadToken( GetCurrentThread(), TOKEN_IMPERSONATE, TRUE, &hToken ) ) { DBG_ASSERT( hToken != NULL ); DBG_REQUIRE( RevertToSelf() ); } if ( !mb.GetDataSetNumber( strMetabasePath.QueryStr(), pdwDataSetNumber ) ) { hr = HRESULT_FROM_WIN32( GetLastError() ); } if ( hToken != NULL ) { DBG_REQUIRE( SetThreadToken( NULL, hToken ) ); DBG_REQUIRE( CloseHandle( hToken ) ); hToken = NULL; } return hr; }