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.

2009 lines
48 KiB

  1. // SSRTEngine.cpp : Implementation of SSR Engine
  2. #include "stdafx.h"
  3. #include "SSRTE.h"
  4. #include "SSRTEngine.h"
  5. #include "SSRMembership.h"
  6. #include "MemberAccess.h"
  7. #include "SSRLog.h"
  8. #include "ActionData.h"
  9. #include "global.h"
  10. #include "util.h"
  11. /////////////////////////////////////////////////////////////////////////////
  12. // CSsrEngine
  13. /*
  14. Routine Description:
  15. Name:
  16. CSsrEngine::CSsrEngine
  17. Functionality:
  18. constructor
  19. Virtual:
  20. no.
  21. Arguments:
  22. none.
  23. Return Value:
  24. none.
  25. Notes:
  26. */
  27. CSsrEngine::CSsrEngine()
  28. : m_pActionData(NULL),
  29. m_pMembership(NULL)
  30. {
  31. HRESULT hr = CComObject<CSsrMembership>::CreateInstance(&m_pMembership);
  32. if (FAILED(hr))
  33. {
  34. throw hr;
  35. }
  36. hr = CComObject<CSsrActionData>::CreateInstance(&m_pActionData);
  37. if (FAILED(hr))
  38. {
  39. throw hr;
  40. }
  41. //
  42. // hold on to these objects
  43. //
  44. m_pMembership->AddRef();
  45. m_pActionData->AddRef();
  46. m_pActionData->SetMembership(m_pMembership);
  47. }
  48. /*
  49. Routine Description:
  50. Name:
  51. CSsrEngine::~CSsrEngine
  52. Functionality:
  53. destructor
  54. Virtual:
  55. yes.
  56. Arguments:
  57. none.
  58. Return Value:
  59. none.
  60. Notes:
  61. */
  62. CSsrEngine::~CSsrEngine()
  63. {
  64. m_pActionData->Release();
  65. m_pMembership->Release();
  66. }
  67. /*
  68. Routine Description:
  69. Name:
  70. CSsrEngine::GetActionData
  71. Functionality:
  72. Retrieve the action data interface
  73. Virtual:
  74. Yes.
  75. Arguments:
  76. ppAD - The out parameter that receives the ISsrActionData interface from
  77. the m_pActionData object
  78. Return Value:
  79. Success:
  80. S_OK.
  81. Failure:
  82. various error codes.
  83. Notes:
  84. */
  85. HRESULT
  86. CSsrEngine::GetActionData (
  87. OUT ISsrActionData ** ppAD
  88. )
  89. {
  90. HRESULT hr = E_SSR_ACTION_DATA_NOT_AVAILABLE;
  91. if (ppAD == NULL)
  92. {
  93. hr = E_INVALIDARG;
  94. }
  95. else if (m_pActionData != NULL)
  96. {
  97. *ppAD = NULL;
  98. hr = m_pActionData->QueryInterface(IID_ISsrActionData, (LPVOID*)ppAD);
  99. if (S_OK != hr)
  100. {
  101. hr = E_SSR_ACTION_DATA_NOT_AVAILABLE;
  102. }
  103. }
  104. return hr;
  105. }
  106. /*
  107. Routine Description:
  108. Name:
  109. CSsrEngine::DoActionVerb
  110. Functionality:
  111. The engine will perform the action.
  112. Virtual:
  113. Yes.
  114. Arguments:
  115. bstrActionVerb - "configure" or "rollback".
  116. lActionType - The action's type.
  117. varFeedbackSink - The COM interface ISsrFeedbackSink given by the caller.
  118. We will use this interface to call back when we want
  119. to give feedback information to the caller.
  120. lFlag - Reserved for future use.
  121. Return Value:
  122. Success:
  123. S_OK.
  124. Failure:
  125. various error codes.
  126. Notes:
  127. */
  128. STDMETHODIMP
  129. CSsrEngine::DoActionVerb (
  130. IN BSTR bstrActionVerb,
  131. IN LONG lActionType,
  132. IN VARIANT varFeedbackSink,
  133. IN LONG lFlag
  134. )
  135. {
  136. if (bstrActionVerb == NULL)
  137. {
  138. g_fblog.LogString(IDS_INVALID_PARAMETER, L"bstrActionVerb");
  139. return E_INVALIDARG;
  140. }
  141. SsrActionVerb lActionVerb = SsrPGetActionVerbFromString(bstrActionVerb);
  142. if (lActionVerb == ActionInvalid)
  143. {
  144. g_fblog.LogString(IDS_INVALID_PARAMETER, bstrActionVerb);
  145. return E_SSR_INVALID_ACTION_VERB;
  146. }
  147. //
  148. // we will only accept SSR_ACTION_APPLY or SSR_ACTION_PREPARE
  149. //
  150. if ( (lActionType != SSR_ACTION_PREPARE) &&
  151. (lActionType != SSR_ACTION_APPLY) )
  152. {
  153. g_fblog.LogString(IDS_INVALID_PARAMETER, L"lActionType");
  154. return E_SSR_INVALID_ACTION_TYPE;
  155. }
  156. HRESULT hr;
  157. VARIANT varFeedbackSinkNull;
  158. varFeedbackSinkNull.vt = VT_NULL;
  159. if ( lActionVerb == ActionConfigure && lActionType == SSR_ACTION_APPLY) {
  160. hr = DoActionVerb (
  161. g_bstrRollback,
  162. SSR_ACTION_PREPARE,
  163. varFeedbackSinkNull,
  164. lFlag);
  165. if (FAILED(hr))
  166. {
  167. g_fblog.LogError(hr, L"CSsrEngine", L"Rollback failed");
  168. return hr;
  169. }
  170. }
  171. //
  172. // need to loop through all members
  173. //
  174. hr = m_pMembership->LoadAllMember();
  175. if (hr == E_SSR_MEMBER_XSD_INVALID)
  176. {
  177. //
  178. // logging has been done by LoadAllMembers
  179. //
  180. return hr;
  181. }
  182. CComVariant var;
  183. hr = m_pMembership->GetAllMembers(&var);
  184. if (FAILED(hr))
  185. {
  186. g_fblog.LogError(hr, L"CSsrEngine", L"m_pMembership->GetAllMembers");
  187. return hr;
  188. }
  189. //
  190. // now we have members to work on, so get the feedback sink ready and
  191. // kick out the actions!
  192. //
  193. if (varFeedbackSink.vt == VT_UNKNOWN || varFeedbackSink.vt == VT_DISPATCH)
  194. {
  195. hr = g_fblog.SetFeedbackSink(varFeedbackSink);
  196. if (FAILED(hr))
  197. {
  198. g_fblog.LogError(hr, L"CSsrEngine", L"g_fblog.SetFeedbackSink");
  199. return hr;
  200. }
  201. }
  202. else if (varFeedbackSink.vt != VT_NULL && varFeedbackSink.vt != VT_EMPTY)
  203. {
  204. //
  205. // if the feedback has something other than NULL or empty, but
  206. // it is not an IUnknown or IDispatch, then, we log the error,
  207. // but we will continue
  208. //
  209. g_fblog.LogString(IDS_INVALID_PARAMETER, L"varFeedbackSink");
  210. }
  211. CSafeArray sa(&var);
  212. //
  213. // We have to discover information about total number of items to be processed.
  214. // Currently, this mimics the actual action, which is a little bit costly. We
  215. // should consider some lookup mechanism without going so much to the members.
  216. //
  217. //vector<ULONG> vecTransformIndexes;
  218. //vector<ULONG> vecScriptIndexes;
  219. //vector<ULONG> vecCustomIndexes;
  220. //
  221. // The following actions will be counted:
  222. // (1) Loading security policy XML files
  223. // (2) Transform using one xsl file and the creation of the output
  224. // file count as one.
  225. // (3) executing a script
  226. // (4) any custom actions
  227. //
  228. DWORD dwTotalSteps = 0;
  229. CSsrMemberAccess * pMA;
  230. CComVariant varMemberName;
  231. //
  232. // ask each member to give us the cost for the action
  233. //
  234. for (ULONG i = 0; i < sa.GetSize(); i++)
  235. {
  236. pMA = NULL;
  237. varMemberName.Clear();
  238. //
  239. // see if this member supports the desired action. If it does
  240. // then get the cost.
  241. //
  242. if (SUCCEEDED(sa.GetElement(i, VT_BSTR, &varMemberName)))
  243. {
  244. pMA = m_pMembership->GetMemberByName(varMemberName.bstrVal);
  245. if (pMA != NULL)
  246. {
  247. dwTotalSteps += pMA->GetActionCost(lActionVerb, lActionType);
  248. }
  249. }
  250. }
  251. //
  252. // if we need to do transformation, then let us cleanup the old ones.
  253. // We won't bother to restore them if somehow we fail to do the transformation
  254. // unless we are doing rollback transformation.
  255. // We must not continue if this fails.
  256. //
  257. WCHAR wszTempDir[MAX_PATH + 2];
  258. wszTempDir[MAX_PATH + 1] = L'\0';
  259. if ( (lActionType == SSR_ACTION_PREPARE ) )
  260. {
  261. if ( lActionVerb == ActionRollback )
  262. {
  263. //
  264. // if we need to do "rollback" transformation, then we need to
  265. // backup our previous rollback output files
  266. //
  267. //
  268. // first, we need a temporary directory
  269. //
  270. hr = SsrPCreateUniqueTempDirectory(wszTempDir, MAX_PATH + 1);
  271. if (SUCCEEDED(hr))
  272. {
  273. hr = MoveRollbackFiles(&sa,
  274. SsrPGetDirectory(lActionVerb, TRUE),
  275. wszTempDir,
  276. true // we want logging
  277. );
  278. }
  279. }
  280. else
  281. {
  282. //
  283. // otherwise, we will just delete them and never bother
  284. // to restore them if anything fails
  285. //
  286. hr = CleanupOutputFiles(&sa,
  287. lActionVerb,
  288. true // we want logging
  289. );
  290. }
  291. if (FAILED(hr))
  292. {
  293. g_fblog.LogError(hr, L"CSsrEngine", L"Cleanup previous result files failed.");
  294. return hr;
  295. }
  296. }
  297. //
  298. // Feedback the total steps info
  299. //
  300. g_fblog.SetTotalSteps(dwTotalSteps);
  301. //
  302. // now let's carry out the action. First, feedback/log the action started
  303. // information.
  304. //
  305. g_fblog.LogFeedback(SSR_FB_START,
  306. (DWORD)S_OK,
  307. NULL,
  308. g_dwResNothing
  309. );
  310. //
  311. // we may decide to presson in case of errors, but we should always
  312. // return the error we found
  313. //
  314. HRESULT hrFirstError = S_OK;
  315. CComPtr<IXMLDOMDocument2> srpDomSecurityPolicy;
  316. //
  317. // ask each member to give us the action data so that we can
  318. // carry out the action.
  319. //
  320. for (i = 0; i < sa.GetSize(); i++)
  321. {
  322. pMA = NULL;
  323. varMemberName.Clear();
  324. //
  325. // see if this member supports the desired action. If it does
  326. // then get the cost.
  327. //
  328. if (SUCCEEDED(sa.GetElement(i, VT_BSTR, &varMemberName)))
  329. {
  330. pMA = m_pMembership->GetMemberByName(varMemberName.bstrVal);
  331. if (pMA == NULL)
  332. {
  333. //
  334. // $undone:shawnwu, should we press on? This shouldn't happen.
  335. //
  336. _ASSERT(FALSE);
  337. g_fblog.LogString(IDS_MISSING_MEMBER, varMemberName.bstrVal);
  338. continue;
  339. }
  340. CMemberAD* pmemberAD = pMA->GetActionDataObject(lActionVerb,
  341. lActionType
  342. );
  343. if (pmemberAD == NULL)
  344. {
  345. //
  346. // $undone:shawnwu, should we press on? This shouldn't happen.
  347. //
  348. _ASSERT(FALSE);
  349. g_fblog.LogString(IDS_MEMBER_NOT_SUPPORT_ACTION, varMemberName.bstrVal);
  350. continue;
  351. }
  352. int iCount = pmemberAD->GetProcedureCount();
  353. //
  354. // mark the entry point for carrying out the action
  355. //
  356. g_fblog.LogFeedback(SSR_FB_START_MEMBER_ACTION,
  357. varMemberName.bstrVal,
  358. bstrActionVerb,
  359. g_dwResNothing
  360. );
  361. for (int iProc = 0; iProc < iCount; iProc++)
  362. {
  363. const CSsrProcedure * pSsrProc = pmemberAD->GetProcedure(iProc);
  364. if (pSsrProc->IsDefaultProcedure())
  365. {
  366. int iFilePairCount = pSsrProc->GetFilePairCount();
  367. for (int iPair = 0; iPair < iFilePairCount; iPair++)
  368. {
  369. //
  370. // get the file pair information so that we can
  371. // determine which action to carry out
  372. //
  373. CSsrFilePair * pfp = pSsrProc->GetFilePair(iPair);
  374. if (pfp->GetFirst() != NULL)
  375. {
  376. //
  377. // if the first file is there, then, we will do
  378. // a transformation.
  379. //
  380. hr = DoTransforms(lActionVerb,
  381. pfp,
  382. &srpDomSecurityPolicy,
  383. lFlag
  384. );
  385. }
  386. else if (pfp->GetSecond() != NULL &&
  387. pfp->IsExecutable() )
  388. {
  389. hr = RunScript(SsrPGetDirectory(lActionVerb, TRUE),
  390. pfp->GetSecond()
  391. );
  392. }
  393. if (hrFirstError == S_OK && FAILED(hr))
  394. {
  395. hrFirstError = hr;
  396. }
  397. g_fblog.Steps(2);
  398. if (!SsrPPressOn(lActionVerb, lActionType, hr))
  399. {
  400. break;
  401. }
  402. }
  403. }
  404. else
  405. {
  406. if (pSsrProc->GetProgID() == NULL &&
  407. pMA->GetProgID() == NULL)
  408. {
  409. //
  410. // we can't do anything because the progID is missing
  411. //
  412. g_fblog.LogString(IDS_MISSING_PROGID, varMemberName.bstrVal);
  413. }
  414. else
  415. {
  416. hr = DoCustom(lActionVerb,
  417. lActionType,
  418. (pSsrProc->GetProgID() != NULL) ? pSsrProc->GetProgID() : pMA->GetProgID(),
  419. varFeedbackSink,
  420. lFlag
  421. );
  422. //
  423. // Feedback steps are counted by the custom member itself
  424. // via the feedback sink we give.
  425. //
  426. }
  427. if (hrFirstError == S_OK && FAILED(hr))
  428. {
  429. hrFirstError = hr;
  430. }
  431. if (!SsrPPressOn(lActionVerb, lActionType, hr))
  432. {
  433. break;
  434. }
  435. }
  436. if (hrFirstError == S_OK && FAILED(hr))
  437. {
  438. hrFirstError = hr;
  439. }
  440. if (!SsrPPressOn(lActionVerb, lActionType, hr))
  441. {
  442. break;
  443. }
  444. }
  445. g_fblog.LogFeedback(SSR_FB_END_MEMBER_ACTION,
  446. varMemberName.bstrVal,
  447. bstrActionVerb,
  448. g_dwResNothing
  449. );
  450. }
  451. }
  452. if (SUCCEEDED(hrFirstError) &&
  453. (lActionType == SSR_ACTION_PREPARE) &&
  454. (lActionVerb == ActionRollback) )
  455. {
  456. //
  457. // transform succeeded, then we need to get rid of the files
  458. // backed up for rollback.
  459. //
  460. ::SsrPDeleteEntireDirectory(wszTempDir);
  461. }
  462. else if ( (lActionType == SSR_ACTION_PREPARE) && (lActionVerb == ActionRollback))
  463. {
  464. //
  465. // transform failed, we need to restore the backup files
  466. // for the rollback. First, we must remove all output files
  467. //
  468. HRESULT hrRestore = CleanupOutputFiles(&sa,
  469. lActionVerb,
  470. false // we don't want logging
  471. );
  472. //
  473. // we will purposely leave the rollback files backed up
  474. // in previous steps in case we failed to restore all of them
  475. // so that we can at least log it and let the user do
  476. // the restoration
  477. //
  478. if (SUCCEEDED(hrRestore))
  479. {
  480. hrRestore = MoveRollbackFiles(&sa,
  481. wszTempDir,
  482. g_wszSsrRoot,
  483. false // no logging
  484. );
  485. if (SUCCEEDED(hrRestore))
  486. {
  487. ::SsrPDeleteEntireDirectory(wszTempDir);
  488. }
  489. else
  490. {
  491. g_fblog.LogError(hr,
  492. L"CSsrEngine",
  493. L"Restore old rollback files failed. These files are located at the directory whose name is the following guid:"
  494. );
  495. g_fblog.LogString(wszTempDir);
  496. }
  497. }
  498. }
  499. //
  500. // now action has complete! Give the HRESULT as feedback.
  501. // Also, we always give back S_OK as the return result if
  502. // everything goes on fine.
  503. //
  504. if (SUCCEEDED(hrFirstError))
  505. {
  506. hrFirstError = S_OK;
  507. }
  508. g_fblog.LogFeedback(SSR_FB_END | FBLog_Log,
  509. hr,
  510. NULL,
  511. g_dwResNothing
  512. );
  513. g_fblog.TerminateFeedback();
  514. return hrFirstError;
  515. }
  516. /*
  517. Routine Description:
  518. Name:
  519. CSsrEngine::DoCustom
  520. Functionality:
  521. We will delegate to the objects of custom implementation for this action.
  522. Virtual:
  523. no.
  524. Arguments:
  525. lActionVerb - action verb
  526. bstrProgID - The member's ProgID
  527. varFeedbackSink - the sink interface if any.
  528. lFlag - reserved for future use.
  529. Return Value:
  530. Success:
  531. various success codes returned from DOM or ourselves.
  532. Use SUCCEEDED(hr) to test.
  533. Failure:
  534. various error codes returned from DOM or ourselves.
  535. Use FAILED(hr) to test.
  536. Notes:
  537. */
  538. HRESULT
  539. CSsrEngine::DoCustom (
  540. IN SsrActionVerb lActionVerb,
  541. IN LONG lActionType,
  542. IN const BSTR bstrProgID,
  543. IN VARIANT varFeedbackSink,
  544. IN LONG lFlag
  545. )
  546. {
  547. g_fblog.LogString(IDS_START_CUSTOM, NULL);
  548. GUID clsID;
  549. CComPtr<ISsrMember> srpMember;
  550. CComVariant varAD;
  551. HRESULT hr = ::CLSIDFromProgID(bstrProgID, &clsID);
  552. if (S_OK == hr)
  553. {
  554. hr = ::CoCreateInstance(clsID,
  555. NULL,
  556. CLSCTX_INPROC_SERVER,
  557. IID_ISsrMember,
  558. (LPVOID*)&srpMember
  559. );
  560. }
  561. if (SUCCEEDED(hr))
  562. {
  563. varAD.vt = VT_UNKNOWN;
  564. varAD.punkVal = NULL;
  565. //
  566. // this m_pActionData must have ISsrActionData unless exception
  567. //
  568. hr = m_pActionData->QueryInterface(IID_ISsrActionData,
  569. (LPVOID*)&(varAD.punkVal)
  570. );
  571. if (FAILED(hr))
  572. {
  573. g_fblog.LogError(hr,
  574. bstrProgID,
  575. L"m_pActionData->QueryInterface failed"
  576. );
  577. }
  578. }
  579. else
  580. {
  581. g_fblog.LogString(IDS_MISSING_CUSTOM_MEMBER, bstrProgID);
  582. }
  583. //
  584. // if we can't provide an log object, then the custom
  585. // object should create one by itself
  586. //
  587. if (SUCCEEDED(hr))
  588. {
  589. CComVariant varLog;
  590. g_fblog.GetLogObject(&varLog);
  591. //
  592. // custom object must let us pass in action context
  593. //
  594. hr = srpMember->SetActionContext(varAD, varLog, varFeedbackSink);
  595. if (FAILED(hr))
  596. {
  597. g_fblog.LogError(hr,
  598. bstrProgID,
  599. L"SetActionContext failed."
  600. );
  601. }
  602. }
  603. //
  604. // logging and feedback will be done by the custom objects
  605. //
  606. if (SUCCEEDED(hr))
  607. {
  608. hr = srpMember->DoActionVerb(SsrPGetActionVerbString(lActionVerb), lActionType, lFlag);
  609. if (FAILED(hr))
  610. {
  611. g_fblog.LogError(hr,
  612. L"DoActionVerb",
  613. SsrPGetActionVerbString(lActionVerb)
  614. );
  615. }
  616. }
  617. g_fblog.LogString(IDS_END_CUSTOM, NULL);
  618. return hr;
  619. }
  620. /*
  621. Routine Description:
  622. Name:
  623. CSsrEngine::DoTransforms
  624. Functionality:
  625. We perform our well defined XSLT transformation action.
  626. Virtual:
  627. no.
  628. Arguments:
  629. lActionVerb - action verb
  630. pfp - CSsrFilePair object that contains the xsl and output file
  631. name information. Output file information may be empty,
  632. in which case in means that the the transformation does
  633. require to create an output file.
  634. ppXmlDom - The security policy DOM object. If this is a NULL object,
  635. then this function will create and load it for later use.
  636. lFlag - The flag that determines the transformation characteristics.
  637. The one we heavily used is SSR_LOADDOM_VALIDATE_ON_PARSE.
  638. This can be bitwise OR'ed. If this is set to 0, then we
  639. use the registered flags for each individual member.
  640. In other words, this flag overwrites the registered flag
  641. if it is not 0.
  642. Return Value:
  643. Success:
  644. various success codes returned from DOM or ourselves.
  645. Use SUCCEEDED(hr) to test.
  646. Failure:
  647. various error codes returned from DOM or ourselves.
  648. Use FAILED(hr) to test.
  649. Notes:
  650. */
  651. HRESULT
  652. CSsrEngine::DoTransforms (
  653. IN SsrActionVerb lActionVerb,
  654. IN CSsrFilePair * pfp,
  655. IN OUT IXMLDOMDocument2 ** ppXmlDom,
  656. IN LONG lFlag
  657. )
  658. {
  659. g_fblog.LogString(IDS_START_XSL_TRANSFORM, NULL);
  660. //
  661. // We will prepare an XML dom object if it doesn't pass in one.
  662. //
  663. HRESULT hr = S_OK;
  664. if (*ppXmlDom == NULL)
  665. {
  666. //
  667. // First of all, we need the SecurityPolicy.xml file
  668. //
  669. CComVariant varXmlPolicy;
  670. hr = m_pActionData->GetProperty(CComBSTR(g_pwszCurrSecurityPolicy),
  671. &varXmlPolicy
  672. );
  673. //
  674. // Loading the security policy XML file is considered SSR Engine actions
  675. //
  676. if (S_OK != hr)
  677. {
  678. g_fblog.LogFeedback(SSR_FB_ERROR_CRITICAL | FBLog_Log,
  679. (LPCWSTR)NULL,
  680. NULL,
  681. IDS_MISSING_SECPOLICY
  682. );
  683. return hr;
  684. }
  685. else if (varXmlPolicy.vt != VT_BSTR)
  686. {
  687. g_fblog.LogFeedback(SSR_FB_ERROR_CRITICAL | FBLog_Log,
  688. (LPCWSTR)NULL,
  689. g_pwszCurrSecurityPolicy,
  690. IDS_SECPOLICY_INVALID_TYPE
  691. );
  692. return hr;
  693. }
  694. CComBSTR bstrSecPolicy(varXmlPolicy.bstrVal);
  695. // bstrSecPolicy += L"\\Policies\\";
  696. // bstrSecPolicy = varXmlPolicy.bstrVal;
  697. if (bstrSecPolicy.m_str == NULL)
  698. {
  699. return E_OUTOFMEMORY;
  700. }
  701. hr = ::CoCreateInstance(CLSID_DOMDocument40,
  702. NULL,
  703. CLSCTX_SERVER,
  704. IID_IXMLDOMDocument2,
  705. (LPVOID*)(ppXmlDom)
  706. );
  707. if (SUCCEEDED(hr))
  708. {
  709. hr = SsrPLoadDOM(bstrSecPolicy, lFlag, (*ppXmlDom));
  710. if (SUCCEEDED(hr))
  711. {
  712. //
  713. // we loaded the security policy xml file
  714. //
  715. g_fblog.LogFeedback(FBLog_Log,
  716. hr,
  717. bstrSecPolicy,
  718. IDS_LOAD_SECPOLICY
  719. );
  720. }
  721. else
  722. {
  723. g_fblog.LogFeedback(SSR_FB_ERROR_CRITICAL | FBLog_Log,
  724. hr,
  725. bstrSecPolicy,
  726. IDS_LOAD_SECPOLICY
  727. );
  728. return hr;
  729. }
  730. }
  731. else
  732. {
  733. g_fblog.LogError(
  734. hr,
  735. L"Can't create CLSID_DOMDocument40 object",
  736. NULL
  737. );
  738. return hr;
  739. }
  740. }
  741. //
  742. // let's check if all section of the security policy xml file
  743. // contains any section that we have no member that understands
  744. //
  745. CComBSTR bstrUnknownMember, bstrExtraInfo;
  746. HRESULT hrCheck;
  747. hrCheck = VerifyDOM((*ppXmlDom), &bstrUnknownMember, &bstrExtraInfo);
  748. if (bstrUnknownMember.Length() > 0)
  749. {
  750. g_fblog.LogFeedback(SSR_FB_ERROR_UNKNOWN_MEMBER | FBLog_Log,
  751. bstrUnknownMember,
  752. bstrExtraInfo,
  753. g_dwResNothing
  754. );
  755. }
  756. //
  757. // let's create the XSL template object
  758. //
  759. CComPtr<IXSLTemplate> srpIXSLTemplate;
  760. hr = ::CoCreateInstance(CLSID_XSLTemplate,
  761. NULL,
  762. CLSCTX_SERVER,
  763. IID_IXSLTemplate,
  764. (LPVOID*)(&srpIXSLTemplate)
  765. );
  766. if (FAILED(hr))
  767. {
  768. g_fblog.LogFeedback(SSR_FB_ERROR_CRITICAL | FBLog_Log,
  769. hr,
  770. NULL,
  771. IDS_FAIL_CREATE_XSLT
  772. );
  773. return hr;
  774. }
  775. //
  776. // now ready to do member wise transform
  777. //
  778. BSTR bstrXslDir = SsrPGetDirectory(lActionVerb, FALSE);
  779. BSTR bstrResultDir = SsrPGetDirectory(lActionVerb, TRUE);
  780. hr = DoMemberTransform(
  781. pfp,
  782. bstrXslDir,
  783. bstrResultDir,
  784. (*ppXmlDom),
  785. srpIXSLTemplate,
  786. lFlag
  787. );
  788. if (FAILED(hr))
  789. {
  790. g_fblog.LogError(hr,
  791. L"DoTransforms",
  792. pfp->GetFirst()
  793. );
  794. }
  795. g_fblog.LogString(IDS_END_XSL_TRANSFORM, NULL);
  796. return hr;
  797. }
  798. /*
  799. Routine Description:
  800. Name:
  801. CSsrEngine::DoMemberTransform
  802. Functionality:
  803. We will do the private transform and then create the output file.
  804. Virtual:
  805. no.
  806. Arguments:
  807. pfp - CSsrFilePair object that contains names of
  808. both xsl and output files. If the latter is empty,
  809. it means it doesn't need to create an output file.
  810. pwszXslFilesDir - the XSL file directory
  811. pwszResultFilesDir - the output file directory
  812. pXmlDOM - The XML DOM object interface
  813. pXslTemplate - The XSL template object interface
  814. lFlag - The flag that determines the transformation characteristics.
  815. The one we heavily used is SSR_LOADDOM_VALIDATE_ON_PARSE.
  816. Return Value:
  817. Success:
  818. various success codes returned from DOM or ourselves.
  819. Use SUCCEEDED(hr) to test.
  820. Failure:
  821. various error codes returned from DOM or ourselves.
  822. Use FAILED(hr) to test.
  823. Notes:
  824. */
  825. HRESULT
  826. CSsrEngine::DoMemberTransform (
  827. IN CSsrFilePair * pfp,
  828. IN LPCWSTR pwszXslFilesDir,
  829. IN LPCWSTR pwszResultFilesDir,
  830. IN IXMLDOMDocument2 * pXmlDOM,
  831. IN IXSLTemplate * pXslTemplate,
  832. IN LONG lFlag
  833. )
  834. {
  835. HRESULT hr = S_OK;
  836. CComBSTR bstrXslFilePath(pwszXslFilesDir);
  837. bstrXslFilePath += L"\\";
  838. bstrXslFilePath += pfp->GetFirst();
  839. CComBSTR bstrResultFilePath;
  840. if (pfp->GetSecond() != NULL)
  841. {
  842. bstrResultFilePath = pwszResultFilesDir;
  843. bstrResultFilePath += L"\\";
  844. bstrResultFilePath += pfp->GetSecond();
  845. }
  846. hr = Transform (bstrXslFilePath,
  847. bstrResultFilePath,
  848. pXmlDOM,
  849. pXslTemplate,
  850. lFlag
  851. );
  852. DWORD dwID = SUCCEEDED(hr) ? IDS_TRANSFORM_SUCCEEDED : IDS_TRANSFORM_FAILED;
  853. g_fblog.LogFeedback(SSR_FB_TRANSFORM_RESULT | FBLog_Log,
  854. hr,
  855. pfp->GetFirst(),
  856. dwID
  857. );
  858. return hr;
  859. }
  860. /*
  861. Routine Description:
  862. Name:
  863. CSsrEngine::Transform
  864. Functionality:
  865. We will do the private transform and then create the output file.
  866. Virtual:
  867. no.
  868. Arguments:
  869. bstrXslPath - The xsl file path.
  870. bstrResultPath - the output file path
  871. pXmlDOM - The XML DOM object interface
  872. pXslTemplate - The XSL template object interface
  873. lFlag - The flag that determines the transformation characteristics.
  874. The one we heavily used is SSR_LOADDOM_VALIDATE_ON_PARSE.
  875. Return Value:
  876. Success:
  877. various success codes returned from DOM or ourselves.
  878. Use SUCCEEDED(hr) to test.
  879. Failure:
  880. various error codes returned from DOM or ourselves.
  881. Use FAILED(hr) to test.
  882. Notes:
  883. */
  884. HRESULT
  885. CSsrEngine::Transform (
  886. IN BSTR bstrXslPath,
  887. IN BSTR bstrResultPath,
  888. IN IXMLDOMDocument2 * pXmlDOM,
  889. IN IXSLTemplate * pXslTemplate,
  890. IN LONG lFlag
  891. )
  892. {
  893. CComBSTR bstrResult;
  894. HRESULT hr = S_OK;
  895. if (bstrResultPath != NULL)
  896. {
  897. //
  898. // we need to create a result file
  899. // using our transformation result.
  900. //
  901. hr = PrivateTransform (
  902. bstrXslPath,
  903. pXmlDOM,
  904. pXslTemplate,
  905. lFlag,
  906. &bstrResult
  907. );
  908. }
  909. else
  910. {
  911. hr = PrivateTransform (
  912. bstrXslPath,
  913. pXmlDOM,
  914. pXslTemplate,
  915. lFlag,
  916. NULL
  917. );
  918. }
  919. //
  920. // we allow transform to have no text results. Or there is no
  921. // output file given. In either case, the effect is simply to call
  922. // the transformation, which may still do meaningful things.
  923. //
  924. if (SUCCEEDED(hr) &&
  925. bstrResult.m_str != NULL &&
  926. bstrResultPath != NULL &&
  927. *bstrResultPath != L'\0' )
  928. {
  929. //
  930. // if there is an output file that needs to be created.
  931. //
  932. HANDLE hFile = ::CreateFile(bstrResultPath,
  933. GENERIC_WRITE,
  934. 0,
  935. NULL,
  936. CREATE_ALWAYS,
  937. FILE_ATTRIBUTE_NORMAL,
  938. NULL
  939. );
  940. if (hFile != INVALID_HANDLE_VALUE)
  941. {
  942. //
  943. // write the results into the file
  944. //
  945. long lLen = wcslen(bstrResult);
  946. DWORD dwWritten = 0;
  947. BOOL bStatus = ::WriteFile(hFile,
  948. bstrResult.m_str,
  949. lLen * sizeof(WCHAR),
  950. &dwWritten,
  951. NULL
  952. );
  953. ::CloseHandle(hFile);
  954. if (!bStatus)
  955. {
  956. g_fblog.LogFeedback(SSR_FB_ERROR_FILE_WRITE | FBLog_Log,
  957. GetLastError(),
  958. bstrResultPath,
  959. IDS_FILEWRITE_FAILED
  960. );
  961. hr = E_FAIL;
  962. }
  963. }
  964. else
  965. {
  966. g_fblog.LogFeedback(SSR_FB_ERROR_FILE_CREATE | FBLog_Log,
  967. GetLastError(),
  968. bstrResultPath,
  969. IDS_FILECREATE_FAILED
  970. );
  971. hr = E_FAIL;
  972. }
  973. }
  974. return hr;
  975. }
  976. /*
  977. Routine Description:
  978. Name:
  979. CSsrEngine::PrivateTransform
  980. Functionality:
  981. Do the real XSLT transformation
  982. Virtual:
  983. no.
  984. Arguments:
  985. bstrXsl - the XSL file path
  986. pxmlDom - The XML DOM object interface
  987. pxslTemplate- The XSL template object interface
  988. uFlag - The flag that determines the transformation
  989. characteristics. The one we heavily used is
  990. SSR_LOADDOM_VALIDATE_ON_PARSE.
  991. pbstrResult - The result string.
  992. Return Value:
  993. Success:
  994. various success codes returned from DOM or ourselves.
  995. Use SUCCEEDED(hr) to test.
  996. Failure:
  997. various error codes returned from DOM or ourselves.
  998. Use FAILED(hr) to test.
  999. Notes:
  1000. */
  1001. HRESULT
  1002. CSsrEngine::PrivateTransform (
  1003. IN BSTR bstrXsl,
  1004. IN IXMLDOMDocument2 * pxmlDom,
  1005. IN IXSLTemplate * pxslTemplate,
  1006. IN LONG lFlag,
  1007. OUT BSTR * pbstrResult OPTIONAL
  1008. )
  1009. {
  1010. if (bstrXsl == NULL ||
  1011. *bstrXsl == L'\0' ||
  1012. pxmlDom == NULL ||
  1013. pxslTemplate == NULL)
  1014. {
  1015. return E_INVALIDARG;
  1016. }
  1017. CComPtr<IXMLDOMDocument2> srpXsl;
  1018. HRESULT hr = ::CoCreateInstance(CLSID_FreeThreadedDOMDocument,
  1019. NULL,
  1020. CLSCTX_SERVER, IID_IXMLDOMDocument2,
  1021. (LPVOID*)(&srpXsl)
  1022. );
  1023. if (SUCCEEDED(hr))
  1024. {
  1025. hr = SsrPLoadDOM(bstrXsl, lFlag, srpXsl);
  1026. }
  1027. if (FAILED(hr))
  1028. {
  1029. return hr;
  1030. }
  1031. short sResult = FALSE;
  1032. CComPtr<IXSLProcessor> srpIXSLProcessor;
  1033. if (pbstrResult != NULL)
  1034. {
  1035. *pbstrResult = NULL;
  1036. }
  1037. hr = pxslTemplate->putref_stylesheet(srpXsl);
  1038. if (FAILED(hr))
  1039. {
  1040. g_fblog.LogString(IDS_XSL_TRANSFORM_FAILED, L"putref_stylesheet");
  1041. }
  1042. if (SUCCEEDED(hr))
  1043. {
  1044. hr = pxslTemplate->createProcessor(&srpIXSLProcessor);
  1045. if (FAILED(hr))
  1046. {
  1047. g_fblog.LogString(IDS_CREATE_IXSLPROC_FAILED, NULL);
  1048. }
  1049. }
  1050. if (SUCCEEDED(hr))
  1051. {
  1052. CComVariant varIDoc2(pxmlDom);
  1053. hr = srpIXSLProcessor->put_input(varIDoc2);
  1054. if (SUCCEEDED(hr))
  1055. {
  1056. hr = srpIXSLProcessor->transform(&sResult);
  1057. if (SUCCEEDED(hr) && (sResult == VARIANT_TRUE))
  1058. {
  1059. //
  1060. // if we want results back
  1061. //
  1062. if (pbstrResult != NULL)
  1063. {
  1064. VARIANT varValue;
  1065. ::VariantInit(&varValue);
  1066. hr = srpIXSLProcessor->get_output(&varValue);
  1067. //
  1068. // if the output is successffuly retrieved,
  1069. // then it is owned by the out parameter
  1070. //
  1071. if (SUCCEEDED(hr) && varValue.vt == VT_BSTR)
  1072. {
  1073. *pbstrResult = varValue.bstrVal;
  1074. //
  1075. // the bstr value is owned by the output parameter now
  1076. //
  1077. varValue.vt = VT_EMPTY;
  1078. varValue.bstrVal = NULL;
  1079. }
  1080. else
  1081. {
  1082. ::VariantClear(&varValue);
  1083. }
  1084. }
  1085. }
  1086. else
  1087. {
  1088. g_fblog.LogString(IDS_XSL_TRANSFORM_FAILED,
  1089. L"IXSLProcessor->transform"
  1090. );
  1091. }
  1092. }
  1093. else
  1094. {
  1095. g_fblog.LogString(IDS_XSL_TRANSFORM_FAILED,
  1096. L"IXSLProcessor->put_input"
  1097. );
  1098. }
  1099. }
  1100. return hr;
  1101. }
  1102. /*
  1103. Routine Description:
  1104. Name:
  1105. CSsrEngine::RunScript
  1106. Functionality:
  1107. We will launch all given scripts
  1108. Virtual:
  1109. No.
  1110. Arguments:
  1111. bstrDirPath - The path of the directory where the scripts resides
  1112. bstrScriptFile - The script file's name
  1113. Return Value:
  1114. Success:
  1115. S_OK of some scripts are run.
  1116. S_FALSE if no scripts can be found to run.
  1117. Failure:
  1118. various error codes.
  1119. Notes:
  1120. 1. We should try to hide the cmd window.
  1121. */
  1122. HRESULT
  1123. CSsrEngine::RunScript (
  1124. IN BSTR bstrDirPath,
  1125. IN BSTR bstrScriptFile
  1126. )
  1127. {
  1128. if (bstrDirPath == NULL || bstrScriptFile == NULL)
  1129. {
  1130. return E_INVALIDARG;
  1131. }
  1132. //
  1133. // create the script file's full path
  1134. //
  1135. int iLen = wcslen(bstrDirPath) + 1 + wcslen(bstrScriptFile) + 1;
  1136. LPWSTR pwszFilePath = new WCHAR[iLen];
  1137. if (pwszFilePath == NULL)
  1138. {
  1139. return E_OUTOFMEMORY;
  1140. }
  1141. //
  1142. // don't return blindly w/o freeing the pwszFilePath from this point on
  1143. //
  1144. HRESULT hr = S_OK;
  1145. _snwprintf(pwszFilePath, iLen, L"%s\\%s", bstrDirPath, bstrScriptFile);
  1146. WIN32_FILE_ATTRIBUTE_DATA wfad;
  1147. if ( !GetFileAttributesEx(pwszFilePath, GetFileExInfoStandard, &wfad) )
  1148. {
  1149. g_fblog.LogFeedback(SSR_FB_ERROR_FILE_MISS | FBLog_Log,
  1150. hr,
  1151. pwszFilePath,
  1152. IDS_CANNOT_ACCESS_FILE
  1153. );
  1154. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  1155. }
  1156. if (SUCCEEDED(hr) && !IsScriptFile(pwszFilePath))
  1157. {
  1158. g_fblog.LogString(IDS_NOT_SUPPORTED_SCRIPT_FILE_TYPE,
  1159. pwszFilePath
  1160. );
  1161. hr = S_FALSE;
  1162. }
  1163. if (S_OK == hr)
  1164. {
  1165. //
  1166. // now kick out the script
  1167. //
  1168. STARTUPINFO si;
  1169. PROCESS_INFORMATION pi;
  1170. ZeroMemory( &si, sizeof(si) );
  1171. si.cb = sizeof(si);
  1172. ZeroMemory( &pi, sizeof(pi) );
  1173. WCHAR wszExitCode[g_dwHexDwordLen];
  1174. g_fblog.LogString(IDS_RUNNING_SCRIPTS, pwszFilePath);
  1175. CComBSTR bstrCmdLine(L"CScript.exe //B ");
  1176. bstrCmdLine += pwszFilePath;
  1177. if (bstrCmdLine.m_str == NULL)
  1178. {
  1179. hr = E_OUTOFMEMORY;
  1180. }
  1181. else
  1182. {
  1183. //
  1184. // this will launch the script w/o a window
  1185. //
  1186. BOOL bRun = ::CreateProcess(
  1187. NULL,
  1188. bstrCmdLine,
  1189. NULL,
  1190. NULL,
  1191. FALSE,
  1192. CREATE_NO_WINDOW,
  1193. NULL,
  1194. NULL,
  1195. &si,
  1196. &pi
  1197. );
  1198. if (!bRun)
  1199. {
  1200. g_fblog.LogFeedback(SSR_FB_ERROR_CRITICAL | FBLog_Log,
  1201. GetLastError(),
  1202. bstrCmdLine,
  1203. IDS_ERROR_CREATE_PROCESS
  1204. );
  1205. //
  1206. // $undone:shawnwu, should we quit?
  1207. //
  1208. }
  1209. else
  1210. {
  1211. //
  1212. // we don't proceed until the script ends
  1213. // and then we log the exit code
  1214. //
  1215. ::WaitForSingleObject( pi.hProcess, INFINITE );
  1216. DWORD dwExitCode;
  1217. bRun = ::GetExitCodeProcess(pi.hProcess, &dwExitCode);
  1218. _snwprintf(wszExitCode, g_dwHexDwordLen, L"0x%X", dwExitCode);
  1219. g_fblog.LogFeedback(SSR_FB_EXIT_CODE | FBLog_Log,
  1220. (LPCWSTR)NULL,
  1221. wszExitCode,
  1222. IDS_EXIT_CODE
  1223. );
  1224. }
  1225. }
  1226. }
  1227. delete [] pwszFilePath;
  1228. return hr;
  1229. }
  1230. /*
  1231. Routine Description:
  1232. Name:
  1233. CSsrEngine::IsScriptFile
  1234. Functionality:
  1235. test if a file is a script file
  1236. Virtual:
  1237. No.
  1238. Arguments:
  1239. pwszFileName - The path of the file
  1240. Return Value:
  1241. true if and only if it is one of the script file types (.vbs, .js, .wsf)
  1242. Notes:
  1243. */
  1244. bool
  1245. CSsrEngine::IsScriptFile (
  1246. IN LPCWSTR pwszFileName
  1247. )const
  1248. {
  1249. //
  1250. // check if the the file is indeed a script
  1251. //
  1252. if (pwszFileName == NULL)
  1253. {
  1254. return false;
  1255. }
  1256. LPCWSTR pwszExt = pwszFileName + wcslen(pwszFileName) - 1;
  1257. while (pwszExt != pwszFileName)
  1258. {
  1259. if (*pwszExt == L'.')
  1260. {
  1261. break;
  1262. }
  1263. else
  1264. {
  1265. pwszExt--;
  1266. }
  1267. }
  1268. return (_wcsicmp(L".js", pwszExt) == 0 ||
  1269. _wcsicmp(L".vbs", pwszExt) == 0 ||
  1270. _wcsicmp(L".wsf", pwszExt) == 0 );
  1271. }
  1272. /*
  1273. Routine Description:
  1274. Name:
  1275. CSsrEngine::VerifyDOM
  1276. Functionality:
  1277. Will check if the every section of the security policy has a member
  1278. to process it.
  1279. Virtual:
  1280. No.
  1281. Arguments:
  1282. pXmlPolicy - The XML policy DOM.
  1283. pbstrUnknownMember - receives the unknown member's name if found.
  1284. pbstrExtraInfo - receives extra info, such as whether the missing
  1285. member is from local system or from the security policy
  1286. Return Value:
  1287. Success: S_OK
  1288. Failure: various error codes
  1289. Notes:
  1290. $undone:shawnwu
  1291. Harmless to call, but no actio is taken at this time. Waiting for
  1292. finalization of security policy schema.
  1293. */
  1294. HRESULT
  1295. CSsrEngine::VerifyDOM (
  1296. IN IXMLDOMDocument2 * pXmlPolicy,
  1297. OUT BSTR * pbstrUnknownMember,
  1298. OUT BSTR * pbstrExtraInfo
  1299. )
  1300. {
  1301. HRESULT hr = S_OK;
  1302. if (pbstrUnknownMember == NULL)
  1303. {
  1304. hr = E_INVALIDARG;
  1305. }
  1306. else
  1307. {
  1308. *pbstrUnknownMember = NULL;
  1309. }
  1310. if (pbstrExtraInfo == NULL)
  1311. {
  1312. hr = E_INVALIDARG;
  1313. }
  1314. else
  1315. {
  1316. *pbstrExtraInfo = NULL;
  1317. }
  1318. if (pXmlPolicy == NULL)
  1319. {
  1320. hr = E_INVALIDARG;
  1321. }
  1322. return hr;
  1323. }
  1324. /*
  1325. Routine Description:
  1326. Name:
  1327. CSsrEngine::CleanupOutputFiles
  1328. Functionality:
  1329. Will clean up all those transformation output files for the given
  1330. action.
  1331. Virtual:
  1332. No.
  1333. Arguments:
  1334. psaMemberNames - The names of the members
  1335. lAction - The action verb.
  1336. bLog - If false, there will be no logging. This prevents
  1337. extra logging during restoration of failed rollback
  1338. transformation.
  1339. Return Value:
  1340. Success: S_OK
  1341. Failure: various error codes
  1342. Notes:
  1343. We must not blindly delete all the files in the output directory
  1344. because some of them may be installed by a member. Only those transformation
  1345. files we are told to generate will be cleanup.
  1346. */
  1347. HRESULT
  1348. CSsrEngine::CleanupOutputFiles (
  1349. IN CSafeArray * psaMemberNames,
  1350. IN SsrActionVerb lAction,
  1351. IN bool bLog
  1352. )
  1353. {
  1354. HRESULT hr = S_OK;
  1355. HRESULT hrLastError = S_OK;
  1356. //
  1357. // log the action
  1358. //
  1359. if (bLog)
  1360. {
  1361. g_fblog.LogString(IDS_START_CLEANUP_CONFIGURE_OUTPUTS, NULL);
  1362. }
  1363. //
  1364. // we will try to finish the work even if errors occur. However
  1365. // we will return such error.
  1366. //
  1367. for (ULONG i = 0; i < psaMemberNames->GetSize(); i++)
  1368. {
  1369. CComVariant varName;
  1370. //
  1371. // Get the indexed element as a bstr = the name of the member
  1372. //
  1373. hr = psaMemberNames->GetElement(i, VT_BSTR, &varName);
  1374. if (SUCCEEDED(hr))
  1375. {
  1376. CSsrMemberAccess * pMA = m_pMembership->GetMemberByName(
  1377. varName.bstrVal);
  1378. if (pMA != NULL)
  1379. {
  1380. //
  1381. // want output file directory (true inside SsrPGetDirectory)
  1382. //
  1383. hr = pMA->MoveOutputFiles(lAction,
  1384. SsrPGetDirectory(lAction, TRUE),
  1385. NULL,
  1386. true,
  1387. bLog
  1388. );
  1389. if (FAILED(hr))
  1390. {
  1391. hrLastError = hr;
  1392. }
  1393. }
  1394. }
  1395. }
  1396. if (bLog)
  1397. {
  1398. g_fblog.LogString(IDS_END_CLEANUP_CONFIGURE_OUTPUTS, NULL);
  1399. }
  1400. return hrLastError;
  1401. }
  1402. /*
  1403. Routine Description:
  1404. Name:
  1405. CSsrEngine::MoveRollbackFiles
  1406. Functionality:
  1407. Will move the rollback files (only those transformation output files
  1408. for rollback) in the source directory root to the destination
  1409. directory root.
  1410. Virtual:
  1411. No.
  1412. Arguments:
  1413. psaMemberNames - The names of the all members
  1414. pwszSrcDirPath - The path of the source directory from which the files
  1415. will to be moved.
  1416. pwszDestDirRoot - The path of the destination directory to which the files
  1417. will be moved .
  1418. Return Value:
  1419. Success: S_OK
  1420. Failure: various error codes
  1421. Notes:
  1422. */
  1423. HRESULT
  1424. CSsrEngine::MoveRollbackFiles (
  1425. IN CSafeArray * psaMemberNames,
  1426. IN LPCWSTR pwszSrcDirPath,
  1427. IN LPCWSTR pwszDestDirPath,
  1428. IN bool bLog
  1429. )
  1430. {
  1431. HRESULT hr = S_OK;
  1432. HRESULT hrLastError = S_OK;
  1433. //
  1434. // it's the output files of rollback transformation that
  1435. // need to be moved.
  1436. //
  1437. if (bLog)
  1438. {
  1439. g_fblog.LogString(IDS_START_BACKUP_ROLLBACK_OUTPUTS, NULL);
  1440. }
  1441. //
  1442. // for each member, we need to move the rollback files
  1443. //
  1444. for (ULONG i = 0; i < psaMemberNames->GetSize(); i++)
  1445. {
  1446. CComVariant varName;
  1447. //
  1448. // this is the i-th member's name
  1449. //
  1450. hr = psaMemberNames->GetElement(i, VT_BSTR, &varName);
  1451. if (SUCCEEDED(hr))
  1452. {
  1453. //
  1454. // get this member's information access class
  1455. //
  1456. CSsrMemberAccess * pMA = m_pMembership->GetMemberByName(varName.bstrVal);
  1457. _ASSERT(pMA != NULL);
  1458. hr = pMA->MoveOutputFiles(ActionRollback,
  1459. pwszSrcDirPath,
  1460. pwszDestDirPath,
  1461. false, // don't delete
  1462. bLog
  1463. );
  1464. }
  1465. }
  1466. if (bLog)
  1467. {
  1468. g_fblog.LogString(IDS_END_BACKUP_ROLLBACK_OUTPUTS, NULL);
  1469. }
  1470. return hrLastError;
  1471. }