Leaked source code of windows server 2003
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.

1405 lines
45 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. cmmprops.cpp
  5. Abstract:
  6. This module contains the implementation of the property search class
  7. Author:
  8. Keith Lau (keithlau@microsoft.com)
  9. Revision History:
  10. keithlau 03/05/98 created
  11. --*/
  12. #include <windows.h>
  13. #include <malloc.h>
  14. #include <stdlib.h>
  15. #include <search.h>
  16. #include "dbgtrace.h"
  17. #include "signatur.h"
  18. #include "cmmprops.h"
  19. #include "cmmtypes.h"
  20. #include "stddef.h"
  21. long g_cCPropertyTableCreations = 0;
  22. long g_cCPropertyTableSearchs = 0;
  23. extern DWORD g_fValidateSignatures;
  24. // =================================================================
  25. // Implementation of CPropertyTableItem
  26. //
  27. CPropertyTableItem::CPropertyTableItem(
  28. CBlockManager *pBlockManager,
  29. LPPROPERTY_TABLE_INSTANCE pInstanceInfo
  30. )
  31. {
  32. _ASSERT(pInstanceInfo);
  33. _ASSERT(pBlockManager);
  34. TraceFunctEnterEx((LPARAM)this, "CPropertyTableItem::CPropertyTableItem");
  35. m_pInstanceInfo = pInstanceInfo;
  36. m_pBlockManager = pBlockManager;
  37. m_fLoaded = FALSE;
  38. m_dwCurrentFragment = 0;
  39. m_faOffsetToFragment = 0;
  40. m_dwCurrentItem = 0;
  41. m_dwCurrentItemInFragment = 0;
  42. m_faOffsetToCurrentItem = INVALID_FLAT_ADDRESS;
  43. TraceFunctLeaveEx((LPARAM)this);
  44. }
  45. CPropertyTableItem::~CPropertyTableItem()
  46. {
  47. _ASSERT(m_pInstanceInfo);
  48. _ASSERT(m_pBlockManager);
  49. TraceFunctEnterEx((LPARAM)this, "CPropertyTableItem::~CPropertyTableItem");
  50. m_pInstanceInfo = NULL;
  51. m_pBlockManager = NULL;
  52. m_fLoaded = FALSE;
  53. m_dwCurrentFragment = 0;
  54. m_faOffsetToFragment = 0;
  55. m_dwCurrentItem = 0;
  56. m_dwCurrentItemInFragment = 0;
  57. m_faOffsetToCurrentItem = INVALID_FLAT_ADDRESS;
  58. TraceFunctLeaveEx((LPARAM)this);
  59. }
  60. HRESULT CPropertyTableItem::AddItem(
  61. LPPROPERTY_ITEM pItem,
  62. DWORD *pdwIndex,
  63. FLAT_ADDRESS *pfaOffsetToItem
  64. )
  65. {
  66. HRESULT hrRes = S_OK;
  67. DWORD cNumSleeps = 0;
  68. const DWORD MAX_ADDITEM_SLEEPS = 5;
  69. DWORD dwPropertyId;
  70. DWORD dwFragmentNumber;
  71. DWORD dwItemsInFragment;
  72. DWORD dwItemInFragment;
  73. DWORD dwSize;
  74. FLAT_ADDRESS faOffset;
  75. _ASSERT(pdwIndex);
  76. _ASSERT(m_pInstanceInfo);
  77. _ASSERT(m_pBlockManager);
  78. TraceFunctEnterEx((LPARAM)this, "CPropertyTableItem::AddItem");
  79. for (;;)
  80. {
  81. // OK, first we determine if we need to create a new fragment
  82. // before we move on ...
  83. dwPropertyId = m_pInstanceInfo->dwProperties;
  84. // Find out about our fragment type
  85. dwItemsInFragment = 1 << m_pInstanceInfo->dwItemBits;
  86. dwItemInFragment = dwPropertyId & (dwItemsInFragment - 1);
  87. dwFragmentNumber = dwPropertyId >> m_pInstanceInfo->dwItemBits;
  88. dwSize = m_pInstanceInfo->dwItemSize;
  89. // See if we already have the desired fragment
  90. hrRes = ReadFragmentFromFragmentNumber(dwFragmentNumber);
  91. if (!SUCCEEDED(hrRes))
  92. {
  93. // It's some other error, return failure ...
  94. if (hrRes != STG_E_PATHNOTFOUND)
  95. {
  96. ErrorTrace((LPARAM)this,
  97. "Unable to ReadFragmentFromFragmentNumber");
  98. TraceFunctLeaveEx((LPARAM)this);
  99. return(hrRes);
  100. }
  101. if (dwFragmentNumber && (m_dwCurrentFragment < dwFragmentNumber))
  102. {
  103. // This is really embarassing, we are on a new fragment
  104. // but the fragment(s) before that are still not created
  105. // yet, we got to retry at this point ...
  106. continue;
  107. }
  108. // OK, so the fragment is not created yet, see if we need to
  109. // create it. THe first entry in a new fragment is responsible
  110. // for creating the fragment
  111. if (!dwItemInFragment)
  112. {
  113. // Build a new fragment structure ...
  114. DWORD dwOffset;
  115. FLAT_ADDRESS faOffsetSlot;
  116. FLAT_ADDRESS *pfaOffset;
  117. PROPERTY_TABLE_FRAGMENT ifFragment;
  118. ifFragment.dwSignature = PROPERTY_FRAGMENT_SIGNATURE_VALID;
  119. ifFragment.faNextFragment = INVALID_FLAT_ADDRESS;
  120. // The next ten or so lines of code is very tricky.
  121. // If we are at the first fragment (i.e. no fragments
  122. // have been created yet), then we would actually have to
  123. // fill in the offset of the allocated block into the
  124. // m_pInstanceInfo->faFirstFragment variable. Note that
  125. // pfaOffset is passed into AtomicAllocWriteAndIncrement
  126. // and the value is assigned INSIDE the locked region,
  127. // which makes this assignment thread-safe.
  128. //
  129. // For the other case, we need to fill in the parent's
  130. // faNextFragment member to link to the newly allocated
  131. // block. Now, since ReadFragmentFromFragmentNumber must
  132. // have failed beforehand at the node right before us.
  133. // m_faOffsetToFragment actually points to our parent's
  134. // fragment. So we pass in the offset of our parent's
  135. // faNextFragment value so the atomic operation can
  136. // fill it in for us.
  137. if (!dwFragmentNumber)
  138. {
  139. // Hook up the first fragment
  140. // _ASSERT(m_pInstanceInfo->faFirstFragment ==
  141. // INVALID_FLAT_ADDRESS);
  142. pfaOffset = &(m_pInstanceInfo->faFirstFragment);
  143. faOffsetSlot = INVALID_FLAT_ADDRESS;
  144. }
  145. else
  146. {
  147. // Hook up subsequent fragments to its parent
  148. //_ASSERT(m_Fragment.faNextFragment == INVALID_FLAT_ADDRESS);
  149. //_ASSERT(m_dwCurrentFragment == dwFragmentNumber);
  150. pfaOffset = &faOffset;
  151. faOffsetSlot = m_faOffsetToFragment +
  152. offsetof(PROPERTY_TABLE_FRAGMENT, faNextFragment);
  153. }
  154. // Attempt to create the fragment, add the item to
  155. // the beginning of the new fragment, and increment the
  156. // property count in one atomic shot
  157. dwOffset = (dwItemInFragment * dwSize) +
  158. sizeof(PROPERTY_TABLE_FRAGMENT);
  159. hrRes = m_pBlockManager->AtomicAllocWriteAndIncrement(
  160. m_pInstanceInfo->dwFragmentSize,
  161. pfaOffset,
  162. faOffsetSlot,
  163. INVALID_FLAT_ADDRESS,
  164. (LPBYTE)&ifFragment,
  165. sizeof(PROPERTY_TABLE_FRAGMENT),
  166. (LPBYTE)pItem,
  167. dwOffset,
  168. dwSize,
  169. &(m_pInstanceInfo->dwProperties),
  170. dwPropertyId,
  171. 1,
  172. &m_bcContext
  173. );
  174. if (pfaOffsetToItem) *pfaOffsetToItem = *pfaOffset + dwOffset;
  175. if (!SUCCEEDED(hrRes))
  176. {
  177. // We can fail for 2 reasons: Error or Retry; we bail
  178. // out if it's an error.
  179. if (hrRes != HRESULT_FROM_WIN32(ERROR_RETRY))
  180. {
  181. // Bail out!
  182. ErrorTrace((LPARAM)this,
  183. "Failed to AtomicAllocWriteAndIncrement (%08x)",
  184. hrRes);
  185. break;
  186. }
  187. }
  188. else
  189. {
  190. // Success
  191. DebugTrace((LPARAM)this,
  192. "Succeeded to AtomicAllocWriteAndIncrement!");
  193. // We might want to update some internal members
  194. // First, hook up the previous fragment to this new
  195. // fragment.
  196. _ASSERT(*pfaOffset != INVALID_FLAT_ADDRESS);
  197. CopyMemory(&m_Fragment,
  198. &ifFragment,
  199. sizeof(PROPERTY_TABLE_FRAGMENT));
  200. m_dwCurrentFragment = dwFragmentNumber;
  201. m_faOffsetToFragment = *pfaOffset;
  202. m_dwCurrentItem = dwPropertyId;
  203. m_dwCurrentItemInFragment = dwItemInFragment;
  204. m_fLoaded = TRUE;
  205. break;
  206. }
  207. // Oooops, someone beat us in using this property ID,
  208. // we must retry immediately. Note since the state already
  209. // changed we would not be required to wait.
  210. continue;
  211. }
  212. // This is the most expensive case, basically, there is nothing
  213. // we can do but give up the time slice, I think besides changing
  214. // algorithm, this is the bast since I'd rather context switch
  215. // right away than switch after exhausting the time quanta
  216. Sleep(0);
  217. //
  218. // If we keep on doing this, then it is likely that there is
  219. // some problem... that our conditions will never be met.
  220. //
  221. if (cNumSleeps > MAX_ADDITEM_SLEEPS) {
  222. FatalTrace((LPARAM) this,
  223. "Looping in AddItem...potential corrupt P1 - bailing");
  224. hrRes = E_FAIL;
  225. _ASSERT(0 && "Potential loop condition (corrupt msg) detected - contact SMTP dev");
  226. break;
  227. }
  228. cNumSleeps++;
  229. ErrorTrace((LPARAM) this,
  230. "Looping for the %d time in AddItem", cNumSleeps);
  231. continue;
  232. }
  233. // This is the simplest case where we don't have to create a new
  234. // fragment so all we do is attempt an atomic write and increment
  235. // Still, there will be a window where some other thread might
  236. // beat us in using this property ID. In that case, we will retry
  237. // immediately.
  238. faOffset = m_faOffsetToFragment + sizeof(PROPERTY_TABLE_FRAGMENT) +
  239. (dwItemInFragment * dwSize);
  240. hrRes = m_pBlockManager->AtomicWriteAndIncrement(
  241. (LPBYTE)pItem,
  242. faOffset,
  243. dwSize,
  244. &(m_pInstanceInfo->dwProperties),
  245. dwPropertyId,
  246. 1,
  247. &m_bcContext
  248. );
  249. if (pfaOffsetToItem) *pfaOffsetToItem = faOffset;
  250. if (!SUCCEEDED(hrRes))
  251. {
  252. // We can fail for 2 reasons: Error or Retry; we bail
  253. // out if it's an error.
  254. if (hrRes != HRESULT_FROM_WIN32(ERROR_RETRY))
  255. {
  256. // Bail out!
  257. ErrorTrace((LPARAM)this,
  258. "Failed to AtomicWriteAndIncrement (%08x)",
  259. hrRes);
  260. break;
  261. }
  262. }
  263. else
  264. {
  265. // Success
  266. DebugTrace((LPARAM)this,
  267. "Succeeded to AtomicWriteAndIncrement!");
  268. break;
  269. }
  270. // Retry scenario ...
  271. } // for (;;)
  272. // Fill in info ...
  273. if (SUCCEEDED(hrRes))
  274. {
  275. *pdwIndex = dwPropertyId;
  276. }
  277. TraceFunctLeaveEx((LPARAM)this);
  278. return(hrRes);
  279. }
  280. HRESULT CPropertyTableItem::UpdateItem(
  281. DWORD dwIndex,
  282. LPPROPERTY_ITEM pItem,
  283. FLAT_ADDRESS *pfaOffsetToItem
  284. )
  285. {
  286. HRESULT hrRes = S_OK;
  287. _ASSERT(m_pInstanceInfo);
  288. _ASSERT(m_pBlockManager);
  289. TraceFunctEnterEx((LPARAM)this, "CPropertyTableItem::UpdateItem");
  290. // Atomically set the item
  291. m_fLoaded = FALSE;
  292. m_dwCurrentItem = dwIndex;
  293. hrRes = GetOrSetNextExistingItem(pItem, PIO_ATOMIC_WRITE_ITEM, pfaOffsetToItem);
  294. TraceFunctLeaveEx((LPARAM)this);
  295. return(hrRes);
  296. }
  297. HRESULT CPropertyTableItem::GetItemAtIndex(
  298. DWORD dwIndex,
  299. LPPROPERTY_ITEM pItem,
  300. LPFLAT_ADDRESS pfaOffset
  301. )
  302. {
  303. HRESULT hrRes;
  304. _ASSERT(m_pInstanceInfo);
  305. TraceFunctEnterEx((LPARAM)this, "CPropertyTableItem::GetItemAtIndex");
  306. // Just pre-set to what we want, and call GetOrSetNextExistingItem ...
  307. m_fLoaded = FALSE;
  308. m_dwCurrentItem = dwIndex;
  309. hrRes = GetOrSetNextExistingItem(pItem, PIO_READ_ITEM, pfaOffset);
  310. TraceFunctLeaveEx((LPARAM)this);
  311. return(hrRes);
  312. }
  313. HRESULT CPropertyTableItem::GetNextItem(
  314. LPPROPERTY_ITEM pItem
  315. )
  316. {
  317. HRESULT hrRes;
  318. _ASSERT(m_pInstanceInfo);
  319. TraceFunctEnterEx((LPARAM)this, "CPropertyTableItem::GetNextItem");
  320. // Just call GetOrSetNextExistingItem ...
  321. hrRes = GetOrSetNextExistingItem(pItem, PIO_READ_ITEM);
  322. TraceFunctLeaveEx((LPARAM)this);
  323. return(hrRes);
  324. }
  325. HRESULT CPropertyTableItem::GetOrSetNextExistingItem(
  326. // This looks at m_dwCurrentItem for index
  327. LPPROPERTY_ITEM pItem,
  328. DWORD dwOperation,
  329. LPFLAT_ADDRESS pfaOffset
  330. )
  331. {
  332. HRESULT hrRes = S_OK;
  333. DWORD dwCurrentItem;
  334. _ASSERT(m_pInstanceInfo);
  335. TraceFunctEnterEx((LPARAM)this, "CPropertyTableItem::GetOrSetNextExistingItem");
  336. // See if we are still in range
  337. dwCurrentItem = m_dwCurrentItem;
  338. if (m_fLoaded)
  339. dwCurrentItem++;
  340. // If we are at the end, respond so.
  341. if (dwCurrentItem == m_pInstanceInfo->dwProperties)
  342. {
  343. m_fLoaded = FALSE;
  344. return(HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS));
  345. }
  346. // We are blatantly out-of-range!
  347. if (dwCurrentItem > m_pInstanceInfo->dwProperties)
  348. {
  349. m_fLoaded = FALSE;
  350. return(STG_E_INVALIDPARAMETER);
  351. }
  352. m_dwCurrentItem = dwCurrentItem;
  353. // See if we are still in the current fragment
  354. if (!m_fLoaded ||
  355. (++m_dwCurrentItemInFragment >= (DWORD)(1 << m_pInstanceInfo->dwItemBits)))
  356. {
  357. FLAT_ADDRESS faOffsetOfFragment;
  358. // We need to load a fragment
  359. if (!m_fLoaded)
  360. {
  361. DWORD dwWhichFragment =
  362. m_dwCurrentItem >> m_pInstanceInfo->dwItemBits;
  363. // Get the offset to the current fragment
  364. hrRes = ReadFragmentFromFragmentNumber(dwWhichFragment);
  365. if (!SUCCEEDED(hrRes))
  366. return(hrRes);
  367. _ASSERT(SUCCEEDED(hrRes));
  368. // Calculate the current item w.r.t the fragment
  369. m_dwCurrentItemInFragment = m_dwCurrentItem &
  370. ((1 << m_pInstanceInfo->dwItemBits) - 1);
  371. }
  372. else
  373. {
  374. // Walk to next node
  375. faOffsetOfFragment = m_Fragment.faNextFragment;
  376. hrRes = ReadFragment(faOffsetOfFragment);
  377. if (!SUCCEEDED(hrRes))
  378. {
  379. ErrorTrace((LPARAM)this,
  380. "Unable to load fragmentat offset %u",
  381. (DWORD)faOffsetOfFragment);
  382. TraceFunctLeaveEx((LPARAM)this);
  383. return(hrRes);
  384. }
  385. // Okay, reset the current item
  386. m_dwCurrentFragment++;
  387. m_dwCurrentItemInFragment = 0;
  388. }
  389. }
  390. // Make sure what we have makes sense
  391. _ASSERT(m_dwCurrentItemInFragment < (DWORD)(1 << m_pInstanceInfo->dwItemBits));
  392. FLAT_ADDRESS faOperateOffset =
  393. m_faOffsetToFragment + sizeof(PROPERTY_TABLE_FRAGMENT) +
  394. (m_dwCurrentItemInFragment * m_pInstanceInfo->dwItemSize);
  395. switch (dwOperation)
  396. {
  397. case PIO_READ_ITEM:
  398. // OK, Issue a read to get the item entry.
  399. DebugTrace((LPARAM)this, "Reading item");
  400. hrRes = ReadItem(faOperateOffset, pItem);
  401. if (SUCCEEDED(hrRes))
  402. m_faOffsetToCurrentItem = faOperateOffset;
  403. break;
  404. case PIO_WRITE_ITEM:
  405. case PIO_ATOMIC_WRITE_ITEM:
  406. // OK, Issue a write to set the item entry.
  407. DebugTrace((LPARAM)this, "Writing item%s",
  408. (dwOperation == PIO_ATOMIC_WRITE_ITEM)?" atomically":"");
  409. hrRes = WriteItem(faOperateOffset, pItem,
  410. (dwOperation == PIO_ATOMIC_WRITE_ITEM));
  411. if (SUCCEEDED(hrRes))
  412. m_faOffsetToCurrentItem = faOperateOffset;
  413. break;
  414. default:
  415. _ASSERT(FALSE);
  416. ErrorTrace((LPARAM)this,
  417. "Invalid operation %u", dwOperation);
  418. hrRes = STG_E_INVALIDFUNCTION;
  419. }
  420. if (SUCCEEDED(hrRes) && pfaOffset)
  421. *pfaOffset = faOperateOffset;
  422. TraceFunctLeaveEx((LPARAM)this);
  423. return(hrRes);
  424. }
  425. inline HRESULT CPropertyTableItem::ReadFragmentFromFragmentNumber(
  426. DWORD dwFragmentNumber
  427. )
  428. {
  429. HRESULT hrRes;
  430. FLAT_ADDRESS faOffsetOfFragment;
  431. _ASSERT(m_pInstanceInfo);
  432. TraceFunctEnterEx((LPARAM)this,
  433. "CPropertyTableItem::ReadFragmentFromFragmentNumber");
  434. // Note this is strictly internal so we don't do much checking
  435. // Initially point to sentinel
  436. m_fLoaded = FALSE;
  437. m_dwCurrentFragment = 0;
  438. faOffsetOfFragment = m_pInstanceInfo->faFirstFragment;
  439. do
  440. {
  441. // Now if we are only one away from the desired node, but the
  442. // fragment does not exist, we will return a special code to
  443. // indicate that
  444. if (faOffsetOfFragment == INVALID_FLAT_ADDRESS)
  445. {
  446. DebugTrace((LPARAM)this,
  447. "Unable to load fragment at offset %u (INVALID_FLAT_ADDRESS)",
  448. (DWORD)faOffsetOfFragment);
  449. hrRes = STG_E_PATHNOTFOUND;
  450. break;
  451. }
  452. hrRes = ReadFragment(faOffsetOfFragment);
  453. if (!SUCCEEDED(hrRes))
  454. {
  455. ErrorTrace((LPARAM)this,
  456. "Unable to load fragment %u at offset %u",
  457. dwFragmentNumber, (DWORD)faOffsetOfFragment);
  458. break;
  459. }
  460. // Walk to next node
  461. m_dwCurrentFragment++;
  462. faOffsetOfFragment = m_Fragment.faNextFragment;
  463. } while (dwFragmentNumber--);
  464. TraceFunctLeaveEx((LPARAM)this);
  465. return(hrRes);
  466. }
  467. inline HRESULT CPropertyTableItem::ReadFragment(
  468. FLAT_ADDRESS faOffset
  469. )
  470. {
  471. HRESULT hrRes;
  472. DWORD dwSize;
  473. _ASSERT(m_pBlockManager);
  474. TraceFunctEnterEx((LPARAM)this, "CPropertyTableItem::ReadFragment");
  475. // Is the fragment correct?
  476. if (faOffset == INVALID_FLAT_ADDRESS)
  477. return(STG_E_INVALIDPARAMETER);
  478. // Load up the minimal fragment header
  479. hrRes = m_pBlockManager->ReadMemory(
  480. (LPBYTE)&m_Fragment,
  481. faOffset,
  482. sizeof(PROPERTY_TABLE_FRAGMENT),
  483. &dwSize,
  484. &m_bcContext);
  485. if (SUCCEEDED(hrRes))
  486. {
  487. if(g_fValidateSignatures && m_Fragment.dwSignature != PROPERTY_FRAGMENT_SIGNATURE_VALID)
  488. ForceCrashIfNeeded();
  489. m_fLoaded = TRUE;
  490. m_faOffsetToFragment = faOffset;
  491. }
  492. TraceFunctLeaveEx((LPARAM)this);
  493. return(hrRes);
  494. }
  495. inline HRESULT CPropertyTableItem::ReadItem(
  496. FLAT_ADDRESS faOffset,
  497. LPPROPERTY_ITEM pItem
  498. )
  499. {
  500. HRESULT hrRes;
  501. DWORD dwSize;
  502. _ASSERT(m_pBlockManager);
  503. TraceFunctEnterEx((LPARAM)this, "CPropertyTableItem::ReadItem");
  504. hrRes = m_pBlockManager->ReadMemory(
  505. (LPBYTE)pItem,
  506. faOffset,
  507. m_pInstanceInfo->dwItemSize,
  508. &dwSize,
  509. &m_bcContext);
  510. DebugTrace((LPARAM)this,
  511. "Loaded item from offset %u, HRESULT = %08x",
  512. (DWORD)faOffset, hrRes);
  513. TraceFunctLeaveEx((LPARAM)this);
  514. return(hrRes);
  515. }
  516. inline HRESULT CPropertyTableItem::WriteItem(
  517. FLAT_ADDRESS faOffset,
  518. LPPROPERTY_ITEM pItem,
  519. BOOL fAtomic
  520. )
  521. {
  522. HRESULT hrRes;
  523. DWORD dwSize;
  524. _ASSERT(m_pBlockManager);
  525. TraceFunctEnterEx((LPARAM)this, "CPropertyTableItem::WriteItem");
  526. if (fAtomic)
  527. {
  528. hrRes = m_pBlockManager->AtomicWriteAndIncrement(
  529. (LPBYTE)pItem,
  530. faOffset,
  531. m_pInstanceInfo->dwItemSize,
  532. NULL, // No increment value, just a write
  533. 0,
  534. 0,
  535. &m_bcContext);
  536. }
  537. else
  538. {
  539. hrRes = m_pBlockManager->WriteMemory(
  540. (LPBYTE)pItem,
  541. faOffset,
  542. m_pInstanceInfo->dwItemSize,
  543. &dwSize,
  544. &m_bcContext);
  545. }
  546. DebugTrace((LPARAM)this,
  547. "Written item to offset %u, HRESULT = %08x",
  548. (DWORD)faOffset, hrRes);
  549. TraceFunctLeaveEx((LPARAM)this);
  550. return(hrRes);
  551. }
  552. // =================================================================
  553. // Implementation of CPropertyTable
  554. //
  555. CPropertyTable::CPropertyTable(
  556. PROPERTY_TABLE_TYPES pttTableType,
  557. DWORD dwValidSignature,
  558. CBlockManager *pBlockManager,
  559. LPPROPERTY_TABLE_INSTANCE pInstanceInfo,
  560. LPPROPERTY_COMPARE_FUNCTION pfnCompare,
  561. const LPINTERNAL_PROPERTY_ITEM pInternalProperties,
  562. DWORD dwInternalProperties
  563. )
  564. {
  565. _ASSERT(pBlockManager);
  566. _ASSERT(pInstanceInfo);
  567. _ASSERT(pfnCompare);
  568. TraceFunctEnterEx((LPARAM)this, "CPropertyTable::CPropertyTable");
  569. // Invalidate before initialization
  570. m_dwSignature = CPROPERTY_TABLE_SIGNATURE_INVALID;
  571. if (pttTableType == PTT_PROPERTY_TABLE)
  572. {
  573. // Enforce very strict checking of consistency
  574. if (!pInternalProperties)
  575. {
  576. _ASSERT(!dwInternalProperties);
  577. }
  578. else
  579. {
  580. _ASSERT(dwInternalProperties);
  581. }
  582. }
  583. else
  584. {
  585. // These parameters must not be set if the table is other
  586. // than a property table
  587. _ASSERT(!pInternalProperties);
  588. _ASSERT(!dwInternalProperties);
  589. }
  590. // Initialize internals
  591. m_dwTableType = pttTableType;
  592. m_pBlockManager = pBlockManager;
  593. m_pfnCompare = pfnCompare;
  594. m_pInstanceInfo = pInstanceInfo;
  595. m_pInternalProperties = pInternalProperties;
  596. m_dwInternalProperties = dwInternalProperties;
  597. m_dwValidInstanceSignature = dwValidSignature;
  598. // Validate the instance info structure
  599. /*
  600. _ASSERT(IsInstanceInfoValid());
  601. _ASSERT(m_pInstanceInfo->dwFragmentSize ==
  602. ((m_pInstanceInfo->dwItemSize << m_pInstanceInfo->dwItemBits) +
  603. sizeof(PROPERTY_TABLE_FRAGMENT)));
  604. */
  605. // figure out what sort of mailmsg property table we are creating.
  606. // if its the global property table then setup member variables to
  607. // do property caching.
  608. //
  609. // There is no reason to cache recipient property offsets at this
  610. // time since the recipient property table is instantiated, used
  611. // once, then thrown away. we'd spend more time making the cache
  612. // then the linear search in SearchForProperty costs
  613. if (m_dwValidInstanceSignature == GLOBAL_PTABLE_INSTANCE_SIGNATURE_VALID) {
  614. m_iCachedPropsBase = IMMPID_MP_BEFORE__+1;
  615. m_cCachedProps = IMMPID_MP_AFTER__ - m_iCachedPropsBase;
  616. } else {
  617. m_iCachedPropsBase = 0xffffffff;
  618. m_cCachedProps = 0;
  619. }
  620. // this is allocated and filled in lazily in InitializePropCache()
  621. m_rgCachedProps = NULL;
  622. // Validate the property table object
  623. m_dwSignature = CPROPERTY_TABLE_SIGNATURE_VALID;
  624. TraceFunctLeaveEx((LPARAM)this);
  625. }
  626. CPropertyTable::~CPropertyTable()
  627. {
  628. _ASSERT(IsValid());
  629. TraceFunctEnterEx((LPARAM)this, "CPropertyTable::~CPropertyTable");
  630. // Invalidate!
  631. m_dwSignature = CPROPERTY_TABLE_SIGNATURE_INVALID;
  632. // free memory
  633. if (m_rgCachedProps) {
  634. _ASSERT(m_cCachedProps != 0);
  635. CMemoryAccess::FreeBlock(m_rgCachedProps);
  636. m_rgCachedProps = NULL;
  637. m_iCachedPropsBase = 0xffffffff;
  638. m_cCachedProps = 0;
  639. }
  640. // Wipe out all info so we make sure we AV if we access this
  641. // afterwards
  642. // Initialize internals
  643. m_dwTableType = PTT_INVALID_TYPE;
  644. m_pBlockManager = NULL;
  645. m_pfnCompare = NULL;
  646. m_pInstanceInfo = NULL;
  647. m_pInternalProperties = NULL;
  648. m_dwInternalProperties = 0;
  649. TraceFunctLeaveEx((LPARAM)this);
  650. }
  651. BOOL CPropertyTable::IsValid()
  652. {
  653. return((m_dwSignature == CPROPERTY_TABLE_SIGNATURE_VALID));
  654. }
  655. BOOL CPropertyTable::IsInstanceInfoValid()
  656. {
  657. BOOL fRet = FALSE;
  658. TraceFunctEnterEx((LPARAM)this, "CPropertyTable::IsInstanceInfoValid");
  659. if (m_pInstanceInfo &&
  660. m_pInstanceInfo->dwSignature == m_dwValidInstanceSignature)
  661. {
  662. fRet = TRUE;
  663. }
  664. else
  665. {
  666. FatalTrace((LPARAM)this, "Invalid signature");
  667. }
  668. TraceFunctLeaveEx((LPARAM)this);
  669. return(fRet);
  670. }
  671. HRESULT CPropertyTable::GetCount(
  672. DWORD *pdwCount
  673. )
  674. {
  675. _ASSERT(IsInstanceInfoValid());
  676. _ASSERT(pdwCount);
  677. if (!IsInstanceInfoValid())
  678. return(STG_E_INVALIDHEADER);
  679. *pdwCount = m_pInstanceInfo->dwProperties;
  680. return(S_OK);
  681. }
  682. HRESULT CPropertyTable::GetPropertyItem(
  683. LPVOID pvPropKey,
  684. LPPROPERTY_ITEM pItem
  685. )
  686. {
  687. HRESULT hrRes = S_OK;
  688. DWORD dwCurrentItem = 0;
  689. _ASSERT(IsInstanceInfoValid());
  690. _ASSERT(m_pfnCompare);
  691. _ASSERT(pvPropKey);
  692. _ASSERT(pItem);
  693. TraceFunctEnter("CPropertyTable::GetPropertyItem");
  694. hrRes = SearchForProperty(pvPropKey, pItem, NULL, NULL);
  695. TraceFunctLeave();
  696. return(hrRes);
  697. }
  698. HRESULT CPropertyTable::GetPropertyItemAndValue(
  699. LPVOID pvPropKey,
  700. LPPROPERTY_ITEM pItem,
  701. DWORD dwLength,
  702. DWORD *pdwLengthRead,
  703. LPBYTE pbValue
  704. )
  705. {
  706. HRESULT hrRes;
  707. FLAT_ADDRESS faItemOffset;
  708. _ASSERT(IsInstanceInfoValid());
  709. _ASSERT(m_pBlockManager);
  710. _ASSERT(pvPropKey);
  711. _ASSERT(pdwLengthRead);
  712. _ASSERT(pItem);
  713. _ASSERT(pbValue);
  714. TraceFunctEnterEx((LPARAM)this, "CPropertyTable::GetPropertyItemAndValue");
  715. // First, find the property
  716. hrRes = SearchForProperty(pvPropKey, pItem, NULL, &faItemOffset);
  717. if (SUCCEEDED(hrRes))
  718. {
  719. // OK, the item is found. Since the offset and length fields could
  720. // have changed between SearchForProperty and now, we need a protected
  721. // call to make sure we read the most up to date info as well as no
  722. // other thread can change it while we are reading.
  723. hrRes = m_pBlockManager->AtomicDereferenceAndRead(
  724. pbValue,
  725. &dwLength,
  726. (LPBYTE)pItem,
  727. faItemOffset,
  728. m_pInstanceInfo->dwItemSize,
  729. offsetof(PROPERTY_ITEM, faOffset),
  730. offsetof(PROPERTY_ITEM, dwSize),
  731. NULL);
  732. *pdwLengthRead = dwLength;
  733. DebugTrace((LPARAM)this,
  734. "AtomicDereferenceAndRead: offset %u, size %u, HRESULT = %08x",
  735. (DWORD)pItem->faOffset, pItem->dwSize, hrRes);
  736. }
  737. TraceFunctLeave();
  738. return(hrRes);
  739. }
  740. HRESULT CPropertyTable::GetPropertyItemAndValueUsingIndex(
  741. DWORD dwIndex,
  742. LPPROPERTY_ITEM pItem,
  743. DWORD dwLength,
  744. DWORD *pdwLengthRead,
  745. LPBYTE pbValue
  746. )
  747. {
  748. HRESULT hrRes;
  749. FLAT_ADDRESS faItemOffset;
  750. _ASSERT(IsInstanceInfoValid());
  751. _ASSERT(m_pBlockManager);
  752. _ASSERT(pdwLengthRead);
  753. _ASSERT(pItem);
  754. _ASSERT(pbValue);
  755. // We've read nothing so far
  756. *pdwLengthRead = 0;
  757. TraceFunctEnterEx((LPARAM)this, "CPropertyTable::GetPropertyItemAndValueUsingIndex");
  758. CPropertyTableItem ptiItem(m_pBlockManager, m_pInstanceInfo);
  759. // First, load the specified property
  760. hrRes = ptiItem.GetItemAtIndex(dwIndex, pItem, &faItemOffset);
  761. if (SUCCEEDED(hrRes))
  762. {
  763. // OK, the item is found. Since the offset and length fields could
  764. // have changed between SearchForProperty and now, we need a protected
  765. // call to make sure we read the most up to date info as well as no
  766. // other thread can change it while we are reading.
  767. hrRes = m_pBlockManager->AtomicDereferenceAndRead(
  768. pbValue,
  769. &dwLength,
  770. (LPBYTE)pItem,
  771. faItemOffset,
  772. m_pInstanceInfo->dwItemSize,
  773. offsetof(PROPERTY_ITEM, faOffset),
  774. offsetof(PROPERTY_ITEM, dwSize),
  775. NULL);
  776. // Set the length read if we succeeded
  777. if (SUCCEEDED(hrRes))
  778. *pdwLengthRead = pItem->dwSize;
  779. DebugTrace((LPARAM)this,
  780. "AtomicDereferenceAndRead: offset %u, size %u, HRESULT = %08x",
  781. (DWORD)pItem->faOffset, pItem->dwSize, hrRes);
  782. }
  783. TraceFunctLeave();
  784. return(hrRes);
  785. }
  786. HRESULT CPropertyTable::PutProperty(
  787. LPVOID pvPropKey,
  788. LPPROPERTY_ITEM pItem,
  789. DWORD dwSize,
  790. LPBYTE pbValue
  791. )
  792. {
  793. HRESULT hrRes;
  794. FLAT_ADDRESS faItemOffset;
  795. DWORD dwIndex;
  796. BOOL fGrow = FALSE;
  797. BOOL fCreate = FALSE;
  798. MAX_PROPERTY_ITEM MaxItem;
  799. PROPERTY_ITEM *pItemCopy = (PROPERTY_ITEM *) &MaxItem;
  800. CBlockContext bcContext;
  801. _ASSERT(IsInstanceInfoValid());
  802. _ASSERT(m_pBlockManager);
  803. _ASSERT(pvPropKey);
  804. _ASSERT(pItem);
  805. _ASSERT(fMaxPropertyItemSizeValid());
  806. // pbValue can be NULL
  807. TraceFunctEnterEx((LPARAM)this, "CPropertyTable::PutProperty");
  808. if (!pbValue && dwSize)
  809. {
  810. hrRes = E_POINTER;
  811. goto Exit;
  812. }
  813. //
  814. // OK, since the search will destroy the extra property info,
  815. // we must save it somewhere. If the size is larger than our
  816. // max size, then we need to bail.
  817. //
  818. if (!fPropertyItemSizeValid(m_pInstanceInfo->dwItemSize))
  819. {
  820. FatalTrace((LPARAM) this,
  821. "Message propety items size %d is invalid... assuming P1 corrupt",
  822. m_pInstanceInfo->dwItemSize);
  823. hrRes = HRESULT_FROM_WIN32(ERROR_FILE_CORRUPT);
  824. goto Exit;
  825. }
  826. MoveMemory((LPVOID)pItemCopy, (LPVOID)pItem, m_pInstanceInfo->dwItemSize);
  827. // First, see if the property exists
  828. hrRes = SearchForProperty(pvPropKey, pItem, &dwIndex, &faItemOffset);
  829. if (SUCCEEDED(hrRes))
  830. {
  831. // If we don't need to specify the value, we can skip this junk
  832. if (pbValue)
  833. {
  834. if (pItem->dwMaxSize >= dwSize)
  835. {
  836. // Best scenario: these's enough space for the new value
  837. DebugTrace((LPARAM)this,
  838. "Replacing property %u at offset %u, %u bytes",
  839. dwIndex, (DWORD)pItem->faOffset, dwSize);
  840. // Update pItem
  841. pItem->dwSize = dwSize;
  842. }
  843. else
  844. {
  845. // We must grow the property, then
  846. DebugTrace((LPARAM)this,
  847. "Growing property %u at offset %u, from %u to %u bytes",
  848. dwIndex, (DWORD)pItem->faOffset, pItem->dwSize, dwSize);
  849. fGrow = TRUE;
  850. }
  851. }
  852. }
  853. else
  854. {
  855. // See if the property is not found ...
  856. if (hrRes != STG_E_UNKNOWN)
  857. {
  858. // Nope, this is a genuine error!
  859. ErrorTrace((LPARAM)this,
  860. "Error searching property: HRESULT = %08x", hrRes);
  861. goto Exit;
  862. }
  863. // Create a new property
  864. DebugTrace((LPARAM)this,
  865. "Creating new property, %u bytes", dwSize);
  866. fCreate = TRUE;
  867. }
  868. // See if we need any new space ...
  869. if (pbValue)
  870. {
  871. if (fCreate || fGrow)
  872. {
  873. FLAT_ADDRESS faOffset;
  874. DWORD dwAllocSize;
  875. // Allocate some new memory
  876. DebugTrace((LPARAM)this, "Allocating %u bytes", dwSize);
  877. hrRes = m_pBlockManager->AllocateMemory(
  878. dwSize,
  879. &faOffset,
  880. &dwAllocSize,
  881. &bcContext);
  882. if (!SUCCEEDED(hrRes))
  883. {
  884. DebugTrace((LPARAM)this, "Allocating failed: HRESULT = %08x", hrRes);
  885. goto Exit;
  886. }
  887. // Update pItem
  888. pItem->faOffset = faOffset;
  889. pItem->dwSize = dwSize;
  890. pItem->dwMaxSize = dwAllocSize;
  891. }
  892. // Atomically write the value
  893. hrRes = m_pBlockManager->AtomicWriteAndIncrement(
  894. pbValue,
  895. pItem->faOffset,
  896. pItem->dwSize,
  897. NULL,
  898. 0,
  899. 0,
  900. &bcContext);
  901. }
  902. if (SUCCEEDED(hrRes))
  903. {
  904. CPropertyTableItem ptiItem(
  905. m_pBlockManager,
  906. m_pInstanceInfo);
  907. FLAT_ADDRESS faOffsetToItem;
  908. if (fCreate)
  909. {
  910. // Atomically create the record
  911. MoveMemory((LPVOID)pItemCopy, (LPVOID)pItem, sizeof(PROPERTY_ITEM));
  912. hrRes = ptiItem.AddItem(pItemCopy, &dwIndex, &faOffsetToItem);
  913. DebugTrace((LPARAM)this,
  914. "AddItem: HRESULT = %08x, new index = %u", hrRes, dwIndex);
  915. }
  916. else
  917. {
  918. // Atomically update the item record
  919. hrRes = ptiItem.UpdateItem(dwIndex, pItem, &faOffsetToItem);
  920. DebugTrace((LPARAM)this,
  921. "UpdateItem: HRESULT = %08x, index = %u", hrRes, dwIndex);
  922. }
  923. if (m_rgCachedProps && SUCCEEDED(hrRes)) {
  924. _ASSERT(faOffsetToItem != INVALID_FLAT_ADDRESS);
  925. UpdatePropCache(pItem, faOffsetToItem, dwIndex);
  926. }
  927. }
  928. if (SUCCEEDED(hrRes) && fCreate)
  929. hrRes = S_FALSE;
  930. Exit:
  931. TraceFunctLeave();
  932. return(hrRes);
  933. }
  934. int __cdecl CompareInternalProperties(const void *pElem1, const void *pElem2)
  935. {
  936. if (((LPINTERNAL_PROPERTY_ITEM)pElem1)->idProp ==
  937. ((LPINTERNAL_PROPERTY_ITEM)pElem2)->idProp)
  938. return(0);
  939. else
  940. {
  941. if (((LPINTERNAL_PROPERTY_ITEM)pElem1)->idProp >
  942. ((LPINTERNAL_PROPERTY_ITEM)pElem2)->idProp)
  943. return(1);
  944. }
  945. return(-1);
  946. }
  947. //
  948. // This function allocates and fills in m_rgCachedProps
  949. //
  950. void CPropertyTable::InitializePropCache() {
  951. TraceFunctEnterEx((LPARAM) this, "CPropertyTable::InitializePropCache");
  952. // it should only be called when there are properties to cache
  953. _ASSERT(m_cCachedProps);
  954. //
  955. // Previously, this was a dynamic allocation based on
  956. // the property stream read in. However, we do not
  957. // return an error in this function... bailing without
  958. // initializing the cache will cause the calling code to
  959. // fall back on not using the cache. A later check of
  960. // the item size will return ERROR_FILE_CORRUPT
  961. //
  962. if (!fPropertyItemSizeValid(m_pInstanceInfo->dwItemSize))
  963. {
  964. _ASSERT(fMaxPropertyItemSizeValid());
  965. _ASSERT(0 && "Invalid property item size");
  966. FatalTrace((LPARAM) this,
  967. "Message propety item size %d is invalid... assuming P1 corrupt",
  968. m_pInstanceInfo->dwItemSize);
  969. goto Exit;
  970. }
  971. // its okay if this allocation failed. in that case we won't have
  972. // the m_rgCachedProps array and will do linear lookups
  973. if (FAILED(CMemoryAccess::AllocBlock((void **) &m_rgCachedProps,
  974. sizeof(PROPCACHEITEM) * m_cCachedProps)))
  975. {
  976. m_rgCachedProps = NULL;
  977. } else {
  978. InterlockedIncrement(&g_cCPropertyTableCreations);
  979. // invalidate all items in the cache
  980. for (DWORD i = 0; i < m_cCachedProps; i++) {
  981. m_rgCachedProps[i].fa = INVALID_FLAT_ADDRESS;
  982. }
  983. // update the cache from what is already in the table
  984. FLAT_ADDRESS fa;
  985. DWORD dwCurrentItem = 0;
  986. MAX_PROPERTY_ITEM MaxItem;
  987. PROPERTY_ITEM *pItem = (PROPERTY_ITEM *) &MaxItem;
  988. CPropertyTableItem ptiItem(m_pBlockManager, m_pInstanceInfo);
  989. HRESULT hrRes = ptiItem.GetItemAtIndex(dwCurrentItem, pItem, &fa);
  990. while (SUCCEEDED(hrRes))
  991. {
  992. // put every item that we come across into the cache
  993. UpdatePropCache(pItem, fa, dwCurrentItem);
  994. // Get the next one. We can do this because the item object
  995. // is single-threaded
  996. hrRes = ptiItem.GetNextItem(pItem);
  997. if (SUCCEEDED(hrRes)) ptiItem.GetOffsetToCurrentItem(&fa);
  998. dwCurrentItem++;
  999. }
  1000. _ASSERT(hrRes == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS));
  1001. }
  1002. Exit:
  1003. TraceFunctLeave();
  1004. }
  1005. //
  1006. // set an item in the property cache. to invalidate an item pass in
  1007. // INVALID_FLAT_ADDRESS for fa.
  1008. //
  1009. void CPropertyTable::UpdatePropCache(LPPROPERTY_ITEM pItem,
  1010. FLAT_ADDRESS fa,
  1011. DWORD dwIndex)
  1012. {
  1013. TraceFunctEnter("CPropertyTable::UpdatePropCache");
  1014. int iCachedProp;
  1015. if (m_dwValidInstanceSignature == GLOBAL_PTABLE_INSTANCE_SIGNATURE_VALID) {
  1016. GLOBAL_PROPERTY_ITEM *pGlobalItem = (GLOBAL_PROPERTY_ITEM *) pItem;
  1017. iCachedProp = MapCachedProp(pGlobalItem->idProp);
  1018. } else {
  1019. iCachedProp = -1;
  1020. }
  1021. if (iCachedProp != -1) {
  1022. DebugTrace((LPARAM) this,
  1023. "iCachedProp = 0x%x fa = 0x%x dwIndex = 0x%x m_rgCachedProps = 0x%x",
  1024. iCachedProp, fa, dwIndex, m_rgCachedProps);
  1025. m_rgCachedProps[iCachedProp].fa = fa;
  1026. m_rgCachedProps[iCachedProp].dwIndex = dwIndex;
  1027. }
  1028. TraceFunctLeave();
  1029. }
  1030. HRESULT CPropertyTable::SearchForProperty(
  1031. LPVOID pvPropKey,
  1032. LPPROPERTY_ITEM pItem,
  1033. DWORD *pdwIndexToItem,
  1034. FLAT_ADDRESS *pfaOffsetToItem
  1035. )
  1036. {
  1037. HRESULT hrRes = S_OK;
  1038. DWORD dwCurrentItem = 0;
  1039. PROP_ID idProp;
  1040. InterlockedIncrement(&g_cCPropertyTableSearchs);
  1041. _ASSERT(IsInstanceInfoValid());
  1042. _ASSERT(m_pBlockManager);
  1043. _ASSERT(m_pfnCompare);
  1044. _ASSERT(pvPropKey);
  1045. _ASSERT(pItem);
  1046. TraceFunctEnter("CPropertyTable::SearchForProperty");
  1047. // Create an instance of the item object
  1048. CPropertyTableItem ptiItem(
  1049. m_pBlockManager,
  1050. m_pInstanceInfo);
  1051. idProp = *(PROP_ID *) pvPropKey;
  1052. // First, search the well-known properties
  1053. if (m_dwInternalProperties &&
  1054. m_dwTableType == PTT_PROPERTY_TABLE)
  1055. {
  1056. LPINTERNAL_PROPERTY_ITEM pInternalItem = NULL;
  1057. INTERNAL_PROPERTY_ITEM KeyItem;
  1058. // Bsearch
  1059. KeyItem.idProp = idProp;
  1060. pInternalItem = (LPINTERNAL_PROPERTY_ITEM)bsearch(
  1061. &KeyItem,
  1062. m_pInternalProperties,
  1063. m_dwInternalProperties,
  1064. sizeof(INTERNAL_PROPERTY_ITEM),
  1065. CompareInternalProperties);
  1066. if (pInternalItem)
  1067. {
  1068. hrRes = ptiItem.GetItemAtIndex(pInternalItem->dwIndex, pItem);
  1069. ptiItem.GetOffsetToCurrentItem(pfaOffsetToItem);
  1070. if (pdwIndexToItem)
  1071. *pdwIndexToItem = pInternalItem->dwIndex;
  1072. return(hrRes);
  1073. }
  1074. // This is not a well-known property
  1075. dwCurrentItem = m_dwInternalProperties;
  1076. }
  1077. DebugTrace((LPARAM)this, "Scanning Property table");
  1078. //
  1079. // see if its in the property cache
  1080. //
  1081. // get an index into the cache array
  1082. int iCachedProp = MapCachedProp(idProp);
  1083. // we lazily initialize the property cache the first time that we need it
  1084. if (iCachedProp != -1 && !m_rgCachedProps) InitializePropCache();
  1085. // if the cache is initialize and this should be in the case then
  1086. // search for it
  1087. if (iCachedProp != -1 && m_rgCachedProps) {
  1088. // see if this cache item is valid, and verify that it points to
  1089. // the item that the user wanted
  1090. if ((pItem != NULL) &&
  1091. (m_rgCachedProps[iCachedProp].fa != INVALID_FLAT_ADDRESS) &&
  1092. SUCCEEDED(ptiItem.ReadItem(m_rgCachedProps[iCachedProp].fa, pItem)) &&
  1093. SUCCEEDED(m_pfnCompare(pvPropKey, pItem)))
  1094. {
  1095. // we've got a winner!
  1096. *pfaOffsetToItem = m_rgCachedProps[iCachedProp].fa;
  1097. if (pdwIndexToItem)
  1098. *pdwIndexToItem = m_rgCachedProps[iCachedProp].dwIndex;
  1099. return S_OK;
  1100. }
  1101. } else if (iCachedProp != -1) {
  1102. // this case can be hit if we couldn't allocate memory for the
  1103. // property cache. we just need to set iCachedProp back to -1
  1104. // so that we do a linear search
  1105. iCachedProp = -1;
  1106. }
  1107. hrRes = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
  1108. //
  1109. // Linear Search
  1110. //
  1111. #ifdef DEBUG
  1112. //
  1113. // In debug builds we do the linear search if we couldn't find it
  1114. // in the cache. we then make sure that the linear search failed
  1115. // as well.
  1116. //
  1117. if (1) {
  1118. #else
  1119. //
  1120. // in retail builds we only do this when the data wasn't in the cache
  1121. //
  1122. if (iCachedProp == -1) {
  1123. #endif
  1124. // Linear search
  1125. FLAT_ADDRESS fa;
  1126. MAX_PROPERTY_ITEM MaxItem;
  1127. // we don't want to walk with pItem because if we don't find the
  1128. // item then we will trash whatever the user had placed in pItem
  1129. PROPERTY_ITEM *pThisItem = NULL;
  1130. //
  1131. // Sanity check size of property item (firewall corrupt messages)
  1132. //
  1133. if (!fPropertyItemSizeValid(m_pInstanceInfo->dwItemSize))
  1134. {
  1135. hrRes = HRESULT_FROM_WIN32(ERROR_FILE_CORRUPT);
  1136. FatalTrace((LPARAM) this,
  1137. "Property Items size %d to large... message corrupt",
  1138. m_pInstanceInfo->dwItemSize);
  1139. }
  1140. else
  1141. {
  1142. pThisItem = (PROPERTY_ITEM *) &MaxItem;
  1143. hrRes = ptiItem.GetItemAtIndex(dwCurrentItem, pThisItem, &fa);
  1144. while (SUCCEEDED(hrRes))
  1145. {
  1146. // Call the user-supplied compare function
  1147. hrRes = m_pfnCompare(pvPropKey, pThisItem);
  1148. if (SUCCEEDED(hrRes))
  1149. break;
  1150. // Get the next one. We can do this because the item object
  1151. // is single-threaded
  1152. hrRes = ptiItem.GetNextItem(pThisItem);
  1153. dwCurrentItem++;
  1154. }
  1155. }
  1156. #ifdef DEBUG
  1157. // if the item was found here, but not found in the cache,
  1158. // then there is an inconsistency that needs to be debugged.
  1159. if (iCachedProp != -1 && SUCCEEDED(hrRes)) {
  1160. DebugTrace(0, "iCachedProp = %i", iCachedProp);
  1161. _ASSERT(FALSE);
  1162. // we dont' want debug builds to behave differently then
  1163. // retail builds, so force it to fail
  1164. hrRes = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
  1165. }
  1166. #endif
  1167. // if we found the item then copy it from pThisItem to pItem
  1168. if (SUCCEEDED(hrRes)) {
  1169. memcpy(pItem, pThisItem, m_pInstanceInfo->dwItemSize);
  1170. }
  1171. }
  1172. // OKay, if we have no more items, then we cannot find the item,
  1173. // otherwise, we let the error code percolate up
  1174. if (!SUCCEEDED(hrRes) &&
  1175. hrRes == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS))
  1176. {
  1177. // Property not found
  1178. hrRes = STG_E_UNKNOWN;
  1179. }
  1180. else
  1181. {
  1182. // Fill in the offset
  1183. ptiItem.GetOffsetToCurrentItem(pfaOffsetToItem);
  1184. if (pdwIndexToItem)
  1185. *pdwIndexToItem = dwCurrentItem;
  1186. }
  1187. TraceFunctLeave();
  1188. return(hrRes);
  1189. }