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.

1334 lines
34 KiB

  1. /*++
  2. Copyright (c) 2002 Microsoft Corporation
  3. Module Name:
  4. backup.cpp
  5. Abstract:
  6. This module contains routines that handle the COM+ VSS writer object for
  7. backup and restore of the catalogs, the catalog databases, and for
  8. WFP-protected system files.
  9. Author:
  10. Patrick Masse (patmasse) 04-02-2002
  11. --*/
  12. #include <windows.h>
  13. #include <stdio.h>
  14. #include <dbgdef.h>
  15. #include <assert.h>
  16. #include <sfc.h>
  17. #include <vss.h>
  18. #include <vswriter.h>
  19. #include <vsbackup.h>
  20. #include "service.h"
  21. #include "errlog.h"
  22. #include "cryptmsg.h"
  23. //***************************************************************************************
  24. //
  25. // _CatDB prototypes
  26. //
  27. //***************************************************************************************
  28. LPWSTR
  29. _CatDBGetCatrootDirW(
  30. BOOL fCatroot2);
  31. LPWSTR
  32. _CatDBCreatePath(
  33. IN LPCWSTR pwsz1,
  34. IN LPCWSTR pwsz2);
  35. BOOL
  36. _CatDBFreeze();
  37. VOID
  38. _CatDBThaw();
  39. //***************************************************************************************
  40. //
  41. // CSystemWriter object declaration
  42. //
  43. //***************************************************************************************
  44. class CSystemWriter :
  45. public CVssWriter
  46. {
  47. private:
  48. static CSystemWriter *sm_pWriter;
  49. STDMETHODCALLTYPE CSystemWriter() {}
  50. public:
  51. virtual STDMETHODCALLTYPE ~CSystemWriter() {}
  52. // CSystemWriter object Startup and Shutdown functions
  53. static bool
  54. Startup();
  55. static void
  56. Shutdown();
  57. // CSystemWriter object exported VSS member functions
  58. virtual bool STDMETHODCALLTYPE
  59. OnIdentify(
  60. IN IVssCreateWriterMetadata *pMetadata);
  61. virtual bool STDMETHODCALLTYPE
  62. OnPrepareBackup(
  63. IN IVssWriterComponents *pWriterComponents);
  64. virtual bool STDMETHODCALLTYPE
  65. OnPrepareSnapshot();
  66. virtual bool STDMETHODCALLTYPE
  67. OnFreeze();
  68. virtual bool STDMETHODCALLTYPE
  69. OnThaw();
  70. virtual bool STDMETHODCALLTYPE
  71. OnAbort();
  72. private:
  73. // CSystemWriter object VSS helper functions
  74. bool
  75. AddCatalogFiles(
  76. IN IVssCreateWriterMetadata *pMetadata,
  77. IN bool fCatroot2);
  78. bool
  79. AddSystemFiles(
  80. IN IVssCreateWriterMetadata *pMetadata);
  81. // CSystemWriter object private initialization functions
  82. static BOOL
  83. IsSystemSetupInProgress();
  84. static BOOL
  85. WaitForServiceRunning(
  86. IN PWSTR wszServiceName);
  87. static DWORD WINAPI
  88. InitializeThreadFunc(
  89. IN PVOID pvResult);
  90. bool STDMETHODCALLTYPE
  91. Initialize();
  92. bool STDMETHODCALLTYPE
  93. Uninitialize();
  94. // Error handling functions
  95. static HRESULT
  96. SqlErrorToWriterError(
  97. IN HRESULT hSqlError);
  98. static HRESULT
  99. WinErrorToWriterError(
  100. IN DWORD dwWinError);
  101. static void
  102. LogSystemErrorEvent(
  103. IN DWORD dwMsgId,
  104. IN PWSTR pwszDetails,
  105. IN DWORD dwSysErrCode);
  106. };
  107. //***************************************************************************************
  108. //
  109. // Globals
  110. //
  111. //***************************************************************************************
  112. // The writer COM+ object guid
  113. CONST GUID g_guidWriterId =
  114. {
  115. 0xe8132975, 0x6f93, 0x4464, { 0xa5, 0x3e, 0x10, 0x50, 0x25, 0x3a, 0xe2, 0x20 }
  116. };
  117. // The writer display name
  118. LPCWSTR g_wszWriterName = L"System Writer";
  119. // The component name
  120. LPCWSTR g_wszComponentName = L"System Files";
  121. // Handle to the initialization thread
  122. HANDLE g_hInitializeThread = NULL;
  123. // Static class member variables
  124. CSystemWriter *CSystemWriter::sm_pWriter = NULL;
  125. // Global from catdbsvc.cpp
  126. extern BOOL g_fShuttingDown;
  127. //***************************************************************************************
  128. //
  129. // CSystemWriter object Startup and Shutdown functions
  130. //
  131. //***************************************************************************************
  132. //---------------------------------------------------------------------------------------
  133. //
  134. // CSystemWriter::Startup()
  135. //
  136. //---------------------------------------------------------------------------------------
  137. bool
  138. CSystemWriter::Startup()
  139. {
  140. bool fRet = true;
  141. DWORD dwThreadId;
  142. //
  143. // Writer object already created?
  144. //
  145. if (sm_pWriter != NULL)
  146. {
  147. goto CommonReturn;
  148. }
  149. //
  150. // Is a system setup currently in progress?
  151. // If so... don't initialize, but return ok.
  152. //
  153. // Notes: Added because any attempt to initialize VSS during GUI-mode setup
  154. // really screws things up.
  155. //
  156. if (IsSystemSetupInProgress())
  157. {
  158. goto CommonReturn;
  159. }
  160. //
  161. // Create the CSystemWriter object
  162. //
  163. sm_pWriter = new CSystemWriter;
  164. if (sm_pWriter == NULL)
  165. {
  166. LogSystemErrorEvent(MSG_SYSTEMWRITER_INIT_FAILURE, L"Allocation of CSystemWriter object failed.", ERROR_OUTOFMEMORY);
  167. goto ErrorReturn;
  168. }
  169. //
  170. // Spin up a thread to do the subscription in.
  171. //
  172. // Notes: We must use a thread to do this, since the rest of this service is
  173. // required early in the boot sequence, and this thread may take quite
  174. // a while to initialize, since it will wait for needed services before
  175. // attempting initialization.
  176. //
  177. g_hInitializeThread = ::CreateThread(
  178. NULL,
  179. 0,
  180. InitializeThreadFunc,
  181. NULL,
  182. 0,
  183. &dwThreadId);
  184. if (g_hInitializeThread == NULL)
  185. {
  186. LogSystemErrorEvent(MSG_SYSTEMWRITER_INIT_FAILURE, L"Creation of CSystemWriter initialization thread failed.", GetLastError());
  187. goto ErrorReturn;
  188. }
  189. CommonReturn:
  190. return fRet;
  191. ErrorReturn:
  192. fRet = false;
  193. if (sm_pWriter)
  194. {
  195. delete sm_pWriter;
  196. sm_pWriter = NULL;
  197. }
  198. goto CommonReturn;
  199. }
  200. //---------------------------------------------------------------------------------------
  201. //
  202. // CSystemWriter::Shutdown()
  203. //
  204. //---------------------------------------------------------------------------------------
  205. void
  206. CSystemWriter::Shutdown()
  207. {
  208. HANDLE hInitializeThread = InterlockedExchangePointer(&g_hInitializeThread, NULL);
  209. if (hInitializeThread != NULL)
  210. {
  211. WaitForSingleObject(hInitializeThread, INFINITE);
  212. CloseHandle(hInitializeThread);
  213. }
  214. if (sm_pWriter)
  215. {
  216. sm_pWriter->Uninitialize();
  217. delete sm_pWriter;
  218. sm_pWriter = NULL;
  219. }
  220. }
  221. //***************************************************************************************
  222. //
  223. // CSystemWriter object exported VSS member functions
  224. //
  225. //***************************************************************************************
  226. //---------------------------------------------------------------------------------------
  227. //
  228. // CSystemWriter::OnIdentify()
  229. //
  230. //---------------------------------------------------------------------------------------
  231. bool STDMETHODCALLTYPE
  232. CSystemWriter::OnIdentify(
  233. IN IVssCreateWriterMetadata *pMetadata)
  234. {
  235. bool fRet = true;
  236. HRESULT hResult;
  237. //
  238. // Set the restore method for the writer
  239. //
  240. hResult = pMetadata->SetRestoreMethod(
  241. VSS_RME_RESTORE_AT_REBOOT,
  242. NULL,
  243. NULL,
  244. VSS_WRE_NEVER,
  245. true);
  246. if (hResult != S_OK)
  247. {
  248. SetWriterFailure(SqlErrorToWriterError(hResult));
  249. goto ErrorReturn;
  250. }
  251. //
  252. // Add one file group component
  253. //
  254. hResult = pMetadata->AddComponent(
  255. VSS_CT_FILEGROUP,
  256. NULL,
  257. g_wszComponentName,
  258. g_wszComponentName,
  259. NULL,
  260. 0,
  261. false,
  262. false,
  263. false);
  264. if (hResult != S_OK)
  265. {
  266. SetWriterFailure(SqlErrorToWriterError(hResult));
  267. goto ErrorReturn;
  268. }
  269. //
  270. // Add catalog files group to component
  271. //
  272. if (!AddCatalogFiles(pMetadata,false))
  273. {
  274. // Writer failure already set by AddCatalogFiles function
  275. goto ErrorReturn;
  276. }
  277. //
  278. // Add catalog database files to component
  279. //
  280. if (!AddCatalogFiles(pMetadata,true))
  281. {
  282. // Writer failure already set by AddCatalogFiles function
  283. goto ErrorReturn;
  284. }
  285. //
  286. // Add system files group to component
  287. //
  288. if (!AddSystemFiles(pMetadata))
  289. {
  290. // Writer failure already set by AddSystemFiles function
  291. goto ErrorReturn;
  292. }
  293. CommonReturn:
  294. return fRet;
  295. ErrorReturn:
  296. fRet = false;
  297. goto CommonReturn;
  298. }
  299. //---------------------------------------------------------------------------------------
  300. //
  301. // CSystemWriter::OnPrepareBackup()
  302. //
  303. //---------------------------------------------------------------------------------------
  304. bool STDMETHODCALLTYPE
  305. CSystemWriter::OnPrepareBackup(
  306. IN IVssWriterComponents *pWriterComponents)
  307. {
  308. //
  309. // Nothing...
  310. //
  311. // Notes: But at a later time, we may want to make sure all of the files are
  312. // in the snapshot here.
  313. //
  314. return true;
  315. }
  316. //---------------------------------------------------------------------------------------
  317. //
  318. // CSystemWriter::OnPrepareSnapshot()
  319. //
  320. //---------------------------------------------------------------------------------------
  321. bool STDMETHODCALLTYPE
  322. CSystemWriter::OnPrepareSnapshot()
  323. {
  324. //
  325. // Nothing...
  326. //
  327. return true;
  328. }
  329. //---------------------------------------------------------------------------------------
  330. //
  331. // CSystemWriter::OnFreeze()
  332. //
  333. //---------------------------------------------------------------------------------------
  334. bool STDMETHODCALLTYPE
  335. CSystemWriter::OnFreeze()
  336. {
  337. if(!_CatDBFreeze())
  338. {
  339. //
  340. // The backup should not continue!
  341. //
  342. SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
  343. return false;
  344. }
  345. return true;
  346. }
  347. //---------------------------------------------------------------------------------------
  348. //
  349. // CSystemWriter::OnThaw()
  350. //
  351. //---------------------------------------------------------------------------------------
  352. bool STDMETHODCALLTYPE
  353. CSystemWriter::OnThaw()
  354. {
  355. _CatDBThaw();
  356. return true;
  357. }
  358. //---------------------------------------------------------------------------------------
  359. //
  360. // CSystemWriter::OnAbort()
  361. //
  362. //---------------------------------------------------------------------------------------
  363. bool STDMETHODCALLTYPE
  364. CSystemWriter::OnAbort()
  365. {
  366. _CatDBThaw();
  367. return true;
  368. }
  369. //***************************************************************************************
  370. //
  371. // CSystemWriter object VSS helper functions
  372. //
  373. //***************************************************************************************
  374. //---------------------------------------------------------------------------------------
  375. //
  376. // CSystemWriter::AddCatalogFiles()
  377. //
  378. //---------------------------------------------------------------------------------------
  379. bool
  380. CSystemWriter::AddCatalogFiles(
  381. IN IVssCreateWriterMetadata *pMetadata,
  382. IN bool fCatroot2)
  383. {
  384. bool fRet = true;
  385. LPWSTR pwszCatroot = NULL;
  386. LPWSTR pwszSearch = NULL;
  387. LPWSTR pwszPathName = NULL;
  388. HANDLE hFindHandle = INVALID_HANDLE_VALUE;
  389. WIN32_FIND_DATAW FindData;
  390. DWORD dwErr;
  391. HRESULT hResult;
  392. //
  393. // Get the directory where the catalog files live
  394. //
  395. pwszCatroot = _CatDBGetCatrootDirW(fCatroot2);
  396. if (pwszCatroot == NULL)
  397. {
  398. SetWriterFailure(WinErrorToWriterError(GetLastError()));
  399. goto ErrorReturn;
  400. }
  401. //
  402. // Build a search string for the catalog directories
  403. //
  404. pwszSearch = _CatDBCreatePath(pwszCatroot, L"{????????????????????????????????????}");
  405. if (pwszSearch == NULL)
  406. {
  407. SetWriterFailure(WinErrorToWriterError(GetLastError()));
  408. goto ErrorReturn;
  409. }
  410. //
  411. // Do the initial find
  412. //
  413. hFindHandle = FindFirstFileW(pwszSearch, &FindData);
  414. if (hFindHandle == INVALID_HANDLE_VALUE)
  415. {
  416. //
  417. // See if a real error occurred, or just no directories
  418. //
  419. dwErr = GetLastError();
  420. if ((dwErr == ERROR_NO_MORE_FILES) ||
  421. (dwErr == ERROR_PATH_NOT_FOUND) ||
  422. (dwErr == ERROR_FILE_NOT_FOUND))
  423. {
  424. //
  425. // There are no directories of this form
  426. //
  427. goto CommonReturn;
  428. }
  429. else
  430. {
  431. SetWriterFailure(WinErrorToWriterError(GetLastError()));
  432. goto ErrorReturn;
  433. }
  434. }
  435. while (TRUE)
  436. {
  437. //
  438. // Only care about directories
  439. //
  440. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  441. {
  442. pwszPathName = _CatDBCreatePath(pwszCatroot, FindData.cFileName);
  443. if (pwszPathName == NULL)
  444. {
  445. SetWriterFailure(WinErrorToWriterError(GetLastError()));
  446. goto ErrorReturn;
  447. }
  448. //
  449. // Add this catalog directory to component files group
  450. //
  451. hResult = pMetadata->AddFilesToFileGroup(
  452. NULL,
  453. g_wszComponentName,
  454. pwszPathName,
  455. L"*",
  456. true,
  457. NULL);
  458. free(pwszPathName);
  459. pwszPathName = NULL;
  460. if (hResult != S_OK)
  461. {
  462. SetWriterFailure(SqlErrorToWriterError(hResult));
  463. goto ErrorReturn;
  464. }
  465. }
  466. //
  467. // Get next file
  468. //
  469. if (!FindNextFileW(hFindHandle, &FindData))
  470. {
  471. //
  472. // Check to make sure the enumeration loop terminated normally
  473. //
  474. if (GetLastError() == ERROR_NO_MORE_FILES)
  475. {
  476. break;
  477. }
  478. else
  479. {
  480. SetWriterFailure(WinErrorToWriterError(GetLastError()));
  481. goto ErrorReturn;
  482. }
  483. }
  484. }
  485. CommonReturn:
  486. if (pwszCatroot != NULL)
  487. {
  488. free(pwszCatroot);
  489. }
  490. if (pwszSearch != NULL)
  491. {
  492. free(pwszSearch);
  493. }
  494. if (pwszPathName != NULL)
  495. {
  496. free(pwszPathName);
  497. }
  498. return (fRet);
  499. ErrorReturn:
  500. fRet = false;
  501. goto CommonReturn;
  502. }
  503. //---------------------------------------------------------------------------------------
  504. //
  505. // CSystemWriter::AddSystemFiles()
  506. //
  507. //---------------------------------------------------------------------------------------
  508. bool
  509. CSystemWriter::AddSystemFiles(
  510. IN IVssCreateWriterMetadata *pMetadata)
  511. {
  512. bool fRet = true;
  513. PROTECTED_FILE_DATA FileData;
  514. DWORD dwAttributes;
  515. PWSTR pwszPathName;
  516. PWSTR pwszFileSpec;
  517. bool bRecursive;
  518. HRESULT hResult;
  519. FileData.FileNumber = 0;
  520. //
  521. // Enumerate all of the files and directories protected by WFP
  522. //
  523. while (SfcGetNextProtectedFile(NULL, &FileData))
  524. {
  525. //
  526. // Make sure this file or directory is currently on this system
  527. //
  528. dwAttributes = GetFileAttributes(FileData.FileName);
  529. if (dwAttributes != INVALID_FILE_ATTRIBUTES)
  530. {
  531. //
  532. // Is this a directory?
  533. //
  534. if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
  535. {
  536. pwszPathName = FileData.FileName;
  537. pwszFileSpec = L"*";
  538. bRecursive = true;
  539. }
  540. else
  541. {
  542. //
  543. // Extract path and filename
  544. //
  545. if (pwszFileSpec = wcsrchr(FileData.FileName, L'\\'))
  546. {
  547. pwszPathName = FileData.FileName;
  548. *(pwszFileSpec++) = 0;
  549. }
  550. else
  551. {
  552. // Should never get here!
  553. assert(FALSE);
  554. }
  555. bRecursive = false;
  556. }
  557. //
  558. // Add this file or directory to component files group
  559. //
  560. hResult = pMetadata->AddFilesToFileGroup(
  561. NULL,
  562. g_wszComponentName,
  563. pwszPathName,
  564. pwszFileSpec,
  565. bRecursive,
  566. NULL);
  567. if (hResult != S_OK)
  568. {
  569. SetWriterFailure(SqlErrorToWriterError(hResult));
  570. goto ErrorReturn;
  571. }
  572. }
  573. }
  574. //
  575. // Check to make sure the enumeration loop terminated normally
  576. //
  577. if (GetLastError() != ERROR_NO_MORE_FILES)
  578. {
  579. SetWriterFailure(WinErrorToWriterError(GetLastError()));
  580. goto ErrorReturn;
  581. }
  582. //
  583. // Kludge to add the WinSxS directory for backup and restore, since
  584. // the SfcGetNextProtectedFile() API does not report files under this
  585. // directory.
  586. //
  587. WCHAR wszWindowsDir[MAX_PATH+1];
  588. //
  589. // Get Windows directory
  590. //
  591. if (!GetWindowsDirectory(wszWindowsDir, MAX_PATH+1))
  592. {
  593. SetWriterFailure(WinErrorToWriterError(GetLastError()));
  594. goto ErrorReturn;
  595. }
  596. //
  597. // Create %WINDIR%\WinSxs directory string
  598. //
  599. pwszPathName = _CatDBCreatePath(wszWindowsDir, L"WinSxS");
  600. if (pwszPathName == NULL)
  601. {
  602. SetWriterFailure(WinErrorToWriterError(GetLastError()));
  603. goto ErrorReturn;
  604. }
  605. //
  606. // Make sure the %WINDIR%\WinSxs directory exists
  607. // and that it is a directory
  608. //
  609. dwAttributes = GetFileAttributes(pwszPathName);
  610. if ((dwAttributes != INVALID_FILE_ATTRIBUTES) &&
  611. (dwAttributes & FILE_ATTRIBUTE_DIRECTORY))
  612. {
  613. //
  614. // Add this directory to component files group
  615. //
  616. hResult = pMetadata->AddFilesToFileGroup(
  617. NULL,
  618. g_wszComponentName,
  619. pwszPathName,
  620. L"*",
  621. true,
  622. NULL);
  623. free(pwszPathName);
  624. pwszPathName = NULL;
  625. if (hResult != S_OK)
  626. {
  627. SetWriterFailure(SqlErrorToWriterError(hResult));
  628. goto ErrorReturn;
  629. }
  630. }
  631. else
  632. {
  633. free(pwszPathName);
  634. pwszPathName = NULL;
  635. }
  636. //
  637. // End kludge
  638. //
  639. CommonReturn:
  640. return fRet;
  641. ErrorReturn:
  642. fRet = false;
  643. goto CommonReturn;
  644. }
  645. //***************************************************************************************
  646. //
  647. // CSystemWriter object private initialization functions
  648. //
  649. //***************************************************************************************
  650. //---------------------------------------------------------------------------------------
  651. //
  652. // CSystemWriter::IsSystemSetupInProgress()
  653. //
  654. // Queries the registry to determine if a system setup is in progress.
  655. //
  656. //---------------------------------------------------------------------------------------
  657. BOOL
  658. CSystemWriter::IsSystemSetupInProgress()
  659. {
  660. HKEY hKey;
  661. LONG lResult;
  662. DWORD dwSystemSetupInProgress = FALSE;
  663. DWORD dwSize = sizeof(dwSystemSetupInProgress);
  664. //
  665. // Open the System Setup key
  666. //
  667. lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"System\\Setup", 0, KEY_QUERY_VALUE, &hKey);
  668. if (lResult == ERROR_SUCCESS)
  669. {
  670. //
  671. // Query SystemSetupInProgress value (assume 0 if value doesn't exist)
  672. //
  673. RegQueryValueEx(hKey, L"SystemSetupInProgress", NULL, NULL, (LPBYTE)&dwSystemSetupInProgress, &dwSize);
  674. //
  675. // Close the System Setup key
  676. //
  677. RegCloseKey(hKey);
  678. }
  679. return (BOOL)dwSystemSetupInProgress;
  680. }
  681. //---------------------------------------------------------------------------------------
  682. //
  683. // CSystemWriter::WaitForServiceRunning()
  684. //
  685. // Blocks until the service specified by wszServiceName enters the SERVICE_RUNNING
  686. // state.
  687. //
  688. // Notes: Uses a QueryServiceStatusEx()/Sleep() loop bevause no sync-object
  689. // mechanism is currently available. Should be changed to use sync-object
  690. // mechanism when available.
  691. //
  692. // Returns: TRUE Service specified is in SERVICE_RUNNING state.
  693. // FALSE An error has occured preventing us from determining the
  694. // state of the service specified.
  695. //
  696. //---------------------------------------------------------------------------------------
  697. BOOL
  698. CSystemWriter::WaitForServiceRunning(
  699. IN PWSTR wszServiceName)
  700. {
  701. BOOL fRet = TRUE;
  702. SC_HANDLE hScm = NULL;
  703. SC_HANDLE hService = NULL;
  704. LPSERVICE_STATUS_PROCESS pInfo = NULL;
  705. DWORD cbInfo = 0;
  706. DWORD cbNeeded = 0;
  707. BOOL fReady = FALSE;
  708. DWORD dwError;
  709. //
  710. // Open the service control manager
  711. //
  712. hScm = OpenSCManager( NULL, NULL, SC_MANAGER_CONNECT|SC_MANAGER_ENUMERATE_SERVICE);
  713. if (!hScm)
  714. {
  715. LogSystemErrorEvent(MSG_SYSTEMWRITER_INIT_FAILURE, L"Could not open the Service Control Manager.", GetLastError());
  716. goto ErrorReturn;
  717. }
  718. //
  719. // Open the service
  720. //
  721. // Notes: This should fail only if the service is not installed.
  722. //
  723. hService = OpenService(hScm, wszServiceName, SERVICE_QUERY_STATUS);
  724. if (!hService)
  725. {
  726. LogSystemErrorEvent(MSG_SYSTEMWRITER_INIT_FAILURE, L"Could not open the EventSystem service for query.", GetLastError());
  727. goto ErrorReturn;
  728. }
  729. //
  730. // This query loop should only execute twixe. First to determine the size of the data, and second to
  731. // retrieve the data. Only if the data size changes in between the first and second loops, will the
  732. // loop execute a third time
  733. //
  734. while(!fReady)
  735. {
  736. if (QueryServiceStatusEx(
  737. hService,
  738. SC_STATUS_PROCESS_INFO,
  739. (LPBYTE)pInfo,
  740. cbInfo,
  741. &cbNeeded))
  742. {
  743. //
  744. // Check that the state of the service is SERVICE_RUNNING.
  745. //
  746. if (pInfo->dwCurrentState == SERVICE_RUNNING)
  747. {
  748. fReady = TRUE;
  749. }
  750. else
  751. {
  752. //
  753. // If not, sleep for awhile
  754. //
  755. Sleep(500);
  756. //
  757. // Check for service shutdown condition
  758. //
  759. if (g_fShuttingDown)
  760. {
  761. goto ErrorReturn;
  762. }
  763. }
  764. }
  765. else
  766. {
  767. if ((dwError = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
  768. {
  769. //
  770. // For all other errors
  771. //
  772. LogSystemErrorEvent(MSG_SYSTEMWRITER_INIT_FAILURE, L"Could not query the status of the EventSystem service.", dwError);
  773. goto ErrorReturn;
  774. }
  775. //
  776. // Just in case we already allocated a buffer on a previous loop
  777. //
  778. if (pInfo)
  779. {
  780. LocalFree((HLOCAL)pInfo);
  781. }
  782. //
  783. // Allocate buffer for the status data
  784. //
  785. pInfo = (LPSERVICE_STATUS_PROCESS) LocalAlloc(LMEM_FIXED, cbNeeded);
  786. if (!pInfo)
  787. {
  788. LogSystemErrorEvent(MSG_SYSTEMWRITER_INIT_FAILURE, L"Could not query the status of the EventSystem service.", GetLastError());
  789. goto ErrorReturn;
  790. }
  791. // Update parameters passed to QueryServiceStatusEx for next loop
  792. cbInfo = cbNeeded;
  793. cbNeeded = 0;
  794. }
  795. }
  796. CommonReturn:
  797. if (pInfo)
  798. {
  799. LocalFree((HLOCAL)pInfo);
  800. }
  801. if (hService)
  802. {
  803. CloseServiceHandle(hService);
  804. }
  805. if (hScm)
  806. {
  807. CloseServiceHandle(hScm);
  808. }
  809. return fRet;
  810. ErrorReturn:
  811. fRet = FALSE;
  812. goto CommonReturn;
  813. }
  814. //---------------------------------------------------------------------------------------
  815. //
  816. // CSystemWriter::InitializeThreadFunc()
  817. //
  818. // This thread initializes the VSS base class. If an error during initialization,
  819. // it is responsible for cleaning-up the object before exiting.
  820. //
  821. // Notes: Waits for the EventSystem, COM+, and VSS services to initialize before
  822. // intializing the VSS base class.
  823. //
  824. //---------------------------------------------------------------------------------------
  825. DWORD
  826. CSystemWriter::InitializeThreadFunc(
  827. IN PVOID pvDummy)
  828. {
  829. UNREFERENCED_PARAMETER(pvDummy);
  830. HRESULT hResult;
  831. bool fCoInitialized = false;
  832. bool fInitialized = false;
  833. //
  834. // Wait for EventSystem service to initialize here...
  835. //
  836. // Notes: The call to Initialize() below requires that the EventSystem be up
  837. // and running or it will hang. We can't add a service-level dependency
  838. // on the EventSystem service, because the EventSystem service fails
  839. // to initialize during GUI-mode system setup, and the rest of our
  840. // service must absolutely be available to the setup process.
  841. //
  842. if (!WaitForServiceRunning(L"EventSystem"))
  843. {
  844. //
  845. // We either couldn't determine the state of the EventSystem service or this
  846. // service is being shutdown, so we should just exit here and not initialize.
  847. //
  848. goto Done;
  849. }
  850. //
  851. // Intialize MTA thread
  852. //
  853. hResult = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
  854. if (hResult != S_OK)
  855. {
  856. LogSystemErrorEvent(MSG_SYSTEMWRITER_INIT_FAILURE, L"CoInitializeEx failed.", hResult);
  857. goto Done;
  858. }
  859. fCoInitialized = true;
  860. //
  861. // Note: CoInitializeSecurity() is called by the service host, so we don't have to do it here.
  862. //
  863. //
  864. // Initialize the base class and subscribe
  865. //
  866. // Notes: This call will wait for the COM+ and VSS services to initialize!
  867. //
  868. fInitialized = sm_pWriter->Initialize();
  869. Done:
  870. //
  871. // Detach this thread from COM+ now, since we're about to exit.
  872. //
  873. if (fCoInitialized)
  874. {
  875. CoUninitialize();
  876. }
  877. //
  878. // If something prevented us from initializing, cleanup the object
  879. //
  880. if (!fInitialized)
  881. {
  882. delete sm_pWriter;
  883. sm_pWriter = NULL;
  884. }
  885. //
  886. // NULL-out and close global handle to this thread.
  887. //
  888. HANDLE hInitializeThread = InterlockedExchangePointer(&g_hInitializeThread, NULL);
  889. if (hInitializeThread != NULL)
  890. {
  891. ::CloseHandle(hInitializeThread);
  892. }
  893. return 0;
  894. }
  895. //---------------------------------------------------------------------------------------
  896. //
  897. // CSystemWriter::Initialize()
  898. //
  899. // Initializes and subscribes to the VSS base class.
  900. //
  901. //---------------------------------------------------------------------------------------
  902. bool STDMETHODCALLTYPE
  903. CSystemWriter::Initialize()
  904. {
  905. bool fRet = true;
  906. HRESULT hResult;
  907. //
  908. // Initialize the VSS base class
  909. //
  910. hResult = CVssWriter::Initialize(
  911. g_guidWriterId,
  912. g_wszWriterName,
  913. VSS_UT_BOOTABLESYSTEMSTATE,
  914. VSS_ST_OTHER,
  915. VSS_APP_SYSTEM,
  916. 60000);
  917. if (hResult != S_OK)
  918. {
  919. LogSystemErrorEvent(MSG_SYSTEMWRITER_INIT_FAILURE, L"System Writer object failed to initialize VSS.", hResult);
  920. goto ErrorReturn;
  921. }
  922. //
  923. // Subscribe to the VSS base class
  924. //
  925. hResult = Subscribe();
  926. if (hResult != S_OK)
  927. {
  928. LogSystemErrorEvent(MSG_SYSTEMWRITER_INIT_FAILURE, L"System Writer object failed to subscribe to VSS.", hResult);
  929. goto ErrorReturn;
  930. }
  931. CommonReturn:
  932. return fRet;
  933. ErrorReturn:
  934. fRet = false;
  935. goto CommonReturn;
  936. }
  937. //---------------------------------------------------------------------------------------
  938. //
  939. // CSystemWriter::Uninitialize()
  940. //
  941. // Unsubscribes from the VSS base class.
  942. //
  943. //---------------------------------------------------------------------------------------
  944. bool STDMETHODCALLTYPE
  945. CSystemWriter::Uninitialize()
  946. {
  947. //
  948. // Unsubscribe from the VSS base class
  949. //
  950. return (Unsubscribe() == S_OK);
  951. }
  952. //***************************************************************************************
  953. //
  954. // Error handling helper functions
  955. //
  956. //***************************************************************************************
  957. //---------------------------------------------------------------------------------------
  958. //
  959. // CSystemWriter::SqlErrorToWriterError()
  960. //
  961. // Translate a SQL writer error code into a VSS writer error.
  962. //
  963. //---------------------------------------------------------------------------------------
  964. HRESULT
  965. CSystemWriter::SqlErrorToWriterError(
  966. IN HRESULT hSqlError)
  967. {
  968. switch(hSqlError)
  969. {
  970. case E_OUTOFMEMORY:
  971. case HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY):
  972. case HRESULT_FROM_WIN32(ERROR_DISK_FULL):
  973. case HRESULT_FROM_WIN32(ERROR_TOO_MANY_OPEN_FILES):
  974. case HRESULT_FROM_WIN32(ERROR_NO_MORE_USER_HANDLES):
  975. return VSS_E_WRITERERROR_OUTOFRESOURCES;
  976. }
  977. return VSS_E_WRITERERROR_NONRETRYABLE;
  978. }
  979. //---------------------------------------------------------------------------------------
  980. //
  981. // CSystemWriter::WinErrorToWriterError()
  982. //
  983. // Translate WinError to a writer error
  984. //
  985. //---------------------------------------------------------------------------------------
  986. HRESULT
  987. CSystemWriter::WinErrorToWriterError(
  988. IN DWORD dwWinError)
  989. {
  990. switch(dwWinError)
  991. {
  992. case ERROR_OUTOFMEMORY:
  993. case ERROR_NOT_ENOUGH_MEMORY:
  994. case ERROR_DISK_FULL:
  995. case ERROR_TOO_MANY_OPEN_FILES:
  996. case ERROR_NO_MORE_USER_HANDLES:
  997. return VSS_E_WRITERERROR_OUTOFRESOURCES;
  998. }
  999. return VSS_E_WRITERERROR_NONRETRYABLE;
  1000. }
  1001. //---------------------------------------------------------------------------------------
  1002. //
  1003. // CSystemWriter::LogSystemErrorEvent()
  1004. //
  1005. // Logs a SYSTEM error event based on the dwMsgId and additional optional info.
  1006. //
  1007. //---------------------------------------------------------------------------------------
  1008. void
  1009. CSystemWriter::LogSystemErrorEvent(
  1010. IN DWORD dwMsgId,
  1011. IN PWSTR pwszDetails,
  1012. IN DWORD dwSysErrCode)
  1013. {
  1014. HANDLE hEventLog = NULL;
  1015. LPWSTR wszDetailsHdr = L"\n\nDetails:\n";
  1016. LPWSTR wszErrorHdr = L"\n\nSystem Error:\n";
  1017. LPWSTR pwszError = NULL;
  1018. LPWSTR pwszExtra = NULL;
  1019. DWORD dwExtraLength = 0;
  1020. LPCWSTR rgpwszStrings[1] = {L""};
  1021. if (pwszDetails)
  1022. {
  1023. dwExtraLength += wcslen(wszDetailsHdr);
  1024. dwExtraLength += wcslen(pwszDetails);
  1025. }
  1026. if (dwSysErrCode)
  1027. {
  1028. dwExtraLength += wcslen(wszErrorHdr);
  1029. //
  1030. // Try to get error message from system
  1031. //
  1032. FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1033. FORMAT_MESSAGE_FROM_SYSTEM |
  1034. FORMAT_MESSAGE_IGNORE_INSERTS,
  1035. NULL,
  1036. dwSysErrCode,
  1037. 0,
  1038. (LPWSTR) &pwszError,
  1039. 0,
  1040. NULL);
  1041. //
  1042. // If we couldn't get an error message from the system, we'll just
  1043. // print out the error code.
  1044. //
  1045. if (!pwszError)
  1046. {
  1047. pwszError = (LPWSTR) LocalAlloc(LMEM_FIXED, 26*sizeof(WCHAR));
  1048. if (pwszError)
  1049. {
  1050. swprintf(pwszError, L"0x%08X (unresolvable)", dwSysErrCode);
  1051. }
  1052. }
  1053. if (pwszError)
  1054. {
  1055. dwExtraLength += wcslen(pwszError);
  1056. }
  1057. }
  1058. if (dwExtraLength)
  1059. {
  1060. //
  1061. // Allocate extra string
  1062. //
  1063. pwszExtra = (LPWSTR) LocalAlloc(LMEM_FIXED, (dwExtraLength+1)*sizeof(WCHAR));
  1064. if (pwszExtra)
  1065. {
  1066. pwszExtra[0] = 0;
  1067. if (pwszDetails)
  1068. {
  1069. wcscat(pwszExtra, wszDetailsHdr);
  1070. wcscat(pwszExtra, pwszDetails);
  1071. }
  1072. if (pwszError)
  1073. {
  1074. wcscat(pwszExtra, wszErrorHdr);
  1075. wcscat(pwszExtra, pwszError);
  1076. }
  1077. }
  1078. }
  1079. if (pwszExtra)
  1080. {
  1081. rgpwszStrings[0] = pwszExtra;
  1082. }
  1083. hEventLog = RegisterEventSourceW(NULL, SZSERVICENAME);
  1084. if (hEventLog != NULL)
  1085. {
  1086. ReportEventW(
  1087. hEventLog,
  1088. EVENTLOG_ERROR_TYPE,
  1089. 0,
  1090. dwMsgId,
  1091. NULL,
  1092. 1,
  1093. 0,
  1094. rgpwszStrings,
  1095. NULL);
  1096. DeregisterEventSource(hEventLog);
  1097. }
  1098. if (pwszError)
  1099. {
  1100. LocalFree((HLOCAL)pwszError);
  1101. }
  1102. if (pwszExtra)
  1103. {
  1104. LocalFree((HLOCAL)pwszExtra);
  1105. }
  1106. }
  1107. //***************************************************************************************
  1108. //
  1109. // Exported wrapper for CSystemWriter object Startup/Shutdown
  1110. //
  1111. //***************************************************************************************
  1112. //---------------------------------------------------------------------------------------
  1113. //
  1114. // _SystemWriterInit()
  1115. //
  1116. //---------------------------------------------------------------------------------------
  1117. VOID
  1118. _SystemWriterInit(
  1119. BOOL fUnInit)
  1120. {
  1121. if (!fUnInit)
  1122. {
  1123. CSystemWriter::Startup();
  1124. }
  1125. else
  1126. {
  1127. CSystemWriter::Shutdown();
  1128. }
  1129. }