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.

2534 lines
75 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. dr_state.cpp
  5. Abstract:
  6. This module contains routines to query the symbolic names and file system
  7. information of all the volumes on a system, and save them out to an
  8. ASR state file using the ASR api.
  9. Also contains routines to read in the volume information stored in an
  10. ASR state file, and recreate them using appropriate mountmgr calls.
  11. Authors:
  12. Steve DeVos (Veritas) (v-stevde) 15-May-1998
  13. Guhan Suriyanarayanan (guhans) 21-Aug-1999
  14. Environment:
  15. User-mode only.
  16. Revision History:
  17. 15-May-1998 v-stevde Initial creation
  18. 21-Aug-1999 guhans Cleaned up and re-wrote this module.
  19. --*/
  20. #include "stdafx.h"
  21. #include <setupapi.h>
  22. #include <winioctl.h>
  23. #include <mountmgr.h>
  24. #include <winasr.h>
  25. #include <ntddvol.h>
  26. #include "dr_state.h"
  27. #include "resource.h"
  28. #include <clusstor.h> // Cluster API's
  29. #include <resapi.h> // Cluster ResUtilEnumResources
  30. #define ASRFMT_VOLUMES_SECTION L"[ASRFMT.FIXEDVOLUMES]"
  31. #define ASRFMT_VOLUMES_SECTION_NAME L"ASRFMT.FIXEDVOLUMES"
  32. #define ASRFMT_REMOVABLE_MEDIA_SECTION L"[ASRFMT.REMOVABLEMEDIA]"
  33. #define ASRFMT_REMOVABLE_MEDIA_SECTION_NAME L"ASRFMT.REMOVABLEMEDIA"
  34. #define ASRFMT_COMMANDS_ENTRY L"1,3000,0,\"%SystemRoot%\\system32\\asr_fmt.exe\",\"/restore\""
  35. const WCHAR ASRFMT_DEVICEPATH_FORMAT[] = L"\\Device\\Harddisk%d\\Partition%d";
  36. #define ASRFMT_DEVICEPATH_FORMAT_LENGTH 36
  37. const WCHAR ASRFMT_CLUSTER_PHYSICAL_DISK[] = L"Physical Disk";
  38. const WCHAR ASRFMT_ASR_ERROR_FILE_PATH[] = L"%SystemRoot%\\repair\\asr.err";
  39. //
  40. // The following must be Ansi strings
  41. //
  42. const char ASRFMT_CLUSTER_DLL_MODULE_NAME[] = "%SystemRoot%\\system32\\syssetup.dll";
  43. const char ASRFMT_CLUSTER_DLL_PROC_NAME[] = "AsrpGetLocalVolumeInfo";
  44. typedef enum {
  45. mmfUndefined = 0,
  46. mmfGetDeviceName,
  47. mmfDeleteDosName,
  48. mmfDeleteVolumeGuid,
  49. mmfCreateSymbolicLinkName
  50. } ASRFMT_MM_FUNCTION;
  51. HANDLE Gbl_hErrorFile = NULL;
  52. //
  53. // Macro Description:
  54. // This macro wraps calls that are expected to return SUCCESS (retcode).
  55. // If ErrorCondition occurs, it sets the LocalStatus to the ErrorCode
  56. // passed in, calls SetLastError() to set the Last Error to ErrorCode,
  57. // and jumps to the EXIT label in the calling function
  58. //
  59. // Arguments:
  60. // ErrorCondition // Result of some function call or conditional expression.
  61. // LocalStatus // Status variable in the calling function
  62. // LONG ErrorCode // An ErrorCode specific to the error and calling function
  63. //
  64. #define ErrExitCode( ErrorCondition, LocalStatus, ErrorCode ) { \
  65. \
  66. if ((BOOL) ErrorCondition) { \
  67. \
  68. wprintf(L"Line %lu, ErrorCode: %lu, GetLastError:%lu\n", \
  69. __LINE__, ErrorCode, GetLastError()); \
  70. \
  71. LocalStatus = (DWORD) ErrorCode; \
  72. \
  73. SetLastError((DWORD) ErrorCode); \
  74. \
  75. goto EXIT; \
  76. } \
  77. }
  78. //
  79. //
  80. // Forward declarations
  81. //
  82. BOOL
  83. DoMountMgrWork(
  84. IN HANDLE hMountMgr,
  85. IN ASRFMT_MM_FUNCTION mmfFunction,
  86. IN PWSTR lpSymbolicName,
  87. IN PWSTR lpDeviceName
  88. );
  89. PMOUNTMGR_MOUNT_POINTS // Must be freed by caller
  90. GetMountPoints();
  91. //
  92. //
  93. //
  94. VOID
  95. FreeVolumeInfo(
  96. IN OUT PASRFMT_VOLUME_INFO *ppVolume
  97. )
  98. {
  99. PASRFMT_VOLUME_INFO pTemp = NULL;
  100. HANDLE hHeap = GetProcessHeap();
  101. if (ppVolume && *ppVolume) {
  102. pTemp = *ppVolume;
  103. while (*ppVolume) {
  104. pTemp = ((*ppVolume)->pNext);
  105. HeapFree(hHeap, 0L, *ppVolume);
  106. *ppVolume = pTemp;
  107. }
  108. }
  109. }
  110. VOID
  111. FreeRemovableMediaInfo(
  112. IN OUT PASRFMT_REMOVABLE_MEDIA_INFO *ppMedia
  113. )
  114. {
  115. PASRFMT_REMOVABLE_MEDIA_INFO pTemp = NULL;
  116. HANDLE hHeap = GetProcessHeap();
  117. if (ppMedia && *ppMedia) {
  118. pTemp = *ppMedia;
  119. while (*ppMedia) {
  120. pTemp = (*ppMedia)->pNext;
  121. HeapFree(hHeap, 0L, *ppMedia);
  122. *ppMedia = pTemp;
  123. }
  124. }
  125. }
  126. VOID
  127. FreeStateInfo(
  128. IN OUT PASRFMT_STATE_INFO *ppState
  129. )
  130. {
  131. if (ppState && *ppState) {
  132. FreeVolumeInfo(&((*ppState)->pVolume));
  133. FreeRemovableMediaInfo(&((*ppState)->pRemovableMedia));
  134. HeapFree(GetProcessHeap(), 0L, (*ppState));
  135. *ppState = NULL;
  136. }
  137. }
  138. /**********************
  139. NAME : ReadStateInfo
  140. **********************/
  141. BOOL
  142. ReadStateInfo(
  143. IN PCWSTR lpwszFilePath,
  144. OUT PASRFMT_STATE_INFO *ppState
  145. )
  146. {
  147. DWORD dwStatus = ERROR_SUCCESS;
  148. HINF hSif = NULL;
  149. BOOL bResult = TRUE;
  150. HANDLE hHeap = NULL;
  151. PASRFMT_VOLUME_INFO pNewVolume = NULL;
  152. PASRFMT_REMOVABLE_MEDIA_INFO pNewMedia = NULL;
  153. INFCONTEXT infVolumeContext,
  154. infMediaContext;
  155. hHeap = GetProcessHeap();
  156. //
  157. // Release the ppState if necessary, and allocate memory.
  158. //
  159. if (*ppState) {
  160. FreeStateInfo(ppState);
  161. }
  162. *ppState = (PASRFMT_STATE_INFO) HeapAlloc(
  163. hHeap,
  164. HEAP_ZERO_MEMORY,
  165. sizeof(ASRFMT_STATE_INFO)
  166. );
  167. ErrExitCode(!(*ppState), dwStatus, ERROR_NOT_ENOUGH_MEMORY);
  168. //
  169. // Open asr.sif
  170. //
  171. hSif = SetupOpenInfFile(
  172. lpwszFilePath,
  173. NULL,
  174. INF_STYLE_WIN4,
  175. NULL
  176. );
  177. ErrExitCode((!hSif || INVALID_HANDLE_VALUE == hSif), dwStatus, GetLastError());
  178. //
  179. // Read in the [VOLUMES] section
  180. //
  181. bResult = SetupFindFirstLineW(hSif, ASRFMT_VOLUMES_SECTION_NAME, NULL, &infVolumeContext);
  182. while (bResult) {
  183. //
  184. // Create a new volumeInfo struct
  185. //
  186. pNewVolume = (PASRFMT_VOLUME_INFO) HeapAlloc(
  187. hHeap,
  188. HEAP_ZERO_MEMORY,
  189. sizeof(ASRFMT_VOLUME_INFO)
  190. );
  191. ErrExitCode(!pNewVolume, dwStatus, ERROR_NOT_ENOUGH_MEMORY);
  192. //
  193. // Read in the information. The VOLUMES section contains:
  194. // [VOLUMES]
  195. // 0.volume-key = 1.system-key, 2."volume-guid", 3."dos-drive-letter",
  196. // 4."FS-Type", 5."volume-label", 6."fs-cluster-size"
  197. //
  198. SetupGetIntField(&infVolumeContext, 0, (PINT) (&pNewVolume->dwIndex));
  199. SetupGetStringField(&infVolumeContext, 2, pNewVolume->szGuid, sizeof(pNewVolume->szGuid) / sizeof(WCHAR), NULL);
  200. SetupGetStringField(&infVolumeContext, 3, pNewVolume->szDosPath, sizeof(pNewVolume->szDosPath) / sizeof(WCHAR), NULL);
  201. SetupGetStringField(&infVolumeContext, 4, pNewVolume->szFsName, sizeof(pNewVolume->szFsName) / sizeof(WCHAR), NULL);
  202. SetupGetStringField(&infVolumeContext, 5, pNewVolume->szLabel, sizeof(pNewVolume->szLabel) / sizeof(WCHAR), NULL);
  203. SetupGetIntField(&infVolumeContext, 6, (PINT) (&pNewVolume->dwClusterSize));
  204. //
  205. // Add this to our list
  206. //
  207. pNewVolume->pNext = (*ppState)->pVolume;
  208. (*ppState)->pVolume = pNewVolume;
  209. (*ppState)->countVolume += 1;
  210. bResult = SetupFindNextLine(&infVolumeContext, &infVolumeContext);
  211. }
  212. //
  213. // Read in the [REMOVABLEMEDIA] section
  214. //
  215. bResult = SetupFindFirstLineW(hSif, ASRFMT_REMOVABLE_MEDIA_SECTION_NAME, NULL, &infMediaContext);
  216. while (bResult) {
  217. //
  218. // Create a new REMOVALBLE_MEDIA struct
  219. //
  220. pNewMedia = (PASRFMT_REMOVABLE_MEDIA_INFO) HeapAlloc(
  221. hHeap,
  222. HEAP_ZERO_MEMORY,
  223. sizeof(ASRFMT_REMOVABLE_MEDIA_INFO)
  224. );
  225. ErrExitCode(!pNewMedia, dwStatus, ERROR_NOT_ENOUGH_MEMORY);
  226. //
  227. // Read in the information. The REMOVABLEMEDIA section contains:
  228. //
  229. // [REMOVABLEMEDIA]
  230. // 0.rm-key = 1.system-key, 2."device-path", 3."volume-guid",
  231. // 4."dos-drive-letter"
  232. //
  233. SetupGetIntField(&infMediaContext, 0, (PINT)(&pNewMedia->dwIndex));
  234. SetupGetStringField(&infMediaContext, 2, pNewMedia->szDevicePath, sizeof(pNewMedia->szDevicePath) / sizeof(WCHAR), NULL);
  235. SetupGetStringField(&infMediaContext, 3, pNewMedia->szVolumeGuid, sizeof(pNewMedia->szVolumeGuid) / sizeof(WCHAR), NULL);
  236. SetupGetStringField(&infMediaContext, 4, pNewMedia->szDosPath, sizeof(pNewMedia->szDosPath) / sizeof(WCHAR), NULL);
  237. //
  238. // Add this to our list
  239. //
  240. pNewMedia->pNext = (*ppState)->pRemovableMedia;
  241. (*ppState)->pRemovableMedia = pNewMedia;
  242. (*ppState)->countMedia += 1;
  243. bResult = SetupFindNextLine(&infMediaContext, &infMediaContext);
  244. }
  245. EXIT:
  246. //
  247. // Set the state pointer to null on failure
  248. //
  249. if (dwStatus != ERROR_SUCCESS) {
  250. if (ppState && *ppState) {
  251. FreeStateInfo(ppState);
  252. }
  253. }
  254. if (hSif && (INVALID_HANDLE_VALUE != hSif)) {
  255. SetupCloseInfFile(hSif);
  256. }
  257. return (BOOL) (ERROR_SUCCESS == dwStatus);
  258. }
  259. //
  260. // WriteStateInfo
  261. //
  262. // This writes out the volumes and removablemedia sections, using
  263. // AsrAddSifEntry. If the write is successful, or there's nothing
  264. // to write, it returns TRUE.
  265. //
  266. BOOL
  267. WriteStateInfo(
  268. IN DWORD_PTR AsrContext, // AsrContext to pass in to AsrAddSifEntry
  269. IN PASRFMT_STATE_INFO pState // data to write.
  270. )
  271. {
  272. WCHAR szSifEntry[ASR_SIF_ENTRY_MAX_CHARS + 1];
  273. DWORD dwIndex = 1;
  274. BOOL bResult = TRUE;
  275. PASRFMT_VOLUME_INFO pVolume = NULL;
  276. PASRFMT_REMOVABLE_MEDIA_INFO pMedia = NULL;
  277. if (!pState) {
  278. //
  279. // Nothing to write
  280. //
  281. return TRUE;
  282. }
  283. bResult = AsrAddSifEntry(
  284. AsrContext,
  285. L"[COMMANDS]", // ASR_SIF_COMMANDS_SECTION_NAME,
  286. ASRFMT_COMMANDS_ENTRY
  287. );
  288. if (!bResult) {
  289. GetLastError(); // for debug
  290. return FALSE;
  291. }
  292. //
  293. // The [ASRFMT.FIXEDVOLUMES] section
  294. //
  295. pVolume = pState->pVolume;
  296. dwIndex = 1;
  297. while (pVolume) {
  298. //
  299. // Write out the information. The VOLUMES section contains:
  300. // [ASRFMT.FIXEDVOLUMES]
  301. // 0.volume-key = 1.system-key, 2."volume-guid", 3."dos-drive-letter",
  302. // 4.FS-Type, 5."volume-label", 6."fs-cluster-size"
  303. //
  304. // form the string
  305. swprintf(
  306. szSifEntry,
  307. (PCWSTR) L"%d=1,\"%ws\",\"%ws\",%ws,\"%ws\",0x%x",
  308. dwIndex,
  309. pVolume->szGuid,
  310. (pVolume->szDosPath ? pVolume->szDosPath : L""),
  311. pVolume->szFsName,
  312. pVolume->szLabel,
  313. pVolume->dwClusterSize
  314. );
  315. bResult = AsrAddSifEntry(
  316. AsrContext,
  317. ASRFMT_VOLUMES_SECTION,
  318. szSifEntry
  319. );
  320. if (!bResult) {
  321. GetLastError(); // for debug
  322. return FALSE;
  323. }
  324. ++dwIndex;
  325. pVolume = pVolume->pNext;
  326. }
  327. //
  328. // The [REMOVABLEMEDIA] section
  329. //
  330. pMedia = pState->pRemovableMedia;
  331. dwIndex = 1;
  332. while (pMedia) {
  333. //
  334. // Write out the information. The REMOVABLEMEDIA section contains:
  335. //
  336. // [ASRFMT.REMOVABLEMEDIA]
  337. // 0.rm-key = 1.system-key, 2."device-path", 3."volume-guid",
  338. // 4."dos-drive-letter"
  339. //
  340. // form the string
  341. swprintf(
  342. szSifEntry,
  343. (PCWSTR) L"%d=1,\"%ws\",\"%ws\",\"%ws\"",
  344. dwIndex,
  345. pMedia->szDevicePath,
  346. pMedia->szVolumeGuid,
  347. (pMedia->szDosPath ? pMedia->szDosPath : L"")
  348. );
  349. bResult = AsrAddSifEntry(
  350. AsrContext,
  351. ASRFMT_REMOVABLE_MEDIA_SECTION,
  352. szSifEntry
  353. );
  354. if (!bResult) {
  355. GetLastError(); // for debug
  356. return FALSE;
  357. }
  358. ++dwIndex;
  359. pMedia = pMedia->pNext;
  360. }
  361. return TRUE;
  362. }
  363. BOOL
  364. GetVolumeDetails(
  365. IN PWSTR lpVolumeGuid,
  366. OUT PWSTR lpFsName,
  367. IN DWORD cchFsName,
  368. OUT PWSTR lpVolumeLabel,
  369. IN DWORD cchVolumeLabel,
  370. OUT LPDWORD lpClusterSize
  371. )
  372. {
  373. DWORD dwFSFlags = 0,
  374. dwSectorsPerCluster = 0,
  375. dwBytesPerSector = 0,
  376. dwNumFreeClusters = 0,
  377. dwTotalNumClusters = 0;
  378. BOOL result1 = TRUE,
  379. result2 = TRUE;
  380. *lpFsName = 0;
  381. *lpVolumeLabel = 0;
  382. *lpClusterSize = 0;
  383. SetErrorMode(SEM_FAILCRITICALERRORS);
  384. result1 = GetVolumeInformation(lpVolumeGuid,
  385. lpVolumeLabel,
  386. cchVolumeLabel,
  387. NULL, // no need for serial number
  388. NULL, // max file name length
  389. &dwFSFlags, // !! we might need to store some of this ...
  390. lpFsName,
  391. cchFsName
  392. );
  393. result2 = GetDiskFreeSpace(lpVolumeGuid,
  394. &dwSectorsPerCluster,
  395. &dwBytesPerSector,
  396. &dwNumFreeClusters,
  397. &dwTotalNumClusters
  398. );
  399. *lpClusterSize = dwSectorsPerCluster * dwBytesPerSector;
  400. return (result1 && result2);
  401. }
  402. BOOL
  403. AddSortedVolumeInfo(
  404. IN OUT PASRFMT_VOLUME_INFO *ppHead,
  405. IN PASRFMT_VOLUME_INFO pNew
  406. )
  407. {
  408. if (!pNew) {
  409. ASSERT(0 && L"Trying to add a null volume");
  410. return TRUE;
  411. }
  412. pNew->pNext = *ppHead;
  413. (*ppHead) = pNew;
  414. return TRUE;
  415. }
  416. BOOL
  417. AddSortedRemovableMediaInfo(
  418. IN OUT PASRFMT_REMOVABLE_MEDIA_INFO *ppHead,
  419. IN PASRFMT_REMOVABLE_MEDIA_INFO pNew
  420. )
  421. {
  422. if (!pNew) {
  423. ASSERT(0 && L"Trying to add a null Removable Media");
  424. return TRUE;
  425. }
  426. pNew->pNext = *ppHead;
  427. (*ppHead) = pNew;
  428. return TRUE;
  429. }
  430. typedef struct _ASRFMT_MP_LINK {
  431. PWSTR pLink;
  432. USHORT cchLink;
  433. struct _ASRFMT_MP_LINK *pNext;
  434. } ASRFMT_MP_LINK, *PASRFMT_MP_LINK;
  435. typedef struct _ASRFMT_MOUNT_POINTS_INFO {
  436. struct _ASRFMT_MOUNT_POINTS_INFO *pNext;
  437. //
  438. // Device Path, of the form \Device\HarddiskVolume1
  439. //
  440. PWSTR pDeviceName;
  441. //
  442. // VolumeGuid for this volume (\??\Volume{GUID})
  443. //
  444. PWSTR pVolumeGuid;
  445. //
  446. // Additional symbolic links to this volume: including
  447. // DOS Drive letter (\DosDevices\C:) and additional Volume
  448. // Guids (\??\Volume{GUID})
  449. //
  450. PASRFMT_MP_LINK pSymbolicLinks;
  451. PVOID lpBufferToFree;
  452. DWORD dwClusterSize;
  453. USHORT cchDeviceName;
  454. USHORT cchVolumeGuid;
  455. BOOL IsClusterShared;
  456. WCHAR szFsName[MAX_PATH + 1];
  457. WCHAR szLabel[MAX_PATH + 1];
  458. } ASRFMT_MOUNT_POINTS_INFO, *PASRFMT_MOUNT_POINTS_INFO;
  459. VOID
  460. FreeLink(
  461. IN PASRFMT_MP_LINK *ppLink
  462. )
  463. {
  464. PASRFMT_MP_LINK pTemp = NULL,
  465. pCurrent = (*ppLink);
  466. HANDLE hHeap = GetProcessHeap();
  467. while (pCurrent) {
  468. pTemp = pCurrent->pNext;
  469. HeapFree(hHeap, 0L, pCurrent);
  470. pCurrent = pTemp;
  471. }
  472. *ppLink = NULL;
  473. }
  474. VOID
  475. FreeMpInfo(
  476. IN PASRFMT_MOUNT_POINTS_INFO *ppMpInfo
  477. )
  478. {
  479. PASRFMT_MOUNT_POINTS_INFO pTemp = NULL,
  480. pCurrent = (*ppMpInfo);
  481. HANDLE hHeap = GetProcessHeap();
  482. while (pCurrent) {
  483. if (pCurrent->pSymbolicLinks) {
  484. FreeLink(&(pCurrent->pSymbolicLinks));
  485. }
  486. if (pCurrent->lpBufferToFree) {
  487. HeapFree(hHeap, 0L, (pCurrent->lpBufferToFree));
  488. pCurrent->lpBufferToFree = NULL;
  489. }
  490. pTemp = pCurrent->pNext;
  491. HeapFree(hHeap, 0L, pCurrent);
  492. pCurrent = pTemp;
  493. }
  494. *ppMpInfo = NULL;
  495. }
  496. BOOL
  497. AddSymbolicLink(
  498. IN PASRFMT_MOUNT_POINTS_INFO pMpInfoList,
  499. IN PWSTR lpDeviceName,
  500. IN USHORT cchDeviceName,
  501. IN PWSTR lpSymbolicLink,
  502. IN USHORT cchSymbolicLink,
  503. IN PVOID lpBufferToFree
  504. )
  505. {
  506. BOOL foundAMatch = FALSE;
  507. HANDLE hHeap = GetProcessHeap();
  508. PASRFMT_MOUNT_POINTS_INFO pMp = NULL;
  509. DWORD dwStatus = ERROR_SUCCESS;
  510. if (!pMpInfoList) {
  511. return FALSE;
  512. }
  513. pMp = pMpInfoList;
  514. while (pMp && !foundAMatch) {
  515. if ((pMp->pDeviceName) && // Node has a device name
  516. (cchDeviceName == pMp->cchDeviceName) && // lengths are equal
  517. !wcsncmp(pMp->pDeviceName, lpDeviceName, cchDeviceName)) { // strings match
  518. //
  519. // We already have a node for this device name.
  520. //
  521. if (!wcsncmp(ASRFMT_WSZ_VOLUME_GUID_PREFIX, lpSymbolicLink, ASRFMT_CB_VOLUME_GUID_PREFIX/sizeof(WCHAR))
  522. && !(pMp->pVolumeGuid)
  523. ) {
  524. //
  525. // This symbolic link looks like a volume GUID, and this node
  526. // doesn't already have a pVolumeGuid set.
  527. //
  528. pMp->pVolumeGuid = lpSymbolicLink;
  529. pMp->cchVolumeGuid = cchSymbolicLink;
  530. }
  531. else {
  532. //
  533. // Either the node already has a pVolumeGuid set, or the
  534. // symbolic link doesn't look like a volume Guid. So it
  535. // must be a new symbolic link.
  536. //
  537. PASRFMT_MP_LINK pNewLink = (PASRFMT_MP_LINK) HeapAlloc(
  538. hHeap,
  539. HEAP_ZERO_MEMORY,
  540. sizeof(ASRFMT_MP_LINK)
  541. );
  542. ErrExitCode(!pNewLink, dwStatus, ERROR_NOT_ENOUGH_MEMORY);
  543. pNewLink->pNext = pMp->pSymbolicLinks;
  544. pMp->pSymbolicLinks = pNewLink;
  545. pNewLink->pLink = lpSymbolicLink;
  546. pNewLink->cchLink = cchSymbolicLink;
  547. }
  548. foundAMatch = TRUE;
  549. }
  550. pMp = pMp->pNext;
  551. }
  552. if (!foundAMatch) {
  553. if (pMpInfoList->pDeviceName) {
  554. //
  555. // pMpInfoList is already taken
  556. //
  557. pMp = (PASRFMT_MOUNT_POINTS_INFO) HeapAlloc(
  558. hHeap,
  559. HEAP_ZERO_MEMORY,
  560. sizeof(ASRFMT_MOUNT_POINTS_INFO)
  561. );
  562. ErrExitCode(!pMp, dwStatus, ERROR_NOT_ENOUGH_MEMORY);
  563. pMp->pNext = pMpInfoList->pNext;
  564. pMpInfoList->pNext = pMp;
  565. }
  566. else {
  567. pMp = pMpInfoList;
  568. }
  569. pMp->pDeviceName = lpDeviceName;
  570. pMp->cchDeviceName = cchDeviceName;
  571. pMp->lpBufferToFree = lpBufferToFree;
  572. //
  573. // Add the symbolic link to this new device
  574. //
  575. AddSymbolicLink(pMp, lpDeviceName, cchDeviceName, lpSymbolicLink, cchSymbolicLink, lpBufferToFree);
  576. }
  577. EXIT:
  578. return (BOOL)(ERROR_SUCCESS == dwStatus);
  579. }
  580. //
  581. // The following two definitions are also in syssetup:asrclus.cpp. This MUST be
  582. // kept in sync.
  583. //
  584. typedef struct _ASRFMT_CLUSTER_VOLUME_INFO {
  585. UINT driveType;
  586. DWORD PartitionNumber;
  587. ULONG FsNameOffset;
  588. USHORT FsNameLength;
  589. ULONG LabelOffset;
  590. USHORT LabelLength;
  591. ULONG SymbolicNamesOffset;
  592. USHORT SymbolicNamesLength;
  593. DWORD dwClusterSize;
  594. } ASRFMT_CLUSTER_VOLUME_INFO, *PASRFMT_CLUSTER_VOLUME_INFO;
  595. typedef struct _ASRFMT_CLUSTER_VOLUMES_TABLE {
  596. DWORD DiskSignature;
  597. DWORD NumberOfEntries;
  598. ASRFMT_CLUSTER_VOLUME_INFO VolumeInfoEntry[1];
  599. } ASRFMT_CLUSTER_VOLUMES_TABLE, *PASRFMT_CLUSTER_VOLUMES_TABLE;
  600. BOOL
  601. GetVolumeDevicePath(
  602. IN PCWSTR lpPartitionDevicePath,
  603. IN CONST cbPartitionDevicePath,
  604. OUT PWSTR *lpVolumeDevicePath
  605. )
  606. {
  607. PMOUNTMGR_MOUNT_POINT mountPointIn = NULL;
  608. PMOUNTMGR_MOUNT_POINTS mountPointsOut = NULL;
  609. MOUNTMGR_MOUNT_POINTS mountPointsTemp;
  610. DWORD mountPointsSize = 0;
  611. HANDLE mpHandle = NULL;
  612. HANDLE heapHandle = NULL;
  613. ULONG index = 0;
  614. LONG status = ERROR_SUCCESS;
  615. BOOL result = FALSE;
  616. memset(&mountPointsTemp, 0L, sizeof(MOUNTMGR_MOUNT_POINTS));
  617. //
  618. // set OUT variables to known values.
  619. //
  620. *lpVolumeDevicePath = NULL;
  621. heapHandle = GetProcessHeap();
  622. ASSERT(heapHandle);
  623. //
  624. // Open the mount manager, and get the devicepath for this partition
  625. //
  626. // allocate memory for the mount point input structure
  627. mountPointIn = (PMOUNTMGR_MOUNT_POINT) HeapAlloc(
  628. heapHandle,
  629. HEAP_ZERO_MEMORY,
  630. sizeof (MOUNTMGR_MOUNT_POINT) + cbPartitionDevicePath
  631. );
  632. ErrExitCode(!mountPointIn, status, ERROR_NOT_ENOUGH_MEMORY);
  633. // get a handle to the mount manager
  634. mpHandle = CreateFileW(
  635. (PCWSTR) MOUNTMGR_DOS_DEVICE_NAME,
  636. 0,
  637. FILE_SHARE_READ | FILE_SHARE_WRITE,
  638. NULL,
  639. OPEN_EXISTING,
  640. FILE_ATTRIBUTE_NORMAL,
  641. INVALID_HANDLE_VALUE
  642. );
  643. ErrExitCode((!mpHandle || INVALID_HANDLE_VALUE == mpHandle), status, GetLastError());
  644. // put the DeviceName right after struct mountPointIn
  645. wcsncpy((PWSTR) (mountPointIn + 1), lpPartitionDevicePath, (cbPartitionDevicePath / sizeof(WCHAR)) - 1);
  646. mountPointIn->DeviceNameOffset = sizeof(*mountPointIn);
  647. mountPointIn->DeviceNameLength = (USHORT) (cbPartitionDevicePath - sizeof(WCHAR));
  648. // this call should fail with ERROR_MORE_DATA
  649. result = DeviceIoControl(
  650. mpHandle,
  651. IOCTL_MOUNTMGR_QUERY_POINTS,
  652. mountPointIn,
  653. sizeof(*mountPointIn) + mountPointIn->DeviceNameLength,
  654. &mountPointsTemp,
  655. sizeof(mountPointsTemp),
  656. &mountPointsSize,
  657. NULL
  658. );
  659. if (!result) {
  660. status = GetLastError();
  661. // if buffer is of insufficient size, resize the buffer.
  662. if (ERROR_MORE_DATA == status ||
  663. ERROR_INSUFFICIENT_BUFFER == status ||
  664. ERROR_BAD_LENGTH == status
  665. ) {
  666. status = ERROR_SUCCESS;
  667. mountPointsOut = (PMOUNTMGR_MOUNT_POINTS) HeapAlloc(
  668. heapHandle,
  669. HEAP_ZERO_MEMORY,
  670. mountPointsTemp.Size
  671. );
  672. ErrExitCode(!mountPointsOut, status, ERROR_NOT_ENOUGH_MEMORY);
  673. }
  674. else {
  675. //
  676. // If some other error occurred, EXIT.
  677. // This is not a fatal error in the case of removable storage media
  678. //
  679. ErrExitCode(status, status, ERROR_SUCCESS);
  680. }
  681. }
  682. else {
  683. //
  684. // the call succeeded when we expected it to fail--something's wrong.
  685. // This is not a fatal error in the case of removable storage media.
  686. //
  687. ErrExitCode(result, status, ERROR_SUCCESS);
  688. }
  689. result = DeviceIoControl(
  690. mpHandle,
  691. IOCTL_MOUNTMGR_QUERY_POINTS,
  692. mountPointIn,
  693. sizeof(*mountPointIn) + mountPointIn->DeviceNameLength,
  694. mountPointsOut,
  695. mountPointsTemp.Size,
  696. &mountPointsSize,
  697. NULL
  698. );
  699. ErrExitCode((!mountPointsSize || !result), status, GetLastError());
  700. (*lpVolumeDevicePath) = (PWSTR) HeapAlloc(
  701. heapHandle,
  702. HEAP_ZERO_MEMORY,
  703. mountPointsOut->MountPoints[0].DeviceNameLength + sizeof(WCHAR)
  704. );
  705. ErrExitCode(!(*lpVolumeDevicePath), status, ERROR_NOT_ENOUGH_MEMORY);
  706. //
  707. // Get the Device Path returned
  708. //
  709. CopyMemory((*lpVolumeDevicePath),
  710. (PWSTR) (((LPBYTE) mountPointsOut) + mountPointsOut->MountPoints[index].SymbolicLinkNameOffset),
  711. mountPointsOut->MountPoints[0].DeviceNameLength
  712. );
  713. EXIT:
  714. //
  715. // Free up locally allocated data
  716. //
  717. if (mountPointIn) {
  718. HeapFree(heapHandle, 0L, mountPointIn);
  719. mountPointIn = NULL;
  720. }
  721. if (mountPointsOut) {
  722. HeapFree(heapHandle, 0L, mountPointsOut);
  723. mountPointsOut = NULL;
  724. }
  725. if (status != ERROR_SUCCESS) {
  726. if (*lpVolumeDevicePath) {
  727. HeapFree(heapHandle, 0L, (*lpVolumeDevicePath));
  728. }
  729. }
  730. if ((mpHandle) && (INVALID_HANDLE_VALUE != mpHandle)) {
  731. CloseHandle(mpHandle);
  732. }
  733. return (BOOL) (status == ERROR_SUCCESS);
  734. }
  735. BOOL
  736. AddClusterInfoToMountPoints(
  737. IN PASRFMT_MOUNT_POINTS_INFO pMpInfoList,
  738. IN PCWSTR lpDeviceName,
  739. IN BOOL bIsClusterShared,
  740. IN PCWSTR lpFsName,
  741. IN DWORD cchFsName,
  742. IN PCWSTR lpLabel,
  743. IN DWORD cchLabel,
  744. IN DWORD dwClusterSize
  745. )
  746. {
  747. BOOL foundAMatch = FALSE;
  748. PASRFMT_MOUNT_POINTS_INFO pMp = NULL;
  749. if (!pMpInfoList) {
  750. return FALSE;
  751. }
  752. pMp = pMpInfoList;
  753. while (pMp && !foundAMatch) {
  754. if ((pMp->pDeviceName) &&
  755. (pMp->cchDeviceName == wcslen(lpDeviceName)) &&
  756. !(wcsncmp(pMp->pDeviceName, lpDeviceName, pMp->cchDeviceName))) {
  757. //
  758. // This is the correct node, copy over the info .
  759. //
  760. pMp->IsClusterShared = bIsClusterShared;
  761. wcsncpy(pMp->szFsName, lpFsName, cchFsName);
  762. wcsncpy(pMp->szLabel, lpLabel, cchLabel);
  763. pMp->dwClusterSize = dwClusterSize;
  764. foundAMatch = TRUE;
  765. }
  766. pMp = pMp->pNext;
  767. }
  768. return foundAMatch;
  769. }
  770. //
  771. // Sanity checks to see if all the offsets in the table are
  772. // inside the buffer
  773. //
  774. DWORD
  775. AsrfmtpSanityCheckClusterTable(
  776. IN PASRFMT_CLUSTER_VOLUMES_TABLE pClusterVolTable,
  777. IN CONST DWORD dwBufferSize
  778. )
  779. {
  780. DWORD dwCount = 0;
  781. if ((sizeof(ASRFMT_CLUSTER_VOLUMES_TABLE) +
  782. (sizeof(ASRFMT_CLUSTER_VOLUME_INFO) * (pClusterVolTable->NumberOfEntries - 1))) > dwBufferSize) {
  783. return ERROR_INVALID_DATA;
  784. }
  785. for (dwCount = 0; dwCount < pClusterVolTable->NumberOfEntries; dwCount++) {
  786. if ((pClusterVolTable->VolumeInfoEntry[dwCount].FsNameOffset +
  787. pClusterVolTable->VolumeInfoEntry[dwCount].FsNameLength) > dwBufferSize) {
  788. return ERROR_INVALID_DATA;
  789. }
  790. if ((pClusterVolTable->VolumeInfoEntry[dwCount].LabelOffset +
  791. pClusterVolTable->VolumeInfoEntry[dwCount].LabelLength) > dwBufferSize) {
  792. return ERROR_INVALID_DATA;
  793. }
  794. if ((pClusterVolTable->VolumeInfoEntry[dwCount].SymbolicNamesLength +
  795. pClusterVolTable->VolumeInfoEntry[dwCount].SymbolicNamesOffset) > dwBufferSize) {
  796. return ERROR_INVALID_DATA;
  797. }
  798. }
  799. return ERROR_SUCCESS;
  800. }
  801. //
  802. // Enums the cluster disks, and for each disk,
  803. // calls across to syssetup!XYZ on the owner node.
  804. //
  805. // Which then goes through all the partitions on the disk,
  806. // gets the volume info for each partition on the disk,
  807. // and passes back the signature and other relevant
  808. // volume info for each partition.
  809. //
  810. // This struct then gets the local disk number for the
  811. // disk, gets the volume guid for that partition, and
  812. // adds in volume nodes for the partition.
  813. //
  814. DWORD
  815. ResourceCallBack(
  816. IN HRESOURCE hOriginal,
  817. IN HRESOURCE hResource,
  818. IN PVOID lpParams
  819. )
  820. {
  821. DISK_DLL_EXTENSION_INFO inBuffer;
  822. PBYTE outBuffer = NULL;
  823. DWORD sizeOutBuffer = 0,
  824. bytesReturned = 0;
  825. DWORD status = ERROR_SUCCESS;
  826. PASRFMT_MOUNT_POINTS_INFO pMountPoints = NULL;
  827. PASRFMT_CLUSTER_VOLUMES_TABLE pClusterVolTable = NULL;
  828. WCHAR szPartitionDevicePath[ASRFMT_DEVICEPATH_FORMAT_LENGTH];
  829. HANDLE heapHandle = NULL;
  830. BOOL done = FALSE,
  831. result = TRUE;
  832. DWORD dwCount = 0;
  833. PWSTR lpDevicePath = NULL,
  834. symbolicLink = NULL,
  835. lpFsName = NULL,
  836. lpLabel = NULL;
  837. USHORT cchFsName = 0,
  838. cchLabel = 0,
  839. cchDevicePath = 0,
  840. cchSymbolicLink = 0;
  841. DWORD dwClusterSize = 0;
  842. if (!lpParams) {
  843. //
  844. // The system must have at least one mount point that has been enumerated
  845. // already (the system volume, at least!), so our mount point list shouldn't be NULL.
  846. //
  847. ASSERT(0);
  848. return ERROR_INVALID_PARAMETER;
  849. }
  850. memset(szPartitionDevicePath, 0L, (ASRFMT_DEVICEPATH_FORMAT_LENGTH)*sizeof(WCHAR));
  851. heapHandle = GetProcessHeap();
  852. pMountPoints = (PASRFMT_MOUNT_POINTS_INFO) lpParams;
  853. //
  854. // Allocate a reasonably-sized memory for the out buffer. If this isn't
  855. // big enough, we'll re-allocate.
  856. //
  857. sizeOutBuffer = 4096;
  858. outBuffer = (PBYTE) HeapAlloc(
  859. heapHandle,
  860. HEAP_ZERO_MEMORY,
  861. sizeOutBuffer
  862. );
  863. ErrExitCode(!outBuffer, status, ERROR_NOT_ENOUGH_MEMORY);
  864. //
  865. // Call AsrGetVolumeInfo on the node owning this disk resource
  866. //
  867. ZeroMemory(&inBuffer, sizeof(inBuffer));
  868. inBuffer.MajorVersion = NT5_MAJOR_VERSION;
  869. strcpy(inBuffer.DllModuleName, ASRFMT_CLUSTER_DLL_MODULE_NAME);
  870. strcpy(inBuffer.DllProcName, ASRFMT_CLUSTER_DLL_PROC_NAME);
  871. status = ClusterResourceControl(
  872. hResource,
  873. NULL,
  874. CLUSCTL_RESOURCE_STORAGE_DLL_EXTENSION,
  875. &inBuffer,
  876. sizeof(DISK_DLL_EXTENSION_INFO),
  877. (PVOID) outBuffer,
  878. sizeOutBuffer,
  879. &bytesReturned
  880. );
  881. if (ERROR_INSUFFICIENT_BUFFER == status) {
  882. //
  883. // The buffer wasn't big enough, re-allocate as needed
  884. //
  885. HeapFree(heapHandle, 0L, outBuffer);
  886. sizeOutBuffer = bytesReturned;
  887. outBuffer = (PBYTE) HeapAlloc(
  888. heapHandle,
  889. HEAP_ZERO_MEMORY,
  890. sizeOutBuffer
  891. );
  892. ErrExitCode(!outBuffer, status, ERROR_NOT_ENOUGH_MEMORY);
  893. status = ClusterResourceControl(
  894. hResource,
  895. NULL,
  896. CLUSCTL_RESOURCE_STORAGE_DLL_EXTENSION,
  897. &inBuffer,
  898. sizeof(DISK_DLL_EXTENSION_INFO),
  899. (PVOID) outBuffer,
  900. sizeOutBuffer,
  901. &bytesReturned
  902. );
  903. }
  904. ErrExitCode((ERROR_SUCCESS != status), status, status);
  905. pClusterVolTable = (PASRFMT_CLUSTER_VOLUMES_TABLE) outBuffer;
  906. //
  907. // Sanity check to see if all the offsets in the table are
  908. // inside the buffer
  909. //
  910. status = AsrfmtpSanityCheckClusterTable(pClusterVolTable, sizeOutBuffer);
  911. ErrExitCode((ERROR_SUCCESS != status), status, status);
  912. //
  913. // Go through the Volume info entries for each partition, and copy over the
  914. // info to the appropriate MpInfo node
  915. //
  916. for (dwCount = 0; dwCount < pClusterVolTable->NumberOfEntries; dwCount++) {
  917. lpFsName = (PWSTR) (((LPBYTE)pClusterVolTable) + pClusterVolTable->VolumeInfoEntry[dwCount].FsNameOffset);
  918. cchFsName = pClusterVolTable->VolumeInfoEntry[dwCount].FsNameLength / sizeof (WCHAR);
  919. lpLabel = (PWSTR) (((LPBYTE)pClusterVolTable) + pClusterVolTable->VolumeInfoEntry[dwCount].LabelOffset);
  920. cchLabel = pClusterVolTable->VolumeInfoEntry[dwCount].LabelLength / sizeof (WCHAR);
  921. dwClusterSize = (DWORD) (pClusterVolTable->VolumeInfoEntry[dwCount].dwClusterSize);
  922. if (!(pClusterVolTable->VolumeInfoEntry[dwCount].SymbolicNamesOffset)) {
  923. continue;
  924. }
  925. //
  926. // This is a "fake" device path (that is actually the first symbolic link), since
  927. // absolute device paths for volumes on remote nodes are not relevant on local node.
  928. //
  929. lpDevicePath = (PWSTR) (((LPBYTE)pClusterVolTable) + pClusterVolTable->VolumeInfoEntry[dwCount].SymbolicNamesOffset);
  930. cchDevicePath = (USHORT) wcslen(lpDevicePath);
  931. AddSymbolicLink(pMountPoints, lpDevicePath, cchDevicePath, lpDevicePath, cchDevicePath, (LPVOID)outBuffer);
  932. //
  933. // Add VolumeInfo to pMountPoints DevicePath;
  934. //
  935. result = AddClusterInfoToMountPoints(
  936. pMountPoints,
  937. lpDevicePath,
  938. TRUE, // IsClusterShared
  939. lpFsName,
  940. cchFsName,
  941. lpLabel,
  942. cchLabel,
  943. dwClusterSize
  944. );
  945. ASSERT(result);
  946. symbolicLink = (PWSTR) ((LPBYTE)lpDevicePath + (sizeof(WCHAR) * (cchDevicePath + 1)));
  947. while (*symbolicLink) {
  948. cchSymbolicLink = (USHORT) wcslen(symbolicLink);
  949. AddSymbolicLink(pMountPoints, lpDevicePath, cchDevicePath, symbolicLink, cchSymbolicLink, (LPVOID)outBuffer);
  950. symbolicLink = (PWSTR) ((LPBYTE)symbolicLink + (sizeof(WCHAR) * (cchSymbolicLink + 1)));
  951. }
  952. }
  953. EXIT:
  954. /* if (outBuffer) {
  955. HeapFree(heapHandle, 0L, outBuffer);
  956. }
  957. */
  958. return status;
  959. }
  960. BOOL
  961. HandleClusterVolumes(
  962. IN PASRFMT_MOUNT_POINTS_INFO pMountPoints
  963. )
  964. {
  965. if (!pMountPoints) {
  966. ASSERT(0 && "pMountPoints is NULL");
  967. return FALSE;
  968. }
  969. ResUtilEnumResources(NULL,
  970. ASRFMT_CLUSTER_PHYSICAL_DISK,
  971. ResourceCallBack,
  972. pMountPoints
  973. );
  974. return TRUE;
  975. }
  976. BOOL
  977. pAcquirePrivilege(
  978. IN CONST PCWSTR szPrivilegeName
  979. )
  980. {
  981. HANDLE hToken = NULL;
  982. BOOL bResult = FALSE;
  983. LUID luid;
  984. TOKEN_PRIVILEGES tNewState;
  985. bResult = OpenProcessToken(GetCurrentProcess(),
  986. MAXIMUM_ALLOWED,
  987. &hToken
  988. );
  989. if (!bResult) {
  990. return FALSE;
  991. }
  992. bResult = LookupPrivilegeValue(NULL, szPrivilegeName, &luid);
  993. if (!bResult) {
  994. CloseHandle(hToken);
  995. return FALSE;
  996. }
  997. tNewState.PrivilegeCount = 1;
  998. tNewState.Privileges[0].Luid = luid;
  999. tNewState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  1000. //
  1001. // We will always call GetLastError below, so clear
  1002. // any prior error values on this thread.
  1003. //
  1004. SetLastError(ERROR_SUCCESS);
  1005. bResult = AdjustTokenPrivileges(
  1006. hToken, // Token Handle
  1007. FALSE, // DisableAllPrivileges
  1008. &tNewState, // NewState
  1009. (DWORD) 0, // BufferLength
  1010. NULL, // PreviousState
  1011. NULL // ReturnLength
  1012. );
  1013. //
  1014. // Supposedly, AdjustTokenPriveleges always returns TRUE
  1015. // (even when it fails). So, call GetLastError to be
  1016. // extra sure everything's cool.
  1017. //
  1018. if (ERROR_SUCCESS != GetLastError()) {
  1019. bResult = FALSE;
  1020. }
  1021. CloseHandle(hToken);
  1022. return bResult;
  1023. }
  1024. BOOL
  1025. AsrfmtpIsInaccessibleSanVolume(
  1026. IN PCWSTR szVolumeName
  1027. )
  1028. /*++
  1029. Routine Description:
  1030. Utility to check if the current volume is a shared SAN disk that's "owned"
  1031. by a different machine (and is hence inaccessible).
  1032. Arguments:
  1033. szVolumeName - Win-32 name for volume interest.
  1034. Return Value:
  1035. If the function succeeds and the volume is a shared SAN disk that is
  1036. owned by some other machine, the return value is a nonzero value.
  1037. If the function fails, or if the volume is not a shared SAN volume that
  1038. is owned by a different machine (ie, is a local unshared volume, or
  1039. a shared volume owned by this machine) the return value
  1040. is zero.
  1041. --*/
  1042. {
  1043. DWORD dwStatus = ERROR_SUCCESS,
  1044. dwDummy = 0;
  1045. HANDLE hVolume = INVALID_HANDLE_VALUE;
  1046. BOOL bIsInaccessibleDevice = FALSE;
  1047. //
  1048. // Get a handle to the first partition on disk
  1049. //
  1050. hVolume = CreateFileW(
  1051. szVolumeName, // lpFileName
  1052. 0, // dwDesiredAccess
  1053. FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
  1054. NULL, // lpSecurityAttributes
  1055. OPEN_EXISTING, // dwCreationFlags
  1056. FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
  1057. NULL // hTemplateFile
  1058. );
  1059. if (INVALID_HANDLE_VALUE == hVolume) {
  1060. //
  1061. // We couldn't open the partition. Now check for the specific error
  1062. // code we're interested in (STATUS_OFF_LINE, which gets mapped to
  1063. // ERROR_NOT_READY).
  1064. //
  1065. dwStatus = GetLastError();
  1066. if (ERROR_NOT_READY == dwStatus) {
  1067. bIsInaccessibleDevice = TRUE;
  1068. }
  1069. }
  1070. else {
  1071. //
  1072. // Dynamic disks don't support this IOCTL, and will return a failure.
  1073. // Basic disks that are online will return FALSE as well.
  1074. //
  1075. bIsInaccessibleDevice = DeviceIoControl(
  1076. hVolume,
  1077. IOCTL_VOLUME_IS_OFFLINE,
  1078. NULL,
  1079. 0,
  1080. NULL,
  1081. 0,
  1082. &dwDummy,
  1083. NULL
  1084. );
  1085. }
  1086. if (INVALID_HANDLE_VALUE != hVolume) {
  1087. CloseHandle(hVolume);
  1088. }
  1089. return bIsInaccessibleDevice;
  1090. }
  1091. BOOL
  1092. BuildStateInfo(
  1093. IN PASRFMT_STATE_INFO pState
  1094. )
  1095. {
  1096. UINT driveType = DRIVE_UNKNOWN;
  1097. WCHAR szVolumeGuid[MAX_PATH + 1];
  1098. PWSTR lpDevName = NULL,
  1099. lpSymbolicLink = NULL;
  1100. USHORT cchDevName = 0,
  1101. cchSymbolicLink = 0;
  1102. DWORD dwCount = 0;
  1103. DWORD dwStatus = ERROR_SUCCESS;
  1104. BOOL bResult = FALSE;
  1105. PMOUNTMGR_MOUNT_POINTS pMountPoints = NULL;
  1106. HANDLE hHeap = NULL;
  1107. PASRFMT_MOUNT_POINTS_INFO pMpInfoList = NULL,
  1108. pMp = NULL;
  1109. hHeap = GetProcessHeap();
  1110. //
  1111. // We need to acquire the backup and restore privileges to write to asr.sif
  1112. //
  1113. if (!pAcquirePrivilege(SE_BACKUP_NAME)) {
  1114. SetLastError(ERROR_PRIVILEGE_NOT_HELD);
  1115. return FALSE;
  1116. }
  1117. if (!pAcquirePrivilege(SE_RESTORE_NAME)) {
  1118. SetLastError(ERROR_PRIVILEGE_NOT_HELD);
  1119. return FALSE;
  1120. }
  1121. pMountPoints = GetMountPoints();
  1122. if (!pMountPoints) {
  1123. //
  1124. // No volumes exist (!)
  1125. //
  1126. SetLastError(ERROR_BAD_ENVIRONMENT);
  1127. return FALSE;
  1128. }
  1129. pMpInfoList = (PASRFMT_MOUNT_POINTS_INFO) HeapAlloc(
  1130. hHeap,
  1131. HEAP_ZERO_MEMORY,
  1132. sizeof(ASRFMT_MOUNT_POINTS_INFO)
  1133. );
  1134. ErrExitCode(!pMpInfoList, dwStatus, ERROR_NOT_ENOUGH_MEMORY);
  1135. //
  1136. // Now, we go through the mountpoint table returned, and
  1137. // create the appropriate structs that we'll need to save.
  1138. //
  1139. // The mount point table consists of entries of the form:
  1140. // device name symbolic link
  1141. // ----------------------------------------------
  1142. // \device\harddiskvolume1 \??\volume{guid1}
  1143. // \device\harddiskvolume1 \dosdevices\c:
  1144. // \device\harddiskvolume1 \??\volume{guid2}
  1145. // \device\harddiskvolume2 \??\volume{guid3}
  1146. // \device\harddiskvolume2 \dosdevices\d:
  1147. // \device\floppy0 \dosdevices\a:
  1148. // \device\floppy0 \??\volume{guid4}
  1149. // \device\cdrom0 \dosdevices\e:
  1150. // \device\cdrom0 \??\volume{guid5}
  1151. //
  1152. // ... etc
  1153. //
  1154. // For fixed disks, we don't care about the device name, and we
  1155. // store the following in asr.sif:
  1156. //
  1157. // [VOLUMES]
  1158. // \??\volume{guid1}, \dosdevices\c:
  1159. // \??\volume{guid1}, \??\volume{guid2}
  1160. // \??\volume{guid3}, \dosdevices\d:
  1161. //
  1162. //
  1163. // For removable devices, we care about the device name as well,
  1164. // and store this in asr.sif:
  1165. //
  1166. // [RemovableMedia]
  1167. // \device\floppy0, \??\volume{guid4}, \dosdevices\a:
  1168. // \device\cdrom0, \??\volume{guid5}, \dosdevices\e:
  1169. //
  1170. //
  1171. // First, we build up our structure containing the info
  1172. //
  1173. for (dwCount = 0; dwCount < pMountPoints->NumberOfMountPoints; dwCount++) {
  1174. lpDevName = (PWSTR) (((LPBYTE)pMountPoints) + pMountPoints->MountPoints[dwCount].DeviceNameOffset);
  1175. cchDevName = pMountPoints->MountPoints[dwCount].DeviceNameLength / sizeof (WCHAR);
  1176. lpSymbolicLink = (PWSTR) (((LPBYTE)pMountPoints) + pMountPoints->MountPoints[dwCount].SymbolicLinkNameOffset);
  1177. cchSymbolicLink = pMountPoints->MountPoints[dwCount].SymbolicLinkNameLength / sizeof (WCHAR);
  1178. AddSymbolicLink(pMpInfoList, lpDevName, cchDevName, lpSymbolicLink, cchSymbolicLink, (LPVOID)NULL);
  1179. }
  1180. //
  1181. // Add the volume info for any cluster volumes, since we cannot access them
  1182. // directly if the disk is owned by another node. This function will fail
  1183. // if we're not running on a cluster--so we don't care about the return value.
  1184. //
  1185. HandleClusterVolumes(pMpInfoList);
  1186. //
  1187. // Now, we go through the list, and build the pVolume and pRemovableMedia
  1188. // structs
  1189. //
  1190. pMp = pMpInfoList;
  1191. while (pMp) {
  1192. if (!(pMp->pDeviceName && pMp->pVolumeGuid)) {
  1193. pMp = pMp->pNext;
  1194. continue;
  1195. }
  1196. DWORD cchGuid = pMp->cchVolumeGuid;
  1197. WCHAR szFsName[ASRFMT_CCH_FS_NAME];
  1198. WCHAR szLabel[ASRFMT_CCH_VOLUME_LABEL];
  1199. DWORD dwClusterSize;
  1200. //
  1201. // GetDriveType needs the volume guid in the dos-name-space, while the
  1202. // mount manager gives the volume guid in the nt-name-space. Convert
  1203. // the name by changing the \??\ at the beginning to \\?\, and adding
  1204. // a back-slash at the end.
  1205. //
  1206. wcsncpy(szVolumeGuid, pMp->pVolumeGuid, cchGuid);
  1207. szVolumeGuid[1] = L'\\';
  1208. szVolumeGuid[cchGuid] = L'\0';
  1209. if (AsrfmtpIsInaccessibleSanVolume(szVolumeGuid)) {
  1210. pMp = pMp->pNext;
  1211. continue;
  1212. }
  1213. szVolumeGuid[cchGuid] = L'\\'; // Trailing back-slash
  1214. szVolumeGuid[cchGuid+1] = L'\0';
  1215. driveType = DRIVE_UNKNOWN;
  1216. if (!pMp->IsClusterShared) {
  1217. driveType = GetDriveType(szVolumeGuid);
  1218. }
  1219. if ((pMp->IsClusterShared) || (DRIVE_FIXED == driveType)) {
  1220. if (!pMp->IsClusterShared) {
  1221. //
  1222. // Get the FS Label, cluster size, and so on.
  1223. //
  1224. bResult = GetVolumeDetails(szVolumeGuid,
  1225. szFsName,
  1226. ASRFMT_CCH_FS_NAME,
  1227. szLabel,
  1228. ASRFMT_CCH_VOLUME_LABEL,
  1229. &dwClusterSize
  1230. );
  1231. // ErrExitCode(!bResult, dwStatus, GetLastError());
  1232. }
  1233. else {
  1234. //
  1235. // If it's a cluster shared disk, then we already
  1236. // got the relavant info earlier
  1237. //
  1238. wcsncpy(szFsName, pMp->szFsName, ASRFMT_CCH_FS_NAME-1);
  1239. wcsncpy(szLabel, pMp->szLabel, ASRFMT_CCH_VOLUME_LABEL-1);
  1240. szFsName[ASRFMT_CCH_FS_NAME-1] = L'\0';
  1241. szLabel[ASRFMT_CCH_VOLUME_LABEL-1] = L'\0';
  1242. dwClusterSize = pMp->dwClusterSize;
  1243. }
  1244. //
  1245. // Now, create a VolumeInfo structure for each symbolic link.
  1246. //
  1247. PASRFMT_MP_LINK pCurrentLink = pMp->pSymbolicLinks;
  1248. if (!pCurrentLink) {
  1249. //
  1250. // This volume does not have any symbolic links attached to it
  1251. //
  1252. PASRFMT_VOLUME_INFO pNewVolume = (PASRFMT_VOLUME_INFO) HeapAlloc(
  1253. hHeap,
  1254. HEAP_ZERO_MEMORY,
  1255. sizeof(ASRFMT_VOLUME_INFO)
  1256. );
  1257. ErrExitCode(!pNewVolume, dwStatus, ERROR_NOT_ENOUGH_MEMORY);
  1258. wcsncpy(pNewVolume->szGuid, pMp->pVolumeGuid, pMp->cchVolumeGuid);
  1259. wcscpy(pNewVolume->szFsName, szFsName);
  1260. wcscpy(pNewVolume->szLabel, szLabel);
  1261. pNewVolume->dwClusterSize = dwClusterSize;
  1262. bResult = AddSortedVolumeInfo(&(pState->pVolume), pNewVolume);
  1263. ErrExitCode(!bResult, dwStatus, GetLastError());
  1264. }
  1265. else {
  1266. while (pCurrentLink) {
  1267. PASRFMT_VOLUME_INFO pNewVolume = (PASRFMT_VOLUME_INFO) HeapAlloc(
  1268. hHeap,
  1269. HEAP_ZERO_MEMORY,
  1270. sizeof(ASRFMT_VOLUME_INFO)
  1271. );
  1272. ErrExitCode(!pNewVolume, dwStatus, ERROR_NOT_ENOUGH_MEMORY);
  1273. wcsncpy(pNewVolume->szGuid, pMp->pVolumeGuid, pMp->cchVolumeGuid);
  1274. wcsncpy(pNewVolume->szDosPath, pCurrentLink->pLink, pCurrentLink->cchLink);
  1275. wcscpy(pNewVolume->szFsName, szFsName);
  1276. wcscpy(pNewVolume->szLabel, szLabel);
  1277. pNewVolume->dwClusterSize = dwClusterSize;
  1278. bResult = AddSortedVolumeInfo(&(pState->pVolume), pNewVolume);
  1279. ErrExitCode(!bResult, dwStatus, GetLastError());
  1280. pCurrentLink = pCurrentLink->pNext;
  1281. }
  1282. }
  1283. }
  1284. else if (DRIVE_UNKNOWN != driveType) {
  1285. PASRFMT_MP_LINK pCurrentLink = pMp->pSymbolicLinks;
  1286. if (!pCurrentLink) {
  1287. //
  1288. // This volume has no symbolic links at all (ie no drive
  1289. // letter or mountpoint)
  1290. //
  1291. PASRFMT_REMOVABLE_MEDIA_INFO pNewMedia = (PASRFMT_REMOVABLE_MEDIA_INFO) HeapAlloc(
  1292. hHeap,
  1293. HEAP_ZERO_MEMORY,
  1294. sizeof(ASRFMT_REMOVABLE_MEDIA_INFO)
  1295. );
  1296. ErrExitCode(!pNewMedia, dwStatus, ERROR_NOT_ENOUGH_MEMORY);
  1297. wcsncpy(pNewMedia->szVolumeGuid, pMp->pVolumeGuid, pMp->cchVolumeGuid);
  1298. wcsncpy(pNewMedia->szDevicePath, pMp->pDeviceName, pMp->cchDeviceName);
  1299. bResult = AddSortedRemovableMediaInfo(&(pState->pRemovableMedia), pNewMedia);
  1300. ErrExitCode(!bResult, dwStatus, GetLastError());
  1301. }
  1302. else {
  1303. while (pCurrentLink) {
  1304. PASRFMT_REMOVABLE_MEDIA_INFO pNewMedia = (PASRFMT_REMOVABLE_MEDIA_INFO) HeapAlloc(
  1305. hHeap,
  1306. HEAP_ZERO_MEMORY,
  1307. sizeof(ASRFMT_REMOVABLE_MEDIA_INFO)
  1308. );
  1309. ErrExitCode(!pNewMedia, dwStatus, ERROR_NOT_ENOUGH_MEMORY);
  1310. wcsncpy(pNewMedia->szVolumeGuid, pMp->pVolumeGuid, pMp->cchVolumeGuid);
  1311. wcsncpy(pNewMedia->szDosPath, pCurrentLink->pLink, pCurrentLink->cchLink);
  1312. wcsncpy(pNewMedia->szDevicePath, pMp->pDeviceName, pMp->cchDeviceName);
  1313. bResult = AddSortedRemovableMediaInfo(&(pState->pRemovableMedia), pNewMedia);
  1314. ErrExitCode(!bResult, dwStatus, GetLastError());
  1315. pCurrentLink = pCurrentLink->pNext;
  1316. }
  1317. }
  1318. }
  1319. pMp = pMp->pNext;
  1320. }
  1321. EXIT:
  1322. if (pMountPoints) {
  1323. HeapFree(hHeap, 0L, pMountPoints);
  1324. pMountPoints = NULL;
  1325. }
  1326. if (pMpInfoList) {
  1327. FreeMpInfo(&pMpInfoList);
  1328. }
  1329. return (ERROR_SUCCESS == dwStatus);
  1330. }
  1331. //
  1332. // Sets the dosdevices (of the form "\DosDevices\X:") for the
  1333. // volume with the GUID passed in (of the form "\??\Volume{Guid}")
  1334. //
  1335. BOOL
  1336. SetDosName(
  1337. IN PWSTR lpVolumeGuid,
  1338. IN PWSTR lpDosPath
  1339. )
  1340. {
  1341. HANDLE hMountMgr = NULL;
  1342. DWORD dwStatus = ERROR_SUCCESS;
  1343. BOOL bResult = TRUE;
  1344. WCHAR szDeviceNameForGuid[MAX_PATH + 1],
  1345. szDeviceNameForDosPath[MAX_PATH + 1];
  1346. if (!lpVolumeGuid || !lpDosPath) {
  1347. SetLastError(ERROR_INVALID_PARAMETER);
  1348. return FALSE;
  1349. }
  1350. //
  1351. // Open the mount manager
  1352. //
  1353. hMountMgr = CreateFileW(
  1354. (PCWSTR) MOUNTMGR_DOS_DEVICE_NAME,
  1355. GENERIC_READ | GENERIC_WRITE,
  1356. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1357. NULL,
  1358. OPEN_EXISTING,
  1359. FILE_ATTRIBUTE_NORMAL,
  1360. INVALID_HANDLE_VALUE
  1361. );
  1362. ErrExitCode((!hMountMgr || INVALID_HANDLE_VALUE == hMountMgr), dwStatus, GetLastError());
  1363. //
  1364. // Get the Device Paths from the GUID and Dos Path
  1365. //
  1366. bResult = DoMountMgrWork(hMountMgr, mmfGetDeviceName, lpVolumeGuid, szDeviceNameForGuid);
  1367. ErrExitCode(!bResult, dwStatus, GetLastError());
  1368. bResult = DoMountMgrWork(hMountMgr, mmfGetDeviceName, lpDosPath, szDeviceNameForDosPath);
  1369. if (bResult && !wcscmp(szDeviceNameForGuid, szDeviceNameForDosPath)) {
  1370. //
  1371. // The Guid already has the Dos Path. We're done.
  1372. //
  1373. ErrExitCode(TRUE, dwStatus, ERROR_SUCCESS);
  1374. }
  1375. //
  1376. // Delete the dos path if it is currently being used by another volume
  1377. //
  1378. if (wcslen(lpDosPath) > 0) {
  1379. bResult = DoMountMgrWork(hMountMgr, mmfDeleteDosName, lpDosPath, NULL);
  1380. }
  1381. //
  1382. // If we're trying to set the drive letter, then delete any other dos path
  1383. // currently being used by this volume.
  1384. //
  1385. if (ASRFMT_LOOKS_LIKE_DOS_DEVICE(lpDosPath, (wcslen(lpDosPath) * sizeof(WCHAR)))
  1386. || (0 == wcslen(lpDosPath))
  1387. ) {
  1388. bResult = DoMountMgrWork(hMountMgr, mmfDeleteDosName, NULL, szDeviceNameForGuid);
  1389. ErrExitCode(!bResult, dwStatus, GetLastError());
  1390. }
  1391. //
  1392. // Assign the Dos Path to this VolumeGuid
  1393. //
  1394. if (wcslen(lpDosPath) > 0) {
  1395. bResult = DoMountMgrWork(hMountMgr, mmfCreateSymbolicLinkName, lpDosPath, lpVolumeGuid);
  1396. ErrExitCode(!bResult, dwStatus, GetLastError());
  1397. }
  1398. EXIT:
  1399. if (hMountMgr && INVALID_HANDLE_VALUE != hMountMgr) {
  1400. CloseHandle(hMountMgr);
  1401. }
  1402. return (BOOL) (ERROR_SUCCESS == dwStatus);
  1403. }
  1404. BOOL
  1405. SetRemovableMediaGuid(
  1406. IN PWSTR lpDeviceName,
  1407. IN PWSTR lpGuid
  1408. )
  1409. {
  1410. static LONG s_LastCdIndex = 0;
  1411. static LONG s_LastFloppyIndex = 0;
  1412. static LONG s_LastJazIndex = 0;
  1413. static PMOUNTMGR_MOUNT_POINTS s_pMountPoints = NULL;
  1414. static HANDLE s_hMountMgr = NULL;
  1415. WCHAR szNewDeviceName[MAX_PATH + 1];
  1416. ZeroMemory(szNewDeviceName, (MAX_PATH+1) * sizeof(WCHAR));
  1417. LONG index = 0;
  1418. if ((!lpDeviceName) && (!lpGuid)) {
  1419. //
  1420. // Both parameters are NULL, we free the mount points and reset Indices.
  1421. //
  1422. s_LastCdIndex = (LONG) s_pMountPoints->NumberOfMountPoints - 1;
  1423. s_LastFloppyIndex = (LONG) s_pMountPoints->NumberOfMountPoints - 1;
  1424. s_LastJazIndex = (LONG) s_pMountPoints->NumberOfMountPoints - 1;
  1425. if (s_pMountPoints) {
  1426. HeapFree(GetProcessHeap(), 0L, s_pMountPoints);
  1427. s_pMountPoints = NULL;
  1428. }
  1429. if (s_hMountMgr && INVALID_HANDLE_VALUE != s_hMountMgr) {
  1430. CloseHandle(s_hMountMgr);
  1431. s_hMountMgr = NULL;
  1432. }
  1433. return TRUE;
  1434. }
  1435. if ((!lpDeviceName) || (!lpGuid)) {
  1436. return FALSE;
  1437. }
  1438. if (!s_pMountPoints) {
  1439. //
  1440. // This is the first time this function is being called (after a
  1441. // clean-up), we get a list of mount points on the current machine
  1442. // and store it.
  1443. //
  1444. s_pMountPoints = GetMountPoints();
  1445. if (!s_pMountPoints) {
  1446. return FALSE;
  1447. }
  1448. s_LastCdIndex = (LONG) s_pMountPoints->NumberOfMountPoints - 1;
  1449. s_LastFloppyIndex = (LONG) s_pMountPoints->NumberOfMountPoints - 1;
  1450. s_LastJazIndex = (LONG) s_pMountPoints->NumberOfMountPoints - 1;
  1451. }
  1452. if ((!s_hMountMgr) || (INVALID_HANDLE_VALUE == s_hMountMgr)) {
  1453. s_hMountMgr = CreateFileW(
  1454. (PCWSTR) MOUNTMGR_DOS_DEVICE_NAME,
  1455. GENERIC_READ | GENERIC_WRITE,
  1456. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1457. NULL,
  1458. OPEN_EXISTING,
  1459. FILE_ATTRIBUTE_NORMAL,
  1460. INVALID_HANDLE_VALUE
  1461. );
  1462. if ((!s_hMountMgr) || (INVALID_HANDLE_VALUE == s_hMountMgr)) {
  1463. return FALSE;
  1464. }
  1465. }
  1466. index = s_pMountPoints->NumberOfMountPoints;
  1467. if (wcsstr(lpDeviceName, L"\\Device\\CdRom")) {
  1468. //
  1469. // We're trying to set the GUID for a CD-ROM device We go through the list of
  1470. // the MountPoints, till we find the next \Device\CdRomX to use
  1471. //
  1472. for (index = s_LastCdIndex; index >= 0; index--) {
  1473. //
  1474. // Copy the device name from the MountPoint over to a temporary string
  1475. //
  1476. wcsncpy(szNewDeviceName,
  1477. (PWSTR)(((LPBYTE)s_pMountPoints) + s_pMountPoints->MountPoints[index].DeviceNameOffset),
  1478. s_pMountPoints->MountPoints[index].DeviceNameLength/sizeof(WCHAR)
  1479. );
  1480. szNewDeviceName[s_pMountPoints->MountPoints[index].DeviceNameLength/sizeof(WCHAR)] = L'\0';
  1481. //
  1482. // Check if this is a CD-ROM device
  1483. //
  1484. if (wcsstr(szNewDeviceName, L"\\Device\\CdRom")) {
  1485. s_LastCdIndex = index - 1;
  1486. //
  1487. // Forward till we skip past any other mount points that are
  1488. // also pointing to this device
  1489. //
  1490. while ((s_LastCdIndex >= 0) &&
  1491. (s_pMountPoints->MountPoints[s_LastCdIndex].UniqueIdOffset == s_pMountPoints->MountPoints[index].UniqueIdOffset) &&
  1492. (s_pMountPoints->MountPoints[s_LastCdIndex].UniqueIdLength == s_pMountPoints->MountPoints[index].UniqueIdLength)
  1493. ) {
  1494. --s_LastCdIndex;
  1495. }
  1496. break;
  1497. }
  1498. }
  1499. }
  1500. else if (wcsstr(lpDeviceName, L"\\Device\\Floppy")) {
  1501. //
  1502. // We're trying to set the GUID for a floppy device We go through the list of
  1503. // the MountPoints, till we find the next \Device\FloppyX to use
  1504. //
  1505. for (index = s_LastFloppyIndex; index >= 0; index--) {
  1506. //
  1507. // Copy the device name from the MountPoint over to a temporary string
  1508. //
  1509. wcsncpy(szNewDeviceName,
  1510. (PWSTR)(((LPBYTE)s_pMountPoints) + s_pMountPoints->MountPoints[index].DeviceNameOffset),
  1511. s_pMountPoints->MountPoints[index].DeviceNameLength/sizeof(WCHAR)
  1512. );
  1513. szNewDeviceName[s_pMountPoints->MountPoints[index].DeviceNameLength/sizeof(WCHAR)] = L'\0';
  1514. //
  1515. // Check if this is a Floppy device
  1516. //
  1517. if (wcsstr(szNewDeviceName, L"\\Device\\Floppy")) {
  1518. s_LastFloppyIndex = index - 1;
  1519. //
  1520. // Forward till we skip past any other mount points that are
  1521. // also pointing to this device
  1522. //
  1523. while ((s_LastFloppyIndex >= 0) &&
  1524. (s_pMountPoints->MountPoints[s_LastFloppyIndex].UniqueIdOffset == s_pMountPoints->MountPoints[index].UniqueIdOffset) &&
  1525. (s_pMountPoints->MountPoints[s_LastFloppyIndex].UniqueIdLength == s_pMountPoints->MountPoints[index].UniqueIdLength)
  1526. ) {
  1527. --s_LastFloppyIndex;
  1528. }
  1529. break;
  1530. }
  1531. }
  1532. }
  1533. else if (wcsstr(lpDeviceName, L"\\Device\\Harddisk") &&
  1534. wcsstr(lpDeviceName, L"DP(") &&
  1535. !wcsstr(lpDeviceName, L"Partition")
  1536. ){
  1537. //
  1538. // This is most likely a JAZ or ZIP drive. We can't do much to identify the
  1539. // JAZ/ZIP drives uniquely, so this may end up in the wrong drive getting the
  1540. // wrong drive letter.
  1541. //
  1542. for (index = s_LastJazIndex; index >= 0; index--) {
  1543. //
  1544. // Copy the device name from the MountPoint over to a temporary string
  1545. //
  1546. wcsncpy(szNewDeviceName,
  1547. (PWSTR)(((LPBYTE)s_pMountPoints) + s_pMountPoints->MountPoints[index].DeviceNameOffset),
  1548. s_pMountPoints->MountPoints[index].DeviceNameLength/sizeof(WCHAR)
  1549. );
  1550. szNewDeviceName[s_pMountPoints->MountPoints[index].DeviceNameLength/sizeof(WCHAR)] = L'\0';
  1551. //
  1552. // Check if this is a JAZ or ZIP device
  1553. //
  1554. if (wcsstr(szNewDeviceName, L"\\Device\\Harddisk") &&
  1555. wcsstr(szNewDeviceName, L"DP(") &&
  1556. !wcsstr(szNewDeviceName, L"Partition")
  1557. ) {
  1558. s_LastJazIndex = index - 1;
  1559. //
  1560. // Forward till we skip past any other mount points that are
  1561. // also pointing to this device
  1562. //
  1563. while ((s_LastJazIndex >= 0) &&
  1564. (s_pMountPoints->MountPoints[s_LastJazIndex].UniqueIdOffset == s_pMountPoints->MountPoints[index].UniqueIdOffset) &&
  1565. (s_pMountPoints->MountPoints[s_LastJazIndex].UniqueIdLength == s_pMountPoints->MountPoints[index].UniqueIdLength)
  1566. ) {
  1567. --s_LastJazIndex;
  1568. }
  1569. break;
  1570. }
  1571. }
  1572. }
  1573. else {
  1574. //
  1575. // We don't recognise this Device
  1576. //
  1577. index = -1;
  1578. }
  1579. if (index < 0) {
  1580. return FALSE;
  1581. }
  1582. if (!DoMountMgrWork(s_hMountMgr, mmfDeleteVolumeGuid, NULL, szNewDeviceName)) {
  1583. return FALSE;
  1584. }
  1585. if (!DoMountMgrWork(s_hMountMgr, mmfCreateSymbolicLinkName, lpGuid, szNewDeviceName)) {
  1586. return FALSE;
  1587. }
  1588. return TRUE;
  1589. }
  1590. BOOL
  1591. DoMountMgrWork(
  1592. IN HANDLE hMountMgr,
  1593. IN ASRFMT_MM_FUNCTION mmfFunction,
  1594. IN PWSTR lpSymbolicName,
  1595. IN PWSTR lpDeviceName
  1596. )
  1597. {
  1598. PMOUNTMGR_MOUNT_POINT pMountPointIn = NULL,
  1599. pDeletePointIn = NULL;
  1600. PMOUNTMGR_MOUNT_POINTS pMountPointsOut = NULL;
  1601. PMOUNTMGR_CREATE_POINT_INPUT pCreatePointIn = NULL;
  1602. MOUNTMGR_MOUNT_POINTS MountPointsTemp;
  1603. DWORD cbSymbolicName = 0,
  1604. cbDeviceName = 0,
  1605. cbMountPoints = 0;
  1606. DWORD index = 0;
  1607. DWORD dwStatus = ERROR_SUCCESS;
  1608. BOOL bResult = TRUE;
  1609. HANDLE hHeap = NULL;
  1610. if (lpSymbolicName && !wcslen(lpSymbolicName)) {
  1611. return TRUE;
  1612. }
  1613. hHeap = GetProcessHeap();
  1614. if (lpSymbolicName) {
  1615. cbSymbolicName = wcslen(lpSymbolicName) * sizeof(WCHAR);
  1616. }
  1617. if (lpDeviceName) {
  1618. cbDeviceName = wcslen(lpDeviceName) * sizeof(WCHAR);
  1619. }
  1620. pMountPointIn = (PMOUNTMGR_MOUNT_POINT) HeapAlloc(
  1621. hHeap,
  1622. HEAP_ZERO_MEMORY,
  1623. sizeof(MOUNTMGR_MOUNT_POINT) + cbSymbolicName + cbDeviceName
  1624. );
  1625. ErrExitCode(!pMountPointIn, dwStatus, ERROR_NOT_ENOUGH_MEMORY);
  1626. if (mmfCreateSymbolicLinkName != mmfFunction) {
  1627. //
  1628. // Query for the Unique Id
  1629. //
  1630. if (cbSymbolicName) {
  1631. pMountPointIn->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  1632. pMountPointIn->SymbolicLinkNameLength = (USHORT) cbSymbolicName;
  1633. CopyMemory(((LPBYTE)pMountPointIn) + pMountPointIn->SymbolicLinkNameOffset,
  1634. lpSymbolicName, pMountPointIn->SymbolicLinkNameLength);
  1635. }
  1636. else {
  1637. pMountPointIn->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  1638. pMountPointIn->DeviceNameLength = (USHORT) cbDeviceName;
  1639. CopyMemory((LPBYTE)pMountPointIn + pMountPointIn->DeviceNameOffset,
  1640. lpDeviceName, pMountPointIn->DeviceNameLength);
  1641. }
  1642. // this call should fail with ERROR_MORE_DATA
  1643. bResult = DeviceIoControl(
  1644. hMountMgr,
  1645. IOCTL_MOUNTMGR_QUERY_POINTS,
  1646. pMountPointIn,
  1647. (sizeof(*pMountPointIn) + pMountPointIn->DeviceNameLength + pMountPointIn->SymbolicLinkNameLength),
  1648. &MountPointsTemp,
  1649. sizeof(MountPointsTemp),
  1650. &cbMountPoints,
  1651. NULL
  1652. );
  1653. if (!bResult) {
  1654. dwStatus = GetLastError();
  1655. // if buffer is of insufficient size, resize the buffer.
  1656. if (ERROR_MORE_DATA == dwStatus ||
  1657. ERROR_INSUFFICIENT_BUFFER == dwStatus ||
  1658. ERROR_BAD_LENGTH == dwStatus
  1659. ) {
  1660. dwStatus = ERROR_SUCCESS;
  1661. pMountPointsOut = (PMOUNTMGR_MOUNT_POINTS) HeapAlloc(
  1662. hHeap,
  1663. HEAP_ZERO_MEMORY,
  1664. MountPointsTemp.Size
  1665. );
  1666. ErrExitCode(!pMountPointsOut, dwStatus, ERROR_NOT_ENOUGH_MEMORY);
  1667. }
  1668. else {
  1669. //
  1670. // If some other error occurred, EXIT.
  1671. // This is not a fatal error in the case of removable storage media
  1672. //
  1673. ErrExitCode(bResult, dwStatus, ERROR_SUCCESS);
  1674. }
  1675. }
  1676. else {
  1677. //
  1678. // the call succeeded when we expected it to fail--something's wrong.
  1679. // This is not a fatal error in the case of removable storage media.
  1680. //
  1681. ErrExitCode(bResult, dwStatus, ERROR_SUCCESS);
  1682. }
  1683. bResult = DeviceIoControl(
  1684. hMountMgr,
  1685. IOCTL_MOUNTMGR_QUERY_POINTS,
  1686. pMountPointIn,
  1687. sizeof(*pMountPointIn) + pMountPointIn->DeviceNameLength + pMountPointIn->SymbolicLinkNameLength,
  1688. pMountPointsOut,
  1689. MountPointsTemp.Size,
  1690. &cbMountPoints,
  1691. NULL
  1692. );
  1693. ErrExitCode((!cbMountPoints || !bResult), dwStatus, GetLastError());
  1694. }
  1695. switch (mmfFunction) {
  1696. case mmfGetDeviceName: {
  1697. //
  1698. // Copy the device name to lpDeviceName, and we're done
  1699. //
  1700. CopyMemory(lpDeviceName,
  1701. ((LPBYTE) pMountPointsOut) + pMountPointsOut->MountPoints[0].DeviceNameOffset,
  1702. pMountPointsOut->MountPoints[0].DeviceNameLength
  1703. );
  1704. // Null-terminate the string
  1705. lpDeviceName[pMountPointsOut->MountPoints[0].DeviceNameLength / sizeof(WCHAR)] = L'\0';
  1706. break;
  1707. }
  1708. case mmfDeleteDosName:
  1709. case mmfDeleteVolumeGuid: {
  1710. DWORD cbName = 0;
  1711. PWSTR lpName = NULL;
  1712. DWORD cbDeletePoint = 0;
  1713. //
  1714. // Go through the list of mount points returned, and delete the appropriate
  1715. // entries.
  1716. //
  1717. for (index = 0; index < pMountPointsOut->NumberOfMountPoints; index++) {
  1718. lpName = (PWSTR) (((LPBYTE)pMountPointsOut) + pMountPointsOut->MountPoints[index].SymbolicLinkNameOffset);
  1719. cbName = (DWORD) pMountPointsOut->MountPoints[index].SymbolicLinkNameLength;
  1720. if ((mmfDeleteDosName == mmfFunction) &&
  1721. (ASRFMT_LOOKS_LIKE_DOS_DEVICE(lpName, cbName))
  1722. ) {
  1723. break;
  1724. }
  1725. if ((mmfDeleteVolumeGuid == mmfFunction) &&
  1726. (ASRFMT_LOOKS_LIKE_VOLUME_GUID(lpName, cbName))
  1727. ) {
  1728. break;
  1729. }
  1730. }
  1731. if (index == pMountPointsOut->NumberOfMountPoints) {
  1732. //
  1733. // No matching entries were found
  1734. //
  1735. break;
  1736. }
  1737. cbDeletePoint = sizeof(MOUNTMGR_MOUNT_POINT) +
  1738. pMountPointsOut->MountPoints[index].SymbolicLinkNameLength +
  1739. pMountPointsOut->MountPoints[index].UniqueIdLength +
  1740. pMountPointsOut->MountPoints[index].DeviceNameLength;
  1741. pDeletePointIn = (PMOUNTMGR_MOUNT_POINT) HeapAlloc(
  1742. hHeap,
  1743. HEAP_ZERO_MEMORY,
  1744. cbDeletePoint
  1745. );
  1746. ErrExitCode(!pDeletePointIn, dwStatus, ERROR_NOT_ENOUGH_MEMORY);
  1747. pDeletePointIn->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  1748. pDeletePointIn->SymbolicLinkNameLength = pMountPointsOut->MountPoints[index].SymbolicLinkNameLength;
  1749. CopyMemory(((LPBYTE)pDeletePointIn) + pDeletePointIn->SymbolicLinkNameOffset,
  1750. ((LPBYTE)pMountPointsOut) + pMountPointsOut->MountPoints[index].SymbolicLinkNameOffset,
  1751. pDeletePointIn->SymbolicLinkNameLength);
  1752. pDeletePointIn->UniqueIdOffset = pDeletePointIn->SymbolicLinkNameOffset +
  1753. pDeletePointIn->SymbolicLinkNameLength;
  1754. pDeletePointIn->UniqueIdLength = pMountPointsOut->MountPoints[index].UniqueIdLength;
  1755. CopyMemory(((LPBYTE)pDeletePointIn) + pDeletePointIn->UniqueIdOffset,
  1756. ((LPBYTE)pMountPointsOut) + pMountPointsOut->MountPoints[index].UniqueIdOffset,
  1757. pDeletePointIn->UniqueIdLength);
  1758. pDeletePointIn->DeviceNameOffset = pDeletePointIn->UniqueIdOffset +
  1759. pDeletePointIn->UniqueIdLength;
  1760. pDeletePointIn->DeviceNameLength = pMountPointsOut->MountPoints[index].DeviceNameLength;
  1761. CopyMemory(((LPBYTE)pDeletePointIn) + pDeletePointIn->DeviceNameOffset,
  1762. ((LPBYTE)pMountPointsOut) + pMountPointsOut->MountPoints[index].DeviceNameOffset,
  1763. pDeletePointIn->DeviceNameLength);
  1764. bResult = DeviceIoControl(hMountMgr,
  1765. IOCTL_MOUNTMGR_DELETE_POINTS,
  1766. pDeletePointIn,
  1767. cbDeletePoint,
  1768. pMountPointsOut,
  1769. MountPointsTemp.Size,
  1770. &cbMountPoints,
  1771. NULL
  1772. );
  1773. ErrExitCode(!bResult, dwStatus, GetLastError());
  1774. break;
  1775. }
  1776. case mmfCreateSymbolicLinkName: {
  1777. pCreatePointIn = (PMOUNTMGR_CREATE_POINT_INPUT) HeapAlloc(
  1778. hHeap,
  1779. HEAP_ZERO_MEMORY,
  1780. sizeof (MOUNTMGR_CREATE_POINT_INPUT) + cbDeviceName + cbSymbolicName
  1781. );
  1782. ErrExitCode(!pCreatePointIn, dwStatus, ERROR_NOT_ENOUGH_MEMORY);
  1783. pCreatePointIn->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT);
  1784. pCreatePointIn->SymbolicLinkNameLength = (USHORT) cbSymbolicName;
  1785. pCreatePointIn->DeviceNameOffset = pCreatePointIn->SymbolicLinkNameOffset + pCreatePointIn->SymbolicLinkNameLength;
  1786. pCreatePointIn->DeviceNameLength = (USHORT) cbDeviceName;
  1787. CopyMemory(((LPBYTE)pCreatePointIn) + pCreatePointIn->SymbolicLinkNameOffset,
  1788. (LPBYTE)lpSymbolicName, pCreatePointIn->SymbolicLinkNameLength);
  1789. CopyMemory(((LPBYTE)pCreatePointIn) + pCreatePointIn->DeviceNameOffset,
  1790. (LPBYTE)lpDeviceName, pCreatePointIn->DeviceNameLength);
  1791. bResult = DeviceIoControl(
  1792. hMountMgr,
  1793. IOCTL_MOUNTMGR_CREATE_POINT,
  1794. pCreatePointIn,
  1795. sizeof(MOUNTMGR_CREATE_POINT_INPUT) + pCreatePointIn->SymbolicLinkNameLength + pCreatePointIn->DeviceNameLength,
  1796. NULL,
  1797. 0,
  1798. &cbMountPoints,
  1799. NULL
  1800. );
  1801. ErrExitCode(!bResult, dwStatus, GetLastError());
  1802. }
  1803. }
  1804. EXIT:
  1805. if (pCreatePointIn) {
  1806. HeapFree(hHeap, 0L, pCreatePointIn);
  1807. pCreatePointIn = NULL;
  1808. }
  1809. if (pDeletePointIn) {
  1810. HeapFree(hHeap, 0L, pDeletePointIn);
  1811. pDeletePointIn = NULL;
  1812. }
  1813. if (pMountPointIn) {
  1814. HeapFree(hHeap, 0L, pMountPointIn);
  1815. pMountPointIn = NULL;
  1816. }
  1817. if (pMountPointsOut) {
  1818. HeapFree(hHeap, 0L, pMountPointsOut);
  1819. pMountPointsOut = NULL;
  1820. }
  1821. return (BOOL) (ERROR_SUCCESS == dwStatus);
  1822. }
  1823. PMOUNTMGR_MOUNT_POINTS // Must be freed by caller
  1824. GetMountPoints()
  1825. {
  1826. PMOUNTMGR_MOUNT_POINTS pMountPointsOut = NULL;
  1827. PMOUNTMGR_MOUNT_POINT pMountPointIn = NULL;
  1828. MOUNTMGR_MOUNT_POINTS MountPointsTemp;
  1829. HANDLE hMountMgr = NULL,
  1830. hHeap = NULL;
  1831. DWORD dwStatus = ERROR_SUCCESS;
  1832. BOOL bResult = TRUE;
  1833. DWORD cbMountPoints = 0;
  1834. hHeap = GetProcessHeap();
  1835. pMountPointIn = (PMOUNTMGR_MOUNT_POINT) HeapAlloc(
  1836. hHeap,
  1837. HEAP_ZERO_MEMORY,
  1838. sizeof(MOUNTMGR_MOUNT_POINT) + sizeof(WCHAR)
  1839. );
  1840. ErrExitCode(!pMountPointIn, dwStatus, ERROR_NOT_ENOUGH_MEMORY);
  1841. // put the DeviceName ("") right after struct pMountPointIn
  1842. wcsncpy((PWSTR) (pMountPointIn + 1), L"", 1);
  1843. pMountPointIn->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  1844. pMountPointIn->DeviceNameLength = 0;
  1845. // get a handle to the mount manager
  1846. hMountMgr = CreateFileW(
  1847. (PCWSTR) MOUNTMGR_DOS_DEVICE_NAME,
  1848. 0,
  1849. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1850. NULL,
  1851. OPEN_EXISTING,
  1852. FILE_ATTRIBUTE_NORMAL,
  1853. INVALID_HANDLE_VALUE
  1854. );
  1855. ErrExitCode((!hMountMgr || INVALID_HANDLE_VALUE == hMountMgr), dwStatus, GetLastError());
  1856. // this call should fail with ERROR_MORE_DATA
  1857. bResult = DeviceIoControl(
  1858. hMountMgr,
  1859. IOCTL_MOUNTMGR_QUERY_POINTS,
  1860. pMountPointIn,
  1861. sizeof(*pMountPointIn) + pMountPointIn->DeviceNameLength,
  1862. &MountPointsTemp,
  1863. sizeof(MountPointsTemp),
  1864. &cbMountPoints,
  1865. NULL
  1866. );
  1867. if (!bResult) {
  1868. dwStatus = GetLastError();
  1869. // if buffer is of insufficient size, resize the buffer.
  1870. if (ERROR_MORE_DATA == dwStatus ||
  1871. ERROR_INSUFFICIENT_BUFFER == dwStatus ||
  1872. ERROR_BAD_LENGTH == dwStatus
  1873. ) {
  1874. dwStatus = ERROR_SUCCESS;
  1875. pMountPointsOut = (PMOUNTMGR_MOUNT_POINTS) HeapAlloc(
  1876. hHeap,
  1877. HEAP_ZERO_MEMORY,
  1878. MountPointsTemp.Size
  1879. );
  1880. ErrExitCode(!pMountPointsOut, dwStatus, ERROR_NOT_ENOUGH_MEMORY);
  1881. }
  1882. else {
  1883. //
  1884. // If some other error occurred, EXIT.
  1885. // This is not a fatal error in the case of removable storage media
  1886. //
  1887. ErrExitCode(bResult, dwStatus, ERROR_SUCCESS);
  1888. }
  1889. }
  1890. else {
  1891. //
  1892. // the call succeeded when we expected it to fail--something's wrong.
  1893. // This is not a fatal error in the case of removable storage media.
  1894. //
  1895. ErrExitCode(bResult, dwStatus, ERROR_SUCCESS);
  1896. }
  1897. bResult = DeviceIoControl(
  1898. hMountMgr,
  1899. IOCTL_MOUNTMGR_QUERY_POINTS,
  1900. pMountPointIn,
  1901. sizeof(*pMountPointIn) + pMountPointIn->DeviceNameLength,
  1902. pMountPointsOut,
  1903. MountPointsTemp.Size,
  1904. &cbMountPoints,
  1905. NULL
  1906. );
  1907. ErrExitCode((!cbMountPoints || !bResult), dwStatus, GetLastError());
  1908. EXIT:
  1909. if (pMountPointIn) {
  1910. HeapFree(hHeap, 0L, pMountPointIn);
  1911. pMountPointIn = NULL;
  1912. }
  1913. if (ERROR_SUCCESS != dwStatus) {
  1914. if (pMountPointsOut) {
  1915. HeapFree(hHeap, 0L, pMountPointsOut);
  1916. pMountPointsOut = NULL;
  1917. }
  1918. }
  1919. if (hMountMgr && INVALID_HANDLE_VALUE != hMountMgr) {
  1920. CloseHandle(hMountMgr);
  1921. }
  1922. return pMountPointsOut;
  1923. }
  1924. //
  1925. // Based on AsrpExpandEnvStrings in syssetup\setupasr.c
  1926. //
  1927. PWSTR // must be freed by caller
  1928. AsrfmtpExpandEnvStrings(
  1929. IN CONST PCWSTR OriginalString
  1930. )
  1931. {
  1932. PWSTR expandedString = NULL;
  1933. UINT cchSize = MAX_PATH + 1, // start with a reasonable default
  1934. cchRequiredSize = 0;
  1935. BOOL result = FALSE;
  1936. DWORD status = ERROR_SUCCESS;
  1937. HANDLE heapHandle = GetProcessHeap();
  1938. expandedString = (PWSTR) HeapAlloc(heapHandle, HEAP_ZERO_MEMORY, (cchSize * sizeof(WCHAR)));
  1939. ErrExitCode((!expandedString), status, ERROR_NOT_ENOUGH_MEMORY);
  1940. cchRequiredSize = ExpandEnvironmentStringsW(OriginalString,
  1941. expandedString,
  1942. cchSize
  1943. );
  1944. if (cchRequiredSize > cchSize) {
  1945. //
  1946. // Buffer wasn't big enough; free and re-allocate as needed
  1947. //
  1948. HeapFree(heapHandle, 0L, expandedString);
  1949. cchSize = cchRequiredSize + 1;
  1950. expandedString = (PWSTR) HeapAlloc(heapHandle, HEAP_ZERO_MEMORY, (cchSize * sizeof(WCHAR)));
  1951. ErrExitCode((!expandedString), status, ERROR_NOT_ENOUGH_MEMORY);
  1952. cchRequiredSize = ExpandEnvironmentStringsW(OriginalString,
  1953. expandedString,
  1954. cchSize
  1955. );
  1956. }
  1957. if ((0 == cchRequiredSize) || (cchRequiredSize > cchSize)) {
  1958. //
  1959. // Either the function failed, or the buffer wasn't big enough
  1960. // even on the second try
  1961. //
  1962. HeapFree(heapHandle, 0L, expandedString);
  1963. expandedString = NULL;
  1964. }
  1965. EXIT:
  1966. return expandedString;
  1967. }
  1968. VOID
  1969. AsrfmtpInitialiseErrorFile()
  1970. {
  1971. PWSTR szErrorFilePath = NULL;
  1972. //
  1973. // Get full path to the error file.
  1974. //
  1975. szErrorFilePath = AsrfmtpExpandEnvStrings(ASRFMT_ASR_ERROR_FILE_PATH);
  1976. if (!szErrorFilePath) {
  1977. return;
  1978. }
  1979. //
  1980. // Open the error log
  1981. //
  1982. Gbl_hErrorFile = CreateFileW(
  1983. szErrorFilePath, // lpFileName
  1984. GENERIC_WRITE | GENERIC_READ, // dwDesiredAccess
  1985. FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
  1986. NULL, // lpSecurityAttributes
  1987. OPEN_ALWAYS, // dwCreationFlags
  1988. FILE_FLAG_WRITE_THROUGH, // dwFlagsAndAttributes
  1989. NULL // hTemplateFile
  1990. );
  1991. HeapFree(GetProcessHeap(), 0L, szErrorFilePath);
  1992. szErrorFilePath = NULL;
  1993. if ((!Gbl_hErrorFile) || (INVALID_HANDLE_VALUE == Gbl_hErrorFile)) {
  1994. return;
  1995. }
  1996. //
  1997. // Move to the end of file
  1998. //
  1999. SetFilePointer(Gbl_hErrorFile, 0L, NULL, FILE_END);
  2000. }
  2001. VOID
  2002. AsrfmtpCloseErrorFile() {
  2003. if ((Gbl_hErrorFile) && (INVALID_HANDLE_VALUE != Gbl_hErrorFile)) {
  2004. CloseHandle(Gbl_hErrorFile);
  2005. Gbl_hErrorFile = NULL;
  2006. }
  2007. }
  2008. VOID
  2009. AsrfmtpLogErrorMessage(
  2010. IN _AsrfmtpMessageSeverity Severity,
  2011. IN const LPCTSTR Message
  2012. )
  2013. {
  2014. SYSTEMTIME currentTime;
  2015. DWORD bytesWritten = 0;
  2016. WCHAR buffer[4196];
  2017. BOOL formatLoaded = FALSE;
  2018. int res = 0;
  2019. CString strFormat;
  2020. if ((!Gbl_hErrorFile) || (INVALID_HANDLE_VALUE == Gbl_hErrorFile)) {
  2021. return;
  2022. }
  2023. //
  2024. // Load the format of the error string to be logged
  2025. //
  2026. if (_SeverityError == Severity) {
  2027. res = strFormat.LoadString(IDS_LOG_ERROR_FORMAT);
  2028. if (res != 0) {
  2029. formatLoaded = TRUE;
  2030. }
  2031. }
  2032. else if (_SeverityWarning == Severity) {
  2033. res = strFormat.LoadString(IDS_LOG_WARNING_FORMAT);
  2034. if (res != 0) {
  2035. formatLoaded = TRUE;
  2036. }
  2037. }
  2038. else {
  2039. //
  2040. // We should only log error or warning messages to the error file
  2041. //
  2042. return;
  2043. }
  2044. //
  2045. // In case someone else wrote to this file since our last write
  2046. //
  2047. SetFilePointer(Gbl_hErrorFile, 0L, NULL, FILE_END);
  2048. //
  2049. // Create our string, and write it out
  2050. //
  2051. GetLocalTime(&currentTime);
  2052. swprintf(buffer,
  2053. (LPCTSTR) (formatLoaded? strFormat : L"\r\n[%04hu/%02hu/%02hu %02hu:%02hu:%02hu] %s\r\n"),
  2054. currentTime.wYear,
  2055. currentTime.wMonth,
  2056. currentTime.wDay,
  2057. currentTime.wHour,
  2058. currentTime.wMinute,
  2059. currentTime.wSecond,
  2060. Message
  2061. );
  2062. WriteFile(Gbl_hErrorFile,
  2063. buffer,
  2064. (wcslen(buffer) * sizeof(WCHAR)),
  2065. &bytesWritten,
  2066. NULL
  2067. );
  2068. }