Source code of Windows XP (NT5)
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.

888 lines
24 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. critdrv.cpp
  5. Abstract:
  6. This module contains routines create a list of the critical volumes on a
  7. system. This is lifted directly from base\fs\utils\ntback50\ui.
  8. Author:
  9. Brian Berkowitz (brianb) 10-Mar-2000
  10. Environment:
  11. User-mode only.
  12. Revision History:
  13. 10-Mar-2000 brianb
  14. Initial creation
  15. --*/
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <objbase.h>
  23. #include <initguid.h>
  24. #include <frsapip.h>
  25. #include <critdrv.h>
  26. // FRS iteration class. Used to iterate through replica sets to
  27. // determine the paths for these replica sets
  28. // constructor
  29. CFRSIter::CFRSIter() :
  30. m_fInitialized(FALSE),
  31. m_hLib(NULL),
  32. m_pfnFrsInitBuRest(NULL),
  33. m_pfnFrsEndBuRest(NULL),
  34. m_pfnFrsGetSets(NULL),
  35. m_pfnFrsEnumSets(NULL),
  36. m_pfnFrsIsSetSysVol(NULL),
  37. m_pfnFrsGetPath(NULL),
  38. m_pfnFrsGetOtherPaths(NULL),
  39. m_stateIteration(x_IterNotStarted)
  40. {
  41. }
  42. // destructor
  43. CFRSIter::~CFRSIter()
  44. {
  45. if (m_stateIteration == x_IterStarted)
  46. CleanupIteration();
  47. if (m_hLib)
  48. FreeLibrary(m_hLib);
  49. }
  50. // initialize entry points and load library
  51. void CFRSIter::Init()
  52. {
  53. if (m_fInitialized)
  54. return;
  55. // load library
  56. m_hLib = LoadLibrary(L"ntfrsapi.dll");
  57. if (m_hLib)
  58. {
  59. // assign etntry points
  60. m_pfnFrsInitBuRest = (PF_FRS_INIT) GetProcAddress(m_hLib, "NtFrsApiInitializeBackupRestore");
  61. m_pfnFrsEndBuRest = (PF_FRS_DESTROY) GetProcAddress(m_hLib, "NtFrsApiDestroyBackupRestore");
  62. m_pfnFrsGetSets = (PF_FRS_GET_SETS) GetProcAddress(m_hLib, "NtFrsApiGetBackupRestoreSets");
  63. m_pfnFrsEnumSets = (PF_FRS_ENUM_SETS) GetProcAddress(m_hLib, "NtFrsApiEnumBackupRestoreSets");
  64. m_pfnFrsIsSetSysVol = (PF_FRS_IS_SYSVOL) GetProcAddress(m_hLib, "NtFrsApiIsBackupRestoreSetASysvol");
  65. m_pfnFrsGetPath = (PF_FRS_GET_PATH) GetProcAddress(m_hLib, "NtFrsApiGetBackupRestoreSetDirectory");
  66. m_pfnFrsGetOtherPaths = (PF_FRS_GET_OTHER_PATHS) GetProcAddress(m_hLib, "NtFrsApiGetBackupRestoreSetPaths");
  67. if (m_pfnFrsInitBuRest == NULL ||
  68. m_pfnFrsEndBuRest == NULL ||
  69. m_pfnFrsGetSets == NULL ||
  70. m_pfnFrsEnumSets == NULL ||
  71. m_pfnFrsIsSetSysVol == NULL ||
  72. m_pfnFrsGetOtherPaths == NULL ||
  73. m_pfnFrsGetPath == NULL)
  74. {
  75. // if we can't get to any entry point, free library and
  76. // fail operation
  77. FreeLibrary(m_hLib);
  78. m_hLib = NULL;
  79. }
  80. }
  81. // indicate that operation is successful
  82. m_fInitialized = TRUE;
  83. }
  84. // initialize the iterator. Return FALSE if iterator is known to be empty
  85. //
  86. BOOL CFRSIter::BeginIteration()
  87. {
  88. ASSERT(m_stateIteration == x_IterNotStarted);
  89. DWORD status;
  90. if (m_hLib == NULL)
  91. {
  92. // if we are not initialized, then there is nothing to iterate
  93. // over
  94. m_stateIteration = x_IterComplete;
  95. return FALSE;
  96. }
  97. // initialize FRS backup restore apis
  98. status = m_pfnFrsInitBuRest
  99. (
  100. NULL,
  101. NTFRSAPI_BUR_FLAGS_NORMAL|NTFRSAPI_BUR_FLAGS_BACKUP,
  102. &m_frs_context
  103. );
  104. if (status != ERROR_SUCCESS)
  105. {
  106. // if this fails then we are done
  107. m_stateIteration = x_IterComplete;
  108. return FALSE;
  109. }
  110. // indicate that we started the iteration
  111. m_stateIteration = x_IterStarted;
  112. status = m_pfnFrsGetSets(m_frs_context);
  113. if (status != ERROR_SUCCESS)
  114. {
  115. // if there are no sets, then indicate we are done
  116. CleanupIteration();
  117. return FALSE;
  118. }
  119. // start at first set
  120. m_iset = 0;
  121. return TRUE;
  122. }
  123. // cleanup iteration after scanning the last element
  124. void CFRSIter::CleanupIteration()
  125. {
  126. m_pfnFrsEndBuRest(&m_frs_context, NTFRSAPI_BUR_FLAGS_NONE, NULL, NULL, NULL);
  127. m_stateIteration = x_IterComplete;
  128. }
  129. // get next iteration set returning the path to the set
  130. // NULL indicates end of iteration
  131. // If fSkipToSysVol is TRUE then ignore non SysVol replication sets
  132. LPWSTR CFRSIter::GetNextSet(BOOL fSkipToSysVol, LPWSTR *pwszPaths)
  133. {
  134. ASSERT(pwszPaths);
  135. ASSERT(m_stateIteration != x_IterNotStarted);
  136. if (m_stateIteration == x_IterComplete)
  137. // if iteration is complete, then we are done
  138. return NULL;
  139. PVOID frs_set;
  140. while(TRUE)
  141. {
  142. // get a set
  143. DWORD status = m_pfnFrsEnumSets(m_frs_context, m_iset, &frs_set);
  144. if (status != ERROR_SUCCESS)
  145. {
  146. // if this fails, then we are done
  147. CleanupIteration();
  148. return NULL;
  149. }
  150. if (fSkipToSysVol)
  151. {
  152. // we are looking for system volumes
  153. BOOL fSysVol;
  154. // test whether this is a system volume
  155. status = m_pfnFrsIsSetSysVol(m_frs_context, frs_set, &fSysVol);
  156. if (status != ERROR_SUCCESS)
  157. {
  158. // if this operation fails, terminate iteration
  159. CleanupIteration();
  160. return NULL;
  161. }
  162. if (!fSysVol)
  163. {
  164. // if not a system volume, then skip to the next
  165. // replica set
  166. m_iset++;
  167. continue;
  168. }
  169. }
  170. // scratch pad for path
  171. WCHAR wsz[MAX_PATH];
  172. DWORD cbPath = MAX_PATH * sizeof(WCHAR);
  173. // get path to root of the replica set
  174. status = m_pfnFrsGetPath
  175. (
  176. m_frs_context,
  177. frs_set,
  178. &cbPath,
  179. wsz
  180. );
  181. WCHAR *wszNew = NULL;
  182. // allocate memory for root
  183. if (status == ERROR_SUCCESS || status == ERROR_INSUFFICIENT_BUFFER)
  184. {
  185. wszNew = new WCHAR[cbPath/sizeof(WCHAR)];
  186. // if allocation fails, then throw OOM
  187. if (wszNew == NULL)
  188. throw E_OUTOFMEMORY;
  189. if (status == ERROR_SUCCESS)
  190. // if the operation was successful, then copy
  191. // path into memory
  192. memcpy(wszNew, wsz, cbPath);
  193. else
  194. {
  195. // otherwise redo the operation
  196. status = m_pfnFrsGetPath
  197. (
  198. m_frs_context,
  199. frs_set,
  200. &cbPath,
  201. wszNew
  202. );
  203. if (status != ERROR_SUCCESS)
  204. {
  205. // if operation failed then second time, then
  206. // delete allocated memory and terminate iteration
  207. delete wszNew;
  208. CleanupIteration();
  209. return NULL;
  210. }
  211. }
  212. }
  213. else
  214. {
  215. // if operation failed due to any error other than
  216. // insufficient buffer, then terminate the iteration
  217. CleanupIteration();
  218. return NULL;
  219. }
  220. // scratch pad for filters
  221. WCHAR wszFilter[MAX_PATH];
  222. DWORD cbFilter = MAX_PATH * sizeof(WCHAR);
  223. // length of scratch pad for paths
  224. cbPath = MAX_PATH * sizeof(WCHAR);
  225. // obtain other paths
  226. status = m_pfnFrsGetOtherPaths
  227. (
  228. m_frs_context,
  229. frs_set,
  230. &cbPath,
  231. wsz,
  232. &cbFilter,
  233. wszFilter
  234. );
  235. WCHAR *wszNewPaths = NULL;
  236. WCHAR *wszNewFilter = NULL;
  237. if (status == ERROR_SUCCESS || status == ERROR_INSUFFICIENT_BUFFER)
  238. {
  239. // allocate space for paths
  240. wszNewPaths = new WCHAR[cbPath/sizeof(WCHAR)];
  241. // allocate space for filters
  242. wszNewFilter = new WCHAR[cbFilter/sizeof(WCHAR)];
  243. if (wszNew == NULL || wszFilter == NULL)
  244. {
  245. // if any allocation fails, then throw OOM
  246. delete wszNew;
  247. throw E_OUTOFMEMORY;
  248. }
  249. if (status == ERROR_SUCCESS)
  250. {
  251. // if operation was successful, then copy
  252. // in allocated paths
  253. memcpy(wszNewPaths, wsz, cbPath);
  254. memcpy(wszNewFilter, wszFilter, cbFilter);
  255. }
  256. else
  257. {
  258. status = m_pfnFrsGetOtherPaths
  259. (
  260. m_frs_context,
  261. frs_set,
  262. &cbPath,
  263. wszNew,
  264. &cbFilter,
  265. wszNewFilter
  266. );
  267. if (status != ERROR_SUCCESS)
  268. {
  269. delete wszNew;
  270. delete wszNewFilter;
  271. CleanupIteration();
  272. return NULL;
  273. }
  274. }
  275. }
  276. else
  277. {
  278. // if any error other than success or INSUFFICENT_BUFFER
  279. // then terminate iteration
  280. CleanupIteration();
  281. return NULL;
  282. }
  283. // delete allocated filter
  284. delete wszNewFilter;
  285. // set iteration to next set
  286. m_iset++;
  287. // return pointer to paths
  288. *pwszPaths = wszNewPaths;
  289. // return path of root of replicated set
  290. return wszNew;
  291. }
  292. }
  293. // terminate iteration, cleaning up anything that needs to be
  294. // cleaned up
  295. //
  296. void CFRSIter::EndIteration()
  297. {
  298. ASSERT(m_stateIteration != x_IterNotStarted);
  299. if (m_stateIteration == x_IterStarted)
  300. CleanupIteration();
  301. // indicate that iteration is no longer in progress
  302. m_stateIteration = x_IterNotStarted;
  303. }
  304. // constructor for string data structure
  305. CWStringData::CWStringData()
  306. {
  307. m_psdlFirst = NULL;
  308. m_psdlCur = NULL;
  309. }
  310. // destructor
  311. CWStringData::~CWStringData()
  312. {
  313. while(m_psdlFirst)
  314. {
  315. WSTRING_DATA_LINK *psdl = m_psdlFirst;
  316. m_psdlFirst = m_psdlFirst->m_psdlNext;
  317. delete psdl;
  318. }
  319. }
  320. // allocate a new link
  321. void CWStringData::AllocateNewLink()
  322. {
  323. WSTRING_DATA_LINK *psdl = new WSTRING_DATA_LINK;
  324. if (psdl == NULL)
  325. throw E_OUTOFMEMORY;
  326. psdl->m_psdlNext = NULL;
  327. if (m_psdlCur)
  328. {
  329. ASSERT(m_psdlFirst);
  330. m_psdlCur->m_psdlNext = psdl;
  331. m_psdlCur = psdl;
  332. }
  333. else
  334. {
  335. ASSERT(m_psdlFirst == NULL);
  336. m_psdlFirst = m_psdlCur = psdl;
  337. }
  338. m_ulNextString = 0;
  339. }
  340. // allocate a string
  341. LPWSTR CWStringData::AllocateString(unsigned cwc)
  342. {
  343. ASSERT(cwc <= sizeof(m_psdlCur->rgwc));
  344. if (m_psdlCur == NULL)
  345. AllocateNewLink();
  346. if (sizeof(m_psdlCur->rgwc) <= (cwc + 1 + m_ulNextString) * sizeof(WCHAR))
  347. AllocateNewLink();
  348. unsigned ulOff = m_ulNextString;
  349. m_ulNextString += cwc + 1;
  350. return m_psdlCur->rgwc + ulOff;
  351. }
  352. // copy a string
  353. LPWSTR CWStringData::CopyString(LPCWSTR wsz)
  354. {
  355. unsigned cwc = (wsz == NULL) ? 0 : wcslen(wsz);
  356. LPWSTR wszNew = AllocateString(cwc);
  357. memcpy(wszNew, wsz, cwc * sizeof(WCHAR));
  358. wszNew[cwc] = '\0';
  359. return wszNew;
  360. }
  361. // constructor for volume list
  362. CVolumeList::CVolumeList() :
  363. m_rgwszVolumes(NULL), // array of volumes
  364. m_cwszVolumes(0), // # of volumes in array
  365. m_cwszVolumesMax(0), // size of array
  366. m_rgwszPaths(NULL), // array of paths
  367. m_cwszPaths(0), // # of paths in array
  368. m_cwszPathsMax(0) // size of array
  369. {
  370. }
  371. // destructor
  372. CVolumeList::~CVolumeList()
  373. {
  374. delete m_rgwszPaths; // delete paths array
  375. delete m_rgwszVolumes; // delete volumes array
  376. }
  377. // add a path to the list if it is not already there
  378. // return TRUE if it is a new path
  379. // return FALSE if path is already in list
  380. //
  381. BOOL CVolumeList::AddPathToList(LPWSTR wszPath)
  382. {
  383. // look for path in list. If found, then return FALSE
  384. for(unsigned iwsz = 0; iwsz < m_cwszPaths; iwsz++)
  385. {
  386. if (_wcsicmp(wszPath, m_rgwszPaths[iwsz]) == 0)
  387. return FALSE;
  388. }
  389. // grow pat array if needed
  390. if (m_cwszPaths == m_cwszPathsMax)
  391. {
  392. // grow path array
  393. LPCWSTR *rgwsz = new LPCWSTR[m_cwszPaths + x_cwszPathsInc];
  394. // throw OOM if memory allocation fails
  395. if (rgwsz == NULL)
  396. throw(E_OUTOFMEMORY);
  397. memcpy(rgwsz, m_rgwszPaths, m_cwszPaths * sizeof(LPCWSTR));
  398. delete m_rgwszPaths;
  399. m_rgwszPaths = rgwsz;
  400. m_cwszPathsMax += x_cwszPathsInc;
  401. }
  402. // add path to array
  403. m_rgwszPaths[m_cwszPaths++] = m_sd.CopyString(wszPath);
  404. return TRUE;
  405. }
  406. // add a volume to the list if it is not already there
  407. // return TRUE if it is added
  408. // return FALSE if it is already on the list
  409. //
  410. BOOL CVolumeList::AddVolumeToList(LPCWSTR wszVolume)
  411. {
  412. // look for volume in array. If found then return FALSE
  413. for(unsigned iwsz = 0; iwsz < m_cwszVolumes; iwsz++)
  414. {
  415. if (_wcsicmp(wszVolume, m_rgwszVolumes[iwsz]) == 0)
  416. return FALSE;
  417. }
  418. // grow volume array if necessary
  419. if (m_cwszVolumes == m_cwszVolumesMax)
  420. {
  421. // grow volume array
  422. LPCWSTR *rgwsz = new LPCWSTR[m_cwszVolumes + x_cwszVolumesInc];
  423. if (rgwsz == NULL)
  424. throw(E_OUTOFMEMORY);
  425. memcpy(rgwsz, m_rgwszVolumes, m_cwszVolumes * sizeof(LPCWSTR));
  426. delete m_rgwszVolumes;
  427. m_rgwszVolumes = rgwsz;
  428. m_cwszVolumesMax += x_cwszVolumesInc;
  429. }
  430. // add volume name to array
  431. m_rgwszVolumes[m_cwszVolumes++] = m_sd.CopyString(wszVolume);
  432. return TRUE;
  433. }
  434. const WCHAR x_wszVolumeRootName[] = L"\\\\?\\GlobalRoot\\Device\\";
  435. const unsigned x_cwcVolumeRootName = sizeof(x_wszVolumeRootName)/sizeof(WCHAR) - 1;
  436. // add a path to our tracking list. If the path is new add it to the
  437. // paths list. If it is a mount point or the root of a volume, then
  438. // determine the volume and add the volume to the list of volumes
  439. //
  440. // can throw E_OUTOFMEMORY
  441. //
  442. void CVolumeList::AddPath(LPWSTR wszTop)
  443. {
  444. // if path is known about then return
  445. if (!AddPathToList(wszTop))
  446. return;
  447. // length of path
  448. unsigned cwc = wcslen(wszTop);
  449. // copy path so that we can add backslash to the end of the path
  450. LPWSTR wszCopy = new WCHAR[cwc + 2];
  451. // if fails, then throw OOM
  452. if (wszCopy == NULL)
  453. throw E_OUTOFMEMORY;
  454. // copyh in original path
  455. memcpy(wszCopy, wszTop, cwc * sizeof(WCHAR));
  456. // append backslash
  457. wszCopy[cwc] = L'\\';
  458. wszCopy[cwc + 1] = L'\0';
  459. while(TRUE)
  460. {
  461. // check for a device root
  462. unsigned cwc = wcslen(wszCopy);
  463. if ((cwc == 3 && wszCopy[1] == ':') ||
  464. (cwc > x_cwcVolumeRootName &&
  465. memcmp(wszCopy, x_wszVolumeRootName, x_cwcVolumeRootName * sizeof(WCHAR)) == 0))
  466. {
  467. // call TryAddVolume with TRUE indicating this is a volume root
  468. TryAddVolumeToList(wszCopy, TRUE);
  469. break;
  470. }
  471. // call TryAddVolume indicating this is not a known device root
  472. if (TryAddVolumeToList(wszCopy, FALSE))
  473. break;
  474. // move back to previous backslash
  475. WCHAR *pch = wszCopy + cwc - 2;
  476. while(--pch > wszTop)
  477. {
  478. if (pch[1] == L'\\')
  479. {
  480. pch[2] = L'\0';
  481. break;
  482. }
  483. }
  484. if (pch == wszTop)
  485. break;
  486. // if path is known about then return
  487. if (!AddPathToList(wszCopy))
  488. break;
  489. }
  490. }
  491. // determine if a path is a volume. If so then add it to the volume
  492. // list and return TRUE. If not, then return FALSE. fVolumeRoot indicates
  493. // that the path is of the form x:\. Otherwise the path is potentially
  494. // an mount point. Validate that it is a reparse point and then try
  495. // finding its volume guid. If this fails, then assume that it is not
  496. // a volume root. If it succeeds, then add the volume guid to the volumes
  497. // list and return TRUE.
  498. //
  499. BOOL CVolumeList::TryAddVolumeToList(LPCWSTR wszPath, BOOL fVolumeRoot)
  500. {
  501. WCHAR wszVolume[256];
  502. if (fVolumeRoot)
  503. {
  504. if (!GetVolumeNameForVolumeMountPoint(wszPath, wszVolume, sizeof(wszVolume)/sizeof(WCHAR)))
  505. // might be the EFI system partition, just pass in the path as the volume string.
  506. wcscpy( wszVolume, wszPath );
  507. //throw E_UNEXPECTED;
  508. }
  509. else
  510. {
  511. DWORD dw = GetFileAttributes(wszPath);
  512. if (dw == -1)
  513. return FALSE;
  514. if ((dw & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
  515. return FALSE;
  516. if (!GetVolumeNameForVolumeMountPoint(wszPath, wszVolume, sizeof(wszVolume)/sizeof(WCHAR)))
  517. return FALSE;
  518. }
  519. AddVolumeToList(wszVolume);
  520. return TRUE;
  521. }
  522. // add a file to the volume list. Simply finds the parent path and adds it
  523. //
  524. void CVolumeList::AddFile(LPWSTR wsz)
  525. {
  526. unsigned cwc = wcslen(wsz);
  527. WCHAR *pwc = wsz + cwc - 1;
  528. while(pwc[1] != L'\\' && pwc != wsz)
  529. continue;
  530. pwc[1] = '\0';
  531. AddPath(wsz);
  532. }
  533. // obtain list of volumes as a MULTI_SZ, caller is responsible for freeing
  534. // the string
  535. //
  536. LPWSTR CVolumeList::GetVolumeList()
  537. {
  538. unsigned cwc = 1;
  539. // compute length of volume list it is length of each string +
  540. // null character + null charactor for last double NULL
  541. for(unsigned iwsz = 0; iwsz < m_cwszVolumes; iwsz++)
  542. cwc += wcslen(m_rgwszVolumes[iwsz]) + 1;
  543. // allocate string
  544. LPWSTR wsz = new WCHAR[cwc];
  545. // throw OOM if memory allocation failed
  546. if (wsz == NULL)
  547. throw E_OUTOFMEMORY;
  548. // copy in strings
  549. WCHAR *pwc = wsz;
  550. for(unsigned iwsz = 0; iwsz < m_cwszVolumes; iwsz++)
  551. {
  552. cwc = wcslen(m_rgwszVolumes[iwsz]) + 1;
  553. memcpy(pwc, m_rgwszVolumes[iwsz], cwc * sizeof(WCHAR));
  554. /* replace \\?\ with \??\ */
  555. memcpy(pwc, L"\\??", sizeof(WCHAR) * 3);
  556. // delete trailing backslash if it exists
  557. if (pwc[cwc - 2] == L'\\')
  558. {
  559. pwc[cwc-2] = L'\0';
  560. cwc--;
  561. }
  562. pwc += cwc;
  563. }
  564. // last null termination
  565. *pwc = L'\0';
  566. return wsz;
  567. }
  568. // path to volume of boot device is
  569. // HKEY_LOCAL_MACHINE\System\Setup
  570. //with Value of SystemPartition parametr
  571. LPCWSTR x_SetupRoot = L"System\\Setup";
  572. // magic perfix for volume devices
  573. WCHAR x_wszWin32VolumePrefix[] = L"\\\\?\\GlobalRoot";
  574. const unsigned x_cwcWin32VolumePrefix = sizeof(x_wszWin32VolumePrefix)/sizeof(WCHAR) - 1;
  575. // structure representing a path from
  576. // HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  577. // and a value to look up
  578. typedef struct _SVCPARM
  579. {
  580. LPCWSTR wszPath;
  581. LPCWSTR wszValue;
  582. } SVCPARM;
  583. const SVCPARM x_rgdbparms[] =
  584. {
  585. {L"CertSvc\\Configuration", L"DBDirectory"},
  586. {L"CertSvc\\Configuration", L"DBLogDirectory"},
  587. {L"CertSvc\\Configuration", L"DBSystemDirectory"},
  588. {L"CertSvc\\Configuration", L"DBTempDirectory"},
  589. {L"DHCPServer\\Parameters", L"DatabasePath"},
  590. {L"DHCPServer\\Parameters", L"DatabaseName"},
  591. {L"DHCPServer\\Parameters", L"BackupDatabasePath"},
  592. {L"NTDS\\Parameters", L"Database backup path"},
  593. {L"NTDS\\Parameters", L"Databases log files path"},
  594. {L"Ntfrs\\Parameters\\Replica Sets", L"Database Directory"}
  595. };
  596. const unsigned x_cdbparms = sizeof(x_rgdbparms)/sizeof(SVCPARM);
  597. LPCWSTR x_wszSvcRoot = L"System\\CurrentControlSet\\Services";
  598. // add roots for various services
  599. BOOL AddServiceRoots(CVolumeList &vl)
  600. {
  601. HKEY hkeyRoot;
  602. // open HKLM\System\CurrentControlSet\Services
  603. if (RegOpenKey(HKEY_LOCAL_MACHINE, x_wszSvcRoot, &hkeyRoot) != ERROR_SUCCESS)
  604. return FALSE;
  605. // loop through individual paths
  606. for(unsigned i = 0; i < x_cdbparms; i++)
  607. {
  608. WCHAR wsz[MAX_PATH*4];
  609. LPCWSTR wszPath = x_rgdbparms[i].wszPath;
  610. LPCWSTR wszValue = x_rgdbparms[i].wszValue;
  611. HKEY hkey;
  612. DWORD cb = sizeof(wsz);
  613. DWORD type;
  614. // open path, skip if open fails
  615. if (RegOpenKey(hkeyRoot, wszPath, &hkey) != ERROR_SUCCESS)
  616. continue;
  617. // add path to volume list if query succeeds
  618. if (RegQueryValueEx
  619. (
  620. hkey,
  621. wszValue,
  622. NULL,
  623. &type,
  624. (BYTE *) wsz,
  625. &cb
  626. ) == ERROR_SUCCESS)
  627. vl.AddPath(wsz);
  628. // close key
  629. RegCloseKey(hkey);
  630. }
  631. // close root key
  632. RegCloseKey(hkeyRoot);
  633. return TRUE;
  634. }
  635. // add volume root of SystemDrive (drive wee boot off of
  636. BOOL AddSystemPartitionRoot(CVolumeList &vl)
  637. {
  638. HKEY hkeySetup;
  639. WCHAR wsz[MAX_PATH];
  640. // open HKLM\System\Setup
  641. if (RegOpenKey(HKEY_LOCAL_MACHINE, x_SetupRoot, &hkeySetup) != ERROR_SUCCESS)
  642. return FALSE;
  643. DWORD cb = sizeof(wsz);
  644. DWORD type;
  645. // query SystemPartition value
  646. if (RegQueryValueEx
  647. (
  648. hkeySetup,
  649. L"SystemPartition",
  650. NULL,
  651. &type,
  652. (BYTE *) wsz,
  653. &cb
  654. ) != ERROR_SUCCESS)
  655. {
  656. // if fails, return FALSE
  657. RegCloseKey(hkeySetup);
  658. return FALSE;
  659. }
  660. // compute size of needed buffer
  661. unsigned cwc = wcslen(wsz);
  662. unsigned cwcNew = x_cwcWin32VolumePrefix + cwc + 1;
  663. LPWSTR wszNew = new WCHAR[cwcNew];
  664. // return failure if memory allocation fials
  665. if (wszNew == NULL)
  666. return FALSE;
  667. // append \\?\GlobalRoot\ to device name
  668. memcpy(wszNew, x_wszWin32VolumePrefix, x_cwcWin32VolumePrefix * sizeof(WCHAR));
  669. memcpy(wszNew + x_cwcWin32VolumePrefix, wsz, cwc * sizeof(WCHAR));
  670. RegCloseKey(hkeySetup);
  671. wszNew[cwcNew-1] = L'\0';
  672. try {
  673. // add path based on device root
  674. vl.AddPath(wszNew);
  675. } catch(...)
  676. {
  677. delete wszNew;
  678. return FALSE;
  679. }
  680. // delete allocated memory
  681. delete wszNew;
  682. return TRUE;
  683. }
  684. // find critical volumes. Return multistring of volume names
  685. // using guid naming convention
  686. LPWSTR pFindCriticalVolumes()
  687. {
  688. WCHAR wsz[MAX_PATH * 4];
  689. // find location of system root
  690. if (!ExpandEnvironmentStrings(L"%systemroot%", wsz, sizeof(wsz)/sizeof(WCHAR)))
  691. {
  692. wprintf(L"ExpandEnvironmentStrings failed for reason %d", GetLastError());
  693. return NULL;
  694. }
  695. CVolumeList vl;
  696. LPWSTR wszPathsT = NULL;
  697. LPWSTR wszT = NULL;
  698. try
  699. {
  700. // add boot drive
  701. if (!AddSystemPartitionRoot(vl))
  702. return NULL;
  703. // add roots for various services
  704. if (!AddServiceRoots(vl))
  705. return NULL;
  706. // add systemroot drive
  707. vl.AddPath(wsz);
  708. {
  709. // add roots for SYSVOL
  710. CFRSIter fiter;
  711. fiter.Init();
  712. fiter.BeginIteration();
  713. while(TRUE)
  714. {
  715. wszT = fiter.GetNextSet(TRUE, &wszPathsT);
  716. if (wszT == NULL)
  717. break;
  718. vl.AddPath(wszT);
  719. LPWSTR wszPathT = wszPathsT;
  720. while(*wszPathT != NULL)
  721. {
  722. vl.AddPath(wszPathT);
  723. wszPathT += wcslen(wszPathT);
  724. }
  725. delete wszT;
  726. delete wszPathsT;
  727. wszT = NULL;
  728. wszPathsT = NULL;
  729. }
  730. fiter.EndIteration();
  731. }
  732. }
  733. catch(...)
  734. {
  735. delete wszT;
  736. delete wszPathsT;
  737. }
  738. // return volume list
  739. return vl.GetVolumeList();
  740. }