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.

826 lines
21 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. Importer.cpp
  5. Abstract:
  6. IIS MetaBase subroutines to support Import
  7. Author:
  8. Mohit Srivastava 04-April-01
  9. Revision History:
  10. Notes:
  11. --*/
  12. #include "precomp.hxx"
  13. const WCHAR CImporter::sm_wszInheritedPropertiesLocationPrefix[] = L"inherited:";
  14. const ULONG CImporter::sm_cchInheritedPropertiesLocationPrefix =
  15. sizeof(sm_wszInheritedPropertiesLocationPrefix)/sizeof(WCHAR) - 1;
  16. //
  17. // public
  18. //
  19. CImporter::CImporter(
  20. LPCWSTR i_wszFileName,
  21. LPCSTR i_pszPassword)
  22. {
  23. m_bInitCalled = false;
  24. m_wszFileName = i_wszFileName;
  25. m_pszPassword = i_pszPassword;
  26. }
  27. CImporter::~CImporter()
  28. {
  29. }
  30. HRESULT CImporter::Init()
  31. {
  32. MD_ASSERT(m_bInitCalled == false);
  33. m_bInitCalled = true;
  34. return InitIST();
  35. }
  36. HRESULT CImporter::ShowPathsInFile(
  37. LPCWSTR pszKeyType,
  38. DWORD dwMDBufferSize,
  39. LPWSTR pszBuffer,
  40. DWORD* pdwMDRequiredBufferSize)
  41. {
  42. HRESULT hr = S_OK;
  43. //
  44. // All of the stuff is read into pISTProperty.
  45. // Now loop through and populate in-memory cache.
  46. // Properties are sorted by location.
  47. //
  48. ULONG acbMBPropertyRow[cMBProperty_NumberOfColumns];
  49. tMBPropertyRow MBPropertyRow;
  50. DWORD dwPreviousLocationID = (DWORD)-1;
  51. DWORD bufLoc = 0;
  52. DWORD dSize = 0;
  53. for(ULONG i=0; ;i++)
  54. {
  55. hr = m_spISTProperty->GetColumnValues(
  56. i,
  57. cMBProperty_NumberOfColumns,
  58. 0,
  59. acbMBPropertyRow,
  60. (LPVOID*)&MBPropertyRow);
  61. if(E_ST_NOMOREROWS == hr)
  62. {
  63. hr = S_OK;
  64. break;
  65. }
  66. else if(FAILED(hr))
  67. {
  68. DBGINFO((DBG_CONTEXT,
  69. "[ReadSomeDataFromXML] GetColumnValues failed with hr = 0x%x. Table:%ws. Read row index:%d.\n", \
  70. hr, wszTABLE_MBProperty, i));
  71. return hr;
  72. }
  73. bool bNewLocation = false;
  74. if(dwPreviousLocationID != *MBPropertyRow.pLocationID)
  75. {
  76. dwPreviousLocationID = *MBPropertyRow.pLocationID;
  77. bNewLocation = true;
  78. }
  79. if(*MBPropertyRow.pID == MD_KEY_TYPE ||
  80. *MBPropertyRow.pID == MD_SERVER_COMMENT)
  81. {
  82. if (!wcscmp((LPCWSTR)MBPropertyRow.pValue, pszKeyType))
  83. {
  84. // MBPropertyRow.pLocation
  85. dSize = (DWORD)wcslen(MBPropertyRow.pLocation);
  86. if (bufLoc + dSize < dwMDBufferSize - 1)
  87. {
  88. wcscpy(&(pszBuffer[bufLoc]), MBPropertyRow.pLocation);
  89. pszBuffer[bufLoc + dSize] = 0;
  90. }
  91. bufLoc += dSize+1;
  92. }
  93. }
  94. }
  95. if (bufLoc < dwMDBufferSize)
  96. {
  97. pszBuffer[bufLoc] = 0;
  98. }
  99. else
  100. {
  101. pszBuffer[dwMDBufferSize-1] = 0;
  102. pszBuffer[dwMDBufferSize-2] = 0;
  103. }
  104. *pdwMDRequiredBufferSize = bufLoc;
  105. return hr;
  106. }
  107. HRESULT CImporter::DoIt(
  108. LPWSTR i_wszSourcePath,
  109. LPCWSTR i_wszKeyType,
  110. DWORD i_dwMDFlags,
  111. CMDBaseObject** o_ppboNew)
  112. /*++
  113. Synopsis:
  114. Arguments: [i_wszSourcePath] -
  115. [i_wszKeyType] -
  116. [i_dwMDFlags] -
  117. [o_ppboNew] -
  118. Return Value:
  119. --*/
  120. {
  121. MD_ASSERT(m_bInitCalled);
  122. MD_ASSERT(i_wszKeyType);
  123. MD_ASSERT(o_ppboNew);
  124. MD_ASSERT(*o_ppboNew == NULL);
  125. HRESULT hr = S_OK;
  126. BOOL bSawSourcePath = false;
  127. LPWSTR pLocation = NULL;
  128. //
  129. // This is a pointer to some node in *o_ppboNew
  130. // It is the current node we are reading to.
  131. //
  132. CMDBaseObject* pboRead = NULL;
  133. //
  134. // Used for decryption
  135. //
  136. IIS_CRYPTO_STORAGE* pStorage = NULL;
  137. g_LockMasterResource.ReadLock();
  138. hr = InitSessionKey(m_spISTProperty, &pStorage, (LPSTR)m_pszPassword);
  139. g_LockMasterResource.ReadUnlock();
  140. if(FAILED(hr))
  141. {
  142. goto exit;
  143. }
  144. //
  145. // Create the parent base object
  146. //
  147. *o_ppboNew = new CMDBaseObject(L"Thenamedoesntmatter", NULL);
  148. if (*o_ppboNew == NULL || !((*o_ppboNew)->IsValid()) )
  149. {
  150. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  151. delete *o_ppboNew;
  152. goto exit;
  153. }
  154. //
  155. // All of the stuff is read into pISTProperty.
  156. // Now loop through and populate in-memory cache.
  157. // Properties are sorted by location.
  158. //
  159. ULONG acbMBPropertyRow[cMBProperty_NumberOfColumns];
  160. tMBPropertyRow MBPropertyRow;
  161. BOOL bSkipLocation = FALSE;
  162. DWORD dwPreviousLocationID = (DWORD)-1;
  163. Relation eRelation = eREL_NONE;
  164. for(ULONG i=0; ;i++)
  165. {
  166. BOOL bLocationWithProperty = TRUE;
  167. BOOL bNewLocation = FALSE;
  168. hr = m_spISTProperty->GetColumnValues(
  169. i,
  170. cMBProperty_NumberOfColumns,
  171. 0,
  172. acbMBPropertyRow,
  173. (LPVOID*)&MBPropertyRow);
  174. if(E_ST_NOMOREROWS == hr)
  175. {
  176. hr = S_OK;
  177. break;
  178. }
  179. else if(FAILED(hr))
  180. {
  181. DBGINFOW((DBG_CONTEXT,
  182. L"[ReadSomeDataFromXML] GetColumnValues failed with hr = 0x%x. Table:%s. Read row index:%d.\n", \
  183. hr, wszTABLE_MBProperty, i));
  184. goto exit;
  185. }
  186. if(0 == wcscmp(MD_GLOBAL_LOCATIONW, MBPropertyRow.pLocation))
  187. {
  188. //
  189. // Ignore globals.
  190. //
  191. continue;
  192. }
  193. if((*MBPropertyRow.pID == MD_LOCATION) && (*MBPropertyRow.pName == MD_CH_LOC_NO_PROPERTYW))
  194. {
  195. bLocationWithProperty = FALSE;
  196. }
  197. if(dwPreviousLocationID != *MBPropertyRow.pLocationID)
  198. {
  199. bNewLocation = TRUE;
  200. bSkipLocation = FALSE;
  201. dwPreviousLocationID = *MBPropertyRow.pLocationID;
  202. pboRead = *o_ppboNew;
  203. pLocation = MBPropertyRow.pLocation;
  204. if(*MBPropertyRow.pGroup == eMBProperty_IIsInheritedProperties)
  205. {
  206. if(_wcsnicmp(
  207. pLocation,
  208. sm_wszInheritedPropertiesLocationPrefix,
  209. sm_cchInheritedPropertiesLocationPrefix) == 0)
  210. {
  211. pLocation += sm_cchInheritedPropertiesLocationPrefix;
  212. }
  213. }
  214. }
  215. if(bSkipLocation)
  216. {
  217. continue;
  218. }
  219. #if DBG
  220. if(bLocationWithProperty == false)
  221. {
  222. MD_ASSERT(bNewLocation);
  223. }
  224. #endif
  225. if(bNewLocation)
  226. {
  227. //
  228. // See if we're at a (grand*)child or self
  229. //
  230. eRelation = GetRelation(i_wszSourcePath, pLocation);
  231. switch(eRelation)
  232. {
  233. case eREL_SELF:
  234. if(*MBPropertyRow.pGroup != eMBProperty_IIsInheritedProperties)
  235. {
  236. bSawSourcePath = true;
  237. }
  238. break;
  239. case eREL_PARENT:
  240. if(!(i_dwMDFlags & MD_IMPORT_INHERITED))
  241. {
  242. bSkipLocation = TRUE;
  243. continue;
  244. }
  245. break;
  246. case eREL_CHILD:
  247. if(i_dwMDFlags & MD_IMPORT_NODE_ONLY)
  248. {
  249. bSkipLocation = TRUE;
  250. continue;
  251. }
  252. break;
  253. default: // eRelation == eREL_NONE
  254. bSkipLocation = TRUE;
  255. continue;
  256. }
  257. if(*MBPropertyRow.pGroup == eMBProperty_IIsInheritedProperties)
  258. {
  259. if(!(i_dwMDFlags & MD_IMPORT_INHERITED))
  260. {
  261. bSkipLocation = TRUE;
  262. continue;
  263. }
  264. }
  265. }
  266. //
  267. // Some checks to see whether we skip just the current property, but not
  268. // necessarily the entire location.
  269. //
  270. if(*MBPropertyRow.pGroup == eMBProperty_IIsInheritedProperties)
  271. {
  272. if( !(fMBProperty_INHERIT & *MBPropertyRow.pAttributes) )
  273. {
  274. continue;
  275. }
  276. }
  277. else
  278. {
  279. //
  280. // Check for keytype match
  281. //
  282. if( eRelation == eREL_SELF &&
  283. *MBPropertyRow.pID == MD_KEY_TYPE &&
  284. MBPropertyRow.pValue != NULL &&
  285. i_wszKeyType[0] != L'\0' )
  286. {
  287. if(_wcsicmp((LPWSTR)MBPropertyRow.pValue, i_wszKeyType) != 0)
  288. {
  289. hr = RETURNCODETOHRESULT(ERROR_NO_MATCH);
  290. goto exit;
  291. }
  292. }
  293. }
  294. if(eRelation == eREL_PARENT)
  295. {
  296. if( !(fMBProperty_INHERIT & *MBPropertyRow.pAttributes) )
  297. {
  298. continue;
  299. }
  300. }
  301. if(bNewLocation && (eRelation != eREL_PARENT))
  302. {
  303. //
  304. // Create node in the metabase if it is not there yet.
  305. // pboRead is pointer to this node.
  306. //
  307. hr = ReadMetaObject(i_wszSourcePath,
  308. *o_ppboNew,
  309. pLocation,
  310. &pboRead);
  311. if(FAILED(hr))
  312. {
  313. goto exit;
  314. }
  315. }
  316. if(bLocationWithProperty)
  317. {
  318. MD_ASSERT(pboRead != NULL);
  319. hr = ReadDataObject(pboRead,
  320. (LPVOID*)&MBPropertyRow,
  321. acbMBPropertyRow,
  322. pStorage,
  323. TRUE);
  324. if(FAILED(hr))
  325. {
  326. goto exit;
  327. }
  328. }
  329. }
  330. if(!bSawSourcePath)
  331. {
  332. hr = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
  333. goto exit;
  334. }
  335. exit:
  336. //
  337. // Cleanup
  338. //
  339. if(FAILED(hr) && NULL != *o_ppboNew)
  340. {
  341. delete (*o_ppboNew);
  342. *o_ppboNew = NULL;
  343. }
  344. delete pStorage;
  345. pStorage = NULL;
  346. return hr;
  347. }
  348. HRESULT CImporter::InitIST()
  349. /*++
  350. Synopsis:
  351. Return Value:
  352. --*/
  353. {
  354. HRESULT hr = S_OK;
  355. STQueryCell QueryCell[1];
  356. //
  357. // Get the property table.
  358. //
  359. QueryCell[0].pData = (LPVOID)m_wszFileName;
  360. QueryCell[0].eOperator = eST_OP_EQUAL;
  361. QueryCell[0].iCell = iST_CELL_FILE;
  362. QueryCell[0].dbType = DBTYPE_WSTR;
  363. QueryCell[0].cbSize = (lstrlenW(m_wszFileName)+1)*sizeof(WCHAR);
  364. ULONG cCell = sizeof(QueryCell)/sizeof(STQueryCell);
  365. //
  366. // No need to initilize dispenser (InitializeSimpleTableDispenser()),
  367. // because we now specify USE_CRT=1 in sources, which means that
  368. // globals will be initialized.
  369. //
  370. hr = DllGetSimpleObjectByIDEx( eSERVERWIRINGMETA_TableDispenser, IID_ISimpleTableDispenser2, (VOID**)&m_spISTDisp, WSZ_PRODUCT_IIS );
  371. if(FAILED(hr))
  372. {
  373. DBGERROR((
  374. DBG_CONTEXT,
  375. "[%s] DllGetSimpleObjectByIDEx failed with hr = 0x%x.\n",__FUNCTION__,hr));
  376. return hr;
  377. }
  378. hr = m_spISTDisp->GetTable(
  379. wszDATABASE_METABASE,
  380. wszTABLE_MBProperty,
  381. (LPVOID)QueryCell,
  382. (LPVOID)&cCell,
  383. eST_QUERYFORMAT_CELLS,
  384. fST_LOS_DETAILED_ERROR_TABLE | fST_LOS_NO_LOGGING,
  385. (LPVOID *)&m_spISTProperty);
  386. //
  387. // Log warnings/errors in getting the mb property table
  388. // Do this BEFORE checking the return code of GetTable.
  389. //
  390. CComPtr<IErrorInfo> spErrorInfo;
  391. HRESULT hrErrorTable = GetErrorInfo(0, &spErrorInfo);
  392. if(hrErrorTable == S_OK) // GetErrorInfo returns S_FALSE when there is no error object
  393. {
  394. //
  395. // Get the ICatalogErrorLogger interface to log the errors.
  396. //
  397. CComPtr<IAdvancedTableDispenser> spISTDispAdvanced;
  398. hrErrorTable = m_spISTDisp->QueryInterface(
  399. IID_IAdvancedTableDispenser,
  400. (LPVOID*)&spISTDispAdvanced);
  401. if(FAILED(hrErrorTable))
  402. {
  403. DBGWARN((
  404. DBG_CONTEXT,
  405. "[%s] Could not QI for Adv Dispenser, hr=0x%x\n", __FUNCTION__, hrErrorTable));
  406. return hr;
  407. }
  408. hrErrorTable = spISTDispAdvanced->GetCatalogErrorLogger(&m_spILogger);
  409. if(FAILED(hrErrorTable))
  410. {
  411. DBGWARN((
  412. DBG_CONTEXT,
  413. "[%s] Could not get ICatalogErrorLogger2, hr=0x%x\n", __FUNCTION__, hrErrorTable));
  414. return hr;
  415. }
  416. //
  417. // Get the ISimpleTableRead2 interface to read the errors.
  418. //
  419. hrErrorTable =
  420. spErrorInfo->QueryInterface(IID_ISimpleTableRead2, (LPVOID*)&m_spISTError);
  421. if(FAILED(hrErrorTable))
  422. {
  423. DBGWARN((DBG_CONTEXT, "[%s] Could not get ISTRead2 from IErrorInfo\n, __FUNCTION__"));
  424. return hr;
  425. }
  426. for(ULONG iRow=0; ; iRow++)
  427. {
  428. tDETAILEDERRORSRow ErrorInfo;
  429. hrErrorTable = m_spISTError->GetColumnValues(
  430. iRow,
  431. cDETAILEDERRORS_NumberOfColumns,
  432. 0,
  433. 0,
  434. (LPVOID*)&ErrorInfo);
  435. if(hrErrorTable == E_ST_NOMOREROWS)
  436. {
  437. break;
  438. }
  439. if(FAILED(hrErrorTable))
  440. {
  441. DBGWARN((DBG_CONTEXT, "[%s] Could not read an error row.\n", __FUNCTION__));
  442. return hr;
  443. }
  444. hrErrorTable =
  445. m_spILogger->ReportError(
  446. BaseVersion_DETAILEDERRORS,
  447. ExtendedVersion_DETAILEDERRORS,
  448. cDETAILEDERRORS_NumberOfColumns,
  449. 0,
  450. (LPVOID*)&ErrorInfo);
  451. if(FAILED(hrErrorTable))
  452. {
  453. DBGWARN((DBG_CONTEXT, "[%s] Could not log error.\n", __FUNCTION__));
  454. return hr;
  455. }
  456. hr = MD_ERROR_READ_METABASE_FILE;
  457. } // for(ULONG iRow=0; ; iRow++)
  458. } // if(hrErrorTable == S_OK)
  459. if(FAILED(hr))
  460. {
  461. DBGERROR((DBG_CONTEXT, "[%s] GetTable failed with hr = 0x%x.\n",__FUNCTION__,hr));
  462. return hr;
  463. }
  464. return hr;
  465. }
  466. //
  467. // private
  468. //
  469. CImporter::Relation CImporter::GetRelation(
  470. LPCWSTR i_wszSourcePath,
  471. LPCWSTR i_wszCheck)
  472. /*++
  473. Synopsis:
  474. Arguments: [i_wszSourcePath] -
  475. [i_wszCheck] -
  476. Return Value:
  477. --*/
  478. {
  479. Relation eRelation = eREL_NONE;
  480. BOOL bIsSourcePath = false;
  481. BOOL bIsChild = IsChild(i_wszSourcePath, i_wszCheck, &bIsSourcePath);
  482. if(bIsChild)
  483. {
  484. eRelation = (bIsSourcePath) ? eREL_SELF : eREL_CHILD;
  485. }
  486. else
  487. {
  488. BOOL bIsParent = IsChild(i_wszCheck, i_wszSourcePath, &bIsSourcePath);
  489. if(bIsParent)
  490. {
  491. MD_ASSERT(bIsSourcePath == false);
  492. eRelation = eREL_PARENT;
  493. }
  494. else
  495. {
  496. eRelation = eREL_NONE;
  497. }
  498. }
  499. return eRelation;
  500. }
  501. BOOL
  502. CImporter::IsChild(
  503. LPCWSTR i_wszParent,
  504. LPCWSTR i_wszCheck,
  505. BOOL *o_pbSamePerson)
  506. /*++
  507. Synopsis:
  508. Arguments: [i_wszParent] - Ex. /LM/w3svc/1/root
  509. [i_wszCheck] - Ex. /LM/w3svc/1
  510. [o_pbSamePerson] - true if i_wszParent and i_wszCheck is same person
  511. Return Value:
  512. true if i_wszCheck is child or same person
  513. --*/
  514. {
  515. MD_ASSERT(i_wszParent != NULL);
  516. MD_ASSERT(i_wszCheck != NULL);
  517. MD_ASSERT(o_pbSamePerson != NULL);
  518. LPCWSTR pParent;
  519. LPCWSTR pCheck;
  520. pParent = i_wszParent;
  521. pCheck = i_wszCheck;
  522. SKIP_DELIMETER(pParent, MD_PATH_DELIMETERW);
  523. SKIP_DELIMETER(pCheck, MD_PATH_DELIMETERW);
  524. if(*pParent == L'\0')
  525. {
  526. switch(*pCheck)
  527. {
  528. case L'\0':
  529. *o_pbSamePerson = TRUE;
  530. break;
  531. default:
  532. *o_pbSamePerson = FALSE;
  533. }
  534. return TRUE;
  535. }
  536. while(*pParent != L'\0')
  537. {
  538. if(_wcsnicmp(pParent, pCheck, 1) == 0)
  539. {
  540. pParent++;
  541. pCheck++;
  542. }
  543. else if(*pParent == MD_PATH_DELIMETERW && pParent[1] == L'\0' && *pCheck == L'\0')
  544. {
  545. *o_pbSamePerson = TRUE;
  546. return TRUE;
  547. }
  548. else
  549. {
  550. return FALSE;
  551. }
  552. }
  553. switch(*pCheck)
  554. {
  555. case L'\0':
  556. *o_pbSamePerson = TRUE;
  557. return TRUE;
  558. case MD_PATH_DELIMETERW:
  559. *o_pbSamePerson = (pCheck[1] == L'\0') ? TRUE : FALSE;
  560. return TRUE;
  561. default:
  562. return FALSE;
  563. }
  564. }
  565. HRESULT CImporter::ReadMetaObject(
  566. IN LPCWSTR i_wszAbsParentPath,
  567. IN CMDBaseObject *i_pboParent,
  568. IN LPCWSTR i_wszAbsChildPath,
  569. OUT CMDBaseObject **o_ppboChild)
  570. /*++
  571. Synopsis:
  572. Returns a pbo for the child. If it does not already exist, it is
  573. created.
  574. Arguments: [i_wszAbsParentPath] -
  575. [i_pboParent] - pbo corresponding to i_wszAbsParentPath
  576. [i_wszAbsChildPath] -
  577. [o_ppboChild] - pbo corresponding to i_wszAbsChildPath
  578. Return Value:
  579. --*/
  580. {
  581. MD_ASSERT(i_pboParent != NULL);
  582. MD_ASSERT(i_wszAbsParentPath != NULL);
  583. MD_ASSERT(i_wszAbsChildPath != NULL);
  584. MD_ASSERT(o_ppboChild != NULL);
  585. HRESULT hr = ERROR_SUCCESS;
  586. HRESULT hrWarn = ERROR_SUCCESS;
  587. int iLenParent = (int)wcslen(i_wszAbsParentPath);
  588. int iLenChild = (int)wcslen(i_wszAbsChildPath);
  589. LPWSTR wszParent = NULL;
  590. LPWSTR wszChild = NULL;
  591. wszParent = new wchar_t[iLenParent+1];
  592. if(wszParent == NULL)
  593. {
  594. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  595. goto exit;
  596. }
  597. wszChild = new wchar_t[iLenChild+1];
  598. if(wszChild == NULL)
  599. {
  600. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  601. goto exit;
  602. }
  603. int idxParent = 0;
  604. int idxChild = 0;
  605. BOOL bRetParent = FALSE;
  606. BOOL bRetChild = FALSE;
  607. CMDBaseObject *pboNew = NULL;
  608. CMDBaseObject *pboLastParent = i_pboParent;
  609. while(1) {
  610. bRetParent = EnumMDPath(i_wszAbsParentPath, wszParent, &idxParent);
  611. bRetChild = EnumMDPath(i_wszAbsChildPath, wszChild, &idxChild);
  612. if(bRetParent == FALSE) {
  613. break;
  614. }
  615. }
  616. while(bRetChild == TRUE) {
  617. //
  618. // This is okay, since function that uses this takes an LPSTR
  619. // and a bool saying whether or not the string is unicode.
  620. //
  621. LPSTR pszTemp = (LPSTR)wszChild;
  622. pboNew = pboLastParent->GetChildObject(pszTemp, &hrWarn, TRUE);
  623. if(pboNew == NULL) {
  624. //
  625. // Create it
  626. //
  627. pboNew = new CMDBaseObject(wszChild, NULL);
  628. if (pboNew == NULL) {
  629. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  630. goto exit;
  631. }
  632. else if (!pboNew->IsValid()) {
  633. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  634. delete (pboNew);
  635. goto exit;
  636. }
  637. hr = pboLastParent->InsertChildObject(pboNew);
  638. if(FAILED(hr)) {
  639. delete pboNew;
  640. goto exit;
  641. }
  642. }
  643. pboLastParent = pboNew;
  644. bRetChild = EnumMDPath(i_wszAbsChildPath, wszChild, &idxChild);
  645. }
  646. //
  647. // Set out params
  648. //
  649. *o_ppboChild = pboLastParent;
  650. exit:
  651. delete [] wszParent;
  652. delete [] wszChild;
  653. return hr;
  654. }
  655. BOOL CImporter::EnumMDPath(
  656. LPCWSTR i_wszFullPath,
  657. LPWSTR io_wszPath,
  658. int* io_iStartIndex)
  659. /*++
  660. Synopsis:
  661. Starting at io_iStartIndex, this function will find the next token.
  662. Eg. i_wszFullPath = /LM/w3svc/1
  663. *io_iStartIndex = 3
  664. io_wszPath => w3svc
  665. *io_iStartIndex = 9
  666. Arguments: [i_wszFullPath] - Ex. /LM/w3svc/1
  667. [io_wszPath] - Should be at least same size as i_wszFullPath
  668. [io_iStartIndex] - 0-based index to start looking from
  669. Return Value:
  670. true if io_wszPath is set.
  671. --*/
  672. {
  673. MD_ASSERT(i_wszFullPath != NULL);
  674. MD_ASSERT(io_wszPath != NULL);
  675. int idxEnd = *io_iStartIndex;
  676. int idxStart = *io_iStartIndex;
  677. if(i_wszFullPath[idxStart] == MD_PATH_DELIMETERW)
  678. {
  679. idxStart++;
  680. idxEnd++;
  681. }
  682. //
  683. // If there is no more to enum, just exit and don't set out params
  684. //
  685. if(i_wszFullPath[idxStart] == L'\0')
  686. {
  687. return FALSE;
  688. }
  689. for(; ; idxEnd++)
  690. {
  691. if(i_wszFullPath[idxEnd] == MD_PATH_DELIMETERW)
  692. {
  693. break;
  694. }
  695. if(i_wszFullPath[idxEnd] == L'\0')
  696. {
  697. break;
  698. }
  699. }
  700. //
  701. // Set out params
  702. //
  703. *io_iStartIndex = idxEnd;
  704. memcpy(io_wszPath, &i_wszFullPath[idxStart], sizeof(wchar_t) * (idxEnd-idxStart));
  705. io_wszPath[idxEnd-idxStart] = L'\0';
  706. return TRUE;
  707. }