Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1410 lines
36 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name :
  4. metacach.cxx
  5. Abstract:
  6. This module contains the tsunami caching routines for metadata.
  7. Author:
  8. Henry Sanders ( henrysa ) 15-Oct-1996
  9. --*/
  10. //
  11. #include <tsunami.hxx>
  12. #include "TsunamiP.Hxx"
  13. #pragma hdrstop
  14. #include <dbgutil.h>
  15. #include <issched.hxx>
  16. #include <metacach.hxx>
  17. extern TCHAR * FlipSlashes( TCHAR * pszPath );
  18. //
  19. // The number of buckets in our hash table.
  20. //
  21. #define METACACHE_TABLE_SIZE 127
  22. #define METACACHE_ENTRY_SIGN ((DWORD)'ECEM')
  23. #define METACACHE_ENTRY_FREE ((DWORD)'ECEf')
  24. // time in minutes to keep entry in metachace after it was used last time
  25. #define TIME_TO_KEEP_METACACHE_ENTRY (5)
  26. //
  27. // Structure of a metacache table entry.
  28. //
  29. typedef struct _METACACHE_ENTRY {
  30. DWORD Signature;
  31. struct _METACACHE_ENTRY *pNext;
  32. DWORD dwDataSetNumber;
  33. DWORD dwServiceID;
  34. PVOID pMetaData;
  35. DWORD dwRefCount;
  36. DWORD dwLastUsedTime;
  37. PMDFREERTN pFreeRoutine;
  38. BOOL bValid;
  39. } METACACHE_ENTRY, *PMETACACHE_ENTRY;
  40. //
  41. // Structure of a hash table bucket.
  42. //
  43. typedef struct _METACACHE_BUCKET {
  44. PMETACACHE_ENTRY pEntry;
  45. CRITICAL_SECTION csCritSec;
  46. } METACACHE_BUCKET;
  47. METACACHE_BUCKET MetaCacheTable[METACACHE_TABLE_SIZE];
  48. DWORD MetaCacheTimerCookie = 0;
  49. DWORD g_dwMetaCacheScavengeCnt = 1;
  50. /************************************************************
  51. * Functions
  52. ************************************************************/
  53. dllexp
  54. PVOID
  55. TsFindMetaData(
  56. IN DWORD dwDataSetNumber,
  57. IN DWORD dwServiceID
  58. )
  59. /*++
  60. Routine Description:
  61. This function takes a data set number and service ID, and tries to find
  62. a formatted chunk of metadata in the cache. If it does so, it returns a
  63. pointer to it, otherwise it returns NULL.
  64. Arguments
  65. dwDataSetNumber - The data set number to be found.
  66. dwServiceID - ID of calling service.
  67. --*/
  68. {
  69. DWORD dwIndex;
  70. PMETACACHE_ENTRY pCurrentEntry;
  71. dwIndex = dwDataSetNumber % METACACHE_TABLE_SIZE;
  72. //
  73. // This needes to be protected, we use a critical section per bucket.
  74. //
  75. EnterCriticalSection(&MetaCacheTable[dwIndex].csCritSec);
  76. pCurrentEntry = MetaCacheTable[dwIndex].pEntry;
  77. // Walk the chain on the bucket. If we find a match, return it.
  78. //
  79. while (pCurrentEntry != NULL )
  80. {
  81. PCOMMON_METADATA pCMD;
  82. pCMD = (PCOMMON_METADATA)pCurrentEntry->pMetaData;
  83. pCMD->CheckSignature();
  84. ASSERT(pCMD->QueryCacheInfo() == pCurrentEntry);
  85. if (pCurrentEntry->dwDataSetNumber == dwDataSetNumber &&
  86. pCurrentEntry->dwServiceID == dwServiceID &&
  87. pCurrentEntry->bValid)
  88. {
  89. ASSERT( pCurrentEntry->Signature == METACACHE_ENTRY_SIGN );
  90. // Found a match. Increment the refcount and return a pointer
  91. // to the metadata.
  92. InterlockedIncrement((LONG *)&pCurrentEntry->dwRefCount);
  93. pCurrentEntry->dwLastUsedTime = g_dwMetaCacheScavengeCnt;
  94. LeaveCriticalSection(&MetaCacheTable[dwIndex].csCritSec);
  95. return pCurrentEntry->pMetaData;
  96. }
  97. // Otherwise try the next one.
  98. pCurrentEntry = pCurrentEntry->pNext;
  99. }
  100. // Didn't find a match, so we'll return NULL.
  101. LeaveCriticalSection(&MetaCacheTable[dwIndex].csCritSec);
  102. return NULL;
  103. }
  104. dllexp
  105. PVOID
  106. TsAddMetaData(
  107. IN PCOMMON_METADATA pMetaData,
  108. IN PMDFREERTN pFreeRoutine,
  109. IN DWORD dwDataSetNumber,
  110. IN DWORD dwServiceID
  111. )
  112. /*++
  113. Routine Description:
  114. Add a chunk of formatted metadata to our cache.
  115. Arguments
  116. pMetaData - MetaData to be added.
  117. dwDataSetNumber - The data set number to be found.
  118. dwServiceID - ID of calling service.
  119. Returns
  120. Pointer to metacache 'handle' to be used when freeing information.
  121. --*/
  122. {
  123. PMETACACHE_ENTRY pNewEntry;
  124. DWORD dwIndex;
  125. pMetaData->CheckSignature();
  126. dwIndex = dwDataSetNumber % METACACHE_TABLE_SIZE;
  127. pNewEntry = (PMETACACHE_ENTRY)ALLOC(sizeof(METACACHE_ENTRY));
  128. if (pNewEntry == NULL)
  129. {
  130. // Couldn't add the entry. No big deal, just return.
  131. return NULL;
  132. }
  133. pNewEntry->Signature = METACACHE_ENTRY_SIGN;
  134. pNewEntry->dwDataSetNumber = dwDataSetNumber;
  135. pNewEntry->dwServiceID = dwServiceID;
  136. pNewEntry->pMetaData = pMetaData;
  137. pNewEntry->pFreeRoutine = pFreeRoutine;
  138. pNewEntry->dwRefCount = 1;
  139. pNewEntry->bValid = TRUE;
  140. pNewEntry->dwLastUsedTime = g_dwMetaCacheScavengeCnt;
  141. pMetaData->SetCacheInfo(pNewEntry);
  142. EnterCriticalSection(&MetaCacheTable[dwIndex].csCritSec);
  143. pNewEntry->pNext = MetaCacheTable[dwIndex].pEntry;
  144. MetaCacheTable[dwIndex].pEntry = pNewEntry;
  145. LeaveCriticalSection(&MetaCacheTable[dwIndex].csCritSec);
  146. return pNewEntry;
  147. }
  148. dllexp
  149. VOID
  150. TsFreeMetaData(
  151. IN PVOID pCacheEntry
  152. )
  153. /*++
  154. Routine Description:
  155. Free a chunk of formatted metadata to the cache. What we really do here
  156. is decrement the ref count. If it goes to 0 and the cache element is
  157. marked deleted, we'll free it here.
  158. Arguments
  159. pMetaData - MetaData to be freed.
  160. --*/
  161. {
  162. PMETACACHE_ENTRY pEntry = (PMETACACHE_ENTRY)pCacheEntry;
  163. PCOMMON_METADATA pCMD;
  164. ASSERT( pEntry->Signature == METACACHE_ENTRY_SIGN );
  165. pCMD = (PCOMMON_METADATA)pEntry->pMetaData;
  166. pCMD->CheckSignature();
  167. ASSERT(pCMD->QueryCacheInfo() == pEntry);
  168. InterlockedDecrement((LONG *)&pEntry->dwRefCount);
  169. }
  170. dllexp
  171. VOID
  172. TsAddRefMetaData(
  173. IN PVOID pCacheEntry
  174. )
  175. /*++
  176. Routine Description:
  177. Increment reference count to chunk of formatted metadata
  178. Arguments
  179. pMetaData - MetaData to be AddRef'ed
  180. --*/
  181. {
  182. PMETACACHE_ENTRY pEntry = (PMETACACHE_ENTRY)pCacheEntry;
  183. ASSERT( pEntry->Signature == METACACHE_ENTRY_SIGN );
  184. InterlockedIncrement((LONG *)&pEntry->dwRefCount);
  185. }
  186. dllexp
  187. VOID
  188. TsFlushMetaCache(
  189. DWORD dwService,
  190. BOOL bTerminating
  191. )
  192. /*++
  193. Routine Description:
  194. Called when we need to flush all of our cached metainformation. We walk
  195. the table, and for each entry we check to see if it's in use. If it's not
  196. we'll free it, otherwise we'll mark it as deleted.
  197. If the passed in dwService ID is non-zero, then we'll only
  198. flush those entries that match the service. Also, if we're terminating,
  199. we'll do some additional checking, and also cancle any callbacks if we need
  200. to.
  201. Arguments
  202. dwService - Service ID of entries to be flushed, 0 for all
  203. services.
  204. bTerminating - TRUE if the caller is terminating.
  205. --*/
  206. {
  207. UINT i;
  208. PMETACACHE_ENTRY pEntry;
  209. PMETACACHE_ENTRY pTrailer;
  210. PCOMMON_METADATA pCMD;
  211. for (i = 0; i < METACACHE_TABLE_SIZE; i++)
  212. {
  213. EnterCriticalSection(&MetaCacheTable[i].csCritSec);
  214. pTrailer = CONTAINING_RECORD(&MetaCacheTable[i].pEntry,
  215. METACACHE_ENTRY, pNext);
  216. // Walk the chain on the bucket. For every entry, if it's not in
  217. // use, free it.
  218. //
  219. while (pTrailer->pNext != NULL )
  220. {
  221. pEntry = pTrailer->pNext;
  222. ASSERT( pEntry->Signature == METACACHE_ENTRY_SIGN );
  223. pCMD = (PCOMMON_METADATA)pEntry->pMetaData;
  224. pCMD->CheckSignature();
  225. ASSERT(pCMD->QueryCacheInfo() == pEntry);
  226. if (dwService == 0 || dwService == pEntry->dwServiceID)
  227. {
  228. if (pEntry->dwRefCount == 0)
  229. {
  230. // This entry is not in use.
  231. // If whoever added it gave us a free routine, call it now.
  232. if (pEntry->pFreeRoutine != NULL)
  233. {
  234. (*(pEntry->pFreeRoutine))(pEntry->pMetaData);
  235. }
  236. // Look at the next one.
  237. pTrailer->pNext = pEntry->pNext;
  238. pEntry->Signature = METACACHE_ENTRY_FREE;
  239. FREE(pEntry);
  240. }
  241. else
  242. {
  243. // In a debug build we'll assert here if we're terminating,
  244. // since that shouldn't happen. In a free build we won't
  245. // assert for that but we will NULL out the free routine to
  246. // keep it from getting called, since presumably the owner is
  247. // going away.
  248. if (bTerminating)
  249. {
  250. DBGPRINTF(( DBG_CONTEXT,
  251. "\n=========================================\n"
  252. "Leftover item in metacache - %8p, bValid = %s\n"
  253. "\t dwServiceID = %8d pMetaData = %8p\n"
  254. "\t dwRefCount = %8d pFreeRoutine = %8p\n"
  255. ,
  256. pEntry,
  257. (pEntry->bValid ? "TRUE" : "FALSE"),
  258. pEntry->dwServiceID,
  259. pEntry->pMetaData,
  260. pEntry->dwRefCount,
  261. pEntry->pFreeRoutine ));
  262. pEntry->pFreeRoutine = NULL;
  263. }
  264. pEntry->bValid = FALSE;
  265. pTrailer = pEntry;
  266. }
  267. }
  268. else
  269. {
  270. pTrailer = pEntry;
  271. }
  272. }
  273. LeaveCriticalSection(&MetaCacheTable[i].csCritSec);
  274. }
  275. }
  276. dllexp
  277. VOID
  278. TsReferenceMetaData(
  279. IN PVOID pEntry
  280. )
  281. /*++
  282. Routine Description:
  283. Called when we need to reference a metadata cache entry. The caller
  284. must have already referenced it once.
  285. Arguments
  286. pEntry - Entry to be referenced.
  287. --*/
  288. {
  289. PMETACACHE_ENTRY pCacheEntry = (PMETACACHE_ENTRY)pEntry;
  290. PCOMMON_METADATA pCMD;
  291. ASSERT( pCacheEntry->Signature == METACACHE_ENTRY_SIGN );
  292. pCMD = (PCOMMON_METADATA)pCacheEntry->pMetaData;
  293. pCMD->CheckSignature();
  294. ASSERT(pCMD->QueryCacheInfo() == pCacheEntry);
  295. InterlockedIncrement((LONG *)&pCacheEntry->dwRefCount);
  296. }
  297. VOID
  298. WINAPI
  299. MetaCacheScavenger(
  300. PVOID pContext
  301. )
  302. /*++
  303. Routine Description:
  304. Called periodically to time out metacache information. We scan the table;
  305. if we find an object that's not in use we free it.
  306. Arguments
  307. None.
  308. --*/
  309. {
  310. UINT i;
  311. PMETACACHE_ENTRY pEntry;
  312. PMETACACHE_ENTRY pTrailer;
  313. PCOMMON_METADATA pCMD;
  314. for (i = 0; i < METACACHE_TABLE_SIZE; i++)
  315. {
  316. if (MetaCacheTable[i].pEntry == NULL)
  317. {
  318. continue;
  319. }
  320. EnterCriticalSection(&MetaCacheTable[i].csCritSec);
  321. pTrailer = CONTAINING_RECORD(&MetaCacheTable[i].pEntry,
  322. METACACHE_ENTRY, pNext);
  323. // Walk the chain on the bucket. For every entry, if it's not in
  324. // use, free it.
  325. //
  326. while (pTrailer->pNext != NULL )
  327. {
  328. pEntry = pTrailer->pNext;
  329. ASSERT( pEntry->Signature == METACACHE_ENTRY_SIGN );
  330. pCMD = (PCOMMON_METADATA)pEntry->pMetaData;
  331. pCMD->CheckSignature();
  332. ASSERT(pCMD->QueryCacheInfo() == pEntry);
  333. if (pEntry->dwRefCount == 0 &&
  334. (pEntry->dwLastUsedTime + TIME_TO_KEEP_METACACHE_ENTRY < g_dwMetaCacheScavengeCnt))
  335. {
  336. // This entry is not in use.
  337. // If whoever added it gave us a free routine, call it now.
  338. if (pEntry->pFreeRoutine != NULL)
  339. {
  340. (*(pEntry->pFreeRoutine))(pEntry->pMetaData);
  341. }
  342. // Free the entry and look at the next one.
  343. pTrailer->pNext = pEntry->pNext;
  344. pEntry->Signature = METACACHE_ENTRY_FREE;
  345. FREE(pEntry);
  346. }
  347. else
  348. {
  349. pTrailer = pEntry;
  350. }
  351. }
  352. LeaveCriticalSection(&MetaCacheTable[i].csCritSec);
  353. }
  354. InterlockedIncrement ((long *)&g_dwMetaCacheScavengeCnt);
  355. }
  356. dllexp
  357. VOID
  358. _TsValidateMetaCache(
  359. VOID
  360. )
  361. /*++
  362. --*/
  363. {
  364. UINT i;
  365. PMETACACHE_ENTRY pEntry;
  366. PCOMMON_METADATA pCMD;
  367. for (i = 0; i < METACACHE_TABLE_SIZE; i++)
  368. {
  369. if (MetaCacheTable[i].pEntry == NULL)
  370. {
  371. continue;
  372. }
  373. EnterCriticalSection(&MetaCacheTable[i].csCritSec);
  374. pEntry = MetaCacheTable[i].pEntry;
  375. while (pEntry != NULL )
  376. {
  377. ASSERT( pEntry->Signature == METACACHE_ENTRY_SIGN );
  378. pCMD = (PCOMMON_METADATA)pEntry->pMetaData;
  379. pCMD->CheckSignature();
  380. ASSERT(pCMD->QueryCacheInfo() == pEntry);
  381. pEntry = pEntry->pNext;
  382. }
  383. LeaveCriticalSection(&MetaCacheTable[i].csCritSec);
  384. }
  385. }
  386. BOOL
  387. MetaCache_Initialize(
  388. VOID
  389. )
  390. /*++
  391. Routine Description:
  392. Initialize our metacache code.
  393. Arguments
  394. Nothing.
  395. --*/
  396. {
  397. UINT i;
  398. for (i = 0; i < METACACHE_TABLE_SIZE; i++)
  399. {
  400. INITIALIZE_CRITICAL_SECTION(&MetaCacheTable[i].csCritSec);
  401. MetaCacheTable[i].pEntry = NULL;
  402. }
  403. MetaCacheTimerCookie = ScheduleWorkItem(
  404. MetaCacheScavenger,
  405. NULL,
  406. 60 * 1000, // 1 minute
  407. TRUE ); // Periodic
  408. if (!MetaCacheTimerCookie)
  409. {
  410. return FALSE;
  411. }
  412. return TRUE;
  413. }
  414. BOOL
  415. MetaCache_Terminate(
  416. VOID
  417. )
  418. /*++
  419. Routine Description:
  420. Terminate our metacache code.
  421. Arguments
  422. Nothing.
  423. --*/
  424. {
  425. UINT i;
  426. if (MetaCacheTimerCookie != 0)
  427. {
  428. RemoveWorkItem(MetaCacheTimerCookie);
  429. MetaCacheTimerCookie = 0;
  430. }
  431. TsFlushMetaCache(0, TRUE);
  432. for (i = 0; i < METACACHE_TABLE_SIZE; i++)
  433. {
  434. DeleteCriticalSection(&MetaCacheTable[i].csCritSec);
  435. }
  436. return TRUE;
  437. }
  438. COMMON_METADATA::COMMON_METADATA(VOID)
  439. : m_IpDnsAccessCheckSize( 0 ),
  440. m_IpDnsAccessCheckPtr ( NULL ),
  441. m_IpDnsAccessCheckTag ( 0 ),
  442. m_fDontLog ( FALSE ),
  443. m_dwAccessPerm ( MD_ACCESS_READ ),
  444. m_dwSslAccessPerm ( 0 ),
  445. m_pAcl ( NULL ),
  446. m_dwAclTag ( 0 ),
  447. m_dwVrLevel ( 0 ),
  448. m_dwVrLen ( 0 ),
  449. m_hVrToken ( NULL ),
  450. m_fVrPassThrough ( FALSE ),
  451. m_dwVrError ( 0 ),
  452. m_Signature ( CMD_SIG ),
  453. m_fDoCache ( TRUE )
  454. {
  455. //
  456. // Hmmm, since most of these values aren't getting initialized, if
  457. // somebody went and deleted all the metadata items from the tree, then
  458. // bad things could happen. We should initialize with defaults things
  459. // that might cause us trouble us
  460. //
  461. } // COMMON_METADATA::COMMON_METADATA()
  462. COMMON_METADATA::~COMMON_METADATA(VOID)
  463. {
  464. CheckSignature();
  465. if ( m_IpDnsAccessCheckTag )
  466. {
  467. FreeMdTag( m_IpDnsAccessCheckTag );
  468. m_IpDnsAccessCheckTag = 0;
  469. }
  470. else if ( m_IpDnsAccessCheckPtr != NULL )
  471. {
  472. LocalFree( m_IpDnsAccessCheckPtr );
  473. m_IpDnsAccessCheckPtr = NULL;
  474. }
  475. if ( m_dwAclTag )
  476. {
  477. FreeMdTag( m_dwAclTag );
  478. m_dwAclTag = 0;
  479. }
  480. if ( m_hVrToken )
  481. {
  482. TsDeleteUserToken( m_hVrToken );
  483. m_hVrToken = NULL;
  484. }
  485. } // COMMON_METADATA::~COMMON_METADATA()
  486. VOID
  487. COMMON_METADATA::FreeMdTag(
  488. DWORD dwTag
  489. )
  490. /*++
  491. Routine Description:
  492. Free a metadata object accessed by reference
  493. Arguments:
  494. dwTag - tag of metadata object reference
  495. Returns:
  496. Nothing
  497. --*/
  498. {
  499. MB mb( (IMDCOM*) m_pInstance->m_Service->QueryMDObject() );
  500. CheckSignature();
  501. mb.ReleaseReferenceData( dwTag );
  502. }
  503. //
  504. // Private constants.
  505. //
  506. #define DEFAULT_MD_RECORDS 40
  507. #define DEFAULT_RECORD_SIZE 50
  508. # define DEF_MD_REC_SIZE ((1 + DEFAULT_MD_RECORDS) * \
  509. (sizeof(METADATA_RECORD) + DEFAULT_RECORD_SIZE))
  510. #define RMD_ASSERT(x) if (!(x)) {DBG_ASSERT(FALSE); return FALSE; }
  511. BOOL
  512. COMMON_METADATA::ReadMetaData(
  513. PIIS_SERVER_INSTANCE pInstance,
  514. MB * pmb,
  515. LPSTR pszURL,
  516. PMETADATA_ERROR_INFO pMDError
  517. )
  518. {
  519. METADATA_GETALL_INTERNAL_RECORD *pMDRecord;
  520. DWORD dwNumMDRecords;
  521. BYTE tmpBuffer[ DEF_MD_REC_SIZE];
  522. BUFFER TempBuff( tmpBuffer, DEF_MD_REC_SIZE);
  523. DWORD i;
  524. DWORD dwDataSetNumber;
  525. INT ch;
  526. LPSTR pszInVr;
  527. LPSTR pszMinInVr;
  528. DWORD dwNeed;
  529. DWORD dwL;
  530. DWORD dwVRLen;
  531. LPSTR pszVrUserName;
  532. LPSTR pszVrPassword;
  533. BYTE tmpPrivateBuffer[ 20 ];
  534. BUFFER PrivateBuffer( tmpPrivateBuffer, 20 );
  535. DWORD dwPrivateBufferUsed;
  536. CheckSignature();
  537. TsValidateMetaCache();
  538. m_pInstance = pInstance;
  539. DBG_ASSERT( TempBuff.QuerySize() >=
  540. (DEFAULT_MD_RECORDS *
  541. (sizeof(METADATA_RECORD) + DEFAULT_RECORD_SIZE))
  542. );
  543. if ( !pmb->Open( pInstance->QueryMDVRPath() ))
  544. {
  545. return FALSE;
  546. }
  547. if ( !pmb->GetAll( pszURL,
  548. METADATA_INHERIT | METADATA_PARTIAL_PATH | METADATA_REFERENCE,
  549. IIS_MD_UT_FILE,
  550. &TempBuff,
  551. &dwNumMDRecords,
  552. &dwDataSetNumber ))
  553. {
  554. return FALSE;
  555. }
  556. pMDRecord = (METADATA_GETALL_INTERNAL_RECORD *)TempBuff.QueryPtr();
  557. i = 0;
  558. //
  559. // Check from where we got VR_PATH
  560. //
  561. pszMinInVr = pszURL ;
  562. if ( *pszURL )
  563. {
  564. for ( pszInVr = pszMinInVr + strlen(pszMinInVr) ;; )
  565. {
  566. ch = *pszInVr;
  567. *pszInVr = '\0';
  568. dwNeed = 0;
  569. if ( !pmb->GetString( pszURL, MD_VR_PATH, IIS_MD_UT_FILE, NULL, &dwNeed, 0 ) &&
  570. GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  571. {
  572. *pszInVr = (CHAR)ch;
  573. // VR_PATH was defined at this level !
  574. break;
  575. }
  576. *pszInVr = (CHAR)ch;
  577. if ( ch )
  578. {
  579. if ( pszInVr > pszMinInVr )
  580. {
  581. pszInVr = CharPrev( pszMinInVr, pszInVr );
  582. }
  583. else
  584. {
  585. //
  586. // VR_PATH was defined above Instance vroot
  587. // or not at all. If defined above, then the reference
  588. // path is empty, so we can claim we found it.
  589. // if not defined, then this will be catch later.
  590. //
  591. break;
  592. }
  593. }
  594. // scan for previous delimiter
  595. while ( *pszInVr != '/' && *pszInVr != '\\' )
  596. {
  597. if ( pszInVr > pszMinInVr )
  598. {
  599. pszInVr = CharPrev( pszMinInVr, pszInVr );
  600. }
  601. else
  602. {
  603. //
  604. // VR_PATH was defined above Instance vroot
  605. // or not at all. If defined above, then the reference
  606. // path is empty, so we can claim we found it.
  607. // if not defined, then this will be catch later.
  608. //
  609. break;
  610. }
  611. }
  612. }
  613. dwVRLen = DIFF(pszInVr - pszMinInVr);
  614. }
  615. else
  616. {
  617. dwVRLen = 0;
  618. pszInVr = pszMinInVr;
  619. }
  620. // Close this now to minimize lock contention.
  621. DBG_REQUIRE(pmb->Close());
  622. for ( dwL = 0 ; pszMinInVr < pszInVr - 1 ; pszMinInVr = CharNext(pszMinInVr) )
  623. {
  624. if ( *pszMinInVr == '/' || *pszMinInVr == '\\' )
  625. {
  626. ++dwL;
  627. }
  628. }
  629. // Now walk through the array of returned metadata objects and format
  630. // each one into our predigested form.
  631. SetVrLevelAndLen( dwL, dwVRLen );
  632. pszVrPassword = NULL;
  633. pszVrUserName = NULL;
  634. dwPrivateBufferUsed = 0;
  635. pMDError->IsValid = FALSE;
  636. for ( ; i < dwNumMDRecords; i++, pMDRecord++ ) {
  637. PVOID pDataPointer;
  638. CHAR *pszMimePtr;
  639. CHAR *pszTemp;
  640. DWORD dwTemp;
  641. pDataPointer = (PVOID) ((PCHAR)TempBuff.QueryPtr() +
  642. pMDRecord->dwMDDataOffset);
  643. switch ( pMDRecord->dwMDIdentifier ) {
  644. case MD_IP_SEC:
  645. RMD_ASSERT( pMDRecord->dwMDDataType == BINARY_METADATA );
  646. if ( pMDRecord->dwMDDataLen )
  647. {
  648. if ( !SetIpDnsAccessCheck( pMDRecord->dwMDDataTag ?
  649. pMDRecord->pbMDData :
  650. pDataPointer,
  651. pMDRecord->dwMDDataLen,
  652. pMDRecord->dwMDDataTag ) )
  653. {
  654. goto FreeRefs;
  655. }
  656. }
  657. break;
  658. case MD_ACCESS_PERM:
  659. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  660. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  661. // 64bit alignment fix
  662. SetAccessPerms(*(UNALIGNED DWORD*) pDataPointer);
  663. break;
  664. case MD_SSL_ACCESS_PERM:
  665. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  666. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  667. // 64bit alignment fix
  668. SetSslAccessPerms( *((UNALIGNED DWORD *) pDataPointer) );
  669. break;
  670. case MD_DONT_LOG:
  671. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  672. DBG_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  673. // 64bit alignment fix
  674. SetDontLogFlag( *((UNALIGNED DWORD *) pDataPointer ));
  675. break;
  676. case MD_VR_PATH:
  677. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  678. if (!QueryVrPath()->Copy((const CHAR *)pDataPointer))
  679. {
  680. goto FreeRefs;
  681. }
  682. break;
  683. case MD_APP_ROOT:
  684. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  685. if (!QueryAppPath()->Copy((const CHAR *)pDataPointer))
  686. {
  687. goto FreeRefs;
  688. }
  689. break;
  690. case MD_VR_USERNAME:
  691. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  692. pszVrUserName = (LPSTR)pDataPointer;
  693. break;
  694. case MD_VR_PASSWORD:
  695. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  696. pszVrPassword = (LPSTR)pDataPointer;
  697. break;
  698. case MD_VR_PASSTHROUGH:
  699. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  700. // 64bit alignment fix
  701. SetVrPassThrough( !!*((UNALIGNED DWORD *) pDataPointer) );
  702. break;
  703. case MD_VR_ACL:
  704. DBG_ASSERT( pMDRecord->dwMDDataTag );
  705. RMD_ASSERT( pMDRecord->dwMDDataType == BINARY_METADATA );
  706. if ( pMDRecord->dwMDDataTag )
  707. {
  708. SetAcl( pMDRecord->pbMDData,
  709. pMDRecord->dwMDDataLen,
  710. pMDRecord->dwMDDataTag );
  711. }
  712. break;
  713. case MD_VR_NO_CACHE:
  714. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  715. // 64bit alignment fix
  716. SetDoCache( !*(UNALIGNED DWORD *) pDataPointer );
  717. break;
  718. default:
  719. if ( !HandlePrivateProperty( pszURL, pInstance, pMDRecord, pDataPointer, &PrivateBuffer, &dwPrivateBufferUsed, pMDError ) )
  720. {
  721. goto FreeRefs;
  722. }
  723. CheckSignature();
  724. break;
  725. }
  726. }
  727. if (!FinishPrivateProperties(&PrivateBuffer, dwPrivateBufferUsed, TRUE))
  728. {
  729. goto FreeRefs;
  730. }
  731. if ( QueryVrPath()->IsEmpty() )
  732. {
  733. DBGPRINTF(( DBG_CONTEXT,
  734. "[ReadMetaData] Virtual Dir Path mapping not found\n" ));
  735. SetLastError( ERROR_FILE_NOT_FOUND );
  736. return FALSE;
  737. }
  738. //
  739. // If this is an UNC share, logon using associated credentials
  740. // keep a reference to this access token in the cache
  741. //
  742. if ( QueryVrPath()->QueryStr()[0] == '\\' &&
  743. QueryVrPath()->QueryStr()[1] == '\\' )
  744. {
  745. if ( pszVrUserName != NULL && pszVrPassword != NULL &&
  746. pszVrUserName[0] )
  747. {
  748. if ( !SetVrUserNameAndPassword( pInstance, pszVrUserName, pszVrPassword ) )
  749. {
  750. return FALSE;
  751. }
  752. }
  753. }
  754. CheckSignature();
  755. TsValidateMetaCache();
  756. return TRUE;
  757. FreeRefs:
  758. FinishPrivateProperties(&PrivateBuffer, dwPrivateBufferUsed, FALSE);
  759. CheckSignature();
  760. TsValidateMetaCache();
  761. for ( ; i < dwNumMDRecords; i++, pMDRecord++ )
  762. {
  763. if ( pMDRecord->dwMDDataTag )
  764. {
  765. pmb->ReleaseReferenceData( pMDRecord->dwMDDataTag );
  766. }
  767. }
  768. return FALSE;
  769. }
  770. BOOL
  771. COMMON_METADATA::SetVrUserNameAndPassword(
  772. PIIS_SERVER_INSTANCE pInstance,
  773. LPSTR pszUserName,
  774. LPSTR pszPassword
  775. )
  776. /*++
  777. Description:
  778. Set the account used to access the virtual root
  779. associated with this metadata
  780. Arguments:
  781. pInstance - current instance
  782. pszUserName - User name
  783. pszPassword - password
  784. Returns:
  785. TRUE if success, otherwise FALSE
  786. --*/
  787. {
  788. LARGE_INTEGER liPwdExpiry;
  789. BOOL fHaveExp;
  790. BOOL fAsGuest;
  791. BOOL fAsAnonymous;
  792. TCP_AUTHENT_INFO TAI;
  793. CheckSignature();
  794. TAI.fDontUseAnonSubAuth = TRUE;
  795. m_hVrToken = TsLogonUser( pszUserName,
  796. pszPassword,
  797. &fAsGuest,
  798. &fAsAnonymous,
  799. pInstance,
  800. &TAI,
  801. NULL,
  802. &liPwdExpiry,
  803. &fHaveExp );
  804. //
  805. // If fail to logo, we remember the error and return SUCCESS
  806. // Caller will have to check metadata after creating it to check
  807. // the error code. Necessary because metadata needs to be set in HTTP_REQUEST
  808. // to send back proper auth status even if virtual root init failed.
  809. //
  810. if ( !m_hVrToken )
  811. {
  812. m_dwVrError = GetLastError();
  813. }
  814. return TRUE;
  815. }
  816. BOOL
  817. COMMON_METADATA::BuildApplPhysicalPath(
  818. MB * pmb,
  819. STR * pstrApplPhysicalPath
  820. ) const
  821. /*++
  822. Description:
  823. This function builds the physical path for the ApplPath of the current
  824. METADATA object. The ApplPath is a metbase path of the form
  825. /LM/W3Svc/<instance>/app-root-path
  826. This function uses the VR_PATH & portion of the APPL_PATH to
  827. construct the appropriate physical path.
  828. Arguments:
  829. pmb - pointer to MB object (Metabase pointer)
  830. pstrApplPhysicalPath - pointer to STR object that will contain
  831. the physical path on return.
  832. Returns:
  833. TRUE on success and FALSE if there are errors.
  834. Use GetLastError() to get the appropriate error code.
  835. --*/
  836. {
  837. BOOL fRet;
  838. INT cOffSet = 0;
  839. CheckSignature();
  840. DBG_ASSERT(NULL != pmb && NULL != pstrApplPhysicalPath);
  841. // m_strAppPath is in the format of /LM/W3SVC/X/ROOT/AppRoot.....
  842. // Now, the next code segment split this format into
  843. // strInstanceMDPath = /LM/W3SVC/X/ROOT/
  844. // strVrPath = /AppRoot....
  845. STR strInstanceMDPath = STR(m_strAppPath);
  846. LPSTR pszVrPath = strInstanceMDPath.QueryStr();
  847. INT VrLevel = 0;
  848. while(*pszVrPath != NULL)
  849. {
  850. if ('/' == *pszVrPath)
  851. {
  852. VrLevel++;
  853. if (5 == VrLevel)
  854. {
  855. break;
  856. }
  857. }
  858. pszVrPath++;
  859. }
  860. STR strVrPath = STR(pszVrPath);
  861. // Case: /LM/W3SVC/1/ROOT
  862. if (4 == VrLevel)
  863. {
  864. strVrPath.Append('/');
  865. // OffSet needs to minus 1 because strInstanceMDPath does not have
  866. // ending '/'
  867. cOffSet = strInstanceMDPath.QueryCCH()-1;
  868. }
  869. else if ( 5 == VrLevel)
  870. {
  871. // Make a copy of VRPath
  872. // Caculate the cOffSet of /LM/W3SVC/X/Root/
  873. // Set the strInstanceMDPath
  874. cOffSet = DIFF(pszVrPath-strInstanceMDPath.QueryStr());
  875. strInstanceMDPath.SetLen(cOffSet);
  876. }
  877. else
  878. {
  879. // Can not resolve Application Physical Path.
  880. DBG_ASSERT(FALSE);
  881. pstrApplPhysicalPath->SetLen(0);
  882. return FALSE;
  883. }
  884. // Open the metabase key from /LM/W3SVC/X/ROOT/
  885. fRet = pmb->Open(strInstanceMDPath.QueryStr());
  886. if (TRUE == fRet)
  887. {
  888. // Get VR Path first. (Note, this is not the final VRpath).
  889. fRet = pmb->GetStr(strVrPath.QueryStr(),
  890. MD_VR_PATH,
  891. IIS_MD_UT_FILE,
  892. pstrApplPhysicalPath,
  893. METADATA_INHERIT,
  894. NULL);
  895. if (TRUE == fRet)
  896. {
  897. BOOL fFound = FALSE;
  898. DWORD dwBufferSizeNeeded;
  899. LPSTR pszTempMDPath = strVrPath.QueryStr();
  900. LPSTR pszTemp = pszTempMDPath + strVrPath.QueryCCH() - 1;
  901. BOOL fNoMoreVR = FALSE; // used to break out infinite loop if there is no VR_PATH
  902. // defined at /LM/W3SVC/X/ROOT
  903. // Find where we get the VR path
  904. do
  905. {
  906. dwBufferSizeNeeded = 0;
  907. if ( !pmb->GetString(strVrPath.QueryStr(),
  908. MD_VR_PATH,
  909. IIS_MD_UT_FILE,
  910. NULL,
  911. &dwBufferSizeNeeded,
  912. 0
  913. )
  914. && GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  915. {
  916. fFound = TRUE;
  917. // cOffSet is the strlen(closest Metabase path that defined
  918. // a MDVrPath property).
  919. // For Example:
  920. // /LM/W3SVC/1/ROOT/VR1/VR2/VR3
  921. // VR2 defines MDVrPath. cOffSet is strlen(/VR2)
  922. // so, based on cOffSet, we can find VR3 later.
  923. cOffSet += strVrPath.QueryCCH();
  924. }
  925. else
  926. {
  927. // '/' is not a DBCS trailing byte.
  928. // going backwords in /VR1/VR2/VR3/.../VRn and search '/'
  929. // and shrink one VR Level
  930. pszTemp = strrchr(pszTempMDPath, '/');
  931. strVrPath.SetLen(DIFF(pszTemp-pszTempMDPath));
  932. // if this is TRUE, then, strVrPath is empty now, and there is no VR_PATH
  933. // defined.
  934. if (fNoMoreVR)
  935. {
  936. break;
  937. }
  938. if (0 == strVrPath.QueryCCH())
  939. {
  940. fNoMoreVR = TRUE;
  941. }
  942. }
  943. } while (!fFound);
  944. pmb->Close();
  945. if (!fFound && 0 == strVrPath.QueryCCH())
  946. {
  947. DBG_ASSERT(FALSE);
  948. pstrApplPhysicalPath->SetLen(0);
  949. return FALSE;
  950. }
  951. pstrApplPhysicalPath->Append(m_strAppPath.QueryStr()+cOffSet);
  952. if (pstrApplPhysicalPath->QueryCCH())
  953. {
  954. CHAR ch;
  955. ch = *CharPrev(pstrApplPhysicalPath->QueryStr(),
  956. pstrApplPhysicalPath->QueryStr()+pstrApplPhysicalPath->QueryCCH());
  957. if (ch != '\\' && ch != '/')
  958. {
  959. pstrApplPhysicalPath->Append("\\");
  960. }
  961. }
  962. FlipSlashes(pstrApplPhysicalPath->QueryStr());
  963. }
  964. else
  965. {
  966. pmb->Close();
  967. }
  968. }
  969. return fRet;
  970. } // COMMON_METADATA::BuildApplPhysicalPath()
  971. BOOL
  972. COMMON_METADATA::BuildPhysicalPath(
  973. LPSTR pszURL,
  974. STR * pstrPhysicalPath
  975. )
  976. {
  977. return BuildPhysicalPathWithAltRoot( pszURL, pstrPhysicalPath, NULL );
  978. }
  979. BOOL
  980. COMMON_METADATA::BuildPhysicalPathWithAltRoot(
  981. LPSTR pszURL,
  982. STR * pstrPhysicalPath,
  983. PCSTR pstrAltRoot
  984. )
  985. /*++
  986. Description:
  987. Construct a physical path of the following components:
  988. - the virtual root mapping
  989. - if only '/' was used off the URI to match the VR, than insert an alternate root
  990. - the significant part of the URI
  991. Arguments:
  992. pszURL - The URL to be converted
  993. pstrPhysicalPath - the resulting physical path
  994. pstrAltRoot - the alternat root
  995. Returns:
  996. TRUE if success, otherwise FALSE
  997. --*/
  998. {
  999. LPSTR pszInVr;
  1000. DWORD dwL;
  1001. INT ch;
  1002. CheckSignature();
  1003. TsValidateMetaCache();
  1004. //
  1005. // Build physical path from VR_PATH & portion of URI not used to define VR_PATH
  1006. //
  1007. //
  1008. // skip the URI components used to locate the virtual root
  1009. //
  1010. pszInVr = pszURL ;
  1011. dwL = QueryVrLevel();
  1012. while ( dwL-- )
  1013. {
  1014. if ( *pszInVr )
  1015. {
  1016. DBG_ASSERT( *pszInVr == '/' || *pszInVr == '\\' );
  1017. ++pszInVr;
  1018. while ( (ch = *pszInVr) && ch != '/' && ch !='\\' )
  1019. {
  1020. pszInVr = CharNext( pszInVr );
  1021. }
  1022. }
  1023. }
  1024. DBG_ASSERT( dwL == (DWORD)-1 );
  1025. if ( !pstrPhysicalPath->Copy( m_strVrPath ) )
  1026. {
  1027. return FALSE;
  1028. }
  1029. //
  1030. // Add the alternate root
  1031. //
  1032. if ( pstrAltRoot &&
  1033. (pszInVr - pszURL) <= 1 )
  1034. {
  1035. //
  1036. // no significant part of the URL has been used as VR alias, so we can add in the
  1037. // alternate root
  1038. //
  1039. if ( pstrPhysicalPath->QueryCCH() )
  1040. {
  1041. //
  1042. // ensure there is one and only one separator
  1043. //
  1044. ch = *CharPrev(pstrPhysicalPath->QueryStr(), pstrPhysicalPath->QueryStr() +
  1045. pstrPhysicalPath->QueryCCH());
  1046. if ( (ch != '/') && (ch != '\\') &&
  1047. (*pstrAltRoot != '/') && (*pstrAltRoot != '\\') )
  1048. {
  1049. if ( !pstrPhysicalPath->Append( "\\" ) )
  1050. {
  1051. return FALSE;
  1052. }
  1053. } else if ( (ch == '/' || ch == '\\') &&
  1054. (*pstrAltRoot == '/' || *pstrAltRoot == '\\') )
  1055. {
  1056. ++pstrAltRoot;
  1057. }
  1058. }
  1059. if ( !pstrPhysicalPath->Append( pstrAltRoot ) )
  1060. {
  1061. return FALSE;
  1062. }
  1063. }
  1064. //
  1065. // Add a path delimiter char between virtual root mount point & significant part of URI
  1066. //
  1067. if ( pstrPhysicalPath->QueryCCH() )
  1068. {
  1069. ch = *CharPrev(pstrPhysicalPath->QueryStr(), pstrPhysicalPath->QueryStr() +
  1070. pstrPhysicalPath->QueryCCH());
  1071. if ( (ch == '/' || ch == '\\') && *pszInVr )
  1072. {
  1073. ++pszInVr;
  1074. }
  1075. }
  1076. if ( !pstrPhysicalPath->Append( pszInVr ) )
  1077. {
  1078. return FALSE;
  1079. }
  1080. //
  1081. // insure physical path last char uses standard directory delimiter
  1082. //
  1083. FlipSlashes( pstrPhysicalPath->QueryStr() );
  1084. CheckSignature();
  1085. TsValidateMetaCache();
  1086. return TRUE;
  1087. }