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.

889 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 (wszNewPaths == NULL || wszNewFilter == NULL)
  244. {
  245. // if any allocation fails, then throw OOM
  246. delete [] wszNewPaths;
  247. delete [] wszNewFilter;
  248. throw E_OUTOFMEMORY;
  249. }
  250. if (status == ERROR_SUCCESS)
  251. {
  252. // if operation was successful, then copy
  253. // in allocated paths
  254. memcpy(wszNewPaths, wsz, cbPath);
  255. memcpy(wszNewFilter, wszFilter, cbFilter);
  256. }
  257. else
  258. {
  259. status = m_pfnFrsGetOtherPaths
  260. (
  261. m_frs_context,
  262. frs_set,
  263. &cbPath,
  264. wszNew,
  265. &cbFilter,
  266. wszNewFilter
  267. );
  268. if (status != ERROR_SUCCESS)
  269. {
  270. delete [] wszNew;
  271. delete [] wszNewFilter;
  272. CleanupIteration();
  273. return NULL;
  274. }
  275. }
  276. }
  277. else
  278. {
  279. // if any error other than success or INSUFFICENT_BUFFER
  280. // then terminate iteration
  281. CleanupIteration();
  282. return NULL;
  283. }
  284. // delete allocated filter
  285. delete [] wszNewFilter;
  286. // set iteration to next set
  287. m_iset++;
  288. // return pointer to paths
  289. *pwszPaths = wszNewPaths;
  290. // return path of root of replicated set
  291. return wszNew;
  292. }
  293. }
  294. // terminate iteration, cleaning up anything that needs to be
  295. // cleaned up
  296. //
  297. void CFRSIter::EndIteration()
  298. {
  299. ASSERT(m_stateIteration != x_IterNotStarted);
  300. if (m_stateIteration == x_IterStarted)
  301. CleanupIteration();
  302. // indicate that iteration is no longer in progress
  303. m_stateIteration = x_IterNotStarted;
  304. }
  305. // constructor for string data structure
  306. CWStringData::CWStringData()
  307. {
  308. m_psdlFirst = NULL;
  309. m_psdlCur = NULL;
  310. }
  311. // destructor
  312. CWStringData::~CWStringData()
  313. {
  314. while(m_psdlFirst)
  315. {
  316. WSTRING_DATA_LINK *psdl = m_psdlFirst;
  317. m_psdlFirst = m_psdlFirst->m_psdlNext;
  318. delete psdl;
  319. }
  320. }
  321. // allocate a new link
  322. void CWStringData::AllocateNewLink()
  323. {
  324. WSTRING_DATA_LINK *psdl = new WSTRING_DATA_LINK;
  325. if (psdl == NULL)
  326. throw E_OUTOFMEMORY;
  327. psdl->m_psdlNext = NULL;
  328. if (m_psdlCur)
  329. {
  330. ASSERT(m_psdlFirst);
  331. m_psdlCur->m_psdlNext = psdl;
  332. m_psdlCur = psdl;
  333. }
  334. else
  335. {
  336. ASSERT(m_psdlFirst == NULL);
  337. m_psdlFirst = m_psdlCur = psdl;
  338. }
  339. m_ulNextString = 0;
  340. }
  341. // allocate a string
  342. LPWSTR CWStringData::AllocateString(unsigned cwc)
  343. {
  344. ASSERT(cwc <= sizeof(m_psdlCur->rgwc));
  345. if (m_psdlCur == NULL)
  346. AllocateNewLink();
  347. if (sizeof(m_psdlCur->rgwc) <= (cwc + 1 + m_ulNextString) * sizeof(WCHAR))
  348. AllocateNewLink();
  349. unsigned ulOff = m_ulNextString;
  350. m_ulNextString += cwc + 1;
  351. return m_psdlCur->rgwc + ulOff;
  352. }
  353. // copy a string
  354. LPWSTR CWStringData::CopyString(LPCWSTR wsz)
  355. {
  356. unsigned cwc = (wsz == NULL) ? 0 : wcslen(wsz);
  357. LPWSTR wszNew = AllocateString(cwc);
  358. memcpy(wszNew, wsz, cwc * sizeof(WCHAR));
  359. wszNew[cwc] = '\0';
  360. return wszNew;
  361. }
  362. // constructor for volume list
  363. CVolumeList::CVolumeList() :
  364. m_rgwszVolumes(NULL), // array of volumes
  365. m_cwszVolumes(0), // # of volumes in array
  366. m_cwszVolumesMax(0), // size of array
  367. m_rgwszPaths(NULL), // array of paths
  368. m_cwszPaths(0), // # of paths in array
  369. m_cwszPathsMax(0) // size of array
  370. {
  371. }
  372. // destructor
  373. CVolumeList::~CVolumeList()
  374. {
  375. delete m_rgwszPaths; // delete paths array
  376. delete m_rgwszVolumes; // delete volumes array
  377. }
  378. // add a path to the list if it is not already there
  379. // return TRUE if it is a new path
  380. // return FALSE if path is already in list
  381. //
  382. BOOL CVolumeList::AddPathToList(LPWSTR wszPath)
  383. {
  384. // look for path in list. If found, then return FALSE
  385. for(unsigned iwsz = 0; iwsz < m_cwszPaths; iwsz++)
  386. {
  387. if (_wcsicmp(wszPath, m_rgwszPaths[iwsz]) == 0)
  388. return FALSE;
  389. }
  390. // grow pat array if needed
  391. if (m_cwszPaths == m_cwszPathsMax)
  392. {
  393. // grow path array
  394. LPCWSTR *rgwsz = new LPCWSTR[m_cwszPaths + x_cwszPathsInc];
  395. // throw OOM if memory allocation fails
  396. if (rgwsz == NULL)
  397. throw(E_OUTOFMEMORY);
  398. memcpy(rgwsz, m_rgwszPaths, m_cwszPaths * sizeof(LPCWSTR));
  399. delete m_rgwszPaths;
  400. m_rgwszPaths = rgwsz;
  401. m_cwszPathsMax += x_cwszPathsInc;
  402. }
  403. // add path to array
  404. m_rgwszPaths[m_cwszPaths++] = m_sd.CopyString(wszPath);
  405. return TRUE;
  406. }
  407. // add a volume to the list if it is not already there
  408. // return TRUE if it is added
  409. // return FALSE if it is already on the list
  410. //
  411. BOOL CVolumeList::AddVolumeToList(LPCWSTR wszVolume)
  412. {
  413. // look for volume in array. If found then return FALSE
  414. for(unsigned iwsz = 0; iwsz < m_cwszVolumes; iwsz++)
  415. {
  416. if (_wcsicmp(wszVolume, m_rgwszVolumes[iwsz]) == 0)
  417. return FALSE;
  418. }
  419. // grow volume array if necessary
  420. if (m_cwszVolumes == m_cwszVolumesMax)
  421. {
  422. // grow volume array
  423. LPCWSTR *rgwsz = new LPCWSTR[m_cwszVolumes + x_cwszVolumesInc];
  424. if (rgwsz == NULL)
  425. throw(E_OUTOFMEMORY);
  426. memcpy(rgwsz, m_rgwszVolumes, m_cwszVolumes * sizeof(LPCWSTR));
  427. delete m_rgwszVolumes;
  428. m_rgwszVolumes = rgwsz;
  429. m_cwszVolumesMax += x_cwszVolumesInc;
  430. }
  431. // add volume name to array
  432. m_rgwszVolumes[m_cwszVolumes++] = m_sd.CopyString(wszVolume);
  433. return TRUE;
  434. }
  435. const WCHAR x_wszVolumeRootName[] = L"\\\\?\\GlobalRoot\\Device\\";
  436. const unsigned x_cwcVolumeRootName = sizeof(x_wszVolumeRootName)/sizeof(WCHAR) - 1;
  437. // add a path to our tracking list. If the path is new add it to the
  438. // paths list. If it is a mount point or the root of a volume, then
  439. // determine the volume and add the volume to the list of volumes
  440. //
  441. // can throw E_OUTOFMEMORY
  442. //
  443. void CVolumeList::AddPath(LPWSTR wszTop)
  444. {
  445. // if path is known about then return
  446. if (!AddPathToList(wszTop))
  447. return;
  448. // length of path
  449. unsigned cwc = wcslen(wszTop);
  450. // copy path so that we can add backslash to the end of the path
  451. LPWSTR wszCopy = new WCHAR[cwc + 2];
  452. // if fails, then throw OOM
  453. if (wszCopy == NULL)
  454. throw E_OUTOFMEMORY;
  455. // copyh in original path
  456. memcpy(wszCopy, wszTop, cwc * sizeof(WCHAR));
  457. // append backslash
  458. wszCopy[cwc] = L'\\';
  459. wszCopy[cwc + 1] = L'\0';
  460. while(TRUE)
  461. {
  462. // check for a device root
  463. cwc = wcslen(wszCopy);
  464. if ((cwc == 3 && wszCopy[1] == ':') ||
  465. (cwc > x_cwcVolumeRootName &&
  466. memcmp(wszCopy, x_wszVolumeRootName, x_cwcVolumeRootName * sizeof(WCHAR)) == 0))
  467. {
  468. // call TryAddVolume with TRUE indicating this is a volume root
  469. TryAddVolumeToList(wszCopy, TRUE);
  470. break;
  471. }
  472. // call TryAddVolume indicating this is not a known device root
  473. if (TryAddVolumeToList(wszCopy, FALSE))
  474. break;
  475. // move back to previous backslash
  476. WCHAR *pch = wszCopy + cwc - 2;
  477. while(--pch > wszTop)
  478. {
  479. if (pch[1] == L'\\')
  480. {
  481. pch[2] = L'\0';
  482. break;
  483. }
  484. }
  485. if (pch == wszTop)
  486. break;
  487. // if path is known about then return
  488. if (!AddPathToList(wszCopy))
  489. break;
  490. }
  491. }
  492. // determine if a path is a volume. If so then add it to the volume
  493. // list and return TRUE. If not, then return FALSE. fVolumeRoot indicates
  494. // that the path is of the form x:\. Otherwise the path is potentially
  495. // an mount point. Validate that it is a reparse point and then try
  496. // finding its volume guid. If this fails, then assume that it is not
  497. // a volume root. If it succeeds, then add the volume guid to the volumes
  498. // list and return TRUE.
  499. //
  500. BOOL CVolumeList::TryAddVolumeToList(LPCWSTR wszPath, BOOL fVolumeRoot)
  501. {
  502. WCHAR wszVolume[256];
  503. if (fVolumeRoot)
  504. {
  505. if (!GetVolumeNameForVolumeMountPoint(wszPath, wszVolume, sizeof(wszVolume)/sizeof(WCHAR)))
  506. // might be the EFI system partition, just pass in the path as the volume string.
  507. wcscpy( wszVolume, wszPath );
  508. //throw E_UNEXPECTED;
  509. }
  510. else
  511. {
  512. DWORD dw = GetFileAttributes(wszPath);
  513. if (dw == -1)
  514. return FALSE;
  515. if ((dw & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
  516. return FALSE;
  517. if (!GetVolumeNameForVolumeMountPoint(wszPath, wszVolume, sizeof(wszVolume)/sizeof(WCHAR)))
  518. return FALSE;
  519. }
  520. AddVolumeToList(wszVolume);
  521. return TRUE;
  522. }
  523. // add a file to the volume list. Simply finds the parent path and adds it
  524. //
  525. void CVolumeList::AddFile(LPWSTR wsz)
  526. {
  527. unsigned cwc = wcslen(wsz);
  528. WCHAR *pwc = wsz + cwc - 1;
  529. while(pwc[1] != L'\\' && pwc != wsz)
  530. continue;
  531. pwc[1] = '\0';
  532. AddPath(wsz);
  533. }
  534. // obtain list of volumes as a MULTI_SZ, caller is responsible for freeing
  535. // the string
  536. //
  537. LPWSTR CVolumeList::GetVolumeList()
  538. {
  539. unsigned cwc = 1;
  540. // compute length of volume list it is length of each string +
  541. // null character + null charactor for last double NULL
  542. for(unsigned iwsz = 0; iwsz < m_cwszVolumes; iwsz++)
  543. cwc += wcslen(m_rgwszVolumes[iwsz]) + 1;
  544. // allocate string
  545. LPWSTR wsz = new WCHAR[cwc];
  546. // throw OOM if memory allocation failed
  547. if (wsz == NULL)
  548. throw E_OUTOFMEMORY;
  549. // copy in strings
  550. WCHAR *pwc = wsz;
  551. for(unsigned iwsz = 0; iwsz < m_cwszVolumes; iwsz++)
  552. {
  553. cwc = wcslen(m_rgwszVolumes[iwsz]) + 1;
  554. memcpy(pwc, m_rgwszVolumes[iwsz], cwc * sizeof(WCHAR));
  555. /* replace \\?\ with \??\ */
  556. memcpy(pwc, L"\\??", sizeof(WCHAR) * 3);
  557. // delete trailing backslash if it exists
  558. if (pwc[cwc - 2] == L'\\')
  559. {
  560. pwc[cwc-2] = L'\0';
  561. cwc--;
  562. }
  563. pwc += cwc;
  564. }
  565. // last null termination
  566. *pwc = L'\0';
  567. return wsz;
  568. }
  569. // path to volume of boot device is
  570. // HKEY_LOCAL_MACHINE\System\Setup
  571. //with Value of SystemPartition parametr
  572. LPCWSTR x_SetupRoot = L"System\\Setup";
  573. // magic perfix for volume devices
  574. WCHAR x_wszWin32VolumePrefix[] = L"\\\\?\\GlobalRoot";
  575. const unsigned x_cwcWin32VolumePrefix = sizeof(x_wszWin32VolumePrefix)/sizeof(WCHAR) - 1;
  576. // structure representing a path from
  577. // HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  578. // and a value to look up
  579. typedef struct _SVCPARM
  580. {
  581. LPCWSTR wszPath;
  582. LPCWSTR wszValue;
  583. } SVCPARM;
  584. const SVCPARM x_rgdbparms[] =
  585. {
  586. {L"CertSvc\\Configuration", L"DBDirectory"},
  587. {L"CertSvc\\Configuration", L"DBLogDirectory"},
  588. {L"CertSvc\\Configuration", L"DBSystemDirectory"},
  589. {L"CertSvc\\Configuration", L"DBTempDirectory"},
  590. {L"DHCPServer\\Parameters", L"DatabasePath"},
  591. {L"DHCPServer\\Parameters", L"DatabaseName"},
  592. {L"DHCPServer\\Parameters", L"BackupDatabasePath"},
  593. {L"NTDS\\Parameters", L"Database backup path"},
  594. {L"NTDS\\Parameters", L"Databases log files path"},
  595. {L"Ntfrs\\Parameters\\Replica Sets", L"Database Directory"}
  596. };
  597. const unsigned x_cdbparms = sizeof(x_rgdbparms)/sizeof(SVCPARM);
  598. LPCWSTR x_wszSvcRoot = L"System\\CurrentControlSet\\Services";
  599. // add roots for various services
  600. BOOL AddServiceRoots(CVolumeList &vl)
  601. {
  602. HKEY hkeyRoot;
  603. // open HKLM\System\CurrentControlSet\Services
  604. if (RegOpenKey(HKEY_LOCAL_MACHINE, x_wszSvcRoot, &hkeyRoot) != ERROR_SUCCESS)
  605. return FALSE;
  606. // loop through individual paths
  607. for(unsigned i = 0; i < x_cdbparms; i++)
  608. {
  609. WCHAR wsz[MAX_PATH*4];
  610. LPCWSTR wszPath = x_rgdbparms[i].wszPath;
  611. LPCWSTR wszValue = x_rgdbparms[i].wszValue;
  612. HKEY hkey;
  613. DWORD cb = sizeof(wsz);
  614. DWORD type;
  615. // open path, skip if open fails
  616. if (RegOpenKey(hkeyRoot, wszPath, &hkey) != ERROR_SUCCESS)
  617. continue;
  618. // add path to volume list if query succeeds
  619. if (RegQueryValueEx
  620. (
  621. hkey,
  622. wszValue,
  623. NULL,
  624. &type,
  625. (BYTE *) wsz,
  626. &cb
  627. ) == ERROR_SUCCESS)
  628. vl.AddPath(wsz);
  629. // close key
  630. RegCloseKey(hkey);
  631. }
  632. // close root key
  633. RegCloseKey(hkeyRoot);
  634. return TRUE;
  635. }
  636. // add volume root of SystemDrive (drive wee boot off of
  637. BOOL AddSystemPartitionRoot(CVolumeList &vl)
  638. {
  639. HKEY hkeySetup;
  640. WCHAR wsz[MAX_PATH];
  641. // open HKLM\System\Setup
  642. if (RegOpenKey(HKEY_LOCAL_MACHINE, x_SetupRoot, &hkeySetup) != ERROR_SUCCESS)
  643. return FALSE;
  644. DWORD cb = sizeof(wsz);
  645. DWORD type;
  646. // query SystemPartition value
  647. if (RegQueryValueEx
  648. (
  649. hkeySetup,
  650. L"SystemPartition",
  651. NULL,
  652. &type,
  653. (BYTE *) wsz,
  654. &cb
  655. ) != ERROR_SUCCESS)
  656. {
  657. // if fails, return FALSE
  658. RegCloseKey(hkeySetup);
  659. return FALSE;
  660. }
  661. // compute size of needed buffer
  662. unsigned cwc = wcslen(wsz);
  663. unsigned cwcNew = x_cwcWin32VolumePrefix + cwc + 1;
  664. LPWSTR wszNew = new WCHAR[cwcNew];
  665. // return failure if memory allocation fials
  666. if (wszNew == NULL)
  667. return FALSE;
  668. // append \\?\GlobalRoot\ to device name
  669. memcpy(wszNew, x_wszWin32VolumePrefix, x_cwcWin32VolumePrefix * sizeof(WCHAR));
  670. memcpy(wszNew + x_cwcWin32VolumePrefix, wsz, cwc * sizeof(WCHAR));
  671. RegCloseKey(hkeySetup);
  672. wszNew[cwcNew-1] = L'\0';
  673. try {
  674. // add path based on device root
  675. vl.AddPath(wszNew);
  676. } catch(...)
  677. {
  678. delete [] wszNew;
  679. return FALSE;
  680. }
  681. // delete allocated memory
  682. delete [] wszNew;
  683. return TRUE;
  684. }
  685. // find critical volumes. Return multistring of volume names
  686. // using guid naming convention
  687. LPWSTR pFindCriticalVolumes()
  688. {
  689. WCHAR wsz[MAX_PATH * 4];
  690. // find location of system root
  691. if (!ExpandEnvironmentStrings(L"%systemroot%", wsz, sizeof(wsz)/sizeof(WCHAR)))
  692. {
  693. wprintf(L"ExpandEnvironmentStrings failed for reason %d", GetLastError());
  694. return NULL;
  695. }
  696. CVolumeList vl;
  697. LPWSTR wszPathsT = NULL;
  698. LPWSTR wszT = NULL;
  699. try
  700. {
  701. // add boot drive
  702. if (!AddSystemPartitionRoot(vl))
  703. return NULL;
  704. // add roots for various services
  705. if (!AddServiceRoots(vl))
  706. return NULL;
  707. // add systemroot drive
  708. vl.AddPath(wsz);
  709. {
  710. // add roots for SYSVOL
  711. CFRSIter fiter;
  712. fiter.Init();
  713. fiter.BeginIteration();
  714. while(TRUE)
  715. {
  716. wszT = fiter.GetNextSet(TRUE, &wszPathsT);
  717. if (wszT == NULL)
  718. break;
  719. vl.AddPath(wszT);
  720. LPWSTR wszPathT = wszPathsT;
  721. while(*wszPathT != NULL)
  722. {
  723. vl.AddPath(wszPathT);
  724. wszPathT += wcslen(wszPathT);
  725. }
  726. delete wszT;
  727. delete wszPathsT;
  728. wszT = NULL;
  729. wszPathsT = NULL;
  730. }
  731. fiter.EndIteration();
  732. }
  733. }
  734. catch(...)
  735. {
  736. delete wszT;
  737. delete wszPathsT;
  738. }
  739. // return volume list
  740. return vl.GetVolumeList();
  741. }