Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1047 lines
28 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. asrclus.c
  5. Abstract:
  6. This module contains ASR routines specifically
  7. implemented for clusters.
  8. Notes:
  9. Naming conventions:
  10. _AsrpXXX private ASR Macros
  11. AsrpXXX private ASR routines
  12. AsrXXX Publically defined and documented routines
  13. Author:
  14. Guhan Suriyanarayanan (guhans) 27-May-2000
  15. Environment:
  16. User-mode only.
  17. Revision History:
  18. 27-May-2000 guhans
  19. Moved cluster-related routines from asr.c to asrclus.c
  20. 01-Mar-2000 guhans
  21. Initial implementation for cluster-specific routines
  22. in asr.c
  23. --*/
  24. #include "setupp.h"
  25. #pragma hdrstop
  26. #include <mountmgr.h> // mountmgr ioctls
  27. #include <clusstor.h> // Cluster API's
  28. #include <resapi.h> // Cluster ResUtilEnumResources
  29. #define THIS_MODULE 'C'
  30. #include "asrpriv.h" // Private ASR definitions and routines
  31. //
  32. // --------
  33. // typedef's local to this module
  34. // --------
  35. //
  36. //
  37. // The cluster resource related typdefs
  38. //
  39. typedef DWORD (* PFN_CLUSTER_RESOURCE_CONTROL) (
  40. IN HRESOURCE hResource,
  41. IN OPTIONAL HNODE hHostNode,
  42. IN DWORD dwControlCode,
  43. IN LPVOID lpInBuffer,
  44. IN DWORD cbInBufferSize,
  45. OUT LPVOID lpOutBuffer,
  46. IN DWORD cbOutBufferSize,
  47. OUT LPDWORD lpcbBytesReturned
  48. );
  49. typedef DWORD (* PFN_RES_UTIL_ENUM_RESOURCES) (
  50. IN HRESOURCE hSelf,
  51. IN LPCWSTR lpszResTypeName,
  52. IN LPRESOURCE_CALLBACK pResCallBack,
  53. IN PVOID pParameter
  54. );
  55. //
  56. // ---------
  57. // global variables used within this module.
  58. // --------
  59. //
  60. PFN_CLUSTER_RESOURCE_CONTROL pfnClusterResourceControl;
  61. //
  62. // ---------
  63. // constants used within this module.
  64. // --------
  65. //
  66. const WCHAR ASR_CLUSTER_PHYSICAL_DISK[] = L"Physical Disk";
  67. const WCHAR ASR_CLUSTER_CLUSAPI_DLL_NAME[] = L"clusapi.dll";
  68. const WCHAR ASR_CLUSTER_RESUTILS_DLL_NAME[] = L"resutils.dll";
  69. //
  70. // The following must be single-byte ansi chars
  71. //
  72. const CHAR ASR_CLUSTER_DLL_MODULE_NAME[] = "%SystemRoot%\\system32\\syssetup.dll";
  73. const CHAR ASR_CLUSTER_DLL_PROC_NAME[] = "AsrpGetLocalDiskInfo";
  74. const CHAR ASR_CLUSTER_CLUSAPI_PROC_NAME[] = "ClusterResourceControl";
  75. const CHAR ASR_CLUSTER_RESUTILS_PROC_NAME[] = "ResUtilEnumResources";
  76. //
  77. // --------
  78. // function implementations
  79. // --------
  80. //
  81. //
  82. // --- AsrpGetLocalVolumeInfo and related helper functions
  83. //
  84. //
  85. // The disk info struct we get back from the remote nodes on the cluster will have
  86. // offsets instead of pointers--we can convert this back to pointers by just adding
  87. // back the base address. We also mark that this struct is packed--so we should just
  88. // free the entire struct instead of freeing each pointer in the struct.
  89. //
  90. BOOL
  91. AsrpUnPackDiskInfo(
  92. IN PVOID InBuffer
  93. )
  94. {
  95. PASR_DISK_INFO pBuffer = (PASR_DISK_INFO) InBuffer;
  96. /* if (!((pBuffer->pDriveLayoutEx) && (pBuffer->pDiskGeometry) && (pBuffer->pPartition0Ex))) {
  97. return FALSE;
  98. }
  99. */
  100. pBuffer->IsPacked = TRUE;
  101. if (pBuffer->pDriveLayoutEx) {
  102. pBuffer->pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) ((LPBYTE)pBuffer + PtrToUlong(pBuffer->pDriveLayoutEx));
  103. }
  104. if (pBuffer->pDiskGeometry) {
  105. pBuffer->pDiskGeometry = (PDISK_GEOMETRY) ((LPBYTE)pBuffer + PtrToUlong((LPBYTE)pBuffer->pDiskGeometry));
  106. }
  107. if (pBuffer->pPartition0Ex) {
  108. pBuffer->pPartition0Ex = (PPARTITION_INFORMATION_EX) ((LPBYTE)pBuffer + PtrToUlong(pBuffer->pPartition0Ex));
  109. }
  110. if (pBuffer->PartitionInfoTable) {
  111. pBuffer->PartitionInfoTable = (PASR_PTN_INFO) ((LPBYTE)pBuffer + PtrToUlong(pBuffer->PartitionInfoTable));
  112. }
  113. if (pBuffer->pScsiAddress) {
  114. pBuffer->pScsiAddress = (PSCSI_ADDRESS) ((LPBYTE)pBuffer + PtrToUlong(pBuffer->pScsiAddress));
  115. }
  116. return TRUE;
  117. }
  118. //
  119. // Copies the info in pLocalDisk to a flat buffer pointed to by lpOutBuffer.
  120. // The pointers are changed to offsets from the start of the buffer.
  121. //
  122. DWORD
  123. AsrpPackDiskInfo(
  124. IN PASR_DISK_INFO pLocalDisk,
  125. OUT PVOID lpOutBuffer,
  126. IN DWORD nOutBufferSize,
  127. OUT LPDWORD lpBytesReturned
  128. )
  129. {
  130. DWORD reqdSize = 0;
  131. PASR_DISK_INFO pBuffer = NULL;
  132. DWORD offset = 0;
  133. MYASSERT(pLocalDisk);
  134. //
  135. // Calculate required size
  136. //
  137. reqdSize = sizeof (ASR_DISK_INFO) +
  138. pLocalDisk->sizeDriveLayoutEx +
  139. pLocalDisk->sizeDiskGeometry +
  140. pLocalDisk->sizePartition0Ex +
  141. pLocalDisk->sizePartitionInfoTable;
  142. if (pLocalDisk->pScsiAddress) {
  143. reqdSize += sizeof(SCSI_ADDRESS);
  144. }
  145. if (lpBytesReturned) {
  146. *lpBytesReturned = reqdSize;
  147. }
  148. if (reqdSize > nOutBufferSize) {
  149. return ERROR_INSUFFICIENT_BUFFER;
  150. }
  151. //
  152. // Copy the ASR_DISK_INFO struct over to outBuffer
  153. //
  154. memcpy(lpOutBuffer, pLocalDisk, sizeof(ASR_DISK_INFO));
  155. pBuffer = (PASR_DISK_INFO) lpOutBuffer;
  156. offset = sizeof(ASR_DISK_INFO); // offset where the next struct will be copied
  157. //
  158. // Now, we go through the buffer and convert all pointers to offsets,
  159. // and copy over the structs they were pointing to.
  160. //
  161. //
  162. // First pointer: PWSTR DevicePath;
  163. // Since the DevicePath makes sense only in the context of the local node,
  164. // we return NULL to the remote node.
  165. //
  166. pBuffer->DevicePath = NULL;
  167. //
  168. // Next pointer: PDRIVE_LAYOUT_INFORMATION_EX pDriveLayoutEx;
  169. //
  170. if (pLocalDisk->pDriveLayoutEx) {
  171. memcpy(((LPBYTE)lpOutBuffer + offset),
  172. pLocalDisk->pDriveLayoutEx,
  173. pLocalDisk->sizeDriveLayoutEx
  174. );
  175. pBuffer->pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) UlongToPtr(offset);
  176. offset += pLocalDisk->sizeDriveLayoutEx;
  177. }
  178. //
  179. // Next pointer: PDISK_GEOMETRY pDiskGeometry;
  180. //
  181. if (pLocalDisk->pDiskGeometry) {
  182. memcpy(((LPBYTE)lpOutBuffer + offset),
  183. pLocalDisk->pDiskGeometry,
  184. pLocalDisk->sizeDiskGeometry
  185. );
  186. pBuffer->pDiskGeometry = (PDISK_GEOMETRY) UlongToPtr(offset);
  187. offset += pLocalDisk->sizeDiskGeometry;
  188. }
  189. //
  190. // Next pointer: PPARTITION_INFORMATION_EX pPartition0Ex;
  191. //
  192. if (pLocalDisk->pPartition0Ex) {
  193. memcpy(((LPBYTE)lpOutBuffer + offset),
  194. pLocalDisk->pPartition0Ex,
  195. pLocalDisk->sizePartition0Ex
  196. );
  197. pBuffer->pPartition0Ex= (PPARTITION_INFORMATION_EX) UlongToPtr(offset);
  198. offset += pLocalDisk->sizePartition0Ex;
  199. }
  200. //
  201. // Next pointer: PASR_PTN_INFO PartitionInfoTable;
  202. //
  203. if (pLocalDisk->PartitionInfoTable) {
  204. memcpy(((LPBYTE)lpOutBuffer + offset),
  205. pLocalDisk->PartitionInfoTable,
  206. pLocalDisk->sizePartitionInfoTable
  207. );
  208. pBuffer->PartitionInfoTable = (PASR_PTN_INFO) UlongToPtr(offset);
  209. offset += pLocalDisk->sizePartitionInfoTable;
  210. }
  211. //
  212. // Last pointer: PSCSI_ADDRESS pScsiAddress;
  213. //
  214. if (pLocalDisk->pScsiAddress) {
  215. memcpy(((LPBYTE)lpOutBuffer + offset),
  216. pLocalDisk->pScsiAddress,
  217. sizeof(SCSI_ADDRESS)
  218. );
  219. pBuffer->pScsiAddress = (PSCSI_ADDRESS) UlongToPtr(offset);
  220. offset += sizeof(SCSI_ADDRESS);
  221. }
  222. MYASSERT(offset <= nOutBufferSize);
  223. return ERROR_SUCCESS;
  224. }
  225. DWORD
  226. WINAPI
  227. AsrpGetLocalDiskInfo(
  228. IN LPSTR lpszDeviceName,
  229. IN LPSTR lpszContextString, // not used
  230. OUT PVOID lpOutBuffer,
  231. IN DWORD nOutBufferSize,
  232. OUT LPDWORD lpBytesReturned
  233. )
  234. {
  235. PASR_DISK_INFO pLocalDisk = NULL;
  236. HANDLE heapHandle = NULL;
  237. DWORD status = ERROR_SUCCESS;
  238. BOOL result = FALSE;
  239. ULONG MaxDeviceNumber = 0;
  240. DWORD cchReqdSize = 0;
  241. heapHandle = GetProcessHeap();
  242. //
  243. // Either the BytesReturned must be non-null (he's getting the required size),
  244. // or the lpOutBuffer must be non-null (he's getting the data).
  245. //
  246. _AsrpErrExitCode(!(lpOutBuffer || lpBytesReturned), status, ERROR_INVALID_PARAMETER);
  247. if (lpBytesReturned) {
  248. *lpBytesReturned = 0;
  249. }
  250. pLocalDisk = (PASR_DISK_INFO) HeapAlloc(
  251. heapHandle,
  252. HEAP_ZERO_MEMORY,
  253. sizeof (ASR_DISK_INFO)
  254. );
  255. _AsrpErrExitCode(!pLocalDisk, status, ERROR_NOT_ENOUGH_MEMORY);
  256. cchReqdSize = MultiByteToWideChar(CP_ACP,
  257. 0,
  258. lpszDeviceName,
  259. -1,
  260. NULL,
  261. 0
  262. );
  263. pLocalDisk->DevicePath = (PWSTR) HeapAlloc(
  264. heapHandle,
  265. HEAP_ZERO_MEMORY,
  266. (cchReqdSize + 1) * (sizeof(WCHAR))
  267. );
  268. _AsrpErrExitCode(!(pLocalDisk->DevicePath), status, ERROR_NOT_ENOUGH_MEMORY);
  269. result = MultiByteToWideChar(CP_ACP,
  270. 0,
  271. lpszDeviceName,
  272. -1,
  273. pLocalDisk->DevicePath,
  274. (cchReqdSize + 1)
  275. );
  276. _AsrpErrExitCode(!result, status, ERROR_INVALID_PARAMETER);
  277. //
  278. // Get the disk layout information
  279. //
  280. result = AsrpInitLayoutInformation(NULL, pLocalDisk, &MaxDeviceNumber, TRUE);
  281. _AsrpErrExitCode(!result, status, GetLastError());
  282. // _AsrpErrExitCode(result && GetLastErr what if createfile fails?
  283. result = AsrpFreeNonFixedMedia(&pLocalDisk);
  284. _AsrpErrExitCode(!result, status, GetLastError());
  285. _AsrpErrExitCode(!pLocalDisk, status, ERROR_SUCCESS);
  286. //
  287. // Copy it to the out buffer without any pointers
  288. //
  289. status = AsrpPackDiskInfo(pLocalDisk, lpOutBuffer, nOutBufferSize, lpBytesReturned);
  290. EXIT:
  291. AsrpFreeStateInformation(&pLocalDisk, NULL);
  292. return status;
  293. }
  294. //
  295. // ---- AsrpInitClusterSharedDisks and related helper functions
  296. //
  297. BOOL
  298. AsrpIsClusteredDiskSame(
  299. IN PASR_DISK_INFO currentDisk,
  300. IN PASR_DISK_INFO clusterDisk
  301. )
  302. {
  303. if (!clusterDisk || !currentDisk) {
  304. MYASSERT(0 && L"Invalid parameter, Disk is NULL");
  305. return FALSE;
  306. }
  307. if (currentDisk->Style != clusterDisk->Style) {
  308. return FALSE;
  309. }
  310. if (PARTITION_STYLE_MBR == clusterDisk->Style) { // currently always true
  311. if (clusterDisk->pDriveLayoutEx) {
  312. if (currentDisk->pDriveLayoutEx) {
  313. return (currentDisk->pDriveLayoutEx->Mbr.Signature == clusterDisk->pDriveLayoutEx->Mbr.Signature);
  314. }
  315. else {
  316. return (currentDisk->TempSignature == clusterDisk->pDriveLayoutEx->Mbr.Signature);
  317. }
  318. }
  319. else {
  320. MYASSERT(0 && L"Cluster disk drive layout is NULL");
  321. return FALSE;
  322. }
  323. }
  324. else {
  325. if (clusterDisk->pDriveLayoutEx && currentDisk->pDriveLayoutEx) {
  326. return (IsEqualGUID(&(currentDisk->pDriveLayoutEx->Gpt.DiskId), &(clusterDisk->pDriveLayoutEx->Gpt.DiskId)));
  327. }
  328. else {
  329. return FALSE;
  330. }
  331. }
  332. return FALSE;
  333. }
  334. DWORD
  335. AsrpResourceCallBack(
  336. RESOURCE_HANDLE hOriginal,
  337. RESOURCE_HANDLE hResource,
  338. PVOID lpParams
  339. )
  340. {
  341. DISK_DLL_EXTENSION_INFO inBuffer;
  342. PBYTE outBuffer = NULL;
  343. DWORD sizeOutBuffer = 0,
  344. bytesReturned = 0;
  345. DWORD status = ERROR_SUCCESS;
  346. PASR_DISK_INFO currentDisk = (PASR_DISK_INFO) lpParams,
  347. clusterDisk = NULL,
  348. prevDisk = NULL;
  349. HANDLE heapHandle = NULL;
  350. BOOL done = FALSE;
  351. if (!lpParams) {
  352. //
  353. // The system must have at least one disk that has been enumerated
  354. // already (the system disk, at least!), so our disk list shouldn't be NULL.
  355. //
  356. return ERROR_INVALID_PARAMETER;
  357. }
  358. heapHandle = GetProcessHeap();
  359. MYASSERT(heapHandle);
  360. //
  361. // Allocate a reasonably-sized memory for the out buffer. If this isn't
  362. // big enough, we'll re-allocate.
  363. //
  364. sizeOutBuffer = ASR_BUFFER_SIZE;
  365. outBuffer = (PBYTE) HeapAlloc(
  366. heapHandle,
  367. HEAP_ZERO_MEMORY,
  368. sizeOutBuffer
  369. );
  370. _AsrpErrExitCode(!outBuffer, status, ERROR_NOT_ENOUGH_MEMORY);
  371. //
  372. // Call AsrpGetLocalDiskInfo on the node owning this disk resource
  373. //
  374. ZeroMemory(&inBuffer, sizeof(inBuffer));
  375. inBuffer.MajorVersion = NT5_MAJOR_VERSION;
  376. strcpy(inBuffer.DllModuleName, ASR_CLUSTER_DLL_MODULE_NAME);
  377. strcpy(inBuffer.DllProcName, ASR_CLUSTER_DLL_PROC_NAME);
  378. status = (pfnClusterResourceControl) (hResource,
  379. NULL,
  380. CLUSCTL_RESOURCE_STORAGE_DLL_EXTENSION,
  381. &inBuffer,
  382. sizeof(DISK_DLL_EXTENSION_INFO),
  383. (PVOID) outBuffer,
  384. sizeOutBuffer,
  385. &bytesReturned
  386. );
  387. if (ERROR_INSUFFICIENT_BUFFER == status) {
  388. //
  389. // The buffer wasn't big enough, re-allocate as needed
  390. //
  391. _AsrpHeapFree(outBuffer);
  392. sizeOutBuffer = bytesReturned;
  393. outBuffer = (PBYTE) HeapAlloc(
  394. heapHandle,
  395. HEAP_ZERO_MEMORY,
  396. sizeOutBuffer
  397. );
  398. _AsrpErrExitCode(!outBuffer, status, ERROR_NOT_ENOUGH_MEMORY);
  399. status = (pfnClusterResourceControl) (
  400. hResource,
  401. NULL,
  402. CLUSCTL_RESOURCE_STORAGE_DLL_EXTENSION,
  403. &inBuffer,
  404. sizeof(DISK_DLL_EXTENSION_INFO),
  405. (PVOID) outBuffer,
  406. sizeOutBuffer,
  407. &bytesReturned
  408. );
  409. }
  410. _AsrpErrExitCode((ERROR_SUCCESS != status), status, status);
  411. //
  412. // outBuffer has a packed disk info struct (ie the pointers are offsets).
  413. //
  414. AsrpUnPackDiskInfo(outBuffer);
  415. clusterDisk = (PASR_DISK_INFO) outBuffer;
  416. clusterDisk->IsClusterShared = TRUE;
  417. clusterDisk->IsPacked = TRUE; // so that we free this properly
  418. //
  419. // Check if clusterDisk already has info in our list (ie is owned
  420. // locally)
  421. //
  422. // Note that for now, clusterDisk is always MBR (since clusters don't
  423. // support shared GPT disks). We don't care here, we handle GPT as well.
  424. //
  425. done = FALSE;
  426. prevDisk = NULL;
  427. while (currentDisk && !done) {
  428. if (AsrpIsClusteredDiskSame(currentDisk, clusterDisk)) {
  429. if (currentDisk->pDriveLayoutEx) {
  430. //
  431. // This disk is owned by the local node (correct?), since
  432. // we would not have gotten the pDriveLayout otherwise
  433. //
  434. currentDisk->IsClusterShared = TRUE;
  435. currentDisk->IsPacked = FALSE;
  436. //
  437. // We don't need the info returned by clusterDisk, we have
  438. // it in currentDisk already.
  439. //
  440. _AsrpHeapFree(clusterDisk); // it's packed.
  441. }
  442. else {
  443. //
  444. // This disk is owned by a remote node. So we add clusterDisk
  445. // in to our list now. We'll remove currentDisk from our
  446. // list later (in RemoveNonFixedDevices).
  447. //
  448. // First though, we copy over DevicePath and DeviceNumber
  449. // from currentDisk, since these are relative to the local
  450. // machine
  451. //
  452. if (currentDisk->DevicePath) {
  453. clusterDisk->DevicePath = (PWSTR) HeapAlloc(
  454. heapHandle,
  455. HEAP_ZERO_MEMORY,
  456. sizeof(WCHAR) * (wcslen(currentDisk->DevicePath) + 1)
  457. );
  458. wcscpy(clusterDisk->DevicePath, currentDisk->DevicePath);
  459. }
  460. clusterDisk->DeviceNumber = currentDisk->DeviceNumber;
  461. //
  462. // Don't bother freeing currentDisk, it'll get taken care
  463. // of in RemoveNonFixedDevices.
  464. //
  465. clusterDisk->pNext = currentDisk->pNext;
  466. currentDisk->pNext = clusterDisk;
  467. currentDisk = clusterDisk; // move forward by one (don't really need to since done will be set to TRUE and we'll get out of the loop)
  468. }
  469. done = TRUE;
  470. }
  471. prevDisk = currentDisk;
  472. currentDisk = currentDisk->pNext;
  473. }
  474. if (!done) {
  475. //
  476. // This disk was not found in our list (strange), let's add
  477. // it in at the end
  478. //
  479. // MYASSERT(0 && L"Clustered disk not found in OriginalDiskList, adding it to the end");
  480. clusterDisk->pNext = NULL;
  481. prevDisk->pNext = clusterDisk;
  482. }
  483. EXIT:
  484. //
  485. // Free up outBuffer on failure. On success, outBuffer shouldn't
  486. // be freed, it will either be part of OriginalDiskList or already
  487. // be freed.
  488. //
  489. if (ERROR_SUCCESS != status) {
  490. _AsrpHeapFree(outBuffer);
  491. }
  492. return status;
  493. }
  494. BOOL
  495. AsrpInitClusterSharedDisks(
  496. IN PASR_DISK_INFO OriginalDiskList
  497. )
  498. {
  499. DWORD status = ERROR_SUCCESS,
  500. dwOldError;
  501. HMODULE hClusApi = NULL,
  502. hResUtils = NULL;
  503. PFN_RES_UTIL_ENUM_RESOURCES pfnResUtilEnumResources = NULL;
  504. dwOldError = GetLastError();
  505. if (!OriginalDiskList) {
  506. SetLastError(ERROR_INVALID_PARAMETER);
  507. return FALSE;
  508. }
  509. hClusApi = LoadLibraryW(ASR_CLUSTER_CLUSAPI_DLL_NAME);
  510. _AsrpErrExitCode(!hClusApi, status, GetLastError());
  511. pfnClusterResourceControl = (PFN_CLUSTER_RESOURCE_CONTROL) GetProcAddress(
  512. hClusApi,
  513. ASR_CLUSTER_CLUSAPI_PROC_NAME
  514. );
  515. _AsrpErrExitCode(!pfnClusterResourceControl, status, GetLastError());
  516. hResUtils = LoadLibraryW(ASR_CLUSTER_RESUTILS_DLL_NAME);
  517. _AsrpErrExitCode(!hResUtils, status, GetLastError());
  518. pfnResUtilEnumResources = (PFN_RES_UTIL_ENUM_RESOURCES) GetProcAddress(
  519. hResUtils,
  520. ASR_CLUSTER_RESUTILS_PROC_NAME
  521. );
  522. _AsrpErrExitCode(!pfnResUtilEnumResources, status, GetLastError());
  523. status = (pfnResUtilEnumResources) (NULL,
  524. ASR_CLUSTER_PHYSICAL_DISK,
  525. AsrpResourceCallBack,
  526. OriginalDiskList
  527. );
  528. EXIT:
  529. if (hClusApi) {
  530. FreeLibrary(hClusApi);
  531. }
  532. if (hResUtils) {
  533. FreeLibrary(hResUtils);
  534. }
  535. // ResUtil will fail if we aren't on a cluster, but that's fine.
  536. SetLastError(dwOldError);
  537. return TRUE;
  538. }
  539. //
  540. // --- AsrpGetLocalVolumeInfo and related helper functions
  541. //
  542. //
  543. // The following two definitions are from asr_fmt:dr_state.cpp. This MUST be
  544. // kept in sync.
  545. //
  546. typedef struct _ASRFMT_CLUSTER_VOLUME_INFO {
  547. UINT driveType;
  548. DWORD PartitionNumber;
  549. ULONG FsNameOffset;
  550. USHORT FsNameLength;
  551. ULONG LabelOffset;
  552. USHORT LabelLength;
  553. ULONG SymbolicNamesOffset;
  554. USHORT SymbolicNamesLength;
  555. DWORD dwClusterSize;
  556. } ASRFMT_CLUSTER_VOLUME_INFO, *PASRFMT_CLUSTER_VOLUME_INFO;
  557. typedef struct _ASRFMT_CLUSTER_VOLUMES_TABLE {
  558. DWORD DiskSignature;
  559. DWORD NumberOfEntries;
  560. ASRFMT_CLUSTER_VOLUME_INFO VolumeInfoEntry[1];
  561. } ASRFMT_CLUSTER_VOLUMES_TABLE, *PASRFMT_CLUSTER_VOLUMES_TABLE;
  562. BOOL
  563. AsrpFmtGetVolumeDetails(
  564. IN PWSTR lpVolumeGuid,
  565. OUT PWSTR lpFsName,
  566. IN DWORD cchFsName,
  567. OUT PWSTR lpVolumeLabel,
  568. IN DWORD cchVolumeLabel,
  569. OUT LPDWORD lpClusterSize
  570. )
  571. {
  572. DWORD dwFSFlags = 0,
  573. dwSectorsPerCluster = 0,
  574. dwBytesPerSector = 0,
  575. dwNumFreeClusters = 0,
  576. dwTotalNumClusters = 0;
  577. BOOL result1 = TRUE,
  578. result2 = TRUE;
  579. *lpFsName = 0;
  580. *lpVolumeLabel = 0;
  581. *lpClusterSize = 0;
  582. SetErrorMode(SEM_FAILCRITICALERRORS);
  583. result1 = GetVolumeInformationW(lpVolumeGuid,
  584. lpVolumeLabel,
  585. cchVolumeLabel,
  586. NULL, // no need for serial number
  587. NULL, // max file name length
  588. &dwFSFlags, // !! we might need to store some of this ...
  589. lpFsName,
  590. cchFsName
  591. );
  592. result2 = GetDiskFreeSpaceW(lpVolumeGuid,
  593. &dwSectorsPerCluster,
  594. &dwBytesPerSector,
  595. &dwNumFreeClusters,
  596. &dwTotalNumClusters
  597. );
  598. *lpClusterSize = dwSectorsPerCluster * dwBytesPerSector;
  599. return (result1 && result2);
  600. }
  601. DWORD
  602. WINAPI
  603. AsrpGetLocalVolumeInfo(
  604. IN LPSTR lpszDeviceName,
  605. IN LPSTR lpszContextString, // not used
  606. OUT PVOID lpOutBuffer,
  607. IN DWORD nOutBufferSize,
  608. OUT LPDWORD lpBytesReturned
  609. )
  610. {
  611. PASR_DISK_INFO pLocalDisk = NULL;
  612. HANDLE heapHandle = NULL;
  613. DWORD status = ERROR_SUCCESS;
  614. BOOL result = FALSE;
  615. ULONG MaxDeviceNumber = 0;
  616. DWORD cchReqdSize = 0,
  617. cchGuid = 0,
  618. offset = 0,
  619. index = 0,
  620. i = 0;
  621. USHORT
  622. cbFsName = 0,
  623. cbLabel = 0,
  624. cbLinks = 0;
  625. PMOUNTMGR_MOUNT_POINTS mountPointsOut = NULL;
  626. WCHAR devicePath[MAX_PATH + 1];
  627. WCHAR volumeGuid[MAX_PATH + 1];
  628. WCHAR fileSystemName[MAX_PATH + 1];
  629. WCHAR volumeLabel[MAX_PATH + 1];
  630. UINT driveType = DRIVE_UNKNOWN;
  631. DWORD clusterSize = 0;
  632. BOOL bufferFull = FALSE,
  633. foundGuid = FALSE;
  634. PPARTITION_INFORMATION_EX currentPartitionEx = NULL;
  635. PASRFMT_CLUSTER_VOLUMES_TABLE pTable = NULL;
  636. heapHandle = GetProcessHeap();
  637. //
  638. // Either the BytesReturned must be non-null (he's getting the required size),
  639. // or the lpOutBuffer must be non-null (he's getting the data).
  640. //
  641. _AsrpErrExitCode(!(lpOutBuffer || lpBytesReturned), status, ERROR_INVALID_PARAMETER);
  642. if (lpBytesReturned) {
  643. *lpBytesReturned = 0;
  644. }
  645. //
  646. // Zero the out buffer
  647. //
  648. if ((lpOutBuffer) && (nOutBufferSize > 0)) {
  649. ZeroMemory(lpOutBuffer, nOutBufferSize);
  650. }
  651. pLocalDisk = (PASR_DISK_INFO) HeapAlloc(
  652. heapHandle,
  653. HEAP_ZERO_MEMORY,
  654. sizeof (ASR_DISK_INFO)
  655. );
  656. _AsrpErrExitCode(!pLocalDisk, status, ERROR_NOT_ENOUGH_MEMORY);
  657. cchReqdSize = MultiByteToWideChar(CP_ACP,
  658. 0,
  659. lpszDeviceName,
  660. -1,
  661. NULL,
  662. 0
  663. );
  664. pLocalDisk->DevicePath = (PWSTR) HeapAlloc(
  665. heapHandle,
  666. HEAP_ZERO_MEMORY,
  667. (cchReqdSize + 1) * (sizeof(WCHAR))
  668. );
  669. _AsrpErrExitCode(!(pLocalDisk->DevicePath), status, ERROR_NOT_ENOUGH_MEMORY);
  670. result = MultiByteToWideChar(CP_ACP,
  671. 0,
  672. lpszDeviceName,
  673. -1,
  674. pLocalDisk->DevicePath,
  675. (cchReqdSize + 1)
  676. );
  677. _AsrpErrExitCode(!result, status, ERROR_INVALID_PARAMETER);
  678. //
  679. // Get the disk layout information
  680. //
  681. result = AsrpInitLayoutInformation(NULL, pLocalDisk, &MaxDeviceNumber, FALSE); // basic info will suffice
  682. _AsrpErrExitCode(!result, status, GetLastError());
  683. _AsrpErrExitCode(!(pLocalDisk->pDriveLayoutEx), status, ERROR_SUCCESS);
  684. //
  685. //
  686. //
  687. offset = sizeof(ASRFMT_CLUSTER_VOLUMES_TABLE) +
  688. (sizeof(ASRFMT_CLUSTER_VOLUME_INFO) * (pLocalDisk->pDriveLayoutEx->PartitionCount - 1));
  689. pTable = (PASRFMT_CLUSTER_VOLUMES_TABLE) lpOutBuffer;
  690. if ((!lpOutBuffer) || (offset > nOutBufferSize)) {
  691. bufferFull = TRUE;
  692. }
  693. if (!bufferFull) {
  694. if (PARTITION_STYLE_MBR == pLocalDisk->pDriveLayoutEx->PartitionStyle) {
  695. pTable->DiskSignature = pLocalDisk->pDriveLayoutEx->Mbr.Signature;
  696. }
  697. else {
  698. //
  699. // At the moment, only MBR disks are cluster shared disks, and so
  700. // we don't handle GPT disks here. If GPT disks are allowed to
  701. // be on a shared bus in a cluster, change this.
  702. //
  703. _AsrpErrExitCode(FALSE, status, ERROR_SUCCESS);
  704. }
  705. pTable->NumberOfEntries = pLocalDisk->pDriveLayoutEx->PartitionCount;
  706. }
  707. for (index = 0; index < pLocalDisk->pDriveLayoutEx->PartitionCount; index++) {
  708. currentPartitionEx = &(pLocalDisk->pDriveLayoutEx->PartitionEntry[index]);
  709. mountPointsOut = NULL;
  710. foundGuid = FALSE;
  711. //
  712. // For each partition, AsrpGetMountPoints gives a list of all mount points,
  713. // then use that to AsrpFmtGetVolumeDetails
  714. //
  715. // get the volumeGuid
  716. if (!(currentPartitionEx->PartitionNumber)) {
  717. //
  718. // Container partitions have partitionNumber = 0, and have no volume Guids.
  719. //
  720. continue;
  721. }
  722. memset(volumeGuid, 0, (MAX_PATH + 1) * sizeof(WCHAR));
  723. swprintf(devicePath,
  724. ASR_WSZ_DEVICE_PATH_FORMAT,
  725. pLocalDisk->DeviceNumber,
  726. currentPartitionEx->PartitionNumber
  727. );
  728. result = AsrpGetMountPoints(
  729. devicePath,
  730. (wcslen(devicePath) + 1)* sizeof(WCHAR), // including \0, in bytes
  731. &mountPointsOut
  732. );
  733. if (!result || !(mountPointsOut)) {
  734. continue;
  735. }
  736. //
  737. // Go through the list of mount points, and pick out one that
  738. // looks like a volume Guid (starts with \??\Volume)
  739. //
  740. cbLinks = sizeof(WCHAR); // \0 at the end
  741. for (i = 0; i < mountPointsOut->NumberOfMountPoints; i++) {
  742. PWSTR linkName = (PWSTR) (
  743. ((LPBYTE) mountPointsOut) +
  744. mountPointsOut->MountPoints[i].SymbolicLinkNameOffset
  745. );
  746. USHORT sizeLinkName = (UINT) (mountPointsOut->MountPoints[i].SymbolicLinkNameLength);
  747. if (!wcsncmp(ASR_WSZ_VOLUME_PREFIX, linkName, wcslen(ASR_WSZ_VOLUME_PREFIX)) &&
  748. !foundGuid) {
  749. wcsncpy(volumeGuid, linkName, sizeLinkName / sizeof(WCHAR));
  750. foundGuid = TRUE;
  751. }
  752. cbLinks += sizeLinkName + (USHORT) sizeof(WCHAR);
  753. }
  754. //
  755. // GetDriveType needs the volume guid in the dos-name-space, while the
  756. // mount manager gives the volume guid in the nt-name-space. Convert
  757. // the name by changing the \??\ at the beginning to \\?\, and adding
  758. // a back-slash at the end.
  759. //
  760. cchGuid = wcslen(volumeGuid);
  761. volumeGuid[1] = L'\\';
  762. volumeGuid[cchGuid] = L'\\'; // Trailing back-slash
  763. volumeGuid[cchGuid+1] = L'\0';
  764. driveType = GetDriveTypeW(volumeGuid);
  765. //
  766. // Get the FS Label, cluster size, and so on.
  767. //
  768. result = AsrpFmtGetVolumeDetails(volumeGuid,
  769. fileSystemName,
  770. MAX_PATH + 1,
  771. volumeLabel,
  772. MAX_PATH + 1,
  773. &clusterSize
  774. );
  775. if (!result) {
  776. continue;
  777. }
  778. cbFsName = wcslen(fileSystemName) * sizeof(WCHAR);
  779. cbLabel = wcslen(volumeLabel) * sizeof(WCHAR);
  780. if (bufferFull) {
  781. offset += (cbFsName + cbLabel + cbLinks);
  782. }
  783. else {
  784. if (offset + cbFsName + cbLabel + cbLinks > nOutBufferSize) {
  785. bufferFull = TRUE;
  786. }
  787. else {
  788. if (cbFsName) {
  789. CopyMemory(((LPBYTE)lpOutBuffer + offset),
  790. fileSystemName,
  791. cbFsName
  792. );
  793. pTable->VolumeInfoEntry[index].FsNameOffset = offset;
  794. pTable->VolumeInfoEntry[index].FsNameLength = cbFsName;
  795. offset += cbFsName;
  796. }
  797. if (cbLabel) {
  798. CopyMemory(((LPBYTE)lpOutBuffer + offset),
  799. volumeLabel,
  800. cbLabel
  801. );
  802. pTable->VolumeInfoEntry[index].LabelOffset = offset;
  803. pTable->VolumeInfoEntry[index].LabelLength = cbLabel;
  804. offset += cbLabel;
  805. }
  806. //
  807. // Copy the symbolic links, separated by zeroes
  808. //
  809. if (mountPointsOut->NumberOfMountPoints > 0) {
  810. pTable->VolumeInfoEntry[index].SymbolicNamesOffset = offset;
  811. }
  812. for (i = 0; i < mountPointsOut->NumberOfMountPoints; i++) {
  813. PWSTR linkName = (PWSTR) (
  814. ((LPBYTE) mountPointsOut) +
  815. mountPointsOut->MountPoints[i].SymbolicLinkNameOffset
  816. );
  817. UINT sizeLinkName = (UINT) (mountPointsOut->MountPoints[i].SymbolicLinkNameLength);
  818. CopyMemory(((LPBYTE)lpOutBuffer + offset),
  819. linkName,
  820. sizeLinkName
  821. );
  822. offset += (sizeLinkName + sizeof(WCHAR));
  823. }
  824. offset += sizeof(WCHAR); // second \0 at the end
  825. pTable->VolumeInfoEntry[index].SymbolicNamesLength = cbLinks;
  826. pTable->VolumeInfoEntry[index].driveType = driveType;
  827. pTable->VolumeInfoEntry[index].PartitionNumber = currentPartitionEx->PartitionNumber;
  828. pTable->VolumeInfoEntry[index].dwClusterSize = clusterSize;
  829. }
  830. }
  831. _AsrpHeapFree(mountPointsOut);
  832. }
  833. if (lpBytesReturned) {
  834. *lpBytesReturned = offset;
  835. }
  836. EXIT:
  837. AsrpFreeStateInformation(&pLocalDisk, NULL);
  838. return status;
  839. }