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.

2453 lines
76 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Abstract:
  4. @doc
  5. @module VsWrtImp.cpp | Implementation of Writer
  6. @end
  7. Author:
  8. Adi Oltean [aoltean] 02/02/2000
  9. TBD:
  10. Add comments.
  11. Remove the C++ exception-handler related code.
  12. Revision History:
  13. Name Date Comments
  14. aoltean 02/02/2000 Created
  15. brianb 03/25/2000 modified to include additional events
  16. brianb 03/28/2000 modified to include timeouts and sync for OnPrepareBackup
  17. brianb 03/28/2000 renamed to vswrtimp.cpp to separate internal state from external interface
  18. brianb 04/19/2000 added security checks
  19. brianb 05/03/2000 new security model
  20. brianb 05/09/2000 fix problem with autolocks
  21. --*/
  22. #include <stdafx.hxx>
  23. #include <eventsys.h>
  24. #include "vs_inc.hxx"
  25. #include "vs_sec.hxx"
  26. #include "vs_idl.hxx"
  27. #include "comadmin.hxx"
  28. #include "vsevent.h"
  29. #include "vswriter.h"
  30. #include "vsbackup.h"
  31. #include "vssmsg.h"
  32. #include "vswrtimp.h"
  33. // xml support
  34. #include "vs_wmxml.hxx"
  35. #include "vs_cmxml.hxx"
  36. #include "rpcdce.h"
  37. ////////////////////////////////////////////////////////////////////////
  38. // Standard foo for file name aliasing. This code block must be after
  39. // all includes of VSS header files.
  40. //
  41. #ifdef VSS_FILE_ALIAS
  42. #undef VSS_FILE_ALIAS
  43. #endif
  44. #define VSS_FILE_ALIAS "WRTWRTIC"
  45. //
  46. ////////////////////////////////////////////////////////////////////////
  47. /////////////////////////////////////////////////////////////////////////////
  48. // Constants
  49. const WCHAR g_wszPublisherID[] = L"VSS Publisher";
  50. // event names
  51. const WCHAR g_wszRequestInfoMethodName[] = L"RequestWriterInfo";
  52. const WCHAR g_wszPrepareForBackupMethodName[] = L"PrepareForBackup";
  53. const WCHAR g_wszBackupCompleteMethodName[] = L"BackupComplete";
  54. const WCHAR g_wszPostRestoreMethodName[] = L"PostRestore";
  55. const WCHAR g_wszPrepareForSnapshotMethodName[] = L"PrepareForSnapshot";
  56. const WCHAR g_wszFreezeMethodName[] = L"Freeze";
  57. const WCHAR g_wszThawMethodName[] = L"Thaw";
  58. const WCHAR g_wszAbortMethodName[] = L"Abort";
  59. // List of received volumes is in the following formatDate
  60. // <Volume Name 1>;<Volume Name 2>: ... :<Volume Name N>
  61. const WCHAR VSS_VOLUME_DELIMITERS[] = L";";
  62. // class describing state machine for writer
  63. class CVssWriterImplStateMachine
  64. {
  65. private:
  66. // disable default and copy constructors
  67. CVssWriterImplStateMachine();
  68. public:
  69. CVssWriterImplStateMachine
  70. (
  71. VSS_WRITER_STATE previousState,
  72. VSS_WRITER_STATE successfulExitState,
  73. VSS_WRITER_STATE failureExitState,
  74. bool bBeginningState,
  75. bool bSuccessiveState,
  76. bool bResetSequenceOnLeave
  77. ) :
  78. m_previousState(previousState),
  79. m_successfulExitState(successfulExitState),
  80. m_failureExitState(failureExitState),
  81. m_bBeginningState(bBeginningState),
  82. m_bSuccessiveState(bSuccessiveState),
  83. m_bResetSequenceOnLeave(bResetSequenceOnLeave)
  84. {
  85. }
  86. // previous state writer must be in to enter the current
  87. // state unless this is the first state of a sequence
  88. VSS_WRITER_STATE m_previousState;
  89. // state we are in if the operation is successful
  90. VSS_WRITER_STATE m_successfulExitState;
  91. // state we are in if the operation is uncessful
  92. VSS_WRITER_STATE m_failureExitState;
  93. // is this state a possible state for the beginning of the sequence
  94. bool m_bBeginningState;
  95. // is this a possible non-beginning state in a sequence
  96. bool m_bSuccessiveState;
  97. // should the sequence be reset on successful exit of the state
  98. bool m_bResetSequenceOnLeave;
  99. };
  100. // definition of state machine
  101. static CVssWriterImplStateMachine s_rgWriterStates[] =
  102. {
  103. // OnPrepareBackup
  104. CVssWriterImplStateMachine
  105. (
  106. VSS_WS_STABLE, // previous state
  107. VSS_WS_STABLE, // next state if successful
  108. VSS_WS_FAILED_AT_PREPARE_BACKUP, // next state if failure
  109. true, // this can be a first state
  110. false, // this must be a first state
  111. false // do not reset sequence on leaving this state
  112. ),
  113. // OnPrepareSnapshot
  114. CVssWriterImplStateMachine
  115. (
  116. VSS_WS_STABLE, // previous state
  117. VSS_WS_WAITING_FOR_FREEZE, // next state if successful
  118. VSS_WS_FAILED_AT_PREPARE_SNAPSHOT, // next state if failure
  119. true, // this can be a first state
  120. true, // this can be a follow on state
  121. false // do not reset sequence on leaving this state
  122. ),
  123. // OnFreeze
  124. CVssWriterImplStateMachine
  125. (
  126. VSS_WS_WAITING_FOR_FREEZE, // previous state
  127. VSS_WS_WAITING_FOR_THAW, // next state if successful
  128. VSS_WS_FAILED_AT_FREEZE, // next state if unsuccessful
  129. false, // this may not be a first state
  130. true, // this must be a follow on state
  131. false // do not reset sequence on leaving this state
  132. ),
  133. // OnThaw
  134. CVssWriterImplStateMachine
  135. (
  136. VSS_WS_WAITING_FOR_THAW, // previous state
  137. VSS_WS_WAITING_FOR_BACKUP_COMPLETE, // next state if successful
  138. VSS_WS_FAILED_AT_THAW, // next state if unsuccessful
  139. false, // this may not be a first state
  140. true, // this must be a follow on state
  141. true // reset sequence on leaving this state
  142. )
  143. };
  144. // state ids
  145. static const unsigned s_ivwsmPrepareForBackup = 0;
  146. static const unsigned s_ivwsmPrepareForSnapshot = 1;
  147. static const unsigned s_ivwsmFreeze = 2;
  148. static const unsigned s_ivwsmThaw = 3;
  149. /////////////////////////////////////////////////////////////////////////////
  150. // CVssWriterImpl constructors/destructors
  151. // constructor
  152. CVssWriterImpl::CVssWriterImpl():
  153. m_WriterID(GUID_NULL),
  154. m_InstanceID(GUID_NULL),
  155. m_usage(VSS_UT_UNDEFINED),
  156. m_source(VSS_ST_UNDEFINED),
  157. m_nLevel(VSS_APP_FRONT_END),
  158. m_dwTimeoutFreeze(VSS_TIMEOUT_FREEZE),
  159. m_CurrentSnapshotSetId(GUID_NULL),
  160. m_bSequenceInProgress(false),
  161. m_nVolumesCount(0),
  162. m_ppwszVolumesArray(NULL),
  163. m_pwszLocalVolumeNameList(NULL),
  164. m_dwEventMask(0),
  165. m_wszWriterName(NULL),
  166. m_state(VSS_WS_STABLE),
  167. m_hevtTimerThread(NULL),
  168. m_hmtxTimerThread(NULL),
  169. m_hThreadTimerThread(NULL),
  170. m_bLocked(false),
  171. m_bLockCreated(false),
  172. m_command(VSS_TC_UNDEFINED),
  173. m_iPreviousSnapshots(0),
  174. m_cbstrSubscriptionId(0),
  175. m_bOnAbortPermitted(false),
  176. m_bFailedAtIdentify(false),
  177. m_hrWriterFailure(S_OK)
  178. {
  179. for(UINT i = 0; i < MAX_PREVIOUS_SNAPSHOTS; i++)
  180. {
  181. m_rgidPreviousSnapshots[i] = GUID_NULL;
  182. m_rgstatePreviousSnapshots[i] = VSS_WS_UNKNOWN;
  183. m_rghrWriterFailurePreviousSnapshots[i] = E_UNEXPECTED;
  184. }
  185. }
  186. // destructor
  187. CVssWriterImpl::~CVssWriterImpl()
  188. {
  189. // terminate timer thread if it is still running
  190. if (m_bLockCreated)
  191. {
  192. Lock();
  193. TerminateTimerThread();
  194. Unlock();
  195. }
  196. // delete volume array
  197. delete[] m_ppwszVolumesArray;
  198. // delete volume list string
  199. ::VssFreeString(m_pwszLocalVolumeNameList);
  200. // delete writer name
  201. free(m_wszWriterName);
  202. if (m_hevtTimerThread)
  203. CloseHandle(m_hevtTimerThread);
  204. if (m_hmtxTimerThread)
  205. CloseHandle(m_hmtxTimerThread);
  206. }
  207. // create an event
  208. void CVssWriterImpl::SetupEvent(IN HANDLE *phevt)
  209. {
  210. CVssFunctionTracer ft(VSSDBG_WRITER, L"CVssWriterImple::SetupEvent");
  211. BS_ASSERT(phevt);
  212. // setup events as enabled and manual reset
  213. *phevt = CreateEvent(NULL, TRUE, TRUE, NULL);
  214. if (*phevt == NULL)
  215. ft.Throw
  216. (
  217. VSSDBG_WRITER,
  218. E_OUTOFMEMORY,
  219. L"Failure to create event object due to error %d.",
  220. GetLastError()
  221. );
  222. }
  223. const WCHAR SETUP_KEY[] = L"SYSTEM\\Setup";
  224. const WCHAR SETUP_INPROGRESS_REG[] = L"SystemSetupInProgress";
  225. const WCHAR UPGRADE_INPROGRESS_REG[] = L"UpgradeInProgress";
  226. // initialize writer object
  227. void CVssWriterImpl::Initialize
  228. (
  229. IN VSS_ID WriterID, // writer class id
  230. IN LPCWSTR wszWriterName, // friendly name of writer
  231. IN VSS_USAGE_TYPE usage, // usage type
  232. IN VSS_SOURCE_TYPE source, // data source type
  233. IN VSS_APPLICATION_LEVEL nLevel, // which freeze event this writer handles
  234. IN DWORD dwTimeoutFreeze // timeout between freeze and thaw
  235. )
  236. {
  237. CVssFunctionTracer ft(VSSDBG_WRITER, L"CVssWriterImpl::Initialize");
  238. {
  239. // determine if we are in setup. If we are then reject the
  240. // initialize call and log an error in the application log
  241. CRegKey cRegKeySetup;
  242. DWORD dwRes;
  243. bool fInSetup = false;
  244. dwRes = cRegKeySetup.Create(HKEY_LOCAL_MACHINE, SETUP_KEY);
  245. if (dwRes == ERROR_SUCCESS)
  246. {
  247. DWORD dwValue;
  248. dwRes = cRegKeySetup.QueryValue(dwValue, SETUP_INPROGRESS_REG);
  249. if (dwRes == ERROR_SUCCESS && dwValue > 0)
  250. fInSetup = true;
  251. dwRes = cRegKeySetup.QueryValue(dwValue, UPGRADE_INPROGRESS_REG);
  252. if (dwRes == ERROR_SUCCESS && dwValue > 0)
  253. fInSetup = true;
  254. }
  255. if (fInSetup)
  256. ft.Throw(VSSDBG_WRITER, VSS_E_BAD_STATE, L"Calling Initialize during setup");
  257. }
  258. // Testing arguments validity
  259. if (wszWriterName == NULL)
  260. ft.Throw
  261. (
  262. VSSDBG_WRITER,
  263. E_INVALIDARG,
  264. L"NULL writer name"
  265. );
  266. switch(nLevel) {
  267. case VSS_APP_SYSTEM:
  268. case VSS_APP_BACK_END:
  269. case VSS_APP_FRONT_END:
  270. break;
  271. default:
  272. ft.Throw
  273. (
  274. VSSDBG_WRITER,
  275. E_INVALIDARG,
  276. L"Invalid app level %d", nLevel
  277. );
  278. }
  279. m_cs.Init(); // Warning - may throw NT exceptions...
  280. m_bLockCreated = true;
  281. // save writer class id
  282. m_WriterID = WriterID;
  283. // save writer name
  284. m_wszWriterName = _wcsdup(wszWriterName);
  285. if (m_wszWriterName == NULL)
  286. ft.Throw
  287. (
  288. VSSDBG_WRITER,
  289. E_OUTOFMEMORY,
  290. L"Cannot allocate writer name"
  291. );
  292. // save usage type
  293. m_usage = usage;
  294. // save source type
  295. m_source = source;
  296. // create guid for this instance
  297. ft.hr = ::CoCreateGuid(&m_InstanceID);
  298. ft.CheckForError(VSSDBG_WRITER, L"CoCreateGuid");
  299. ft.Trace
  300. (
  301. VSSDBG_WRITER,
  302. L" InstanceId for Writer %s is" WSTR_GUID_FMT,
  303. m_wszWriterName,
  304. GUID_PRINTF_ARG(m_InstanceID)
  305. );
  306. // save app level
  307. m_nLevel = nLevel;
  308. // save timeout
  309. m_dwTimeoutFreeze = dwTimeoutFreeze;
  310. // setup thread mutex
  311. m_hmtxTimerThread = CreateMutex(NULL, FALSE, NULL);
  312. if (m_hmtxTimerThread == NULL)
  313. ft.Throw
  314. (
  315. VSSDBG_WRITER,
  316. E_OUTOFMEMORY,
  317. L"Failure to create mutex object due to error %d.",
  318. GetLastError()
  319. );
  320. // setup event used to control the timer thread
  321. SetupEvent(&m_hevtTimerThread);
  322. }
  323. // start a sequence
  324. // critical section (m_cs) must be locked upone entry to this routine
  325. void CVssWriterImpl::BeginSequence
  326. (
  327. IN CVssID &SnapshotSetId
  328. )
  329. {
  330. CVssFunctionTracer ft(VSSDBG_WRITER, L"CVssWriterImpl::BeginSequence");
  331. AssertLocked();
  332. // terminate timer thread if it is still operating
  333. TerminateTimerThread();
  334. // setup current snapshot set id
  335. m_CurrentSnapshotSetId = SnapshotSetId;
  336. // indicate that sequence is in progress
  337. m_bSequenceInProgress = true;
  338. BS_ASSERT(m_bOnAbortPermitted == false);
  339. // current state is STABLE (i.e., beginning of sequence, clears
  340. // any completion state we were in)
  341. m_state = VSS_WS_STABLE;
  342. // indicate that there is no failure
  343. m_hrWriterFailure = S_OK;
  344. }
  345. INT CVssWriterImpl::SearchForPreviousSequence(
  346. IN VSS_ID& idSnapshotSet
  347. )
  348. {
  349. for(INT iSeqIndex = 0;
  350. iSeqIndex < MAX_PREVIOUS_SNAPSHOTS;
  351. iSeqIndex++)
  352. {
  353. if (idSnapshotSet == m_rgidPreviousSnapshots[iSeqIndex])
  354. return iSeqIndex;
  355. } // end for
  356. return INVALID_SEQUENCE_INDEX;
  357. }
  358. // Reset the sequence-related data members
  359. // critical section must be locked prior to entering this state
  360. void CVssWriterImpl::ResetSequence(bool bCalledFromTimerThread)
  361. {
  362. CVssFunctionTracer ft(VSSDBG_WRITER, L"CVssWriterImpl::ResetSequence");
  363. AssertLocked();
  364. if (m_bSequenceInProgress)
  365. {
  366. // We need to test to not add the same SSID twice - bug 228622.
  367. if (SearchForPreviousSequence(m_CurrentSnapshotSetId) == INVALID_SEQUENCE_INDEX)
  368. {
  369. BS_ASSERT(m_iPreviousSnapshots < MAX_PREVIOUS_SNAPSHOTS);
  370. m_rgidPreviousSnapshots[m_iPreviousSnapshots] = m_CurrentSnapshotSetId;
  371. m_rgstatePreviousSnapshots[m_iPreviousSnapshots] = m_state;
  372. m_rghrWriterFailurePreviousSnapshots[m_iPreviousSnapshots] = m_hrWriterFailure;
  373. m_iPreviousSnapshots = (m_iPreviousSnapshots + 1) % MAX_PREVIOUS_SNAPSHOTS;
  374. }
  375. else
  376. BS_ASSERT(false); // The same SSID was already added - programming error.
  377. }
  378. // Reset the sequence-related data members
  379. m_bSequenceInProgress = false;
  380. m_bOnAbortPermitted = false;
  381. // reset writer callback function
  382. m_pWriterCallback = NULL;
  383. // reset volumes array
  384. m_nVolumesCount = 0;
  385. delete[] m_ppwszVolumesArray;
  386. m_ppwszVolumesArray = NULL;
  387. ::VssFreeString(m_pwszLocalVolumeNameList);
  388. m_CurrentSnapshotSetId = GUID_NULL;
  389. // if bCalledFromTimerThread is true, this means that the timer
  390. // thread is causing the sequence to be reset. We are in the timer
  391. // thread already and it will terminate upon completion of this call
  392. // so we shouldn't try causing it to terminate again.
  393. if (!bCalledFromTimerThread)
  394. TerminateTimerThread();
  395. }
  396. // indicate why the writer failed
  397. HRESULT CVssWriterImpl::SetWriterFailure(HRESULT hr)
  398. {
  399. if (hr != VSS_E_WRITERERROR_TIMEOUT &&
  400. hr != VSS_E_WRITERERROR_RETRYABLE &&
  401. hr != VSS_E_WRITERERROR_NONRETRYABLE &&
  402. hr != VSS_E_WRITERERROR_OUTOFRESOURCES &&
  403. hr != VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT)
  404. return E_INVALIDARG;
  405. m_hrWriterFailure = hr;
  406. return S_OK;
  407. }
  408. // determine if path specified is on one of the volumes that is snapshot
  409. bool CVssWriterImpl::IsPathAffected
  410. (
  411. IN LPCWSTR wszPath
  412. ) const
  413. {
  414. // Test the status
  415. if (!m_bSequenceInProgress)
  416. return false;
  417. // check for empty volume count
  418. if (m_nVolumesCount == 0)
  419. return false;
  420. // Get the volume mount point
  421. WCHAR wszVolumeMP[MAX_PATH];
  422. BOOL bRes = ::GetVolumePathNameW(wszPath, wszVolumeMP, MAX_PATH);
  423. if (!bRes)
  424. return false;
  425. // Get the volume name
  426. WCHAR wszVolumeName[MAX_PATH];
  427. bRes = ::GetVolumeNameForVolumeMountPointW(wszVolumeMP, wszVolumeName, MAX_PATH);
  428. if (!bRes)
  429. return false;
  430. // Search to see if that volume is within snapshotted volumes
  431. for (int nIndex = 0; nIndex < m_nVolumesCount; nIndex++)
  432. {
  433. BS_ASSERT(m_ppwszVolumesArray[nIndex]);
  434. if (::wcscmp(wszVolumeName, m_ppwszVolumesArray[nIndex]) == 0)
  435. return true;
  436. }
  437. return false;
  438. }
  439. // obtain IVssWriterCallback from IDispatch pointer
  440. // caller is responsible for releasing interface that is returned
  441. void CVssWriterImpl::GetCallback
  442. (
  443. IN IDispatch *pWriterCallback,
  444. OUT IVssWriterCallback **ppCallback
  445. )
  446. {
  447. CVssFunctionTracer ft(VSSDBG_WRITER, L"CVssWriterImpl::GetCallback");
  448. // check that pointer is supplied
  449. BS_ASSERT(pWriterCallback != NULL);
  450. ft.hr = CoSetProxyBlanket
  451. (
  452. pWriterCallback,
  453. RPC_C_AUTHN_DEFAULT,
  454. RPC_C_AUTHZ_DEFAULT,
  455. NULL,
  456. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  457. RPC_C_IMP_LEVEL_IDENTIFY,
  458. NULL,
  459. EOAC_NONE
  460. );
  461. // note E_NOINTERFACE means that the pWriterCallback is a in-proc callback
  462. // and there is no proxy
  463. if (FAILED(ft.hr) && ft.hr != E_NOINTERFACE)
  464. {
  465. if (m_hrWriterFailure == S_OK)
  466. m_hrWriterFailure = VSS_E_WRITERERROR_NONRETRYABLE;
  467. ft.LogError(VSS_ERROR_BLANKET_FAILED, VSSDBG_WRITER << ft.hr);
  468. ft.Throw
  469. (
  470. VSSDBG_WRITER,
  471. E_UNEXPECTED,
  472. L"Call to CoSetProxyBlanket failed. hr = 0x%08lx", ft.hr
  473. );
  474. }
  475. // try QueryInterface for IVssWriterCallback interface
  476. ft.hr = pWriterCallback->SafeQI(IVssWriterCallback, ppCallback);
  477. if (FAILED(ft.hr))
  478. {
  479. if (m_hrWriterFailure == S_OK)
  480. m_hrWriterFailure = VSS_E_WRITERERROR_NONRETRYABLE;
  481. ft.LogError(VSS_ERROR_QI_IVSSWRITERCALLBACK, VSSDBG_WRITER << ft.hr);
  482. ft.Throw
  483. (
  484. VSSDBG_WRITER,
  485. E_UNEXPECTED,
  486. L"Error querying for IVssWriterCallback interface. hr = 0x%08lx",
  487. ft.hr
  488. );
  489. }
  490. }
  491. // create basic writer metadata for OnIdentify method
  492. CVssCreateWriterMetadata *CVssWriterImpl::CreateBasicWriterMetadata()
  493. {
  494. CVssFunctionTracer ft(VSSDBG_WRITER, L"CVssWriterImpl::CreateBasicWriterMetadata");
  495. // create object supporting IVssCreateMetadata interface
  496. CVssCreateWriterMetadata *pMetadata = new CVssCreateWriterMetadata;
  497. if (pMetadata == NULL)
  498. {
  499. m_hrWriterFailure = VSS_E_WRITERERROR_OUTOFRESOURCES;
  500. ft.Throw
  501. (
  502. VSSDBG_WRITER,
  503. E_OUTOFMEMORY,
  504. L"Cannot create CVssCreateWriterMetadata due to allocation failure."
  505. );
  506. }
  507. // call initialize to create IDENTIFICATION section
  508. ft.hr = pMetadata->Initialize
  509. (
  510. m_InstanceID,
  511. m_WriterID,
  512. m_wszWriterName,
  513. m_usage,
  514. m_source
  515. );
  516. if (ft.HrFailed())
  517. {
  518. m_hrWriterFailure = VSS_E_WRITERERROR_OUTOFRESOURCES;
  519. delete pMetadata;
  520. ft.Throw
  521. (
  522. VSSDBG_WRITER,
  523. ft.hr,
  524. L"CVssCreateWriterMetadata::Initialize failed. hr = 0x%08lx",
  525. ft.hr
  526. );
  527. }
  528. // return object
  529. return pMetadata;
  530. }
  531. static LPCWSTR x_wszElementRoot = L"root";
  532. static LPCWSTR x_wszElementWriterComponents = L"WRITER_COMPONENTS";
  533. // get writer components for OnPrepareBackup, OnBackupComplete, and OnPostRestore
  534. // methods
  535. void CVssWriterImpl::InternalGetWriterComponents
  536. (
  537. IN IVssWriterCallback *pCallback,
  538. OUT IVssWriterComponentsInt **ppWriter,
  539. bool bWriteable
  540. )
  541. {
  542. CVssFunctionTracer ft(VSSDBG_WRITER, L"CVssWriterImpl::InternalGetWriterComponents");
  543. BS_ASSERT(pCallback);
  544. BS_ASSERT(ppWriter);
  545. *ppWriter = NULL;
  546. // call GetContent callback method on the backup application
  547. CComBSTR bstrId(m_InstanceID);
  548. if (!bstrId)
  549. {
  550. m_hrWriterFailure = VSS_E_WRITERERROR_OUTOFRESOURCES;
  551. ft.Throw
  552. (
  553. VSSDBG_WRITER,
  554. E_OUTOFMEMORY,
  555. L"Cannot allocate instance Id string"
  556. );
  557. }
  558. try
  559. {
  560. BOOL bPartialFileSupport;
  561. ft.hr = pCallback->GetBackupState
  562. (
  563. &m_bComponentsSelected,
  564. &m_bBootableSystemStateBackup,
  565. &m_backupType,
  566. &bPartialFileSupport,
  567. NULL
  568. );
  569. }
  570. catch(...)
  571. {
  572. ft.Trace(VSSDBG_WRITER, L"IVssWriterCallback::GetBackupState threw an exception.");
  573. throw;
  574. }
  575. if (ft.HrFailed())
  576. {
  577. m_hrWriterFailure = VSS_E_WRITERERROR_RETRYABLE;
  578. ft.Throw
  579. (
  580. VSSDBG_WRITER,
  581. ft.hr,
  582. L"IVssWriterCallback::GetBackupState failed. hr = 0x%08lx",
  583. ft.hr
  584. );
  585. }
  586. CComBSTR bstrWriterComponentsDoc;
  587. try
  588. {
  589. ft.hr = pCallback->GetContent(bstrId, &bstrWriterComponentsDoc);
  590. }
  591. catch(...)
  592. {
  593. m_hrWriterFailure = VSS_E_WRITERERROR_RETRYABLE;
  594. ft.Trace(VSSDBG_WRITER, L"IVssWriterCallback::GetContent threw an exception.");
  595. throw;
  596. }
  597. if (ft.HrFailed())
  598. {
  599. m_hrWriterFailure = VSS_E_WRITERERROR_RETRYABLE;
  600. ft.Throw
  601. (
  602. VSSDBG_WRITER,
  603. ft.hr,
  604. L"Cannot get WRITER_COMPONENTS document. hr = 0x%08lx",
  605. ft.hr
  606. );
  607. }
  608. if (ft.hr == S_FALSE)
  609. {
  610. // reset status code
  611. ft.hr = S_OK;
  612. // allocate null writer components object
  613. *ppWriter = (IVssWriterComponentsInt *) new CVssNULLWriterComponents
  614. (
  615. m_InstanceID,
  616. m_WriterID
  617. );
  618. if (*ppWriter == NULL)
  619. {
  620. // indicate that the writer failed due to an out of resources condition
  621. m_hrWriterFailure = VSS_E_WRITERERROR_OUTOFRESOURCES;
  622. ft.Throw (VSSDBG_WRITER, E_OUTOFMEMORY, L"Can't allocate CVssWriterComponents object");
  623. }
  624. (*ppWriter)->AddRef();
  625. }
  626. else
  627. {
  628. CXMLDocument doc;
  629. if (!doc.LoadFromXML(bstrWriterComponentsDoc) ||
  630. !doc.FindElement(x_wszElementRoot, true))
  631. {
  632. m_hrWriterFailure = VSS_E_WRITERERROR_NONRETRYABLE;
  633. ft.LogError(VSS_ERROR_WRITER_COMPONENTS_CORRUPT, VSSDBG_WRITER);
  634. ft.Throw
  635. (
  636. VSSDBG_WRITER,
  637. VSS_E_CORRUPT_XML_DOCUMENT,
  638. L"Internally transferred WRITER_COMPONENTS document is invalid"
  639. );
  640. }
  641. doc.SetToplevel();
  642. *ppWriter = (IVssWriterComponentsInt *)
  643. new CVssWriterComponents
  644. (
  645. doc.GetCurrentNode(),
  646. doc.GetInterface(),
  647. bWriteable
  648. );
  649. if (*ppWriter == NULL)
  650. {
  651. m_hrWriterFailure = VSS_E_WRITERERROR_OUTOFRESOURCES;
  652. ft.Throw (VSSDBG_WRITER, E_OUTOFMEMORY, L"Can't allocate CVssWriterComponents object");
  653. }
  654. (*ppWriter)->AddRef();
  655. ft.hr = (*ppWriter)->Initialize(true);
  656. if (ft.HrFailed())
  657. {
  658. m_hrWriterFailure = VSS_E_WRITERERROR_OUTOFRESOURCES;
  659. (*ppWriter)->Release();
  660. *ppWriter = NULL;
  661. ft.Throw
  662. (
  663. VSSDBG_WRITER,
  664. ft.hr,
  665. L"Failed to initialize WRITER_COMPONENTS document. hr = 0x%08lx",
  666. ft.hr
  667. );
  668. }
  669. }
  670. }
  671. // called when entering a state to verify whether this state can be
  672. // validly entered and generate appropriate error if not.
  673. // this routine always obtains the critical section. If this routine
  674. // is called then LeaveState must also be called in order to free the
  675. // critical section.
  676. bool CVssWriterImpl::EnterState
  677. (
  678. IN const CVssWriterImplStateMachine &vwsm,
  679. IN BSTR bstrSnapshotSetId
  680. ) throw(HRESULT)
  681. {
  682. CVssFunctionTracer ft(VSSDBG_WRITER, L"CVssWriterImpl::EnterState");
  683. CVssID id;
  684. // obtain lock just in case next call throws
  685. // no matter how this routine exits, the critical section must be locked
  686. Lock();
  687. // initialize id to snapshot set id
  688. id.Initialize(ft, (LPWSTR)bstrSnapshotSetId, E_OUTOFMEMORY);
  689. // If failed on Identify then we cannot enter in a new state until
  690. // subsequent Identify calls will succeed
  691. if (m_bFailedAtIdentify)
  692. return false;
  693. if (!m_bSequenceInProgress)
  694. {
  695. if (!vwsm.m_bBeginningState)
  696. // not a beginning state. Sequence must have been
  697. // interrupted.
  698. return false;
  699. else
  700. {
  701. // BUG 219757 - PrepareForSnapshot, etc. cannot be
  702. // called for the same Snapshot Set if PrepareForBackup failed
  703. // Also we assume here that each new sequence have an UNIQUE SSID.
  704. // This check is needed since the PrepareForBackup phase is optional
  705. // and can be skipped sometimes. Therefore we need to distinguish between
  706. // the case when PrepareForBackup was skipped and the case when PrepareForBackup
  707. // was called and failed.
  708. // Search for a previous sequence with the same Snapshot Set ID.
  709. // If found (this means that a PrepareForBackup was called),
  710. // then reject the call.
  711. if (SearchForPreviousSequence(id) != INVALID_SEQUENCE_INDEX)
  712. return false;
  713. // it is a beginning state, start the sequence
  714. BeginSequence(id);
  715. return true;
  716. }
  717. }
  718. else
  719. {
  720. if (vwsm.m_bSuccessiveState)
  721. {
  722. // it is a valid non-beginning state in the sequence
  723. if (id != m_CurrentSnapshotSetId)
  724. {
  725. // if snapshot set id doesn't match and this is not
  726. // a beginning state, then the event must be ignored.
  727. // We must have aborted the sequence it references.
  728. if (!vwsm.m_bBeginningState)
  729. return false;
  730. }
  731. else
  732. {
  733. // make sure current state matches previous state
  734. // of state we are about to enter
  735. return m_state == vwsm.m_previousState;
  736. }
  737. }
  738. }
  739. // We are trying to start a new sequence.
  740. // This means that the previous sequence was not properly
  741. // terminated. Abort the previous sequence and then
  742. // start a new one.
  743. ft.Trace(VSSDBG_WRITER,
  744. L"*** Warning ***: Writer %s with ID "WSTR_GUID_FMT
  745. L"attempts to reset the previous sequence with Snapshot Set ID "WSTR_GUID_FMT
  746. L". Current state = %d",
  747. m_wszWriterName, GUID_PRINTF_ARG(m_InstanceID), GUID_PRINTF_ARG(m_CurrentSnapshotSetId), (INT)m_state);
  748. DoAbort(false);
  749. BeginSequence(id);
  750. return true;
  751. }
  752. // do abort on failure of the sequence
  753. // critical section must be locked prior to entering this state
  754. void CVssWriterImpl::DoAbort
  755. (
  756. IN bool bCalledFromTimerThread
  757. )
  758. {
  759. CVssFunctionTracer ft(VSSDBG_WRITER, L"CVssWriterImpl::DoAbort");
  760. AssertLocked();
  761. // do nothing if in a sequence
  762. if (!m_bSequenceInProgress)
  763. return;
  764. // catch any exceptions so that we properly reset the
  765. // sequence
  766. BS_ASSERT(m_pWriter);
  767. try
  768. {
  769. // call writer's abort function (depending on the state)
  770. switch(m_state)
  771. {
  772. default:
  773. BS_ASSERT(m_bOnAbortPermitted == false);
  774. break;
  775. case VSS_WS_STABLE:
  776. // This is possible since you may get an Abort
  777. // in (or after) PrepareForBackup (BUG # 301686)
  778. BS_ASSERT(m_bOnAbortPermitted == true);
  779. break;
  780. case VSS_WS_WAITING_FOR_FREEZE:
  781. case VSS_WS_WAITING_FOR_THAW:
  782. case VSS_WS_WAITING_FOR_BACKUP_COMPLETE:
  783. case VSS_WS_FAILED_AT_PREPARE_BACKUP:
  784. case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
  785. case VSS_WS_FAILED_AT_FREEZE:
  786. // Fixing bug 225936
  787. if (m_bOnAbortPermitted)
  788. m_pWriter->OnAbort();
  789. else
  790. ft.Trace(VSSDBG_WRITER, L"Abort skipped in state %d", m_state);
  791. m_bOnAbortPermitted = false;
  792. break;
  793. }
  794. }
  795. VSS_STANDARD_CATCH(ft)
  796. if (ft.HrFailed())
  797. ft.Trace
  798. (
  799. VSSDBG_WRITER,
  800. L"OnAbort failed. hr = 0x%08lx",
  801. ft.hr
  802. );
  803. // set appropriate failure state
  804. switch(m_state)
  805. {
  806. default:
  807. m_state = VSS_WS_UNKNOWN;
  808. BS_ASSERT(false);
  809. break;
  810. // This state is not really kept in the m_state member
  811. case VSS_WS_FAILED_AT_IDENTIFY:
  812. BS_ASSERT(false);
  813. break;
  814. case VSS_WS_FAILED_AT_PREPARE_BACKUP:
  815. case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT:
  816. case VSS_WS_FAILED_AT_FREEZE:
  817. case VSS_WS_FAILED_AT_THAW:
  818. // don't change state if already in a failure state
  819. break;
  820. case VSS_WS_STABLE:
  821. // if current state is STABLE then it means
  822. // we were in PrepareBackup
  823. m_state = VSS_WS_FAILED_AT_PREPARE_BACKUP;
  824. break;
  825. case VSS_WS_WAITING_FOR_FREEZE:
  826. // if we were waiting for freeze then we failed
  827. // between PrepareSync and Freeze
  828. m_state = VSS_WS_FAILED_AT_PREPARE_SNAPSHOT;
  829. break;
  830. case VSS_WS_WAITING_FOR_THAW:
  831. // if we were waiting for thaw then we failed
  832. // between freeze and thaw
  833. m_state = VSS_WS_FAILED_AT_FREEZE;
  834. break;
  835. case VSS_WS_WAITING_FOR_BACKUP_COMPLETE:
  836. // if we were waiting for completion then
  837. // we failed after thaw.
  838. m_state = VSS_WS_FAILED_AT_THAW;
  839. break;
  840. }
  841. if (bCalledFromTimerThread && m_hrWriterFailure == S_OK)
  842. m_hrWriterFailure = VSS_E_WRITERERROR_TIMEOUT;
  843. // reset sequence
  844. ResetSequence(bCalledFromTimerThread);
  845. }
  846. // exit a state. This routine must be called with the critical
  847. // section acquired. For a state, EnterState is called first, then work is
  848. // done, then LeaveState is called. This routine will set the state upon
  849. // exit and possibly reset the snapshot sequence if we are at the end of the
  850. // sequence or the sequence is aborted.
  851. void CVssWriterImpl::LeaveState
  852. (
  853. IN const CVssWriterImplStateMachine &vwsm, // current state
  854. IN bool bSucceeded // did operation succeed
  855. )
  856. {
  857. AssertLocked();
  858. // don't change state or call abort if we are not in a sequence
  859. if (m_bSequenceInProgress)
  860. {
  861. m_state = bSucceeded ? vwsm.m_successfulExitState
  862. : vwsm.m_failureExitState;
  863. // call abort on failure when we are not in the exit state
  864. if (!bSucceeded && !vwsm.m_bResetSequenceOnLeave)
  865. DoAbort(false);
  866. else if (vwsm.m_bResetSequenceOnLeave)
  867. // if sequence ends at this state (THAW) then
  868. // reset variables
  869. ResetSequence(false);
  870. }
  871. Unlock();
  872. }
  873. // arguments to timer function
  874. class CVssTimerArgs
  875. {
  876. private:
  877. CVssTimerArgs();
  878. public:
  879. CVssTimerArgs(CVssWriterImpl *pWriter, VSS_ID id) :
  880. m_snapshotSetId(id),
  881. m_pWriter(pWriter)
  882. {
  883. }
  884. // snapshot set that we are monitoring
  885. VSS_ID m_snapshotSetId;
  886. // pointer to writer
  887. CVssWriterImpl *m_pWriter;
  888. };
  889. // timer thread startup routine
  890. DWORD CVssWriterImpl::StartTimerThread(void *pv)
  891. {
  892. CVssFunctionTracer ft(VSSDBG_WRITER, L"CVssWriterImpl::StartTimerThread");
  893. CVssTimerArgs *pArgs = (CVssTimerArgs *) pv;
  894. BS_ASSERT(pArgs);
  895. BS_ASSERT(pArgs->m_pWriter);
  896. bool bCoInitializeSucceeded = false;
  897. try
  898. {
  899. // coinitialize thread
  900. ft.hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  901. if (ft.HrFailed())
  902. {
  903. pArgs->m_pWriter->m_hrWriterFailure = VSS_E_WRITERERROR_OUTOFRESOURCES;
  904. ft.TranslateError
  905. (
  906. VSSDBG_WRITER,
  907. ft.hr,
  908. L"CoInitializeEx"
  909. );
  910. }
  911. bCoInitializeSucceeded = true;
  912. // call timer func
  913. pArgs->m_pWriter->TimerFunc(pArgs->m_snapshotSetId);
  914. }
  915. VSS_STANDARD_CATCH(ft)
  916. if (bCoInitializeSucceeded)
  917. CoUninitialize();
  918. // delete timer arguments
  919. delete pArgs;
  920. return 0;
  921. }
  922. // function implementing timer functionality
  923. void CVssWriterImpl::TimerFunc(VSS_ID snapshotSetId)
  924. {
  925. CVssFunctionTracer ft(VSSDBG_WRITER, L"CVssWriterImpl::TimerFunc");
  926. // wait on event to insure that only one timer is active at
  927. // any point in time
  928. if (WaitForSingleObject(m_hmtxTimerThread, INFINITE) == WAIT_FAILED)
  929. {
  930. DWORD dwErr = GetLastError();
  931. ft.Trace(VSSDBG_WRITER, L"WaitForSingleObject failed with error %d", dwErr);
  932. BS_ASSERT(FALSE && "WaitForSingleObject failed");
  933. }
  934. // reset timer event
  935. if (!ResetEvent(m_hevtTimerThread))
  936. {
  937. DWORD dwErr = GetLastError();
  938. ft.Trace(VSSDBG_WRITER, L"ResetEvent failed with error %d", dwErr);
  939. BS_ASSERT(FALSE && "ResetEvent failed");
  940. }
  941. Lock();
  942. // make sure that we are still in a snapshot sequence
  943. if (!m_bSequenceInProgress || snapshotSetId != GetCurrentSnapshotSetId())
  944. {
  945. // not in sequence, exit function
  946. Unlock();
  947. // allow another timer thread to start
  948. ReleaseMutex(m_hmtxTimerThread);
  949. return;
  950. }
  951. // initial command is to abort the current sequence on timeout
  952. m_command = VSS_TC_ABORT_CURRENT_SEQUENCE;
  953. Unlock();
  954. DWORD dwTimeout = m_dwTimeoutFreeze;
  955. if (WaitForSingleObject(m_hevtTimerThread, dwTimeout) == WAIT_FAILED)
  956. {
  957. ft.Trace
  958. (
  959. VSSDBG_WRITER,
  960. L"Wait in timer thread failed due to reason %d.",
  961. GetLastError()
  962. );
  963. // allow another thread to start
  964. ReleaseMutex(m_hmtxTimerThread);
  965. return;
  966. }
  967. CVssWriterImplLock lock(this);
  968. if (m_command != VSS_TC_TERMINATE_THREAD)
  969. {
  970. BS_ASSERT(m_command == VSS_TC_ABORT_CURRENT_SEQUENCE);
  971. // cause current sequence to abort
  972. ft.Trace(VSSDBG_WRITER, L"Aborting due to timeout\n");
  973. DoAbort(true);
  974. }
  975. // allow another timer thread to start
  976. ReleaseMutex(m_hmtxTimerThread);
  977. }
  978. /////////////////////////////////////////////////////////////////////////////
  979. // IVssWriter implementation
  980. STDMETHODIMP CVssWriterImpl::RequestWriterInfo
  981. (
  982. IN BSTR bstrSnapshotSetId,
  983. IN BOOL bWriterMetadata,
  984. IN BOOL bWriterState,
  985. IN IDispatch* pWriterCallback
  986. )
  987. {
  988. CVssFunctionTracer ft( VSSDBG_WRITER, L"CVssWriterImpl::RequestWriterInfo" );
  989. // MTA synchronization: The critical section will be left automatically at the end of scope.
  990. CVssWriterImplLock lock(this);
  991. // created metadata, deleted on exit from routine
  992. CVssCreateWriterMetadata *pcwm = NULL;
  993. try
  994. {
  995. // validate that the flags make sense
  996. if (bWriterMetadata && bWriterState ||
  997. !bWriterMetadata && !bWriterState)
  998. ft.Throw(VSSDBG_WRITER, E_INVALIDARG, L"Incorrect flags");
  999. // if we are requesting writer state then we must have a snapshot
  1000. // set id
  1001. if (bWriterState && bstrSnapshotSetId == NULL)
  1002. ft.Throw(VSSDBG_WRITER, E_INVALIDARG, L"NULL required input parameter.");
  1003. if (!IsBackupOperator())
  1004. ft.Throw(VSSDBG_WRITER, E_ACCESSDENIED, L"Backup Operator privileges are not set");
  1005. // get IVssWriterCallback interface
  1006. CComPtr<IVssWriterCallback> pCallback;
  1007. GetCallback(pWriterCallback, &pCallback);
  1008. if (bWriterMetadata)
  1009. {
  1010. // BUG 219757: The identify phase marked as failed
  1011. m_bFailedAtIdentify = true;
  1012. // obtain writer metadata
  1013. // create basic metadata using initialization parameters
  1014. pcwm = CreateBasicWriterMetadata();
  1015. // call writer's OnIdentify method to get more metadata
  1016. BS_ASSERT(m_pWriter);
  1017. bool bSucceeded;
  1018. try
  1019. {
  1020. bSucceeded = m_pWriter->OnIdentify
  1021. (
  1022. (IVssCreateWriterMetadata *) pcwm
  1023. );
  1024. }
  1025. catch(...)
  1026. {
  1027. ft.Trace(VSSDBG_WRITER, L"Writer's OnIdentify method threw and exception.");
  1028. throw;
  1029. }
  1030. if (!bSucceeded)
  1031. {
  1032. // indicate failure if writer fails OnIdentify
  1033. ft.Throw(VSSDBG_WRITER, S_FALSE, L"Writer's OnIdentify method returned false.");
  1034. }
  1035. CComBSTR bstrXML;
  1036. CComBSTR bstrInstanceId(m_InstanceID);
  1037. CComBSTR bstrWriterId(m_WriterID);
  1038. CComBSTR bstrWriterName(m_wszWriterName);
  1039. if (!bstrInstanceId ||
  1040. !bstrWriterId ||
  1041. !bstrWriterName)
  1042. ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Couldn't allocate memory for ids or name");
  1043. // save WRITER_METADATA document as XML string
  1044. ft.hr = pcwm->SaveAsXML(&bstrXML);
  1045. if (FAILED(ft.hr))
  1046. ft.Throw
  1047. (
  1048. VSSDBG_WRITER,
  1049. E_OUTOFMEMORY,
  1050. L"Cannot save XML document as string. hr = 0x%08lx",
  1051. ft.hr
  1052. );
  1053. // callback through ExposeWriterMetadata method
  1054. try
  1055. {
  1056. ft.hr = pCallback->ExposeWriterMetadata
  1057. (
  1058. bstrInstanceId,
  1059. bstrWriterId,
  1060. bstrWriterName,
  1061. bstrXML
  1062. );
  1063. }
  1064. catch(...)
  1065. {
  1066. ft.Trace(VSSDBG_WRITER, L"IVssWriterCallback::ExposeWriterMetadata threw an exception.");
  1067. throw;
  1068. }
  1069. // BUG 219757: The identify phase marked as succeeded.
  1070. m_bFailedAtIdentify = false;
  1071. }
  1072. else
  1073. {
  1074. // get writer state
  1075. CComBSTR bstrInstanceId(m_InstanceID);
  1076. if (!bstrInstanceId)
  1077. ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Couldn't allocate memory for ids or name");
  1078. CVssID id;
  1079. id.Initialize(ft, (LPCWSTR) bstrSnapshotSetId, E_INVALIDARG);
  1080. VSS_WRITER_STATE state;
  1081. HRESULT hrWriterFailure;
  1082. // BUG 219757 - deal with the Identify failures correctly.
  1083. if (m_bFailedAtIdentify)
  1084. {
  1085. state = VSS_WS_FAILED_AT_IDENTIFY;
  1086. hrWriterFailure = m_hrWriterFailure;
  1087. }
  1088. else
  1089. {
  1090. if (id == GUID_NULL ||
  1091. (m_bSequenceInProgress && id == m_CurrentSnapshotSetId))
  1092. {
  1093. state = m_state;
  1094. hrWriterFailure = m_hrWriterFailure;
  1095. }
  1096. else
  1097. {
  1098. // Search for the previous sequence with the same ID
  1099. INT nPreviousSequence = SearchForPreviousSequence(id);
  1100. if (nPreviousSequence == INVALID_SEQUENCE_INDEX)
  1101. {
  1102. state = VSS_WS_UNKNOWN;
  1103. hrWriterFailure = E_UNEXPECTED;
  1104. }
  1105. else
  1106. {
  1107. BS_ASSERT(m_rgidPreviousSnapshots[nPreviousSequence] == id);
  1108. state = m_rgstatePreviousSnapshots[nPreviousSequence];
  1109. hrWriterFailure = m_rghrWriterFailurePreviousSnapshots[nPreviousSequence];
  1110. }
  1111. }
  1112. }
  1113. // call Backup's ExposeCurrentState callback method
  1114. try
  1115. {
  1116. ft.hr = pCallback->ExposeCurrentState
  1117. (
  1118. bstrInstanceId,
  1119. state,
  1120. hrWriterFailure
  1121. );
  1122. }
  1123. catch(...)
  1124. {
  1125. ft.Trace(VSSDBG_WRITER, L"IVssWriterCallback::ExposeCurrentState threw an exception");
  1126. throw;
  1127. }
  1128. }
  1129. }
  1130. VSS_STANDARD_CATCH(ft)
  1131. delete pcwm;
  1132. // Bug 255996
  1133. return S_OK;
  1134. }
  1135. // process PrepareForBackup event
  1136. STDMETHODIMP CVssWriterImpl::PrepareForBackup
  1137. (
  1138. IN BSTR bstrSnapshotSetId,
  1139. IN IDispatch* pWriterCallback
  1140. )
  1141. {
  1142. CVssFunctionTracer ft( VSSDBG_WRITER, L"CVssWriterImpl::PrepareForBackup" );
  1143. try
  1144. {
  1145. ft.Trace(VSSDBG_WRITER, L"\nReceived Event: PrepareForBackup\nParameters:\n");
  1146. ft.Trace(VSSDBG_WRITER, L"\tSnapshotSetID = %s\n", (LPWSTR)bstrSnapshotSetId);
  1147. // access check
  1148. if (!IsBackupOperator())
  1149. {
  1150. m_hrWriterFailure = VSS_E_WRITERERROR_NONRETRYABLE;
  1151. ft.Throw(VSSDBG_WRITER, E_ACCESSDENIED, L"Backup Operator privileges are not set");
  1152. }
  1153. // enter PrepareForBackup state
  1154. if (!EnterState
  1155. (
  1156. s_rgWriterStates[s_ivwsmPrepareForBackup],
  1157. bstrSnapshotSetId
  1158. ))
  1159. {
  1160. m_hrWriterFailure = VSS_E_WRITERERROR_RETRYABLE;
  1161. ft.Throw
  1162. (
  1163. VSSDBG_WRITER,
  1164. E_UNEXPECTED,
  1165. L"Couldn't properly begin sequence"
  1166. );
  1167. }
  1168. AssertLocked();
  1169. // get IVssWriterCallback interface
  1170. CComPtr<IVssWriterCallback> pCallback;
  1171. GetCallback(pWriterCallback, &pCallback);
  1172. // get IVssWriterComponentsExt interface
  1173. CComPtr<IVssWriterComponentsInt> pComponents;
  1174. InternalGetWriterComponents(pCallback, &pComponents, true);
  1175. BS_ASSERT(m_pWriter);
  1176. // call writer's OnPrepareBackup method
  1177. bool bResult;
  1178. try
  1179. {
  1180. bResult = m_pWriter->OnPrepareBackup(pComponents);
  1181. BS_ASSERT(m_bOnAbortPermitted == false);
  1182. m_bOnAbortPermitted = true;
  1183. }
  1184. catch(...)
  1185. {
  1186. ft.Trace(VSSDBG_WRITER, L"Writer's OnPrepareBackup method threw an exception");
  1187. if (m_hrWriterFailure == S_OK)
  1188. m_hrWriterFailure = VSS_E_WRITERERROR_NONRETRYABLE;
  1189. throw;
  1190. }
  1191. if (!bResult)
  1192. ft.Throw( VSSDBG_WRITER, E_UNEXPECTED, L"Writer rejected the prepare");
  1193. // save changes to components if any
  1194. if (pComponents)
  1195. {
  1196. bool bChanged;
  1197. // determine if components are changed
  1198. ft.hr = pComponents->IsChanged(&bChanged);
  1199. BS_ASSERT(ft.hr == S_OK);
  1200. if (bChanged)
  1201. {
  1202. // get instance id
  1203. CComBSTR bstrWriterInstanceId(m_InstanceID);
  1204. if (!bstrWriterInstanceId)
  1205. ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Couldn't allocate instance id string");
  1206. // get WRITER_COMPONENTS XML document
  1207. CComBSTR bstrWriterComponentsDocument;
  1208. ft.hr = pComponents->SaveAsXML(&bstrWriterComponentsDocument);
  1209. if (ft.HrFailed())
  1210. {
  1211. m_hrWriterFailure = VSS_E_WRITERERROR_OUTOFRESOURCES;
  1212. ft.Throw
  1213. (
  1214. VSSDBG_WRITER,
  1215. E_OUTOFMEMORY,
  1216. L"Saving WRITER_COMPONENTS document as XML failed. hr = 0x%08lx",
  1217. ft.hr
  1218. );
  1219. }
  1220. // callback to set component in BACKUP_COMPONENTS document
  1221. try
  1222. {
  1223. ft.hr = pCallback->SetContent(bstrWriterInstanceId, bstrWriterComponentsDocument);
  1224. }
  1225. catch(...)
  1226. {
  1227. m_hrWriterFailure = VSS_E_WRITERERROR_RETRYABLE;
  1228. ft.Trace(VSSDBG_WRITER, L"IVssWriterCallback::SetContent threw an exception.");
  1229. throw;
  1230. }
  1231. if (ft.HrFailed())
  1232. {
  1233. m_hrWriterFailure = VSS_E_WRITERERROR_RETRYABLE;
  1234. ft.Throw
  1235. (
  1236. VSSDBG_WRITER,
  1237. ft.hr,
  1238. L"IVssWriterCallback::SetContent failed. hr = 0x%08lx",
  1239. ft.hr
  1240. );
  1241. }
  1242. }
  1243. }
  1244. }
  1245. VSS_STANDARD_CATCH(ft)
  1246. // leave PrepareBackup state
  1247. LeaveState(s_rgWriterStates[s_ivwsmPrepareForBackup], ft.HrSucceeded());
  1248. // Bug 255996
  1249. return S_OK;
  1250. }
  1251. // process PrepareForSnapshot event
  1252. STDMETHODIMP CVssWriterImpl::PrepareForSnapshot
  1253. (
  1254. IN BSTR bstrSnapshotSetId, // snapshot set id
  1255. IN BSTR bstrVolumeNamesList // list of volume names separated by ';'
  1256. )
  1257. {
  1258. CVssFunctionTracer ft( VSSDBG_WRITER, L"CVssWriterImpl::PrepareForSnapshot" );
  1259. try
  1260. {
  1261. ft.Trace(VSSDBG_WRITER, L"\nReceived Event: PrepareForSnapshot\nParameters:\n");
  1262. ft.Trace(VSSDBG_WRITER, L"\tSnapshotSetID = %s\n", (LPWSTR)bstrSnapshotSetId);
  1263. ft.Trace(VSSDBG_WRITER, L"\tVolumeNamesList = %s\n", (LPWSTR)bstrVolumeNamesList);
  1264. // should only be called by coordinator
  1265. // check for admin privileges
  1266. if (!IsAdministrator())
  1267. {
  1268. m_hrWriterFailure = VSS_E_WRITERERROR_NONRETRYABLE;
  1269. ft.Throw(VSSDBG_WRITER, E_ACCESSDENIED, L"ADMIN privileges are not set");
  1270. }
  1271. // enter PrepareForSnapshot state
  1272. if (!EnterState
  1273. (
  1274. s_rgWriterStates[s_ivwsmPrepareForSnapshot],
  1275. bstrSnapshotSetId
  1276. ))
  1277. {
  1278. m_hrWriterFailure = VSS_E_WRITERERROR_RETRYABLE;
  1279. ft.Throw
  1280. (
  1281. VSSDBG_WRITER,
  1282. E_UNEXPECTED,
  1283. L"improper state transition"
  1284. );
  1285. }
  1286. AssertLocked();
  1287. // Get the array of volume names
  1288. BS_ASSERT(m_pwszLocalVolumeNameList == NULL);
  1289. ::VssSafeDuplicateStr(ft, m_pwszLocalVolumeNameList, (LPWSTR)bstrVolumeNamesList);
  1290. // Get the number of volumes
  1291. BS_ASSERT(m_nVolumesCount == 0);
  1292. m_nVolumesCount = 0; // For safety
  1293. LPWSTR pwszVolumesToBeParsed = m_pwszLocalVolumeNameList;
  1294. // parse volume name string
  1295. while(true)
  1296. {
  1297. // get pointer to next volume
  1298. WCHAR* pwszNextVolume = ::wcstok(pwszVolumesToBeParsed, VSS_VOLUME_DELIMITERS);
  1299. pwszVolumesToBeParsed = NULL;
  1300. if (pwszNextVolume == NULL)
  1301. // no more volumes
  1302. break;
  1303. // skip if volume name is empty
  1304. if (pwszNextVolume[0] == L'\0')
  1305. continue;
  1306. // count of volumes
  1307. m_nVolumesCount++;
  1308. }
  1309. // make sure there is at least one volume
  1310. if (m_nVolumesCount == 0)
  1311. {
  1312. m_hrWriterFailure = VSS_E_WRITERERROR_RETRYABLE;
  1313. ft.LogError(VSS_ERROR_EMPTY_SNAPSHOT_SET, VSSDBG_WRITER);
  1314. ft.Throw
  1315. (
  1316. VSSDBG_WRITER,
  1317. E_UNEXPECTED,
  1318. L"No volumes in the snapshot set"
  1319. );
  1320. }
  1321. // Allocate the array of pointers to volume names
  1322. BS_ASSERT(m_nVolumesCount > 0);
  1323. BS_ASSERT(m_ppwszVolumesArray == NULL);
  1324. m_ppwszVolumesArray = new LPWSTR[m_nVolumesCount];
  1325. if (m_ppwszVolumesArray == NULL)
  1326. {
  1327. m_hrWriterFailure = VSS_E_WRITERERROR_OUTOFRESOURCES;
  1328. ft.Throw( VSSDBG_WRITER, E_OUTOFMEMORY, L"Memory allocation error");
  1329. }
  1330. //
  1331. // Copy the volume names into the array.
  1332. //
  1333. // re-copy the whole volume list
  1334. ::wcscpy(m_pwszLocalVolumeNameList, (LPWSTR)bstrVolumeNamesList);
  1335. // Fill the array by re-parsing the volume list.
  1336. INT nVolumesIndex = 0;
  1337. pwszVolumesToBeParsed = m_pwszLocalVolumeNameList;
  1338. while(true)
  1339. {
  1340. WCHAR* pwszNextVolume = ::wcstok(pwszVolumesToBeParsed, VSS_VOLUME_DELIMITERS);
  1341. pwszVolumesToBeParsed = NULL;
  1342. if (pwszNextVolume == NULL)
  1343. break;
  1344. if (pwszNextVolume[0] == L'\0')
  1345. continue;
  1346. BS_ASSERT(nVolumesIndex < m_nVolumesCount);
  1347. m_ppwszVolumesArray[nVolumesIndex] = pwszNextVolume;
  1348. nVolumesIndex++;
  1349. }
  1350. BS_ASSERT(nVolumesIndex == m_nVolumesCount);
  1351. // Call the writer's OnPrepareSnapshot method
  1352. BS_ASSERT(m_pWriter);
  1353. bool bResult;
  1354. try
  1355. {
  1356. bResult = m_pWriter->OnPrepareSnapshot();
  1357. m_bOnAbortPermitted = true;
  1358. }
  1359. catch(...)
  1360. {
  1361. if (m_hrWriterFailure == S_OK)
  1362. m_hrWriterFailure = VSS_E_WRITERERROR_NONRETRYABLE;
  1363. ft.Trace(VSSDBG_WRITER, L"Writer's OnPrepareSnapshot method threw an execption");
  1364. throw;
  1365. }
  1366. if (!bResult)
  1367. ft.Throw( VSSDBG_WRITER, E_UNEXPECTED, L"Writer rejected the prepare");
  1368. }
  1369. VSS_STANDARD_CATCH(ft)
  1370. // leave PrepareSnapshot state
  1371. LeaveState(s_rgWriterStates[s_ivwsmPrepareForSnapshot], ft.HrSucceeded());
  1372. // Bug 255996
  1373. return S_OK;
  1374. }
  1375. // process freeze event
  1376. STDMETHODIMP CVssWriterImpl::Freeze
  1377. (
  1378. IN BSTR bstrSnapshotSetId,
  1379. IN INT nLevel
  1380. )
  1381. {
  1382. CVssFunctionTracer ft( VSSDBG_WRITER, L"CVssWriterImpl::Freeze" );
  1383. try
  1384. {
  1385. ft.Trace( VSSDBG_WRITER, L"\nReceived Event: Freeze\nParameters:\n");
  1386. ft.Trace( VSSDBG_WRITER, L"\tSnapshotSetID = %s\n", (LPWSTR)bstrSnapshotSetId);
  1387. ft.Trace( VSSDBG_WRITER, L"\tLevel = %d\n", nLevel);
  1388. // should only be called by the coordinator, access check for admin privileges
  1389. if (!IsAdministrator())
  1390. ft.Throw(VSSDBG_WRITER, E_ACCESSDENIED, L"ADMIN privileges are not set");
  1391. // Ignore other Levels
  1392. if (m_nLevel != nLevel)
  1393. return S_OK;
  1394. // enter freeze state
  1395. if (!EnterState
  1396. (
  1397. s_rgWriterStates[s_ivwsmFreeze],
  1398. bstrSnapshotSetId
  1399. ))
  1400. {
  1401. m_hrWriterFailure = VSS_E_WRITERERROR_RETRYABLE;
  1402. ft.Throw
  1403. (
  1404. VSSDBG_WRITER,
  1405. E_UNEXPECTED,
  1406. L"Improper entry into state"
  1407. );
  1408. }
  1409. AssertLocked();
  1410. // Call writer's OnFreeze
  1411. BS_ASSERT(m_pWriter);
  1412. bool bResult;
  1413. try
  1414. {
  1415. bResult = m_pWriter->OnFreeze();
  1416. BS_ASSERT(m_bOnAbortPermitted == true);
  1417. }
  1418. catch(...)
  1419. {
  1420. if (m_hrWriterFailure == S_OK)
  1421. m_hrWriterFailure = VSS_E_WRITERERROR_NONRETRYABLE;
  1422. ft.Trace(VSSDBG_WRITER, L"Writer's OnFreeze Method threw and exception");
  1423. throw;
  1424. }
  1425. if (!bResult)
  1426. ft.Throw( VSSDBG_WRITER, E_UNEXPECTED, L"Writer rejected the freeze");
  1427. // setup arguments to timer thread
  1428. CVssTimerArgs *pArgs = new CVssTimerArgs(this, m_CurrentSnapshotSetId);
  1429. if (pArgs == NULL)
  1430. {
  1431. m_hrWriterFailure = VSS_E_WRITERERROR_OUTOFRESOURCES;
  1432. ft.Throw
  1433. (
  1434. VSSDBG_WRITER,
  1435. E_OUTOFMEMORY,
  1436. L"Cannot create timer args due to allocation failure"
  1437. );
  1438. }
  1439. DWORD tid;
  1440. // create timer thread
  1441. m_hThreadTimerThread =
  1442. CreateThread
  1443. (
  1444. NULL,
  1445. VSS_STACK_SIZE,
  1446. &CVssWriterImpl::StartTimerThread,
  1447. pArgs,
  1448. 0,
  1449. &tid
  1450. );
  1451. if (m_hThreadTimerThread == NULL)
  1452. {
  1453. m_hrWriterFailure = VSS_E_WRITERERROR_OUTOFRESOURCES;
  1454. delete pArgs;
  1455. ft.Throw
  1456. (
  1457. VSSDBG_WRITER,
  1458. E_OUTOFMEMORY,
  1459. L"Failure to create thread due to error %d.",
  1460. GetLastError()
  1461. );
  1462. }
  1463. }
  1464. VSS_STANDARD_CATCH(ft)
  1465. // leave OnFreeze state
  1466. LeaveState( s_rgWriterStates[s_ivwsmFreeze], ft.HrSucceeded());
  1467. // Bug 255996
  1468. return S_OK;
  1469. }
  1470. // handle IVssWriter::Thaw event
  1471. STDMETHODIMP CVssWriterImpl::Thaw
  1472. (
  1473. IN BSTR bstrSnapshotSetId
  1474. )
  1475. {
  1476. CVssFunctionTracer ft( VSSDBG_WRITER, L"CVssWriterImpl::Thaw" );
  1477. try
  1478. {
  1479. ft.Trace( VSSDBG_WRITER, L"\nReceived Event: Thaw\nParameters:\n");
  1480. ft.Trace( VSSDBG_WRITER, L"\tSnapshotSetID = %s\n", (LPWSTR)bstrSnapshotSetId);
  1481. // should only be called by coordinator. Access check for admin
  1482. if (!IsAdministrator())
  1483. {
  1484. m_hrWriterFailure = VSS_E_WRITERERROR_NONRETRYABLE;
  1485. ft.Throw(VSSDBG_WRITER, E_ACCESSDENIED, L"ADMIN privileges are not set");
  1486. }
  1487. // enter Thaw state
  1488. if (!EnterState
  1489. (
  1490. s_rgWriterStates[s_ivwsmThaw],
  1491. bstrSnapshotSetId
  1492. ))
  1493. {
  1494. m_hrWriterFailure = VSS_E_WRITERERROR_RETRYABLE;
  1495. ft.Throw
  1496. (
  1497. VSSDBG_WRITER,
  1498. E_UNEXPECTED,
  1499. L"Improper entry into state"
  1500. );
  1501. }
  1502. AssertLocked();
  1503. // We should "live" in a sequence since Thaw is not the first phase of the sequence.
  1504. BS_ASSERT(m_bSequenceInProgress);
  1505. // Call writer's OnThaw
  1506. BS_ASSERT(m_pWriter);
  1507. bool bResult;
  1508. try
  1509. {
  1510. bResult = m_pWriter->OnThaw();
  1511. }
  1512. catch(...)
  1513. {
  1514. if (m_hrWriterFailure == S_OK)
  1515. m_hrWriterFailure = VSS_E_WRITERERROR_NONRETRYABLE;
  1516. ft.Trace(VSSDBG_WRITER, L"Writer's OnThaw method threw an exception");
  1517. throw;
  1518. }
  1519. // throw veto if writer vetoes the event
  1520. if (!bResult)
  1521. ft.Throw( VSSDBG_WRITER, E_UNEXPECTED, L"Writer rejected the thaw");
  1522. }
  1523. VSS_STANDARD_CATCH(ft)
  1524. // leave OnThaw state
  1525. LeaveState(s_rgWriterStates[s_ivwsmThaw], ft.HrSucceeded());
  1526. // Bug 255996
  1527. return S_OK;
  1528. }
  1529. // process backup complete event
  1530. STDMETHODIMP CVssWriterImpl::BackupComplete
  1531. (
  1532. IN BSTR bstrSnapshotSetId,
  1533. IN IDispatch* pWriterCallback
  1534. )
  1535. {
  1536. CVssFunctionTracer ft( VSSDBG_WRITER, L"CVssWriterImpl::BackupComplete" );
  1537. // MTA synchronization: The critical section will be left automatically at the end of scope.
  1538. CVssWriterImplLock lock(this);
  1539. try
  1540. {
  1541. ft.Trace(VSSDBG_WRITER, L"\nReceived Event: OnBackupComplete\nParameters:\n");
  1542. ft.Trace(VSSDBG_WRITER, L"\tSnapshotSetID = %s\n", (LPWSTR)bstrSnapshotSetId);
  1543. // access check
  1544. if (!IsBackupOperator())
  1545. {
  1546. m_hrWriterFailure = VSS_E_WRITERERROR_NONRETRYABLE;
  1547. ft.Throw(VSSDBG_WRITER, E_ACCESSDENIED, L"Backup Operator privileges are not set");
  1548. }
  1549. BS_ASSERT(m_bSequenceInProgress == false);
  1550. BS_ASSERT(m_CurrentSnapshotSetId == GUID_NULL);
  1551. CVssID id;
  1552. id.Initialize(ft, (LPCWSTR) bstrSnapshotSetId, E_INVALIDARG);
  1553. // We must search for a previous state - Thaw already ended the sequence.
  1554. INT iPreviousSequence = SearchForPreviousSequence(id);
  1555. if (iPreviousSequence == INVALID_SEQUENCE_INDEX)
  1556. {
  1557. m_hrWriterFailure = VSS_E_WRITERERROR_RETRYABLE;
  1558. ft.Throw
  1559. (
  1560. VSSDBG_WRITER,
  1561. E_UNEXPECTED,
  1562. L"Couldn't find a previous sequence with the same Snapshot Set ID"
  1563. );
  1564. }
  1565. // We found a previous sequence with the same SSID.
  1566. BS_ASSERT(id == m_rgidPreviousSnapshots[iPreviousSequence]);
  1567. // BUG 228622 - If we do not have a previous successful Thaw transition
  1568. // then we cannot call BackupComplete
  1569. if (m_rgstatePreviousSnapshots[iPreviousSequence] != VSS_WS_WAITING_FOR_BACKUP_COMPLETE)
  1570. {
  1571. m_hrWriterFailure = VSS_E_WRITERERROR_RETRYABLE;
  1572. ft.Throw
  1573. (
  1574. VSSDBG_WRITER,
  1575. E_UNEXPECTED,
  1576. L"Couldn't call BackupComplete without OnThaw as a previous state [%d]",
  1577. m_rgstatePreviousSnapshots[iPreviousSequence]
  1578. );
  1579. }
  1580. // BUG 219692 - indicate that sequence is complete even in the saved states
  1581. m_rgstatePreviousSnapshots[iPreviousSequence] = VSS_WS_STABLE;
  1582. // get IVssWriterCallback interface
  1583. CComPtr<IVssWriterCallback> pCallback;
  1584. GetCallback(pWriterCallback, &pCallback);
  1585. // get IVssWriterComponentsInt object
  1586. CComPtr<IVssWriterComponentsInt> pComponents;
  1587. InternalGetWriterComponents(pCallback, &pComponents, false);
  1588. // call writer's OnBackupComplete method
  1589. BS_ASSERT(m_pWriter);
  1590. try
  1591. {
  1592. if (!m_pWriter->OnBackupComplete(pComponents))
  1593. ft.hr = S_FALSE;
  1594. }
  1595. catch(...)
  1596. {
  1597. if (m_hrWriterFailure == S_OK)
  1598. m_hrWriterFailure = VSS_E_WRITERERROR_NONRETRYABLE;
  1599. ft.Trace(VSSDBG_WRITER, L"Writer's OnBackupComplete method threw an exception.");
  1600. throw;
  1601. }
  1602. }
  1603. VSS_STANDARD_CATCH(ft)
  1604. // indicate that sequence is complete
  1605. if (m_state == VSS_WS_WAITING_FOR_BACKUP_COMPLETE)
  1606. m_state = VSS_WS_STABLE;
  1607. // Bug 255996
  1608. return S_OK;
  1609. }
  1610. STDMETHODIMP CVssWriterImpl::BackupShutdown
  1611. (
  1612. IN BSTR bstrSnapshotSetId
  1613. )
  1614. {
  1615. UNREFERENCED_PARAMETER(bstrSnapshotSetId);
  1616. CVssFunctionTracer ft( VSSDBG_WRITER, L"CVssWriterImpl::BackupShutdown");
  1617. ft.hr = E_NOTIMPL;
  1618. return ft.hr;
  1619. }
  1620. // handle IVssWriter::Abort event
  1621. STDMETHODIMP CVssWriterImpl::Abort
  1622. (
  1623. IN BSTR bstrSnapshotSetId
  1624. )
  1625. {
  1626. CVssFunctionTracer ft( VSSDBG_WRITER, L"CVssWriterImpl::Abort" );
  1627. ft.Trace( VSSDBG_WRITER, L"\nReceived Event: Abort\nParameters:\n");
  1628. ft.Trace( VSSDBG_WRITER, L"\tSnapshotSetID = %s\n", (LPWSTR)bstrSnapshotSetId);
  1629. if (!IsBackupOperator())
  1630. ft.Throw(VSSDBG_WRITER, E_ACCESSDENIED, L"Backup privileges are not set");
  1631. Lock();
  1632. // call do abort function
  1633. DoAbort(false);
  1634. Unlock();
  1635. return S_OK;
  1636. }
  1637. // process restore event
  1638. STDMETHODIMP CVssWriterImpl::PostRestore
  1639. (
  1640. IN IDispatch* pWriterCallback
  1641. )
  1642. {
  1643. CVssFunctionTracer ft( VSSDBG_WRITER, L"CVssWriterImpl::Restore" );
  1644. ft.Trace(VSSDBG_WRITER, L"\nReceived Event: Restore\n");
  1645. // MTA synchronization: The critical section will be left automatically at the end of scope.
  1646. CVssWriterImplLock lock(this);
  1647. m_hrWriterFailure = S_OK;
  1648. try
  1649. {
  1650. // access check
  1651. if (!IsRestoreOperator())
  1652. {
  1653. m_hrWriterFailure = VSS_E_WRITERERROR_NONRETRYABLE;
  1654. ft.Throw(VSSDBG_WRITER, E_ACCESSDENIED, L"Backup Operator privileges are not set");
  1655. }
  1656. // get writer callback interface
  1657. CComPtr<IVssWriterCallback> pCallback;
  1658. GetCallback(pWriterCallback, &pCallback);
  1659. CComPtr<IVssWriterComponentsInt> pComponents;
  1660. // get IVssWriterComponentsInt object
  1661. InternalGetWriterComponents(pCallback, &pComponents, false);
  1662. // call writer's OnPostRestore method
  1663. BS_ASSERT(m_pWriter);
  1664. try
  1665. {
  1666. if (!m_pWriter->OnPostRestore(pComponents))
  1667. ft.hr = S_FALSE;
  1668. }
  1669. catch(...)
  1670. {
  1671. if (m_hrWriterFailure == S_OK)
  1672. m_hrWriterFailure = VSS_E_WRITERERROR_NONRETRYABLE;
  1673. ft.Trace(VSSDBG_WRITER, L"Writer's OnPostRestore method threw an exception");
  1674. throw;
  1675. }
  1676. }
  1677. VSS_STANDARD_CATCH(ft)
  1678. // Bug 255996
  1679. return S_OK;
  1680. }
  1681. // process restore event
  1682. STDMETHODIMP CVssWriterImpl::PreRestore
  1683. (
  1684. IN IDispatch* pWriterCallback
  1685. )
  1686. {
  1687. UNREFERENCED_PARAMETER(pWriterCallback);
  1688. CVssFunctionTracer ft( VSSDBG_WRITER, L"CVssWriterImpl::PreRestore" );
  1689. BS_ASSERT(FALSE);
  1690. return S_OK;
  1691. }
  1692. // process restore event
  1693. STDMETHODIMP CVssWriterImpl::PostSnapshot
  1694. (
  1695. IN BSTR bstrSnapshotSetId,
  1696. IN IDispatch* pWriterCallback,
  1697. IN BSTR SnapshotDevicesList
  1698. )
  1699. {
  1700. UNREFERENCED_PARAMETER(pWriterCallback);
  1701. UNREFERENCED_PARAMETER(bstrSnapshotSetId);
  1702. UNREFERENCED_PARAMETER(SnapshotDevicesList);
  1703. CVssFunctionTracer ft( VSSDBG_WRITER, L"CVssWriterImpl::PostSnapshot" );
  1704. BS_ASSERT(FALSE);
  1705. return S_OK;
  1706. }
  1707. // table of names of events that we are subscribing to
  1708. // NOTE: this table is based on definition of VSS_EVENT_MASK. Each
  1709. // offset corresponds to a bit on that mask
  1710. const WCHAR *g_rgwszSubscriptions[] =
  1711. {
  1712. g_wszPrepareForBackupMethodName, // VSS_EVENT_PREPAREBackup
  1713. g_wszPrepareForSnapshotMethodName, // VSS_EVENT_PREPARESnapshot
  1714. g_wszFreezeMethodName, // VSS_EVENT_FREEZE
  1715. g_wszThawMethodName, // VSS_EVENT_THAW
  1716. g_wszAbortMethodName, // VSS_EVENT_ABORT
  1717. g_wszBackupCompleteMethodName, // VSS_EVENT_BACKUPCOMPLETE
  1718. g_wszRequestInfoMethodName, // VSS_EVENT_REQUESTINFO
  1719. g_wszPostRestoreMethodName // VSS_EVENT_POST_RESTORE
  1720. };
  1721. /////////////////////////////////////////////////////////////////////////////
  1722. // Subscription-related members
  1723. // create subscriptions
  1724. void CVssWriterImpl::Subscribe()
  1725. {
  1726. CVssFunctionTracer ft(VSSDBG_WRITER, L"CVssWriterImpl::Subscribe");
  1727. // validate that caller can subscribe to the event
  1728. if (!IsProcessBackupOperator() &&
  1729. !IsProcessLocalService() &&
  1730. !IsProcessNetworkService())
  1731. ft.Throw
  1732. (
  1733. VSSDBG_WRITER,
  1734. E_ACCESSDENIED,
  1735. L"Caller is not either a backup operator, administrator, local service, or network service"
  1736. );
  1737. // currently we subscribe to all events
  1738. m_dwEventMask = VSS_EVENT_ALL;
  1739. if (m_bstrSubscriptionName.Length() > 0)
  1740. ft.Throw
  1741. (
  1742. VSSDBG_XML,
  1743. VSS_E_WRITER_ALREADY_SUBSCRIBED,
  1744. L"The writer has already called the Subscribe function."
  1745. );
  1746. // create event system
  1747. CComPtr<IEventSystem> pSystem;
  1748. ft.hr = CoCreateInstance
  1749. (
  1750. CLSID_CEventSystem,
  1751. NULL,
  1752. CLSCTX_SERVER,
  1753. IID_IEventSystem,
  1754. (void **) &pSystem
  1755. );
  1756. ft.CheckForError(VSSDBG_WRITER, L"CoCreateInstance");
  1757. CComBSTR bstrClassId = CLSID_VssEvent;
  1758. CComBSTR bstrIID = IID_IVssWriter;
  1759. CComBSTR bstrProgId = PROGID_EventSubscription;
  1760. // see if event class already exists
  1761. CComBSTR bstrQuery = "EventClassID == ";
  1762. if (!bstrQuery)
  1763. ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Cannot allocate BSTR.");
  1764. bstrQuery.Append(bstrClassId);
  1765. if (!bstrQuery)
  1766. ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Cannot allocate BSTR.");
  1767. int location;
  1768. CComPtr<IEventObjectCollection> pCollection;
  1769. ft.hr = pSystem->Query
  1770. (
  1771. PROGID_EventClassCollection,
  1772. bstrQuery,
  1773. &location,
  1774. (IUnknown **) &pCollection
  1775. );
  1776. ft.CheckForError(VSSDBG_WRITER, L"IEventSystem::Query");
  1777. long cEvents;
  1778. ft.hr = pCollection->get_Count(&cEvents);
  1779. ft.CheckForError(VSSDBG_WRITER, L"IEventObjectCollection::get_Count");
  1780. if (cEvents == 0)
  1781. {
  1782. // event class does not exist, create it. Note that there is a
  1783. // potential race condition here if two writers try creating the event
  1784. // class at the same time. We create the event class during installation
  1785. // so that this should rarely happen
  1786. CComPtr<IEventClass> pEvent;
  1787. CComBSTR bstrEventClassName = L"VssEvent";
  1788. WCHAR buf[MAX_PATH*2];
  1789. // event class typelib
  1790. UINT cwc = ExpandEnvironmentStrings
  1791. (
  1792. L"%systemroot%\\system32\\eventcls.dll",
  1793. buf,
  1794. sizeof(buf)/sizeof(WCHAR)
  1795. );
  1796. if (cwc == 0)
  1797. {
  1798. ft.hr = HRESULT_FROM_WIN32(GetLastError());
  1799. ft.CheckForError(VSSDBG_WRITER, L"ExpandEnvironmentStrings");
  1800. }
  1801. CComBSTR bstrTypelib = buf;
  1802. // create event class
  1803. ft.hr = CoCreateInstance
  1804. (
  1805. CLSID_CEventClass,
  1806. NULL,
  1807. CLSCTX_SERVER,
  1808. IID_IEventClass,
  1809. (void **) &pEvent
  1810. );
  1811. ft.CheckForError(VSSDBG_WRITER, L"CoCreatInstance");
  1812. // setup class id
  1813. ft.hr = pEvent->put_EventClassID(bstrClassId);
  1814. ft.CheckForError(VSSDBG_WRITER, L"IEventClass::put_EventClassID");
  1815. // set up class name
  1816. ft.hr = pEvent->put_EventClassName(bstrEventClassName);
  1817. ft.CheckForError(VSSDBG_WRITER, L"IEventClass::put_EventClassName");
  1818. // set up typelib
  1819. ft.hr = pEvent->put_TypeLib(bstrTypelib);
  1820. ft.CheckForError(VSSDBG_WRITER, L"IEventClass::put_TypeLib");
  1821. // store event class
  1822. ft.hr = pSystem->Store(PROGID_EventClass, pEvent);
  1823. ft.CheckForError(VSSDBG_WRITER, L"IEventSystem::Store");
  1824. }
  1825. // create subscription id
  1826. VSS_ID SubscriptionId;
  1827. ft.hr = ::CoCreateGuid(&SubscriptionId);
  1828. ft.CheckForError(VSSDBG_WRITER, L"CoCreateGuid");
  1829. m_bstrSubscriptionName = SubscriptionId;
  1830. // get IUnknown for subscribers class
  1831. IUnknown *pUnkSubscriber = GetUnknown();
  1832. UINT iwsz, mask;
  1833. try
  1834. {
  1835. // loop through subscriptions
  1836. for(mask = 1, iwsz = 0; mask < VSS_EVENT_ALL; mask = mask << 1, iwsz++)
  1837. {
  1838. if (m_dwEventMask & mask && g_rgwszSubscriptions[iwsz] != NULL)
  1839. {
  1840. // create IEventSubscription object
  1841. CComPtr<IEventSubscription> pSubscription;
  1842. ft.hr = CoCreateInstance
  1843. (
  1844. CLSID_CEventSubscription,
  1845. NULL,
  1846. CLSCTX_SERVER,
  1847. IID_IEventSubscription,
  1848. (void **) &pSubscription
  1849. );
  1850. ft.CheckForError(VSSDBG_WRITER, L"CoCreateInstance");
  1851. // set subscription name
  1852. ft.hr = pSubscription->put_SubscriptionName(m_bstrSubscriptionName);
  1853. ft.CheckForError(VSSDBG_WRITER, L"IEventSubscription::put_SubscriptionName");
  1854. // set event class id
  1855. ft.hr = pSubscription->put_EventClassID(bstrClassId);
  1856. ft.CheckForError(VSSDBG_WRITER, L"IEventSubscription::put_EventClassID");
  1857. // set interface id
  1858. ft.hr = pSubscription->put_InterfaceID(bstrIID);
  1859. ft.CheckForError(VSSDBG_WRITER, L"IEventSubscription::put_InterfaceID");
  1860. // set subcriber interface
  1861. ft.hr = pSubscription->put_SubscriberInterface(pUnkSubscriber);
  1862. ft.CheckForError(VSSDBG_WRITER, L"IEventSubscription::put_SubscriberInterface");
  1863. // make subscription per user since this is not necessarily in local system
  1864. ft.hr = pSubscription->put_PerUser(TRUE);
  1865. ft.CheckForError(VSSDBG_WRITER, L"IEventSubscription::put_PerUser");
  1866. // set method name for subscrpition
  1867. ft.hr = pSubscription->put_MethodName(CComBSTR(g_rgwszSubscriptions[iwsz]));
  1868. ft.CheckForError(VSSDBG_WRITER, L"IEventSubscription::put_MethodName");
  1869. // store subscription
  1870. ft.hr = pSystem->Store(bstrProgId, pSubscription);
  1871. ft.CheckForError(VSSDBG_WRITER, L"IEventSystem::Store");
  1872. // get constructed subscription id and save it
  1873. ft.hr = pSubscription->get_SubscriptionID(&m_rgbstrSubscriptionId[m_cbstrSubscriptionId]);
  1874. ft.CheckForError(VSSDBG_WRITER, L"IEventSubscription::get_SubscriptionID");
  1875. // increment count of
  1876. m_cbstrSubscriptionId++;
  1877. }
  1878. }
  1879. }
  1880. VSS_STANDARD_CATCH(ft)
  1881. // if the operation fails with us partially subscribed, then unsubscribe
  1882. if (ft.HrFailed() && m_cbstrSubscriptionId)
  1883. {
  1884. Unsubscribe();
  1885. ft.Throw(VSSDBG_WRITER, ft.hr, L"Rethrowing exception");
  1886. }
  1887. }
  1888. // terminate timer thread
  1889. // assumes caller has the critical section locked
  1890. void CVssWriterImpl::TerminateTimerThread()
  1891. {
  1892. CVssFunctionTracer ft(VSSDBG_WRITER, L"CVssWriterImpl::TerminateTimerThread");
  1893. AssertLocked();
  1894. if (m_hThreadTimerThread)
  1895. {
  1896. // cause timer thread to terminate
  1897. m_command = VSS_TC_TERMINATE_THREAD;
  1898. if (!SetEvent(m_hevtTimerThread))
  1899. {
  1900. DWORD dwErr = GetLastError();
  1901. ft.Trace(VSSDBG_WRITER, L"SetEvent failed with error %d\n", dwErr);
  1902. BS_ASSERT(FALSE && "SetEvent failed");
  1903. }
  1904. // get thread handle
  1905. HANDLE hThread = m_hThreadTimerThread;
  1906. m_hThreadTimerThread = NULL;
  1907. // unlock during wait
  1908. Unlock();
  1909. if (WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED)
  1910. {
  1911. DWORD dwErr = GetLastError();
  1912. ft.Trace(VSSDBG_WRITER, L"WaitForSingleObject failed with error %d\n", dwErr);
  1913. BS_ASSERT(FALSE && "WaitForSingleObject failed");
  1914. }
  1915. CloseHandle(hThread);
  1916. Lock();
  1917. }
  1918. }
  1919. // unsubscribe this writer from IVssWriter events
  1920. void CVssWriterImpl::Unsubscribe()
  1921. {
  1922. CVssFunctionTracer ft(VSSDBG_WRITER, L"CVssWriterImpl::Unsubscribe");
  1923. // terminate timer thread if active
  1924. Lock();
  1925. TerminateTimerThread();
  1926. Unlock();
  1927. // make sure subscription name was assigned; if not assume subscriptions
  1928. // weren't created
  1929. if (m_bstrSubscriptionName.Length() == 0)
  1930. return;
  1931. // create event system
  1932. CComPtr<IEventSystem> pSystem;
  1933. ft.hr = CoCreateInstance
  1934. (
  1935. CLSID_CEventSystem,
  1936. NULL,
  1937. CLSCTX_SERVER,
  1938. IID_IEventSystem,
  1939. (void **) &pSystem
  1940. );
  1941. ft.CheckForError(VSSDBG_WRITER, L"CoCreateInstance");
  1942. #if 0
  1943. WCHAR buf[256];
  1944. int location;
  1945. swprintf(buf, L"SubscriptionName = \"%s\"", m_bstrSubscriptionName);
  1946. CComPtr<IEventObjectCollection> pCollection;
  1947. ft.hr = pSystem->Query
  1948. (
  1949. PROGID_EventSubscriptionCollection,
  1950. buf,
  1951. &location,
  1952. (IUnknown **) &pCollection
  1953. );
  1954. ft.CheckForError(VSSDBG_WRITER, L"IEventSystem::Query");
  1955. long cSub;
  1956. ft.hr = pCollection->get_Count(&cSub);
  1957. ft.CheckForError(VSSDBG_WRITER, L"IEventObjectCollection::get_Count");
  1958. pCollection = NULL;
  1959. #endif
  1960. for(UINT iSubscription = 0; iSubscription < m_cbstrSubscriptionId; iSubscription++)
  1961. {
  1962. // setup query string
  1963. CComBSTR bstrQuery = L"SubscriptionID == ";
  1964. if (!bstrQuery)
  1965. ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"allocation of BSTR failed");
  1966. // if subscription exists, then remove it
  1967. if (m_rgbstrSubscriptionId[iSubscription])
  1968. {
  1969. bstrQuery.Append(m_rgbstrSubscriptionId[iSubscription]);
  1970. if (!bstrQuery)
  1971. ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"allocation of BSTR failed");
  1972. int location;
  1973. // remove subscription
  1974. ft.hr = pSystem->Remove(PROGID_EventSubscription, bstrQuery, &location);
  1975. ft.CheckForError(VSSDBG_WRITER, L"IEventSystem::Remove");
  1976. // indicate that subscription was removed
  1977. m_rgbstrSubscriptionId[iSubscription].Empty();
  1978. }
  1979. }
  1980. #if 0
  1981. ft.hr = pSystem->Query
  1982. (
  1983. PROGID_EventSubscriptionCollection,
  1984. buf,
  1985. &location,
  1986. (IUnknown **) &pCollection
  1987. );
  1988. ft.CheckForError(VSSDBG_WRITER, L"IEventSystem::Query");
  1989. ft.hr = pCollection->get_Count(&cSub);
  1990. ft.CheckForError(VSSDBG_WRITER, L"IEventObjectCollection::get_Count");
  1991. pCollection = NULL;
  1992. #endif
  1993. // reset subscription name so unsubscribe does nothing if called again
  1994. m_bstrSubscriptionName.Empty();
  1995. m_cbstrSubscriptionId = 0;
  1996. }
  1997. // create a internal writer class and link it up to the external writer class
  1998. void CVssWriterImpl::CreateWriter
  1999. (
  2000. CVssWriter *pWriter, // external writer
  2001. IVssWriterImpl **ppImpl // interface to be used by external writer
  2002. )
  2003. {
  2004. CVssFunctionTracer ft(VSSDBG_WRITER, L"CVssWriterImpl::CreateWriter");
  2005. BS_ASSERT(ppImpl);
  2006. BS_ASSERT(pWriter);
  2007. *ppImpl = NULL;
  2008. // create internal wrier class
  2009. CComObject<CVssWriterImpl> *pImpl;
  2010. // create CVssWriterImpl object <core writer class>
  2011. ft.hr = CComObject<CVssWriterImpl>::CreateInstance(&pImpl);
  2012. if (ft.HrFailed())
  2013. ft.Throw
  2014. (
  2015. VSSDBG_WRITER,
  2016. E_OUTOFMEMORY,
  2017. L"Failed to create CVssWriterImpl. hr = 0x%08lx",
  2018. ft.hr
  2019. );
  2020. // set reference count of internal writer to 1
  2021. pImpl->GetUnknown()->AddRef();
  2022. // link external writer into internal writer
  2023. pImpl->SetWriter(pWriter);
  2024. // return internal writer interface
  2025. *ppImpl = (IVssWriterImpl *) pImpl;
  2026. }