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.

605 lines
22 KiB

  1. /*++
  2. Copyright (c) 2002 Microsoft Corporation
  3. Module Name:
  4. writer.h
  5. Abstract:
  6. Implementation file for FRS writer
  7. Author:
  8. Reuven Lax 17-Sep-2002
  9. --*/
  10. #include "writer.h"
  11. CFrsWriter* CFrsWriter::m_pWriterInstance = NULL;
  12. DWORD InitializeFrsWriter()
  13. /*++
  14. Routine Description:
  15. This routine is called by the FRS service to initialize the writer.
  16. Return Value:
  17. DWORD
  18. --*/
  19. {
  20. #undef DEBSUB
  21. #define DEBSUB "InitializeFrsWriter:"
  22. DPRINT(4, "Initializing the FRS Writer\n");
  23. // initialize COM
  24. HRESULT hr = S_OK;
  25. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  26. if (FAILED(hr)) {
  27. DPRINT1(1, "CoInitializeEx failed with hresult 0x%08lx\n", hr);
  28. return HRESULT_CODE(hr);
  29. }
  30. // create the writer
  31. hr = CFrsWriter::CreateWriter();
  32. if (FAILED(hr))
  33. DPRINT1(1, "CFrsWriter::CreateWriter failed with hresult 0x%08lx\n", hr);
  34. CoUninitialize();
  35. return HRESULT_CODE(hr);
  36. }
  37. void ShutDownFrsWriter()
  38. /*++
  39. Routine Description:
  40. This routine is called by the FRS service to shutdown the writer.
  41. --*/
  42. {
  43. #undef DEBSUB
  44. #define DEBSUB "ShutDownFrsWriter:"
  45. DPRINT(4, "Shutting down the FRS writer\n");
  46. HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  47. if (FAILED(hr))
  48. DPRINT1(1, "CoInitializeEx failed with hresult 0x%08lx\n", hr);
  49. CFrsWriter::DestroyWriter();
  50. if (SUCCEEDED(hr))
  51. CoUninitialize();
  52. }
  53. bool STDMETHODCALLTYPE CFrsWriter::OnIdentify(IN IVssCreateWriterMetadata *pMetadata)
  54. /*++
  55. Routine Description:
  56. This routine is called in response to an Identify event being sent to this writer. The writer
  57. is responsible for reporting on all of its metadata in this routine.
  58. Arguments:
  59. pMetadata - Interface used to report on metadata
  60. Return Value:
  61. boolean
  62. --*/
  63. {
  64. #undef DEBSUB
  65. #define DEBSUB "CFrsWriter::OnIdentify:"
  66. DPRINT(4, "Writer received OnIdentify event\n");
  67. HRESULT hr = S_OK;
  68. // set the restore method
  69. hr = pMetadata->SetRestoreMethod(VSS_RME_CUSTOM, // method
  70. NULL, // wszService
  71. NULL, // wszUserProcedure
  72. VSS_WRE_NEVER, // writerRestore
  73. false // bRebootRequired
  74. );
  75. if (FAILED(hr)) {
  76. DPRINT1(1, "IVssCreateWriterMetadata::SetRestoreMethod failed with hresult 0x%08lx\n", hr);
  77. return false;
  78. }
  79. // initialize FRS backup API
  80. DWORD winStatus = 0;
  81. void* context = NULL;
  82. winStatus = ::NtFrsApiInitializeBackupRestore(NULL,
  83. NTFRSAPI_BUR_FLAGS_BACKUP | NTFRSAPI_BUR_FLAGS_NORMAL,
  84. &context);
  85. if (!WIN_SUCCESS(winStatus)) {
  86. DPRINT1(1, "NtFrsApiInitializeBackupRestore failed with status 0x%08lx\n", winStatus);
  87. return false;
  88. }
  89. FRS_ASSERT(context != NULL);
  90. // stick the backup context into an auto object to ensure that it's always destroyed
  91. CAutoFrsBackupRestore autoContext(context);
  92. // get an enumeration for all the replica sets
  93. winStatus = ::NtFrsApiGetBackupRestoreSets(autoContext.m_context);
  94. if (!WIN_SUCCESS(winStatus)) {
  95. DPRINT1(1, "NtFrsApiGetBackupRestoreSets failed with status 0x%08lx\n", winStatus);
  96. return false;
  97. }
  98. // process each replica set
  99. DWORD index = 0;
  100. void* replicaSet = NULL;
  101. winStatus = ::NtFrsApiEnumBackupRestoreSets(autoContext.m_context, index, &replicaSet);
  102. while (WIN_SUCCESS(winStatus)) {
  103. FRS_ASSERT(replicaSet != NULL);
  104. // each replica set reports the same excludes. only add them once.
  105. CAutoFrsPointer<WCHAR> filters = NULL;
  106. if (!ProcessReplicaSet(autoContext.m_context, replicaSet, pMetadata, filters.GetAddress()))
  107. return false;
  108. if (filters != NULL && index == 0) {
  109. if (!AddExcludes(pMetadata, filters)) {
  110. DPRINT(1, "failed to add filtered exclude files\n");
  111. return false;
  112. }
  113. }
  114. ++index;
  115. winStatus = ::NtFrsApiEnumBackupRestoreSets(autoContext.m_context, index, &replicaSet);
  116. }
  117. if (winStatus != ERROR_NO_MORE_ITEMS) {
  118. DPRINT1(1, "NtFrsApiEnumBackupRestoreSets failed with status 0x%08lx\n", winStatus);
  119. return false;
  120. }
  121. return true;
  122. }
  123. bool CFrsWriter::AddExcludes(IVssCreateWriterMetadata* pMetadata, WCHAR* filters)
  124. /*++
  125. Routine Description:
  126. This is a helper routine used by ProcessReplicaSet to create the exclude-file list.
  127. Arguments:
  128. pMetadata - Interface used to report on metadata
  129. filters - list of exclude files
  130. Return Value:
  131. boolean
  132. --*/
  133. {
  134. #undef DEBSUB
  135. #define DEBSUB "CFrsWriter::AddExcludes:"
  136. WCHAR* currentFilter = filters;
  137. // for each filtered filespec, add an exclude specification to the writer metadata
  138. while (*currentFilter) {
  139. WCHAR* path = NULL;
  140. WCHAR* filespec = NULL;
  141. bool recursive = false;
  142. size_t excludeLength = wcslen(currentFilter); // --- grab size before we modify the string
  143. if (!ParseExclude(currentFilter, &path, &filespec, &recursive)) {
  144. DPRINT(1, "filtered exclude file has an incorrect format\n");
  145. return false;
  146. }
  147. HRESULT hr = pMetadata->AddExcludeFiles(path, filespec, recursive);
  148. if (FAILED(hr)) {
  149. DPRINT1(1, "IVssBackupComponents::AddExcludeFiles failed with hresult 0x%08lx\n", hr);
  150. return false;
  151. }
  152. currentFilter += excludeLength + 1;
  153. }
  154. return true;
  155. }
  156. bool CFrsWriter::ParseExclude(WCHAR* exclude, WCHAR** path, WCHAR** filespec, bool* recursive)
  157. /*++
  158. Routine Description:
  159. This is a helper routine used to parse an exclude specification.
  160. Arguments:
  161. exclude - the specification for the exclude file
  162. path -OUT the root path of the exclude file
  163. filespec - OUT the exclude filespec
  164. recursive - OUT whether this is a recursive specification or not
  165. Return Value:
  166. boolean
  167. --*/
  168. {
  169. #undef DEBSUB
  170. #define DEBSUB "CFrsWriter::ParseExclude:"
  171. const WCHAR* RecursionSpec = L" /s";
  172. const WCHAR DirSeperator = L'\\';
  173. //verify parameters
  174. FRS_ASSERT(exclude && path && filespec && recursive);
  175. *path = *filespec = NULL;
  176. *recursive = false;
  177. // find the last wack in the path
  178. WCHAR* loc = wcsrchr(exclude, DirSeperator);
  179. if (loc == NULL)
  180. return false;
  181. // setup the return values
  182. *loc = L'\0';
  183. *path = exclude;
  184. *filespec = loc + 1;
  185. // check to see if this is a recursive specification
  186. loc = wcsstr(*filespec, RecursionSpec);
  187. if (loc != NULL) {
  188. *loc = L'\0';
  189. *recursive = true;
  190. }
  191. return (wcslen(*path) > 0) && (wcslen(*filespec) > 0);
  192. }
  193. bool CFrsWriter::ProcessReplicaSet(void* context, void* replicaSet, IVssCreateWriterMetadata* pMetadata, WCHAR** retFilters)
  194. /*++
  195. Routine Description:
  196. This is a helper routine used by OnIdentify to create the writer metadata.
  197. Arguments:
  198. context - The context that identifies us to FRS.
  199. replicaSet - The indentifier for the current replica set
  200. pMetadata - Interface used to report on metadata
  201. filters - return the list of filtered files
  202. Return Value:
  203. boolean
  204. --*/
  205. {
  206. #undef DEBSUB
  207. #define DEBSUB "CFrsWriter::ProcessReplicaSet:"
  208. FRS_ASSERT(retFilters);
  209. *retFilters = NULL;
  210. // constants that determine component names
  211. const WCHAR* SysvolLogicalPath = L"SYSVOL";
  212. DWORD winStatus = 0;
  213. // all of these need to be defined here, since otherwise destructors don't get called when
  214. // and SEH exception is thrown
  215. CAutoFrsPointer<WCHAR> setType;
  216. DWORD typeSize = 0;
  217. CAutoFrsPointer<WCHAR> setGuid;
  218. DWORD guidSize = 0;
  219. CAutoFrsPointer<WCHAR> directory;
  220. DWORD dirSize = 0;
  221. CAutoFrsPointer<WCHAR> paths;
  222. DWORD pathSize = 0;
  223. CAutoFrsPointer<WCHAR> filters;
  224. DWORD filterSize = 0;
  225. __try {
  226. // figure out what type of replica set this is
  227. winStatus = ::NtFrsApiGetBackupRestoreSetType(context, replicaSet, NULL, &typeSize);
  228. FRS_ASSERT(winStatus == ERROR_MORE_DATA);
  229. setType = (WCHAR*)::FrsAlloc(typeSize);
  230. winStatus = ::NtFrsApiGetBackupRestoreSetType(context, replicaSet, setType, &typeSize);
  231. if (!WIN_SUCCESS(winStatus)) {
  232. DPRINT1(1, "NtFrsApiGetBackupRestoreSetType failed with status 0x%08lx\n", winStatus);
  233. return false;
  234. }
  235. // figure out what the name of this replica set is
  236. winStatus = ::NtFrsApiGetBackupRestoreSetGuid(context, replicaSet, NULL, &guidSize);
  237. FRS_ASSERT(winStatus == ERROR_MORE_DATA);
  238. setGuid = (WCHAR*)::FrsAlloc(guidSize);
  239. winStatus = ::NtFrsApiGetBackupRestoreSetGuid(context, replicaSet, setGuid, &guidSize);
  240. if (!WIN_SUCCESS(winStatus)) {
  241. DPRINT1(1, "NtFrsApiGetBackupRestoreSetGuid failed with status 0x%08lx\n", winStatus);
  242. return false;
  243. }
  244. const WCHAR* logicalPath = NULL;
  245. HRESULT hr = S_OK;
  246. if (wcscmp(setType, NTFRSAPI_REPLICA_SET_TYPE_ENTERPRISE) == 0 ||
  247. wcscmp(setType, NTFRSAPI_REPLICA_SET_TYPE_DOMAIN) == 0) {
  248. // if this is a SYSVOL replica set, add a component with the SYSVOL logical path
  249. logicalPath = SysvolLogicalPath;
  250. hr = pMetadata->AddComponent(VSS_CT_FILEGROUP, // type
  251. logicalPath, // wszLogicalPath
  252. setGuid, // wszComponentName
  253. NULL, // wszCaption
  254. NULL, // pbIcon
  255. 0, // cbIcon
  256. false, // bRestoreMetadata
  257. true, // bNotifyOnBackupComplete
  258. true, // bSelectable
  259. true // bSelectableForRestore
  260. );
  261. if (FAILED(hr)) {
  262. DPRINT1(1, "IVssCreateWriterMetadata::AddComponent failed with hresult 0x%08lx\n", hr);
  263. return false;
  264. }
  265. } else {
  266. // otherwise, add a component a component with the generic logical path
  267. logicalPath = setType;
  268. hr = pMetadata->AddComponent(VSS_CT_FILEGROUP, // type
  269. logicalPath, // wszLogicalPath
  270. setGuid, // wszComponentName
  271. NULL, // wszCaption
  272. NULL, // pbIcon
  273. 0, // cbIcon
  274. false, // bRestoreMetadata
  275. true, // bNotifyOnBackupComplete
  276. true, // bSelectable
  277. true // bSelectableForRestore
  278. );
  279. if (FAILED(hr)) {
  280. DPRINT1(1, "IVssCreateWriterMetadata::AddComponent failed with hresult 0x%08lx\n", hr);
  281. return false;
  282. }
  283. // add the root replication directory to the filegroup. This isn't necessary for SYSVOL since
  284. // that will be included in the call to NtFrsApiGetBackupRestoreSetPaths.
  285. winStatus = ::NtFrsApiGetBackupRestoreSetDirectory(context, replicaSet, &dirSize, NULL);
  286. FRS_ASSERT(winStatus == ERROR_INSUFFICIENT_BUFFER);
  287. directory = (WCHAR*)::FrsAlloc(dirSize);
  288. // I assume that the directory cannot change in this short windows. If so, we must loop.
  289. winStatus = ::NtFrsApiGetBackupRestoreSetDirectory(context, replicaSet, &dirSize, directory);
  290. if (!WIN_SUCCESS(winStatus)) {
  291. DPRINT1(1, "NtFrsApiGetBackupRestoreSetDirectory failed with status 0x%08lx\n", winStatus);
  292. return false;
  293. }
  294. hr = pMetadata->AddFilesToFileGroup(logicalPath, // wszLogicalPath
  295. setGuid, // wszGroupName
  296. directory, // wszPath
  297. L"*", // wszFilespec
  298. true, // bRecursive
  299. NULL // wszAlternateLocation
  300. );
  301. if (FAILED(hr)) {
  302. DPRINT1(1, "IVssCreateWriterMetadata::AddFilesToFileGroup failed with hresult 0x%08lx\n", hr);
  303. return false;
  304. }
  305. }
  306. winStatus = ::NtFrsApiGetBackupRestoreSetPaths(context,
  307. replicaSet,
  308. &pathSize,
  309. NULL,
  310. &filterSize,
  311. NULL
  312. );
  313. FRS_ASSERT(winStatus == ERROR_INSUFFICIENT_BUFFER);
  314. paths = (WCHAR*)::FrsAlloc(pathSize);
  315. filters = (WCHAR*)::FrsAlloc(filterSize);
  316. // once again, I assume that the sizes won't change in this window
  317. winStatus = ::NtFrsApiGetBackupRestoreSetPaths(context,
  318. replicaSet,
  319. &pathSize,
  320. paths,
  321. &filterSize,
  322. filters
  323. );
  324. if (!WIN_SUCCESS(winStatus)) {
  325. DPRINT1(1, "NtFrsApiGetBackupRestoreSetPaths failed with status 0x%08lx\n", winStatus);
  326. return false;
  327. }
  328. // add all of the paths to the group
  329. WCHAR* currentPath = paths;
  330. while (*currentPath) {
  331. hr = pMetadata->AddFilesToFileGroup(logicalPath, // wszLogicalPath
  332. setGuid, // wszGroupName
  333. currentPath, // wszPath
  334. L"*", // wszFilespec
  335. true, // bRecursive
  336. NULL // wszAlternateLocation
  337. );
  338. if (FAILED(hr)) {
  339. DPRINT1(1, "IVssCreateWriterMetadata::AddFilesToFileGroup failed with hresult 0x%08lx\n", hr);
  340. return false;
  341. }
  342. currentPath += wcslen(currentPath) + 1;
  343. }
  344. *retFilters = filters.Detach();
  345. return true;
  346. } __except(GetExceptionCode() == ERROR_OUTOFMEMORY) {
  347. DPRINT(1, "Out of memory\n");
  348. return false;
  349. }
  350. }
  351. bool STDMETHODCALLTYPE CFrsWriter::OnPrepareSnapshot()
  352. /*++
  353. Routine Description:
  354. This routine is called in response to an Identify event being sent to this writer. The writer
  355. will freeze FRS in this event.
  356. Arguments:
  357. Return Value:
  358. boolean
  359. --*/
  360. {
  361. #undef DEBSUB
  362. #define DEBSUB "CFrsWriter::OnPrepareSnapshot:"
  363. DPRINT(4, "Received OnPrepareSnapshot event\n");
  364. DWORD winStatus = ::FrsFreezeForBackup();
  365. if (!WIN_SUCCESS(winStatus)) {
  366. DPRINT1(1, "FrsFreezeForBackup failed with status 0x%08lx\n", winStatus);
  367. CVssWriter::SetWriterFailure(VSS_E_WRITERERROR_RETRYABLE);
  368. return false;
  369. }
  370. return true;
  371. }
  372. bool STDMETHODCALLTYPE CFrsWriter::OnFreeze()
  373. {
  374. #undef DEBSUB
  375. #define DEBSUB "CFrsWriter::OnFreeze:"
  376. DPRINT(4, "Received OnFreeze event\n");
  377. return true;
  378. }
  379. bool STDMETHODCALLTYPE CFrsWriter::OnThaw()
  380. /*++
  381. Routine Description:
  382. This routine is called in response to a Thaw event being sent to this writer. The writer
  383. will thaw FRS in this event.
  384. Arguments:
  385. Return Value:
  386. boolean
  387. --*/
  388. {
  389. #undef DEBSUB
  390. #define DEBSUB "CFrsWriter::OnThaw:"
  391. DPRINT(4, "Received OnThaw event\n");
  392. DWORD winStatus = ::FrsThawAfterBackup();
  393. if (!WIN_SUCCESS(winStatus)) {
  394. DPRINT1(1, "FrsThawAfterBackup failed with status 0x%08lx\n", winStatus);
  395. CVssWriter::SetWriterFailure(VSS_E_WRITERERROR_RETRYABLE);
  396. return false;
  397. }
  398. return true;
  399. }
  400. bool STDMETHODCALLTYPE CFrsWriter::OnAbort()
  401. /*++
  402. Routine Description:
  403. This routine is called in response to an Abort event being sent to this writer. The writer
  404. will thaw FRS in this event.
  405. Arguments:
  406. Return Value:
  407. boolean
  408. --*/
  409. {
  410. #undef DEBSUB
  411. #define DEBSUB "CFrsWriter::OnAbort:"
  412. DPRINT(4, "Received OnAbort event\n");
  413. DWORD winStatus = ::FrsThawAfterBackup();
  414. if (!WIN_SUCCESS(winStatus)) {
  415. DPRINT1(1, "FrsThawAfterBackup failed with status 0x%08lx\n", winStatus);
  416. return false;
  417. }
  418. return true;
  419. }
  420. HRESULT CFrsWriter::CreateWriter()
  421. /*++
  422. Routine Description:
  423. This routine is called to create and initialize the FRS writer. It must be called from
  424. a thread that has COM initialized with multi-threaded apartments.
  425. Arguments:
  426. Return Value:
  427. HRESULT
  428. --*/
  429. {
  430. #undef DEBSUB
  431. #define DEBSUB "CFrsWriter::CreateWriter:"
  432. // initialization is idempotent
  433. if (m_pWriterInstance != NULL)
  434. return S_OK;
  435. // try and create the writer
  436. m_pWriterInstance = new CFrsWriter();
  437. if (m_pWriterInstance == NULL)
  438. return E_OUTOFMEMORY;
  439. // try and initialize the writer
  440. HRESULT hr = S_OK;
  441. hr = m_pWriterInstance->Initialize();
  442. if (FAILED(hr)) {
  443. delete m_pWriterInstance;
  444. m_pWriterInstance = NULL;
  445. }
  446. return hr;
  447. }
  448. void CFrsWriter::DestroyWriter()
  449. /*++
  450. Routine Description:
  451. This routine is called to destroy the FRS writer.
  452. Arguments:
  453. Return Value:
  454. HRESULT
  455. --*/
  456. {
  457. #undef DEBSUB
  458. #define DEBSUB "CFrsWriter::DestroyWriter:"
  459. delete m_pWriterInstance;
  460. m_pWriterInstance = NULL;
  461. }
  462. HRESULT STDMETHODCALLTYPE CFrsWriter::Initialize()
  463. {
  464. #undef DEBSUB
  465. #define DEBSUB "CFrsWriter::Initialize:"
  466. HRESULT hr = S_OK;
  467. hr = CVssWriter::Initialize(WriterId, // WriterID
  468. WriterName, // wszWriterName
  469. VSS_UT_BOOTABLESYSTEMSTATE, // usage type
  470. VSS_ST_OTHER, // source type
  471. VSS_APP_SYSTEM // nLevel
  472. );
  473. if (FAILED(hr)) {
  474. DPRINT1(1, "CVssWriter::Initialize failed with hresult 0x%08lx\n", hr);
  475. return hr;
  476. }
  477. hr = CVssWriter::Subscribe();
  478. if (FAILED(hr))
  479. DPRINT1(1, "CVssWriter::Subscribe failed with hresult 0x%08lx\n", hr);
  480. return hr;
  481. }
  482. void CFrsWriter::Uninitialize()
  483. {
  484. #undef DEBSUB
  485. #define DEBSUB "CFrsWriter::Uninitialize:"
  486. HRESULT hr = CVssWriter::Unsubscribe();
  487. if (FAILED(hr))
  488. DPRINT1(1, "CVssWriter::Unsubscribe failed with hresult 0x%08lx\n", hr);
  489. }