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.

2167 lines
58 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. baseobj.cxx
  5. Abstract:
  6. Basic Object Class for IIS MetaBase.
  7. Author:
  8. Michael W. Thomas 20-May-96
  9. Revision History:
  10. --*/
  11. #include "precomp.hxx"
  12. CMDBaseObject::CMDBaseObject(
  13. LPSTR strName,
  14. LPSTR
  15. )
  16. /*++
  17. Routine Description:
  18. Constructor for an object.
  19. Arguments:
  20. Name - The name of the object.
  21. Tag - Optional tag for the object. Intended to store a physical path.
  22. Return Value:
  23. --*/
  24. :
  25. m_strMDName(strName),
  26. m_bufKey(),
  27. m_pboParent(NULL),
  28. m_pbocChildHead (NULL),
  29. m_cbo(0),
  30. m_phtChildren(NULL),
  31. m_dwReadCounter (0),
  32. m_dwReadPathCounter (0),
  33. m_dwWriteCounter (0),
  34. m_dwWritePathCounter (0),
  35. m_dwNumNonInheritableData (0)
  36. {
  37. BOOL fRet;
  38. DWORD i;
  39. m_dwDataSetNumber = InterlockedExchangeAdd ((LONG *)&g_dwCMDBaseObjectNextUniqueDataSetNumber,2);
  40. if (m_dwDataSetNumber==0 || m_dwDataSetNumber==0xFFFFFFFF) // check for possible zero
  41. {
  42. m_dwDataSetNumber = InterlockedExchangeAdd ((LONG *)&g_dwCMDBaseObjectNextUniqueDataSetNumber,2);
  43. }
  44. fRet = GenerateKey();
  45. MD_ASSERT(fRet);
  46. for (i = 0; i < INVALID_END_METADATA; i++) {
  47. m_pdcarrayDataHead[i] = NULL;
  48. }
  49. SetLastChangeTime();
  50. };
  51. CMDBaseObject::CMDBaseObject(
  52. LPWSTR strName,
  53. LPWSTR
  54. )
  55. /*++
  56. Routine Description:
  57. Constructor for an object.
  58. Arguments:
  59. Name - The name of the object.
  60. Tag - Optional tag for the object. Intended to store a physical path.
  61. Return Value:
  62. --*/
  63. :
  64. m_strMDName(strName),
  65. m_bufKey(),
  66. m_pboParent(NULL),
  67. m_pbocChildHead (NULL),
  68. m_cbo(0),
  69. m_phtChildren(NULL),
  70. m_dwReadCounter (0),
  71. m_dwReadPathCounter (0),
  72. m_dwWriteCounter (0),
  73. m_dwWritePathCounter (0),
  74. m_dwNumNonInheritableData (0)
  75. {
  76. BOOL fRet;
  77. DWORD i;
  78. m_dwDataSetNumber = InterlockedExchangeAdd ((LONG *)&g_dwCMDBaseObjectNextUniqueDataSetNumber,2);
  79. if (m_dwDataSetNumber==0 || m_dwDataSetNumber==0xFFFFFFFF) // check for possible zero
  80. {
  81. m_dwDataSetNumber = InterlockedExchangeAdd ((LONG *)&g_dwCMDBaseObjectNextUniqueDataSetNumber,2);
  82. }
  83. fRet = GenerateKey();
  84. MD_ASSERT(fRet);
  85. for (i = 0; i < INVALID_END_METADATA; i++) {
  86. m_pdcarrayDataHead[i] = NULL;
  87. }
  88. SetLastChangeTime();
  89. };
  90. CMDBaseObject::~CMDBaseObject()
  91. /*++
  92. Routine Description:
  93. Destructor for an object. Deletes all data and recursively deletes
  94. all child objects.
  95. Arguments:
  96. Return Value:
  97. --*/
  98. {
  99. PDATA_CONTAINER pdcIndex, pdcSave;
  100. PBASEOBJECT_CONTAINER pbocIndex, pbocSave;
  101. int i;
  102. for (i = 1; i < INVALID_END_METADATA; i++) {
  103. for (pdcIndex=m_pdcarrayDataHead[i];pdcIndex!=NULL;pdcIndex=pdcSave) {
  104. pdcSave=pdcIndex->NextPtr;
  105. DeleteDataObject(pdcIndex->pbdDataObject);
  106. delete(pdcIndex);
  107. }
  108. }
  109. if (m_phtChildren)
  110. delete(m_phtChildren);
  111. for (pbocIndex=m_pbocChildHead;pbocIndex!=NULL;pbocIndex=pbocSave) {
  112. pbocSave=pbocIndex->NextPtr;
  113. delete(pbocIndex->pboMetaObject);
  114. delete(pbocIndex);
  115. }
  116. }
  117. BOOL
  118. CMDBaseObject::SetName(
  119. LPSTR strName,
  120. BOOL bUnicode
  121. )
  122. /*++
  123. Routine Description:
  124. Sets the name of an object.
  125. Arguments:
  126. Name - The name of the object.
  127. Return Value:
  128. BOOL - TRUE is succeeded.
  129. --*/
  130. {
  131. BOOL fRet;
  132. if (bUnicode)
  133. fRet = m_strMDName.SafeCopy((LPWSTR)strName);
  134. else
  135. fRet = m_strMDName.SafeCopy((LPSTR)strName);
  136. if (fRet)
  137. return GenerateKey();
  138. /* else */
  139. return FALSE;
  140. };
  141. BOOL
  142. CMDBaseObject::SetName(
  143. LPWSTR strName
  144. )
  145. /*++
  146. Routine Description:
  147. Sets the name of an object.
  148. Arguments:
  149. Name - The name of the object.
  150. Return Value:
  151. BOOL - TRUE is succeeded.
  152. --*/
  153. {
  154. BOOL fRet;
  155. fRet = m_strMDName.SafeCopy(strName);
  156. if (fRet)
  157. return GenerateKey();
  158. /* else */
  159. return FALSE;
  160. };
  161. HRESULT
  162. CMDBaseObject::InsertChildObject(
  163. IN CMDBaseObject *pboChild
  164. )
  165. /*++
  166. Routine Description:
  167. Inserts a child object into the list of child objects.
  168. Arguments:
  169. Child - the object to insert.
  170. Return Value:
  171. DWORD - ERROR_SUCCESS
  172. ERROR_NOT_ENOUGH_MEMORY
  173. ERROR_DUP_NAME
  174. --*/
  175. {
  176. MD_ASSERT(pboChild != NULL);
  177. MD_ASSERT(pboChild->m_bufKey.QuerySize() > 0);
  178. HRESULT hresReturn = ERROR_SUCCESS;
  179. PBASEOBJECT_CONTAINER pbocNew = new BASEOBJECT_CONTAINER;
  180. // Bail if not enough memory.
  181. if (pbocNew == NULL)
  182. return RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  183. pbocNew->pboMetaObject = pboChild;
  184. pbocNew->NextPtr = NULL;
  185. pboChild->SetParent(this);
  186. hresReturn = AddChildObjectToHash(pboChild,
  187. pbocNew);
  188. // Attach to the chain at the end (to keep enumeration ordering)
  189. if (SUCCEEDED(hresReturn))
  190. {
  191. if (m_pbocChildHead == NULL)
  192. m_pbocChildHead = pbocNew;
  193. else
  194. m_pbocChildTail->NextPtr = pbocNew;
  195. m_pbocChildTail = pbocNew;
  196. m_cbo++;
  197. SetLastChangeTime();
  198. }
  199. else
  200. delete pbocNew;
  201. return(hresReturn);
  202. }
  203. CMDBaseObject *
  204. CMDBaseObject::GetChildObject(
  205. IN OUT LPSTR &strName,
  206. OUT HRESULT *phresReturn,
  207. IN BOOL bUnicode
  208. )
  209. /*++
  210. Routine Description:
  211. Gets a child object by name. Updates strName to point past the end of the Name if found.
  212. Arguments:
  213. Name - name of the object. End delimeter can be '\0', '\\', or '/'.
  214. Return Value:
  215. CBaseObject * - The child object or NULL if the child is not found.
  216. Notes:
  217. --*/
  218. {
  219. CMDBaseObject *pboReturn = NULL;
  220. LPSTR pchDelimiter = strName;
  221. // Find the delimiter. Change to terminate character.
  222. if (bUnicode)
  223. {
  224. LPWSTR pchDelimiterW = (LPWSTR) pchDelimiter;
  225. WCHAR chW;
  226. while ((chW = *pchDelimiterW) != MD_ALT_PATH_DELIMETERW &&
  227. chW != MD_PATH_DELIMETERW &&
  228. chW != (WCHAR)L'\0')
  229. {
  230. pchDelimiterW++;
  231. }
  232. pchDelimiter = (LPSTR) pchDelimiterW;
  233. }
  234. else
  235. {
  236. CHAR chA;
  237. while ((chA = *(LPSTR) pchDelimiter) != MD_ALT_PATH_DELIMETERA &&
  238. chA != MD_PATH_DELIMETERA &&
  239. chA != (CHAR) '\0')
  240. {
  241. (LPSTR) pchDelimiter = CharNextExA(CP_ACP,
  242. (LPSTR) pchDelimiter,
  243. 0);
  244. }
  245. }
  246. // Find the child.
  247. pboReturn = FindChild(strName, (int)DIFF(pchDelimiter-strName), bUnicode, phresReturn);
  248. // If we found the name, move up the pointer to the delimiter
  249. if (pboReturn != NULL)
  250. {
  251. MD_ASSERT(*phresReturn == ERROR_SUCCESS);
  252. strName = pchDelimiter;
  253. }
  254. #if 0 // SAB
  255. // If we didn't find the name, return the "not found" error.
  256. else if (*phresReturn == ERROR_SUCCESS)
  257. {
  258. *phresReturn = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
  259. }
  260. #endif
  261. return(pboReturn);
  262. }
  263. CMDBaseObject *
  264. CMDBaseObject::EnumChildObject(
  265. IN DWORD dwEnumObjectIndex
  266. )
  267. /*++
  268. Routine Description:
  269. Gets a child object by index.
  270. Arguments:
  271. EnumObjectIndex - The 0 based index of the object to get.
  272. Return Value:
  273. CMDBaseObject * - The child object or NULL if the child is not found.
  274. Notes:
  275. --*/
  276. {
  277. PBASEOBJECT_CONTAINER pbocCurrent;
  278. CMDBaseObject *pboReturn;
  279. DWORD i;
  280. for (pbocCurrent = m_pbocChildHead, i=0;
  281. (pbocCurrent!=NULL) && (i < dwEnumObjectIndex);
  282. pbocCurrent=pbocCurrent->NextPtr, i++) {
  283. }
  284. if (pbocCurrent != NULL) {
  285. pboReturn = pbocCurrent->pboMetaObject;
  286. }
  287. else {
  288. pboReturn = NULL;
  289. }
  290. return (pboReturn);
  291. }
  292. PBASEOBJECT_CONTAINER
  293. CMDBaseObject::NextChildObject(
  294. IN PBASEOBJECT_CONTAINER pbocCurrent
  295. )
  296. /*++
  297. Routine Description:
  298. Given a BASEOBJECT_CONTAINER returns the next BASEOBJECT_CONTAINER in the linked list.
  299. Much more efficient than EnumchildObject, if the whole list is being traversed.
  300. Arguments:
  301. pbocCurrent - Current container object.
  302. Return Value:
  303. PBASEOBJECT_CONTAINER - The child object container or NULL if the container is not found.
  304. Notes:
  305. --*/
  306. {
  307. if (pbocCurrent == NULL)
  308. {
  309. return m_pbocChildHead;
  310. }
  311. return pbocCurrent->NextPtr;
  312. }
  313. HRESULT
  314. CMDBaseObject::RemoveChildObject(
  315. IN LPTSTR strName,
  316. IN BOOL bUnicode
  317. )
  318. /*++
  319. Routine Description:
  320. Removes a child object from the list of child objects and deletes it.
  321. Arguments:
  322. Name - The name of the object to remove.
  323. Return Value:
  324. DWORD - ERROR_SUCCESS
  325. ERROR_PATH_NOT_FOUND
  326. --*/
  327. {
  328. MD_ASSERT (strName != NULL);
  329. CMDBaseObject* pboCurrent;
  330. BASEOBJECT_CONTAINER* pbocPrev;
  331. HRESULT hresReturn;
  332. // Find the object, including the previous container.
  333. pboCurrent = FindChild(strName,
  334. /* Length */ -1,
  335. bUnicode,
  336. &hresReturn,
  337. /* fUseHash */ FALSE,
  338. &pbocPrev);
  339. if (hresReturn == ERROR_SUCCESS)
  340. { // Either we found it, or it's not there. But no errors occurred.
  341. if (pboCurrent != NULL)
  342. { // We found it.
  343. BASEOBJECT_CONTAINER* pbocCurrent;
  344. RemoveChildObjectFromHash(pboCurrent);
  345. // Remove from the container chain, keeping a pointer to the container to delete.
  346. if (pbocPrev == NULL)
  347. {
  348. pbocCurrent = m_pbocChildHead;
  349. MD_ASSERT(pbocCurrent != NULL);
  350. m_pbocChildHead = pbocCurrent->NextPtr;
  351. // If tail pointed to pbocCurrent, then head will become NULL,
  352. // in which case tail will be ignored.
  353. }
  354. else
  355. {
  356. pbocCurrent = pbocPrev->NextPtr;
  357. MD_ASSERT(pbocCurrent != NULL);
  358. pbocPrev->NextPtr = pbocCurrent->NextPtr;
  359. if (m_pbocChildTail == pbocCurrent)
  360. {
  361. MD_ASSERT(pbocPrev->NextPtr == NULL);
  362. m_pbocChildTail = pbocPrev;
  363. }
  364. }
  365. // Delete the container. The base object itself is deleted as part of
  366. // CMDHandle::RemoveNotifications.
  367. delete pbocCurrent;
  368. MD_ASSERT(m_cbo != 0);
  369. m_cbo--;
  370. SetLastChangeTime();
  371. }
  372. // If FindChild() succeeded but didn't find anything, return the error.
  373. else
  374. {
  375. hresReturn = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
  376. }
  377. }
  378. return hresReturn;
  379. }
  380. HRESULT
  381. CMDBaseObject::AddChildObjectToHash(
  382. IN CMDBaseObject *pboChild,
  383. IN BASEOBJECT_CONTAINER* pbocChild
  384. )
  385. /*++
  386. Routine Description:
  387. Add child object from the hash table.
  388. Arguments:
  389. Child - The object to remove.
  390. pbocChild - The container for the child object. If NULL,
  391. the child must already be on the child list.
  392. This routine will find the child container, and will
  393. not check the child list for ERROR_DUP_NAME.
  394. Return Value:
  395. DWORD - ERROR_SUCCESS
  396. ERROR_NOT_ENOUGH_MEMORY
  397. ERROR_DUP_NAME
  398. --*/
  399. {
  400. HRESULT hresReturn = NO_ERROR;
  401. BOOL bCheckForDups = (pbocChild == NULL) ? FALSE : TRUE;
  402. // Should we create the hash table now?
  403. if (m_phtChildren == NULL && m_cbo >= cboCreateHashThreashold)
  404. { // Time to create hash table
  405. // Just skip if we can't create table for some reason.
  406. m_phtChildren = new CChildNodeHashTable;
  407. if (m_phtChildren != NULL)
  408. { // Create successful. Let's fill the sucker.
  409. BASEOBJECT_CONTAINER* pboc = m_pbocChildHead;
  410. while (pboc != NULL)
  411. {
  412. LK_RETCODE ret;
  413. MD_ASSERT(pboc->pboMetaObject != NULL);
  414. MD_ASSERT(pboc->pboMetaObject->m_bufKey.QuerySize() > 0);
  415. ret = m_phtChildren->InsertRecord(pboc,
  416. /* fOverwrite */ FALSE);
  417. MD_ASSERT(ret == LK_SUCCESS);
  418. if (ret != LK_SUCCESS)
  419. {
  420. delete m_phtChildren;
  421. m_phtChildren = NULL;
  422. break;
  423. }
  424. pboc = pboc->NextPtr;
  425. }
  426. }
  427. }
  428. // Use hash table if it exists.
  429. if (m_phtChildren != NULL)
  430. {
  431. LK_RETCODE ret;
  432. if (pbocChild == NULL) {
  433. //
  434. // Need container for insert function.
  435. // If it came in as NULL, then the node is not
  436. // really new (ie. rename) and should already be
  437. // on the list, so find it.
  438. //
  439. BASEOBJECT_CONTAINER* pbocIndex = m_pbocChildHead;
  440. while ((pbocIndex != NULL) && (pbocIndex->pboMetaObject != pboChild)) {
  441. pbocIndex = pbocIndex->NextPtr;
  442. }
  443. DBG_ASSERT((pbocIndex != NULL) && (pbocIndex->pboMetaObject == pboChild));
  444. pbocChild = pbocIndex;
  445. }
  446. // Put in hash table. This looks for dups.
  447. ret = m_phtChildren->InsertRecord(pbocChild,
  448. /* fOverwrite */ FALSE);
  449. DBG_ASSERT( ret != LK_KEY_EXISTS);
  450. if (ret == LK_KEY_EXISTS)
  451. {
  452. return RETURNCODETOHRESULT(ERROR_DUP_NAME);
  453. }
  454. if (ret != LK_SUCCESS)
  455. {
  456. MD_ASSERT(ret == LK_SUCCESS); // Put up debug assert now.
  457. delete m_phtChildren;
  458. m_phtChildren = NULL;
  459. goto NoHashTable;
  460. }
  461. }
  462. // If hash table doesn't exist, check for duplicate by searching chain.
  463. else
  464. {
  465. NoHashTable:
  466. if (m_pbocChildHead != NULL && bCheckForDups)
  467. {
  468. LPSTR strChildName;
  469. // Check for duplicates
  470. strChildName = pboChild->GetName(/* bUnicode */ TRUE);
  471. if (strChildName == NULL)
  472. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  473. else if (FindChild(strChildName,
  474. /* Length */ -1,
  475. /* bUnicode */ TRUE,
  476. &hresReturn,
  477. /* fUseHash */ FALSE,
  478. NULL) != NULL)
  479. {
  480. hresReturn = RETURNCODETOHRESULT(ERROR_DUP_NAME);
  481. }
  482. }
  483. }
  484. return hresReturn;
  485. }
  486. VOID
  487. CMDBaseObject::RemoveChildObjectFromHash(
  488. IN CMDBaseObject *pboChild
  489. )
  490. /*++
  491. Routine Description:
  492. Removes a child object from the hash table.
  493. Arguments:
  494. Child - The object to remove.
  495. Return Value:
  496. none
  497. --*/
  498. {
  499. // Delete from the hash table.
  500. if (m_phtChildren != NULL)
  501. {
  502. m_phtChildren->DeleteKey(&pboChild->m_bufKey);
  503. // Delete the hash table if we've gone below the threashold.
  504. if (m_cbo <= cboDeleteHashThreashold)
  505. {
  506. delete m_phtChildren;
  507. m_phtChildren = NULL;
  508. }
  509. }
  510. }
  511. HRESULT
  512. CMDBaseObject::RemoveChildObject(
  513. IN CMDBaseObject *pboChild
  514. )
  515. /*++
  516. Routine Description:
  517. Removes a child object from the list of child objects and deletes it.
  518. Arguments:
  519. Name - The name of the object to remove.
  520. Return Value:
  521. DWORD - ERROR_SUCCESS
  522. ERROR_PATH_NOT_FOUND
  523. --*/
  524. {
  525. MD_ASSERT (pboChild != NULL);
  526. BASEOBJECT_CONTAINER* pbocCurrent;
  527. BASEOBJECT_CONTAINER* pbocPrev;
  528. HRESULT hresReturn;
  529. // Find the object in the container chain.
  530. pbocPrev = NULL;
  531. pbocCurrent = m_pbocChildHead;
  532. while (pbocCurrent != NULL && pbocCurrent->pboMetaObject != pboChild)
  533. {
  534. pbocPrev = pbocCurrent;
  535. pbocCurrent = pbocCurrent->NextPtr;
  536. }
  537. if (pbocCurrent != NULL)
  538. { // Found it
  539. MD_ASSERT (pbocCurrent->pboMetaObject == pboChild);
  540. RemoveChildObjectFromHash(pboChild);
  541. // Remove from the container chain.
  542. if (pbocPrev == NULL)
  543. {
  544. m_pbocChildHead = pbocCurrent->NextPtr;
  545. // If tail pointed to pbocCurrent, then head will become NULL,
  546. // in which case tail will be ignored.
  547. }
  548. else
  549. {
  550. pbocPrev->NextPtr = pbocCurrent->NextPtr;
  551. if (m_pbocChildTail == pbocCurrent)
  552. {
  553. MD_ASSERT(pbocPrev->NextPtr == NULL);
  554. m_pbocChildTail = pbocPrev;
  555. }
  556. }
  557. // Delete it. Actual base object is deleted as part of
  558. // CMDHandle::RemoveNotifications.
  559. delete pbocCurrent;
  560. hresReturn = ERROR_SUCCESS;
  561. MD_ASSERT(m_cbo != 0);
  562. m_cbo--;
  563. SetLastChangeTime();
  564. }
  565. else {
  566. hresReturn = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
  567. }
  568. return hresReturn;
  569. }
  570. HRESULT
  571. CMDBaseObject::InsertDataObject(
  572. IN CMDBaseData *pbdInsert
  573. )
  574. /*++
  575. Routine Description:
  576. Inserts a data object into the list of data objects of that type.
  577. Arguments:
  578. Data - The data object to insert.
  579. Return Value:
  580. DWORD - ERROR_SUCCESS
  581. ERROR_INTERNAL_ERROR
  582. Notes:
  583. Does not check for duplicates. This should be checked by the calling routine.
  584. --*/
  585. {
  586. HRESULT hresReturn = ERROR_SUCCESS;
  587. MD_ASSERT (pbdInsert != NULL);
  588. PDATA_CONTAINER *pdcHead;
  589. PDATA_CONTAINER pdcNew;
  590. pdcNew = new (DATA_CONTAINER);
  591. if (pdcNew == NULL) {
  592. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  593. }
  594. else {
  595. pdcHead = &(m_pdcarrayDataHead[pbdInsert->GetDataType()]);
  596. pdcNew->NextPtr = NULL;
  597. pdcNew->pbdDataObject = pbdInsert;
  598. if (*pdcHead == NULL) {
  599. *pdcHead = pdcNew;
  600. }
  601. else {
  602. //
  603. // It seems likely that the first paths read in will be the most common
  604. // paths, so insert at end of list
  605. //
  606. PDATA_CONTAINER pdcIndex;
  607. for (pdcIndex = *pdcHead;
  608. pdcIndex->NextPtr != NULL;
  609. pdcIndex = pdcIndex->NextPtr) {
  610. }
  611. MD_ASSERT(pdcIndex!=NULL);
  612. MD_ASSERT(pdcIndex->NextPtr==NULL);
  613. pdcIndex->NextPtr = pdcNew;
  614. if ((pbdInsert->GetAttributes() & METADATA_INHERIT) == 0) {
  615. m_dwNumNonInheritableData++;
  616. }
  617. }
  618. }
  619. if (SUCCEEDED(hresReturn)) {
  620. SetLastChangeTime();
  621. }
  622. return(hresReturn);
  623. }
  624. HRESULT
  625. CMDBaseObject::SetDataObject(
  626. IN CMDBaseData *pbdNew
  627. )
  628. /*++
  629. Routine Description:
  630. Sets a data object.
  631. If data of that name does not already exist,
  632. it creates and inserts a data object into the list of data objects
  633. of that type.
  634. If data of that name aready exists, it sets the new data values.
  635. Arguments:
  636. Data - The data to insert.
  637. Return Value:
  638. DWORD - ERROR_SUCCESS
  639. ERROR_NOT_ENOUGH_MEMORY
  640. ERROR_INTERNAL_ERROR
  641. Notes:
  642. Checks for duplicates.
  643. --*/
  644. {
  645. HRESULT hresReturn;
  646. MD_ASSERT (pbdNew != NULL);
  647. CMDBaseData *pbdOld = GetDataObject(pbdNew->GetIdentifier(), METADATA_NO_ATTRIBUTES, ALL_METADATA); //Check for all types
  648. if (pbdOld == pbdNew) {
  649. //
  650. // It's already there, leave it alone.
  651. //
  652. hresReturn = ERROR_SUCCESS;
  653. }
  654. else {
  655. //
  656. // Insert the new first so if there's a problem leave the old.
  657. //
  658. hresReturn = InsertDataObject(pbdNew);
  659. if (SUCCEEDED(hresReturn)) {
  660. pbdNew->IncrementReferenceCount();
  661. if (pbdOld != NULL) {
  662. hresReturn = RemoveDataObject(pbdOld, TRUE);
  663. MD_ASSERT(SUCCEEDED(hresReturn));
  664. }
  665. }
  666. }
  667. return(hresReturn);
  668. }
  669. HRESULT
  670. CMDBaseObject::SetDataObject(
  671. IN PMETADATA_RECORD pmdrMDData,
  672. IN BOOL bUnicode)
  673. /*++
  674. Routine Description:
  675. Sets a data object.
  676. If data of that name does not already exist,
  677. it creates and inserts a data object into the list of data objects
  678. of that type.
  679. If data of that name aready exists, it sets the new data values.
  680. Arguments:
  681. Data - The data to set.
  682. Identifier - The identifier of the data.
  683. Attributes - The flags for the data.
  684. METADATA_INHERIT
  685. UserType - The User Type for the data. User Defined.
  686. DataType - The Type of the data.
  687. DWORD_METADATA
  688. STRING_METADATA
  689. BINARY_METADATA
  690. DataLen - The length of the data. Only used if DataType == BINARY_METADATA.
  691. Data - Pointer to the data.
  692. Return Value:
  693. DWORD - ERROR_SUCCESS
  694. ERROR_NOT_ENOUGH_MEMORY
  695. ERROR_INTERNAL_ERROR
  696. MD_ERROR_CANNOT_REMOVE_SECURE_ATTRIBUTE
  697. Notes:
  698. Checks for duplicates.
  699. --*/
  700. {
  701. HRESULT hresReturn;
  702. CMDBaseData *pbdNew;
  703. CMDBaseData *pbdOld = GetDataObject(pmdrMDData->dwMDIdentifier, METADATA_NO_ATTRIBUTES, ALL_METADATA); //Check for all types
  704. if ((pbdOld != NULL) &&
  705. ((pbdOld->GetAttributes() & METADATA_SECURE) != 0) &&
  706. ((pmdrMDData->dwMDAttributes & METADATA_SECURE) == 0)) {
  707. hresReturn = MD_ERROR_CANNOT_REMOVE_SECURE_ATTRIBUTE;
  708. }
  709. else {
  710. pbdNew = MakeDataObject(pmdrMDData, bUnicode);
  711. if (pbdNew == NULL) {
  712. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  713. }
  714. else {
  715. if (pbdOld == pbdNew) {
  716. //
  717. // It's already there, just correct the ref count,
  718. // which MakeDataObject incremented.
  719. //
  720. DeleteDataObject(pbdNew);
  721. hresReturn = ERROR_SUCCESS;
  722. }
  723. else {
  724. hresReturn = InsertDataObject(pbdNew);
  725. if (FAILED(hresReturn)) {
  726. DeleteDataObject(pbdNew);
  727. pbdNew = NULL;
  728. }
  729. else {
  730. if (pbdOld!=NULL) {
  731. //
  732. // Data exists with same name.
  733. // Need to delete old data.
  734. //
  735. hresReturn = RemoveDataObject(pbdOld, TRUE);
  736. MD_ASSERT(SUCCEEDED(hresReturn));
  737. }
  738. }
  739. }
  740. }
  741. }
  742. return(hresReturn);
  743. }
  744. HRESULT
  745. CMDBaseObject::RemoveDataObject(
  746. IN CMDBaseData *pbdRemove,
  747. IN BOOL bDelete
  748. )
  749. /*++
  750. Routine Description:
  751. Removes and optionally deletes a data object.
  752. Arguments:
  753. Remove - The data object to remove.
  754. Delete - If true, the object is deleted.
  755. Return Value:
  756. BOOL - TRUE if the data was successfully removed.
  757. FALSE if the data object is not associated with this metaobject.
  758. --*/
  759. {
  760. HRESULT hresReturn;
  761. MD_ASSERT (pbdRemove != NULL);
  762. PDATA_CONTAINER *ppdcHead;
  763. PDATA_CONTAINER pdcSave;
  764. ppdcHead = &(m_pdcarrayDataHead[pbdRemove->GetDataType()]);
  765. if (*ppdcHead == NULL) {
  766. hresReturn = MD_ERROR_DATA_NOT_FOUND;
  767. }
  768. else {
  769. if ((*ppdcHead)->pbdDataObject == pbdRemove) {
  770. pdcSave = *ppdcHead;
  771. *ppdcHead = (*ppdcHead)->NextPtr;
  772. delete pdcSave;
  773. hresReturn = ERROR_SUCCESS;
  774. }
  775. else {
  776. PDATA_CONTAINER ppdcIndex;
  777. for (ppdcIndex = *ppdcHead;
  778. (ppdcIndex->NextPtr!=NULL) && (ppdcIndex->NextPtr->pbdDataObject!=pbdRemove);
  779. ppdcIndex=ppdcIndex->NextPtr) {
  780. }
  781. if (ppdcIndex->NextPtr==NULL) {
  782. hresReturn = MD_ERROR_DATA_NOT_FOUND;
  783. }
  784. else {
  785. MD_ASSERT(ppdcIndex->NextPtr->pbdDataObject == pbdRemove);
  786. pdcSave = ppdcIndex->NextPtr;
  787. ppdcIndex->NextPtr = pdcSave->NextPtr;
  788. delete (pdcSave);
  789. hresReturn = ERROR_SUCCESS;
  790. }
  791. }
  792. }
  793. if (SUCCEEDED(hresReturn)) {
  794. if ((pbdRemove->GetAttributes() & METADATA_INHERIT) == 0) {
  795. m_dwNumNonInheritableData--;
  796. }
  797. if (bDelete) {
  798. DeleteDataObject(pbdRemove);
  799. }
  800. SetLastChangeTime();
  801. }
  802. return (hresReturn);
  803. }
  804. CMDBaseData *
  805. CMDBaseObject::RemoveDataObject(
  806. IN DWORD dwIdentifier,
  807. IN DWORD dwDataType,
  808. IN BOOL bDelete
  809. )
  810. /*++
  811. Routine Description:
  812. Removes and optionally deletes a data object.
  813. Arguments:
  814. Name - The name of the data to remove.
  815. DataType - Optional type of the data to remove. If specified, only data of that
  816. type will be removed.
  817. bDelete - If true, the object is deleted.
  818. Return Value:
  819. CMDBaseData * - Pointer to the data object removed. If bDelete == TRUE, the pointer will still be
  820. returned, but will not be valid.
  821. NULL if the data was not found.
  822. --*/
  823. {
  824. CMDBaseData *pbdRemove;
  825. pbdRemove=GetDataObject(dwIdentifier, METADATA_NO_ATTRIBUTES, dwDataType);
  826. if (pbdRemove != NULL) {
  827. MD_REQUIRE(RemoveDataObject(pbdRemove, bDelete) == ERROR_SUCCESS);
  828. }
  829. return(pbdRemove);
  830. }
  831. bool
  832. CMDBaseObject::GenerateKey()
  833. {
  834. LPSTR pstr = (LPSTR) m_strMDName.QueryStrW();
  835. if (pstr == NULL)
  836. return FALSE;
  837. return GenerateBufFromStr(pstr,
  838. /* cch */ -1,
  839. /* fUnicode */ TRUE,
  840. &m_bufKey);
  841. }
  842. bool
  843. CMDBaseObject::GenerateBufFromStr(
  844. IN const char* pstr,
  845. IN int cch,
  846. IN BOOL fUnicode,
  847. OUT CMDKeyBuffer* pbuf)
  848. /*++
  849. Routine Description:
  850. Fills the given buffer with the object key based on the given string.
  851. Arguments:
  852. str - The string to convert into the key.
  853. fUnicode - TRUE if the string is unicode, FALSE if ansi.
  854. pbuf - Pointer to the buffer that will contain the new key.
  855. Return Value:
  856. BOOL - FALSE if out-of-memory allocating the buffer.
  857. --*/
  858. {
  859. BUFFER bufUnicode; // Use this to hold unicode string if needed.
  860. int cchRet; // Length of actual converted string.
  861. MD_ASSERT(cch != 0); // Must either be -1 or a non-null string length.
  862. // If not unicode, convert to unicode now.
  863. if (!fUnicode)
  864. {
  865. // If we know the size, guess at the unicode size.
  866. if (cch > 0)
  867. if (!bufUnicode.Resize(cch*2+50))
  868. return FALSE;
  869. // Loop until we have big enough buffer to hold unicode string
  870. for ( ; ; )
  871. {
  872. // Buffer length can't be zero, or MultiByteToWideChar() will
  873. // interpret this by returning "required buffer length" and do
  874. // no conversion.
  875. MD_ASSERT(bufUnicode.QuerySize() > 1);
  876. cchRet = MultiByteToWideChar(CP_ACP,
  877. MB_PRECOMPOSED,
  878. pstr,
  879. cch,
  880. (LPWSTR) bufUnicode.QueryPtr(),
  881. bufUnicode.QuerySize()/2);
  882. // Handle error during conversion.
  883. if (cchRet == 0)
  884. {
  885. // If error wasn't lack of buffer, fail.
  886. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  887. return FALSE;
  888. // Otherwise, make the buffer larger and try again.
  889. /* else */
  890. if (!bufUnicode.Resize(bufUnicode.QuerySize()+50))
  891. return FALSE;
  892. }
  893. // Succeed, continue.
  894. else
  895. break;
  896. }
  897. // Point to the buffer now.
  898. pstr = (char *) bufUnicode.QueryPtr();
  899. cch = cchRet * 2;
  900. }
  901. // If we know the length, guess at the destination length.
  902. if (cch > 0)
  903. {
  904. if (!pbuf->Resize(cch))
  905. return FALSE;
  906. }
  907. // Otherwise, reset the length to whatever is allocated.
  908. else
  909. pbuf->SyncSize();
  910. // Loop until we have a buffer large enough.
  911. for ( ; ; )
  912. {
  913. // Buffer size can't be 0, because LCMapString will interpret
  914. // this by returning "required buffer length" and not actually
  915. // converting the string.
  916. MD_ASSERT(pbuf->QuerySize() > 0);
  917. cchRet = LCMapStringW(LOCALE_SYSTEM_DEFAULT,
  918. LCMAP_UPPERCASE,
  919. (LPWSTR) pstr,
  920. (cch < 0) ? cch : cch/2,
  921. (LPWSTR) pbuf->QueryPtr(),
  922. pbuf->QuerySize()/2);
  923. // Handle errors
  924. if (cchRet == 0)
  925. {
  926. // If error wasn't lack of buffer, fail.
  927. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  928. return FALSE;
  929. // Otherwise, make the buffer larger and try again.
  930. /* else */
  931. if (!pbuf->Resize(pbuf->QuerySize() + 50))
  932. return FALSE;
  933. }
  934. else
  935. break;
  936. }
  937. // If last character is a null-terminator, remove it in the key.
  938. if (*((LPWSTR) pbuf->QueryPtr() + cchRet - 1) == (WCHAR) '\0')
  939. cchRet--;
  940. // Resize the buffer to the final length. Length includes null-terminator.
  941. if (!pbuf->Resize(cchRet*2))
  942. {
  943. return FALSE;
  944. }
  945. return TRUE;
  946. }
  947. CMDBaseData *
  948. CMDBaseObject::GetDataObjectByType(
  949. IN DWORD dwIdentifier,
  950. IN DWORD dwDataType
  951. )
  952. /*++
  953. Routine Description:
  954. Gets a data object from the list passed in.
  955. Arguments:
  956. Identifier - The identifier of the data to get.
  957. ListHead - The head of the list to search.
  958. Return Value:
  959. CMDBaseData * - Pointer to the data object found.
  960. NULL if the data was not found.
  961. --*/
  962. {
  963. PDATA_CONTAINER pdcIndex;
  964. CMDBaseData *pbdReturn = NULL;
  965. MD_ASSERT((dwDataType > ALL_METADATA) && (dwDataType < INVALID_END_METADATA));
  966. for (pdcIndex=m_pdcarrayDataHead[dwDataType];pdcIndex!=NULL;pdcIndex=pdcIndex->NextPtr) {
  967. if (dwIdentifier == pdcIndex->pbdDataObject->GetIdentifier()) {
  968. break;
  969. }
  970. }
  971. if (pdcIndex != NULL) {
  972. pbdReturn = pdcIndex->pbdDataObject;
  973. }
  974. return (pbdReturn);
  975. }
  976. CMDBaseData *
  977. CMDBaseObject::GetDataObject(
  978. IN DWORD dwIdentifier,
  979. IN DWORD dwAttributes,
  980. IN DWORD dwDataType,
  981. CMDBaseObject **ppboAssociated
  982. )
  983. /*++
  984. Routine Description:
  985. Gets a data object.
  986. Arguments:
  987. Identifier - The identifier of the data to get.
  988. DataType - Optional type of the data to get.
  989. Return Value:
  990. CMDBaseData * - Pointer to the data object found.
  991. NULL if the data was not found.
  992. --*/
  993. {
  994. CMDBaseData *pbdReturn = NULL;
  995. DWORD i;
  996. if (dwDataType == ALL_METADATA) {
  997. for (i = 1; (pbdReturn == NULL) && (i < INVALID_END_METADATA); i++) {
  998. pbdReturn = GetDataObjectByType(dwIdentifier, i);
  999. }
  1000. }
  1001. else {
  1002. pbdReturn = GetDataObjectByType(dwIdentifier, dwDataType);
  1003. }
  1004. if ((ppboAssociated != NULL) && (pbdReturn != NULL)) {
  1005. //
  1006. // Found data in this object
  1007. //
  1008. *ppboAssociated = this;
  1009. }
  1010. if ((pbdReturn == NULL) &&
  1011. (dwAttributes & METADATA_INHERIT) &&
  1012. (GetParent()!=NULL)) {
  1013. pbdReturn = GetParent()->GetInheritableDataObject(dwIdentifier,
  1014. dwDataType,
  1015. ppboAssociated);
  1016. }
  1017. return (pbdReturn);
  1018. }
  1019. CMDBaseData *
  1020. CMDBaseObject::GetInheritableDataObject(
  1021. IN DWORD dwIdentifier,
  1022. IN DWORD dwDataType,
  1023. CMDBaseObject **ppboAssociated
  1024. )
  1025. /*++
  1026. Routine Description:
  1027. Gets a data object.
  1028. Arguments:
  1029. Identifier - The identifier of the data to get.
  1030. DataType - Optional type of the data to get.
  1031. Return Value:
  1032. CMDBaseData * - Pointer to the data object found.
  1033. NULL if the data was not found.
  1034. --*/
  1035. {
  1036. CMDBaseData *pbdReturn = NULL;
  1037. DWORD i;
  1038. if (dwDataType == ALL_METADATA) {
  1039. for (i = 1; (pbdReturn == NULL) && (i < INVALID_END_METADATA); i++) {
  1040. pbdReturn = GetDataObjectByType(dwIdentifier, i);
  1041. }
  1042. }
  1043. else {
  1044. pbdReturn = GetDataObjectByType(dwIdentifier, dwDataType);
  1045. }
  1046. if ((pbdReturn != NULL) &&
  1047. ((pbdReturn->GetAttributes() & METADATA_INHERIT) == 0)) {
  1048. pbdReturn = NULL;
  1049. }
  1050. if ((ppboAssociated != NULL) && (pbdReturn != NULL)) {
  1051. //
  1052. // Found data in this object
  1053. //
  1054. *ppboAssociated = this;
  1055. }
  1056. if ((pbdReturn == NULL) && (GetParent() != NULL)) {
  1057. pbdReturn = GetParent()->GetInheritableDataObject(dwIdentifier,
  1058. dwDataType,
  1059. ppboAssociated);
  1060. }
  1061. return (pbdReturn);
  1062. }
  1063. CMDBaseData *
  1064. CMDBaseObject::EnumDataObjectByType(
  1065. IN DWORD &dwEnumDataIndex,
  1066. IN DWORD dwUserType,
  1067. IN DWORD dwDataType
  1068. )
  1069. /*++
  1070. Routine Description:
  1071. Gets a data object from the list passed in.
  1072. Arguments:
  1073. EnumDataIndex - The 0 based index of the data to get.
  1074. Updated by the number of matching entries found,
  1075. not including the entry returned, if any.
  1076. UserType - Optional UserType of the data to get.
  1077. ListHead - The head of the list to search.
  1078. Return Value:
  1079. CMDBaseData * - Pointer to the data object found.
  1080. NULL if the data was not found.
  1081. --*/
  1082. {
  1083. PDATA_CONTAINER pdcIndex;
  1084. CMDBaseData *dataReturn = NULL;
  1085. MD_ASSERT((dwDataType > ALL_METADATA) && (dwDataType < INVALID_END_METADATA));
  1086. if (dwUserType == ALL_METADATA) {
  1087. for (pdcIndex = m_pdcarrayDataHead[dwDataType];
  1088. (pdcIndex!=NULL) && dwEnumDataIndex != 0;
  1089. pdcIndex=pdcIndex->NextPtr, dwEnumDataIndex--) {
  1090. }
  1091. }
  1092. else {
  1093. for (pdcIndex=m_pdcarrayDataHead[dwDataType];
  1094. (pdcIndex!=NULL);
  1095. pdcIndex=pdcIndex->NextPtr) {
  1096. if (dwUserType == pdcIndex->pbdDataObject->GetUserType()) {
  1097. if (dwEnumDataIndex == 0) {
  1098. break;
  1099. }
  1100. dwEnumDataIndex--;
  1101. }
  1102. }
  1103. }
  1104. if (pdcIndex != NULL) {
  1105. dataReturn = pdcIndex->pbdDataObject;
  1106. }
  1107. return (dataReturn);
  1108. }
  1109. CMDBaseData *
  1110. CMDBaseObject::EnumDataObject(
  1111. IN DWORD dwEnumDataIndex,
  1112. IN DWORD dwAttributes,
  1113. IN DWORD dwUserType,
  1114. IN DWORD dwDataType,
  1115. CMDBaseObject **ppboAssociated
  1116. )
  1117. /*++
  1118. Routine Description:
  1119. Enumerates a data object.
  1120. Arguments:
  1121. EnumDataIndex - The 0 based index of the data to get.
  1122. Attributes - Specifies the Attributes of the get operation.
  1123. UserType - Optional UserType of the data to get.
  1124. DataType - Optional type of the data to get.
  1125. Return Value:
  1126. CMDBaseData * - Pointer to the data object found.
  1127. NULL if the data was not found.
  1128. --*/
  1129. {
  1130. CMDBaseData *pbdReturn = NULL;
  1131. PVOID *ppvMainDataBuf;
  1132. DWORD dwNumBufferEntries;
  1133. DWORD i;
  1134. if (dwDataType == ALL_METADATA) {
  1135. for (i = 1; (pbdReturn == NULL) && (i < INVALID_END_METADATA); i++) {
  1136. pbdReturn = EnumDataObjectByType(dwEnumDataIndex, dwUserType, i);
  1137. }
  1138. }
  1139. else {
  1140. pbdReturn = EnumDataObjectByType(dwEnumDataIndex, dwUserType, dwDataType);
  1141. }
  1142. if ((ppboAssociated != NULL) && (pbdReturn != NULL)) {
  1143. //
  1144. // Found data in this object
  1145. //
  1146. *ppboAssociated = this;
  1147. }
  1148. if ((pbdReturn == NULL) && (dwAttributes & METADATA_INHERIT) && (GetParent() != NULL)) {
  1149. //
  1150. // Not in current object and inherited data is specified.
  1151. // Build list of data objects in current meta object,
  1152. // and call parent for inherited data.
  1153. //
  1154. ppvMainDataBuf = GetMainDataBuffer();
  1155. MD_ASSERT (ppvMainDataBuf != NULL);
  1156. dwNumBufferEntries = 0;
  1157. CopyDataObjectsToBuffer(dwUserType, dwDataType, ppvMainDataBuf, dwNumBufferEntries, FALSE, FALSE);
  1158. pbdReturn = GetParent()->EnumInheritableDataObject(dwEnumDataIndex,
  1159. dwUserType,
  1160. dwDataType,
  1161. ppvMainDataBuf,
  1162. dwNumBufferEntries,
  1163. ppboAssociated);
  1164. FreeMainDataBuffer(ppvMainDataBuf);
  1165. }
  1166. return (pbdReturn);
  1167. }
  1168. CMDBaseData *
  1169. CMDBaseObject::EnumInheritableDataObjectByType(
  1170. IN DWORD &dwEnumDataIndex,
  1171. IN DWORD dwUserType,
  1172. IN DWORD dwDataType,
  1173. IN OUT PVOID *ppvMainDataBuf,
  1174. IN OUT DWORD &dwNumBufferEntries)
  1175. /*++
  1176. Routine Description:
  1177. Gets a data object from the list passed in.
  1178. Arguments:
  1179. EnumDataIndex - The 0 based index of the data to get.
  1180. Updated by the number of matching entries found,
  1181. not including the entry returned, if any.
  1182. UserType - Optional UserType of the data to get.
  1183. ListHead - The head of the list to search.
  1184. MainDataBuf - The buffer filled with previously enumerated values.
  1185. NumBufferEntries - The number of entries in MainDataBuf.
  1186. Return Value:
  1187. CMDBaseData * - Pointer to the data object found.
  1188. NULL if the data was not found.
  1189. --*/
  1190. {
  1191. PDATA_CONTAINER pdcIndex;
  1192. CMDBaseData *pbdReturn = NULL;
  1193. BOOL bRet;
  1194. MD_ASSERT((dwDataType > ALL_METADATA) && (dwDataType < INVALID_END_METADATA));
  1195. if (dwUserType == ALL_METADATA) {
  1196. for (pdcIndex = m_pdcarrayDataHead[dwDataType];
  1197. (pdcIndex!=NULL);
  1198. pdcIndex=pdcIndex->NextPtr) {
  1199. if (((pdcIndex->pbdDataObject->GetAttributes() & METADATA_INHERIT) != 0) &&
  1200. !IsDataInBuffer(pdcIndex->pbdDataObject->GetIdentifier(), ppvMainDataBuf)) {
  1201. if (dwEnumDataIndex == 0) {
  1202. break;
  1203. }
  1204. else {
  1205. bRet = InsertItemIntoDataBuffer((PVOID)pdcIndex->pbdDataObject, ppvMainDataBuf, dwNumBufferEntries);
  1206. MD_ASSERT(bRet);
  1207. if (!bRet) {
  1208. pdcIndex = NULL;
  1209. break;
  1210. }
  1211. }
  1212. dwEnumDataIndex--;
  1213. }
  1214. }
  1215. }
  1216. else {
  1217. for (pdcIndex = m_pdcarrayDataHead[dwDataType];
  1218. (pdcIndex!=NULL);
  1219. pdcIndex=pdcIndex->NextPtr) {
  1220. if (dwUserType == pdcIndex->pbdDataObject->GetUserType() &&
  1221. ((pdcIndex->pbdDataObject->GetAttributes() & METADATA_INHERIT) != 0) &&
  1222. !IsDataInBuffer(pdcIndex->pbdDataObject->GetIdentifier(), ppvMainDataBuf)) {
  1223. if (dwEnumDataIndex == 0) {
  1224. break;
  1225. }
  1226. else {
  1227. bRet = InsertItemIntoDataBuffer((PVOID)pdcIndex->pbdDataObject, ppvMainDataBuf, dwNumBufferEntries);
  1228. MD_ASSERT(bRet);
  1229. if (!bRet) {
  1230. pdcIndex = NULL;
  1231. break;
  1232. }
  1233. }
  1234. dwEnumDataIndex--;
  1235. }
  1236. }
  1237. }
  1238. if (pdcIndex != NULL) {
  1239. pbdReturn = pdcIndex->pbdDataObject;
  1240. }
  1241. return (pbdReturn);
  1242. }
  1243. CMDBaseData *
  1244. CMDBaseObject::EnumInheritableDataObject(
  1245. DWORD &dwEnumDataIndex,
  1246. DWORD dwUserType,
  1247. DWORD dwDataType,
  1248. CMDBaseObject **ppboAssociated)
  1249. {
  1250. PVOID *ppvMainDataBuf = GetMainDataBuffer();
  1251. DWORD dwNumBufferEntries = 0;
  1252. CMDBaseData *pbdReturn;
  1253. MD_ASSERT(ppvMainDataBuf != NULL);
  1254. pbdReturn = EnumInheritableDataObject(dwEnumDataIndex,
  1255. dwUserType,
  1256. dwDataType,
  1257. ppvMainDataBuf,
  1258. dwNumBufferEntries,
  1259. ppboAssociated);
  1260. FreeMainDataBuffer(ppvMainDataBuf);
  1261. return(pbdReturn);
  1262. }
  1263. CMDBaseData *
  1264. CMDBaseObject::EnumInheritableDataObject(
  1265. IN OUT DWORD &dwEnumDataIndex,
  1266. IN DWORD dwUserType,
  1267. IN DWORD dwDataType,
  1268. IN OUT PVOID *ppvMainDataBuf,
  1269. IN OUT DWORD &dwNumBufferEntries,
  1270. CMDBaseObject **ppboAssociated)
  1271. {
  1272. CMDBaseData *pbdReturn = NULL;
  1273. DWORD i;
  1274. if (dwDataType == ALL_METADATA) {
  1275. for (i = 1; (pbdReturn == NULL) && (i < INVALID_END_METADATA); i++) {
  1276. pbdReturn = EnumInheritableDataObjectByType(dwEnumDataIndex,
  1277. dwUserType,
  1278. i,
  1279. ppvMainDataBuf,
  1280. dwNumBufferEntries);
  1281. }
  1282. }
  1283. else {
  1284. pbdReturn = EnumInheritableDataObjectByType(dwEnumDataIndex,
  1285. dwUserType,
  1286. dwDataType,
  1287. ppvMainDataBuf,
  1288. dwNumBufferEntries);
  1289. }
  1290. if ((ppboAssociated != NULL) && (pbdReturn != NULL)) {
  1291. //
  1292. // Found data in this object
  1293. //
  1294. *ppboAssociated = this;
  1295. }
  1296. if ((pbdReturn == NULL) && (GetParent() != NULL)) {
  1297. //
  1298. // Not in current object.
  1299. // Call parent for inherited data.
  1300. //
  1301. pbdReturn = GetParent()->EnumInheritableDataObject(dwEnumDataIndex,
  1302. dwUserType,
  1303. dwDataType,
  1304. ppvMainDataBuf,
  1305. dwNumBufferEntries,
  1306. ppboAssociated);
  1307. }
  1308. return (pbdReturn);
  1309. }
  1310. VOID
  1311. CMDBaseObject::CopyDataObjectsToBufferByType(
  1312. IN DWORD dwUserType,
  1313. IN DWORD dwDataType,
  1314. OUT PVOID *ppvMainDataBuf,
  1315. IN OUT DWORD &dwNumBufferEntries,
  1316. IN BOOL bInheritableOnly,
  1317. IN BOOL bNonSecureOnly)
  1318. /*++
  1319. Routine Description:
  1320. Copies all data objects which match the criteria specified
  1321. by the parameters to MainDataBuf.
  1322. Arguments:
  1323. UserType - Optional UserType of the data to copy.
  1324. ListHead - The list of data objects.
  1325. MainDataBuf - The buffer to copy the data objects to.
  1326. NumBufferEntries - The Number of data objects in MainDataBuf.
  1327. bInheritableOnly - If TRUE, only copies data objects that are
  1328. inheritable and not already in the buffer.
  1329. bNonSecureOnly - If TRUE, then only retrieve non-secure properties
  1330. Return Value:
  1331. --*/
  1332. {
  1333. PDATA_CONTAINER pdcIndex;
  1334. BOOL bRet;
  1335. MD_ASSERT((dwDataType > ALL_METADATA) && (dwDataType < INVALID_END_METADATA));
  1336. if (dwUserType == ALL_METADATA) {
  1337. for (pdcIndex = m_pdcarrayDataHead[dwDataType];
  1338. (pdcIndex!=NULL);
  1339. pdcIndex=pdcIndex->NextPtr) {
  1340. if ((!bInheritableOnly) ||
  1341. (((pdcIndex->pbdDataObject->GetAttributes() & METADATA_INHERIT) != 0) &&
  1342. !IsDataInBuffer(pdcIndex->pbdDataObject->GetIdentifier(), ppvMainDataBuf))){
  1343. if (bNonSecureOnly && pdcIndex->pbdDataObject->GetAttributes() & METADATA_SECURE) {
  1344. continue;
  1345. }
  1346. bRet = InsertItemIntoDataBuffer((PVOID)pdcIndex->pbdDataObject, ppvMainDataBuf, dwNumBufferEntries);
  1347. MD_ASSERT(bRet);
  1348. if (!bRet) {
  1349. break;
  1350. }
  1351. }
  1352. }
  1353. }
  1354. else {
  1355. for (pdcIndex = m_pdcarrayDataHead[dwDataType];
  1356. (pdcIndex!=NULL);
  1357. pdcIndex=pdcIndex->NextPtr) {
  1358. if (dwUserType == pdcIndex->pbdDataObject->GetUserType()) {
  1359. if ((!bInheritableOnly) ||
  1360. (((pdcIndex->pbdDataObject->GetAttributes() & METADATA_INHERIT) != 0) &&
  1361. !IsDataInBuffer(pdcIndex->pbdDataObject->GetIdentifier(), ppvMainDataBuf))){
  1362. if (bNonSecureOnly && pdcIndex->pbdDataObject->GetAttributes() & METADATA_SECURE) {
  1363. continue;
  1364. }
  1365. bRet = InsertItemIntoDataBuffer((PVOID)pdcIndex->pbdDataObject, ppvMainDataBuf, dwNumBufferEntries);
  1366. MD_ASSERT(bRet);
  1367. if (!bRet) {
  1368. break;
  1369. }
  1370. }
  1371. }
  1372. }
  1373. }
  1374. }
  1375. VOID
  1376. CMDBaseObject::CopyDataObjectsToBuffer(
  1377. IN DWORD dwUserType,
  1378. IN DWORD dwDataType,
  1379. OUT PVOID *ppvMainDataBuf,
  1380. IN OUT DWORD &dwNumBufferEntries,
  1381. IN BOOL bInheritableOnly,
  1382. IN BOOL bNonSecureOnly)
  1383. /*++
  1384. Routine Description:
  1385. Copies all data objects which match the criteria specified
  1386. by the parameters to MainDataBuf.
  1387. Arguments:
  1388. UserType - Optional UserType of the data to copy.
  1389. DataType - Optional UserType of the data to copy.
  1390. MainDataBuf - The buffer to copy the data objects to.
  1391. NumBufferEntries - The Number of data objects in MainDataBuf.
  1392. bInheritableOnly - If TRUE, only copies data objects that are
  1393. inheritable and not already in the buffer.
  1394. bNonSecureOnly - If TRUE, then copy only non-secure properties
  1395. Return Value:
  1396. --*/
  1397. {
  1398. DWORD i;
  1399. if (dwDataType == ALL_METADATA) {
  1400. for (i = 1; i < INVALID_END_METADATA; i++) {
  1401. CopyDataObjectsToBufferByType(dwUserType, i, ppvMainDataBuf, dwNumBufferEntries, bInheritableOnly, bNonSecureOnly);
  1402. }
  1403. }
  1404. else {
  1405. CopyDataObjectsToBufferByType(dwUserType, dwDataType, ppvMainDataBuf, dwNumBufferEntries, bInheritableOnly, bNonSecureOnly);
  1406. }
  1407. }
  1408. DWORD
  1409. CMDBaseObject::GetAllDataObjects(
  1410. OUT PVOID *ppvMainDataBuf,
  1411. IN DWORD dwAttributes,
  1412. IN DWORD dwUserType,
  1413. IN DWORD dwDataType,
  1414. IN BOOL bInheritableOnly,
  1415. IN BOOL bNonSecureOnly
  1416. )
  1417. /*++
  1418. Routine Description:
  1419. Gets all data objects which match the criteria specified by the parameters.
  1420. Arguments:
  1421. MainDataBuf - The buffer to store the data objects in.
  1422. Attributes - Specifies the Attributes of the get operation.
  1423. UserType - Optional UserType of the data to get.
  1424. DataType - Optional type of the data to get.
  1425. bInheritableOnly - If TRUE, only gets data objects that are
  1426. inheritable and not already in the buffer.
  1427. bNonSecureOnly - If TRUE, only copy non-secure properties
  1428. Return Value:
  1429. DWORD - Number of Data Objects in Buffer.
  1430. --*/
  1431. {
  1432. DWORD dwNumBufferEntries;
  1433. CMDBaseObject *objIndex;
  1434. //
  1435. // Not in current object and inherited data is specified.
  1436. // Build list of data objects in current meta object,
  1437. // and call parent for inherited data.
  1438. //
  1439. MD_ASSERT (ppvMainDataBuf != NULL);
  1440. dwNumBufferEntries = 0;
  1441. CopyDataObjectsToBuffer(dwUserType,
  1442. dwDataType,
  1443. ppvMainDataBuf,
  1444. dwNumBufferEntries,
  1445. bInheritableOnly,
  1446. bNonSecureOnly);
  1447. if (dwAttributes & METADATA_INHERIT) {
  1448. for (objIndex = GetParent(); objIndex != NULL; objIndex = objIndex->GetParent()) {
  1449. objIndex->CopyDataObjectsToBuffer(dwUserType,
  1450. dwDataType,
  1451. ppvMainDataBuf,
  1452. dwNumBufferEntries,
  1453. TRUE,
  1454. bNonSecureOnly);
  1455. }
  1456. }
  1457. return (dwNumBufferEntries);
  1458. }
  1459. HRESULT
  1460. CMDBaseObject::GetDataRecursive(
  1461. IN OUT BUFFER *pbufMainDataBuf,
  1462. IN DWORD dwMDIdentifier,
  1463. IN DWORD dwMDDataType,
  1464. IN OUT DWORD &rdwNumMetaObjects)
  1465. {
  1466. CMDBaseObject *pboChild;
  1467. DWORD i;
  1468. MD_ASSERT (pbufMainDataBuf != NULL);
  1469. HRESULT hresReturn = ERROR_SUCCESS;
  1470. if (GetDataObject(dwMDIdentifier,
  1471. METADATA_NO_ATTRIBUTES,
  1472. dwMDDataType,
  1473. NULL) != NULL) {
  1474. DWORD dwSize = sizeof(CMDBaseObject *) * (rdwNumMetaObjects + 1);
  1475. if (pbufMainDataBuf->QuerySize() < dwSize) {
  1476. if (!pbufMainDataBuf->Resize(dwSize + (sizeof(CMDBaseObject *) * 1000))) {
  1477. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  1478. }
  1479. }
  1480. if (SUCCEEDED(hresReturn)) {
  1481. ((CMDBaseObject **)(pbufMainDataBuf->QueryPtr()))[rdwNumMetaObjects++] = (CMDBaseObject *)this;
  1482. }
  1483. }
  1484. for (i = 0;
  1485. SUCCEEDED(hresReturn) &&
  1486. (pboChild = EnumChildObject(i)) != NULL;
  1487. i++) {
  1488. hresReturn = pboChild->GetDataRecursive(pbufMainDataBuf,
  1489. dwMDIdentifier,
  1490. dwMDDataType,
  1491. rdwNumMetaObjects);
  1492. }
  1493. return hresReturn;
  1494. }
  1495. VOID
  1496. CMDBaseObject::SetLastChangeTime(PFILETIME pftLastChangeTime)
  1497. {
  1498. if (pftLastChangeTime != NULL) {
  1499. m_ftLastChangeTime = *pftLastChangeTime;
  1500. }
  1501. else {
  1502. GetSystemTimeAsFileTime(&m_ftLastChangeTime);
  1503. }
  1504. }
  1505. PFILETIME
  1506. CMDBaseObject::GetLastChangeTime()
  1507. {
  1508. return &m_ftLastChangeTime;
  1509. }
  1510. DWORD
  1511. CMDBaseObject::GetObjectLevel()
  1512. {
  1513. DWORD dwLevel = 0;
  1514. if (m_pboParent != NULL) {
  1515. dwLevel = m_pboParent->GetObjectLevel() + 1;
  1516. }
  1517. return dwLevel;
  1518. }
  1519. BOOL
  1520. CMDBaseObject::IsDataInBuffer(
  1521. IN DWORD dwIdentifier,
  1522. IN PVOID *ppvMainDataBuf)
  1523. /*++
  1524. Routine Description:
  1525. Checks if the buffer contains an object with the specified id.
  1526. Arguments:
  1527. Identifier - The id to check for.
  1528. MainDataBuf - The buffer to search.
  1529. Return Value:
  1530. BOOL - TRUE if the buffer contains data with the specified id.
  1531. --*/
  1532. {
  1533. BOOL bReturn = FALSE;
  1534. DWORD i;
  1535. CMDBaseData *pbdDataObject;
  1536. for (i = 0;
  1537. (pbdDataObject = (CMDBaseData *)GetItemFromDataBuffer(ppvMainDataBuf, i)) != NULL;
  1538. i++) {
  1539. if (pbdDataObject->GetIdentifier() == dwIdentifier) {
  1540. bReturn = TRUE;
  1541. break;
  1542. }
  1543. }
  1544. return (bReturn);
  1545. }
  1546. #if 0 // No longer used. /SAB
  1547. BOOL
  1548. CMDBaseObject::CompareDelimitedString(
  1549. IN LPTSTR strNonDelimitedString,
  1550. IN OUT LPTSTR &strDelimitedString,
  1551. IN BOOL bUnicode)
  1552. /*++
  1553. Routine Description:
  1554. Compared a nondelimeted string to a delimeted string.
  1555. Updates Delimited String on success to point past the string.
  1556. Arguments:
  1557. NonDelimiterString - The nondelimited string.
  1558. DelimiterString - The delimited string.
  1559. Return Value:
  1560. BOOL - TRUE if strings are the same.
  1561. --*/
  1562. {
  1563. LPTSTR i,j;
  1564. BOOL RetCode = FALSE;
  1565. j = strDelimitedString;
  1566. DWORD dwStringLen;
  1567. /*
  1568. //
  1569. // Change in semantics. To differentiate between "/" and "//",
  1570. // the leading delimeter is skipped before we get here.
  1571. //
  1572. // Skip leading delimeter, if any
  1573. //
  1574. if ((*j == MD_PATH_DELIMETER) || (*j == MD_ALT_PATH_DELIMETER)) {
  1575. j++;
  1576. }
  1577. */
  1578. if (bUnicode) {
  1579. dwStringLen = wcslen((LPWSTR)strNonDelimitedString);
  1580. //
  1581. // Compare up to delimiter
  1582. // Actually we don't need to check for the delimiter here
  1583. // because NonDelimitedString cannot contain delimiter, so
  1584. // *j==*i will fail on delimiter. Also do not need to check if *i
  1585. // == \0 because *j==*i would fail if *j were not also equal to \0
  1586. // for (i=strNonDelimitedString;((*j == *i) && (*j!=(TCHAR)'\0'));i++,j++) {
  1587. // }
  1588. if (_wcsnicmp((LPWSTR)strDelimitedString, (LPWSTR)strNonDelimitedString, dwStringLen) == 0) {
  1589. if (((*((LPWSTR)strDelimitedString + dwStringLen)==MD_ALT_PATH_DELIMETERW) ||
  1590. (*((LPWSTR)strDelimitedString + dwStringLen)==MD_PATH_DELIMETERW) ||
  1591. (*((LPWSTR)strDelimitedString + dwStringLen)== (WCHAR)'\0'))) { //We have a match
  1592. RetCode = TRUE;
  1593. strDelimitedString += dwStringLen * sizeof(WCHAR); //Point to next section or \0
  1594. }
  1595. }
  1596. }
  1597. else {
  1598. dwStringLen = MD_STRLEN(strNonDelimitedString);
  1599. //
  1600. // Compare up to delimiter
  1601. // Actually we don't need to check for the delimiter here
  1602. // because NonDelimitedString cannot contain delimiter, so
  1603. // *j==*i will fail on delimiter. Also do not need to check if *i
  1604. // == \0 because *j==*i would fail if *j were not also equal to \0
  1605. // for (i=strNonDelimitedString;((*j == *i) && (*j!=(TCHAR)'\0'));i++,j++) {
  1606. // }
  1607. if (MD_STRNICMP(strDelimitedString, strNonDelimitedString, dwStringLen) == 0) {
  1608. DWORD dwStrBytes = MD_STRBYTES(strNonDelimitedString);
  1609. if (((*(strDelimitedString + dwStrBytes)==MD_ALT_PATH_DELIMETERA) ||
  1610. (*(strDelimitedString + dwStrBytes)==MD_PATH_DELIMETERA) ||
  1611. (*(strDelimitedString + dwStrBytes)== (CHAR)'\0'))) { //We have a match
  1612. RetCode = TRUE;
  1613. strDelimitedString += dwStrBytes; //Point to next section or \0
  1614. }
  1615. }
  1616. }
  1617. return (RetCode);
  1618. }
  1619. #endif
  1620. CMDBaseObject*
  1621. CMDBaseObject::FindChild(
  1622. LPSTR szName, // Name of child to find.
  1623. int cchName, // Length of the name.
  1624. BOOL fUnicode, // TRUE if unicode name.
  1625. HRESULT* phresult, // Result code.
  1626. BOOL fUseHash, // Allow use of hash table
  1627. BASEOBJECT_CONTAINER** ppbocPrev) // If non-NULL & !fUseHash, prev. object container in list.
  1628. {
  1629. UCHAR localBufferForBufKey[SIZE_FOR_ON_STACK_BUFFER];
  1630. CMDKeyBuffer bufKey (localBufferForBufKey,SIZE_FOR_ON_STACK_BUFFER);
  1631. BASEOBJECT_CONTAINER* pbocCurrent = NULL;
  1632. MD_ASSERT(phresult != NULL);
  1633. //
  1634. // Trap case of being called with an empty path segment.
  1635. // GenerateBufFromStr should not be called with cch == 0
  1636. //
  1637. if( cchName == 0 )
  1638. {
  1639. *phresult = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
  1640. return NULL;
  1641. }
  1642. // Convert the given string to a key.
  1643. if (!GenerateBufFromStr(szName, cchName, fUnicode, &bufKey))
  1644. {
  1645. *phresult = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  1646. return NULL;
  1647. }
  1648. // Use hash table if it exists and we are allowed to.
  1649. if (fUseHash && m_phtChildren != NULL)
  1650. {
  1651. m_phtChildren->FindKey(&bufKey, &pbocCurrent);
  1652. }
  1653. // Otherwise use brute force linear search.
  1654. else
  1655. {
  1656. BASEOBJECT_CONTAINER* pbocPrev = NULL;
  1657. pbocCurrent = m_pbocChildHead;
  1658. while (pbocCurrent != NULL &&
  1659. !FCompareKeys(&bufKey, &pbocCurrent->pboMetaObject->m_bufKey))
  1660. {
  1661. pbocPrev = pbocCurrent;
  1662. pbocCurrent = pbocCurrent->NextPtr;
  1663. }
  1664. if (ppbocPrev != NULL)
  1665. *ppbocPrev = pbocPrev;
  1666. }
  1667. *phresult = ERROR_SUCCESS;
  1668. if (pbocCurrent != NULL)
  1669. return pbocCurrent->pboMetaObject;
  1670. /* else */
  1671. return NULL;
  1672. }
  1673. void CMDBaseObject::CascadingDataCleanup()
  1674. /*++
  1675. Routine Description:
  1676. Deletes all data and recursively deletes all data of child objects.
  1677. Arguments:
  1678. Return Value:
  1679. --*/
  1680. {
  1681. PDATA_CONTAINER pdcIndex, pdcSave;
  1682. PBASEOBJECT_CONTAINER pbocIndex, pbocSave;
  1683. int i;
  1684. for (i = 1; i < INVALID_END_METADATA; i++) {
  1685. for (pdcIndex=m_pdcarrayDataHead[i];pdcIndex!=NULL;pdcIndex=pdcSave) {
  1686. pdcSave=pdcIndex->NextPtr;
  1687. delete(pdcIndex);
  1688. }
  1689. m_pdcarrayDataHead[i] = NULL;
  1690. }
  1691. for (pbocIndex=m_pbocChildHead;pbocIndex!=NULL;pbocIndex=pbocSave) {
  1692. pbocSave=pbocIndex->NextPtr;
  1693. pbocIndex->pboMetaObject->CascadingDataCleanup();
  1694. }
  1695. return;
  1696. }