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.

1267 lines
36 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. #include <clusdisk.h>
  30. #define THIS_MODULE 'C'
  31. #include "asrpriv.h" // Private ASR definitions and routines
  32. //
  33. // --------
  34. // typedef's local to this module
  35. // --------
  36. //
  37. //
  38. // The cluster resource related typdefs
  39. //
  40. typedef DWORD (* PFN_CLUSTER_RESOURCE_CONTROL) (
  41. IN HRESOURCE hResource,
  42. IN OPTIONAL HNODE hHostNode,
  43. IN DWORD dwControlCode,
  44. IN LPVOID lpInBuffer,
  45. IN DWORD cbInBufferSize,
  46. OUT LPVOID lpOutBuffer,
  47. IN DWORD cbOutBufferSize,
  48. OUT LPDWORD lpcbBytesReturned
  49. );
  50. typedef DWORD (* PFN_RES_UTIL_ENUM_RESOURCES) (
  51. IN HRESOURCE hSelf,
  52. IN LPCWSTR lpszResTypeName,
  53. IN LPRESOURCE_CALLBACK pResCallBack,
  54. IN PVOID pParameter
  55. );
  56. //
  57. // ---------
  58. // global variables used within this module.
  59. // --------
  60. //
  61. PFN_CLUSTER_RESOURCE_CONTROL pfnClusterResourceControl;
  62. //
  63. // ---------
  64. // constants used within this module.
  65. // --------
  66. //
  67. const WCHAR ASR_CLUSTER_PHYSICAL_DISK[] = L"Physical Disk";
  68. const WCHAR ASR_CLUSTER_CLUSAPI_DLL_NAME[] = L"clusapi.dll";
  69. const WCHAR ASR_CLUSTER_RESUTILS_DLL_NAME[] = L"resutils.dll";
  70. //
  71. // The following must be single-byte ansi chars
  72. //
  73. const CHAR ASR_CLUSTER_DLL_MODULE_NAME[] = "%SystemRoot%\\system32\\syssetup.dll";
  74. const CHAR ASR_CLUSTER_DLL_PROC_NAME[] = "AsrpGetLocalDiskInfo";
  75. const CHAR ASR_CLUSTER_CLUSAPI_PROC_NAME[] = "ClusterResourceControl";
  76. const CHAR ASR_CLUSTER_RESUTILS_PROC_NAME[] = "ResUtilEnumResources";
  77. //
  78. // --------
  79. // function implementations
  80. // --------
  81. //
  82. //
  83. // --- AsrpGetLocalVolumeInfo and related helper functions
  84. //
  85. //
  86. // The disk info struct we get back from the remote nodes on the cluster will have
  87. // offsets instead of pointers--we can convert this back to pointers by just adding
  88. // back the base address. We also mark that this struct is packed--so we should just
  89. // free the entire struct instead of freeing each pointer in the struct.
  90. //
  91. BOOL
  92. AsrpUnPackDiskInfo(
  93. IN PVOID InBuffer,
  94. IN CONST DWORD dwSizeBuffer
  95. )
  96. {
  97. PASR_DISK_INFO pBuffer = (PASR_DISK_INFO) InBuffer;
  98. DWORD dwNextOffset = 0;
  99. /* if (!((pBuffer->pDriveLayoutEx) && (pBuffer->pDiskGeometry) && (pBuffer->pPartition0Ex))) {
  100. return FALSE;
  101. }
  102. */
  103. //
  104. // Do some sanity checks to ensure that the offsets in the structure make sense
  105. //
  106. if (pBuffer->pDriveLayoutEx) {
  107. //
  108. // Make sure the buffer is big enough to hold this struct, and
  109. // that the entire struct fits within the buffer
  110. //
  111. if ((dwSizeBuffer < sizeof(DRIVE_LAYOUT_INFORMATION_EX)) ||
  112. (PtrToUlong(pBuffer->pDriveLayoutEx) > (dwSizeBuffer - sizeof(DRIVE_LAYOUT_INFORMATION_EX)))) {
  113. return FALSE;
  114. }
  115. //
  116. // Set the minimum value for the next struct
  117. //
  118. dwNextOffset = PtrToUlong(pBuffer->pDriveLayoutEx) + sizeof(DRIVE_LAYOUT_INFORMATION_EX);
  119. }
  120. if (pBuffer->pDiskGeometry) {
  121. //
  122. // Make sure this struct doesn't overlap with the previous struct
  123. //
  124. if (PtrToUlong(pBuffer->pDiskGeometry) < dwNextOffset) {
  125. return FALSE;
  126. }
  127. //
  128. // Make sure we haven't run off the end
  129. //
  130. if (dwNextOffset > dwSizeBuffer) {
  131. return FALSE;
  132. }
  133. //
  134. // Make sure the rest of buffer is big enough to hold this struct, and
  135. // that the entire struct fits within the buffer
  136. //
  137. if (((dwSizeBuffer - dwNextOffset) < sizeof(DISK_GEOMETRY)) ||
  138. (PtrToUlong(pBuffer->pDiskGeometry) > (dwSizeBuffer - sizeof(DISK_GEOMETRY)))) {
  139. return FALSE;
  140. }
  141. //
  142. // Set the minimum value for the next struct
  143. //
  144. dwNextOffset = PtrToUlong(pBuffer->pDiskGeometry) + sizeof(DISK_GEOMETRY);
  145. }
  146. if (pBuffer->pPartition0Ex) {
  147. //
  148. // Make sure this struct doesn't overlap with the previous struct
  149. //
  150. if (PtrToUlong(pBuffer->pPartition0Ex) < dwNextOffset) {
  151. return FALSE;
  152. }
  153. //
  154. // Make sure we haven't run off the end
  155. //
  156. if (dwNextOffset > dwSizeBuffer) {
  157. return FALSE;
  158. }
  159. //
  160. // Make sure the rest of buffer is big enough to hold this struct, and
  161. // that the entire struct fits within the buffer
  162. //
  163. if (((dwSizeBuffer - dwNextOffset) < sizeof(PARTITION_INFORMATION_EX)) ||
  164. (PtrToUlong(pBuffer->pPartition0Ex) > (dwSizeBuffer - sizeof(PARTITION_INFORMATION_EX)))) {
  165. return FALSE;
  166. }
  167. //
  168. // Set the minimum value for the next struct
  169. //
  170. dwNextOffset = PtrToUlong(pBuffer->pPartition0Ex) + sizeof(PARTITION_INFORMATION_EX);
  171. }
  172. if (pBuffer->PartitionInfoTable) {
  173. //
  174. // Make sure this struct doesn't overlap with the previous struct
  175. //
  176. if (PtrToUlong(pBuffer->PartitionInfoTable) < dwNextOffset) {
  177. return FALSE;
  178. }
  179. //
  180. // Make sure we haven't run off the end
  181. //
  182. if (dwNextOffset > dwSizeBuffer) {
  183. return FALSE;
  184. }
  185. //
  186. // Make sure the rest of buffer is big enough to hold this struct, and
  187. // that the entire struct fits within the buffer
  188. //
  189. if (((dwSizeBuffer - dwNextOffset) < sizeof(ASR_PTN_INFO)) ||
  190. (PtrToUlong(pBuffer->PartitionInfoTable) > (dwSizeBuffer - sizeof(ASR_PTN_INFO)))) {
  191. return FALSE;
  192. }
  193. //
  194. // Set the minimum value for the next struct
  195. //
  196. dwNextOffset = PtrToUlong(pBuffer->PartitionInfoTable) + sizeof(ASR_PTN_INFO);
  197. }
  198. if (pBuffer->pScsiAddress) {
  199. //
  200. // Make sure this struct doesn't overlap with the previous struct
  201. //
  202. if (PtrToUlong(pBuffer->pScsiAddress) < dwNextOffset) {
  203. return FALSE;
  204. }
  205. //
  206. // Make sure we haven't run off the end
  207. //
  208. if (dwNextOffset > dwSizeBuffer) {
  209. return FALSE;
  210. }
  211. //
  212. // Make sure the rest of buffer is big enough to hold this struct, and
  213. // that the entire struct fits within the buffer
  214. //
  215. if (((dwSizeBuffer - dwNextOffset) < sizeof(SCSI_ADDRESS)) ||
  216. (PtrToUlong(pBuffer->pScsiAddress) > (dwSizeBuffer - sizeof(SCSI_ADDRESS)))) {
  217. return FALSE;
  218. }
  219. //
  220. // Set the minimum value for the next struct
  221. //
  222. dwNextOffset = PtrToUlong(pBuffer->pScsiAddress) + sizeof(SCSI_ADDRESS);
  223. }
  224. //
  225. // Make sure we haven't run off the end
  226. //
  227. if (dwNextOffset > dwSizeBuffer) {
  228. return FALSE;
  229. }
  230. pBuffer->IsPacked = TRUE;
  231. //
  232. // Convert the offsets to pointers
  233. //
  234. if (pBuffer->pDriveLayoutEx) {
  235. pBuffer->pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) ((LPBYTE)pBuffer + PtrToUlong(pBuffer->pDriveLayoutEx));
  236. }
  237. if (pBuffer->pDiskGeometry) {
  238. pBuffer->pDiskGeometry = (PDISK_GEOMETRY) ((LPBYTE)pBuffer + PtrToUlong((LPBYTE)pBuffer->pDiskGeometry));
  239. }
  240. if (pBuffer->pPartition0Ex) {
  241. pBuffer->pPartition0Ex = (PPARTITION_INFORMATION_EX) ((LPBYTE)pBuffer + PtrToUlong(pBuffer->pPartition0Ex));
  242. }
  243. if (pBuffer->PartitionInfoTable) {
  244. pBuffer->PartitionInfoTable = (PASR_PTN_INFO) ((LPBYTE)pBuffer + PtrToUlong(pBuffer->PartitionInfoTable));
  245. }
  246. if (pBuffer->pScsiAddress) {
  247. pBuffer->pScsiAddress = (PSCSI_ADDRESS) ((LPBYTE)pBuffer + PtrToUlong(pBuffer->pScsiAddress));
  248. }
  249. return TRUE;
  250. }
  251. //
  252. // Copies the info in pLocalDisk to a flat buffer pointed to by lpOutBuffer.
  253. // The pointers are changed to offsets from the start of the buffer.
  254. //
  255. DWORD
  256. AsrpPackDiskInfo(
  257. IN PASR_DISK_INFO pLocalDisk,
  258. OUT PVOID lpOutBuffer,
  259. IN DWORD nOutBufferSize,
  260. OUT LPDWORD lpBytesReturned
  261. )
  262. {
  263. DWORD reqdSize = 0;
  264. PASR_DISK_INFO pBuffer = NULL;
  265. DWORD offset = 0;
  266. MYASSERT(pLocalDisk);
  267. //
  268. // Calculate required size
  269. //
  270. reqdSize = sizeof (ASR_DISK_INFO) +
  271. pLocalDisk->sizeDriveLayoutEx +
  272. pLocalDisk->sizeDiskGeometry +
  273. pLocalDisk->sizePartition0Ex +
  274. pLocalDisk->sizePartitionInfoTable;
  275. if (pLocalDisk->pScsiAddress) {
  276. reqdSize += sizeof(SCSI_ADDRESS);
  277. }
  278. if (lpBytesReturned) {
  279. *lpBytesReturned = reqdSize;
  280. }
  281. if (reqdSize > nOutBufferSize) {
  282. return ERROR_INSUFFICIENT_BUFFER;
  283. }
  284. //
  285. // Copy the ASR_DISK_INFO struct over to outBuffer
  286. //
  287. memcpy(lpOutBuffer, pLocalDisk, sizeof(ASR_DISK_INFO));
  288. pBuffer = (PASR_DISK_INFO) lpOutBuffer;
  289. offset = sizeof(ASR_DISK_INFO); // offset where the next struct will be copied
  290. //
  291. // Now, we go through the buffer and convert all pointers to offsets,
  292. // and copy over the structs they were pointing to.
  293. //
  294. //
  295. // First pointer: PWSTR DevicePath;
  296. // Since the DevicePath makes sense only in the context of the local node,
  297. // we return NULL to the remote node.
  298. //
  299. pBuffer->DevicePath = NULL;
  300. //
  301. // Next pointer: PDRIVE_LAYOUT_INFORMATION_EX pDriveLayoutEx;
  302. //
  303. if (pLocalDisk->pDriveLayoutEx) {
  304. memcpy(((LPBYTE)lpOutBuffer + offset),
  305. pLocalDisk->pDriveLayoutEx,
  306. pLocalDisk->sizeDriveLayoutEx
  307. );
  308. pBuffer->pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) UlongToPtr(offset);
  309. offset += pLocalDisk->sizeDriveLayoutEx;
  310. }
  311. //
  312. // Next pointer: PDISK_GEOMETRY pDiskGeometry;
  313. //
  314. if (pLocalDisk->pDiskGeometry) {
  315. memcpy(((LPBYTE)lpOutBuffer + offset),
  316. pLocalDisk->pDiskGeometry,
  317. pLocalDisk->sizeDiskGeometry
  318. );
  319. pBuffer->pDiskGeometry = (PDISK_GEOMETRY) UlongToPtr(offset);
  320. offset += pLocalDisk->sizeDiskGeometry;
  321. }
  322. //
  323. // Next pointer: PPARTITION_INFORMATION_EX pPartition0Ex;
  324. //
  325. if (pLocalDisk->pPartition0Ex) {
  326. memcpy(((LPBYTE)lpOutBuffer + offset),
  327. pLocalDisk->pPartition0Ex,
  328. pLocalDisk->sizePartition0Ex
  329. );
  330. pBuffer->pPartition0Ex= (PPARTITION_INFORMATION_EX) UlongToPtr(offset);
  331. offset += pLocalDisk->sizePartition0Ex;
  332. }
  333. //
  334. // Next pointer: PASR_PTN_INFO PartitionInfoTable;
  335. //
  336. if (pLocalDisk->PartitionInfoTable) {
  337. memcpy(((LPBYTE)lpOutBuffer + offset),
  338. pLocalDisk->PartitionInfoTable,
  339. pLocalDisk->sizePartitionInfoTable
  340. );
  341. pBuffer->PartitionInfoTable = (PASR_PTN_INFO) UlongToPtr(offset);
  342. offset += pLocalDisk->sizePartitionInfoTable;
  343. }
  344. //
  345. // Last pointer: PSCSI_ADDRESS pScsiAddress;
  346. //
  347. if (pLocalDisk->pScsiAddress) {
  348. memcpy(((LPBYTE)lpOutBuffer + offset),
  349. pLocalDisk->pScsiAddress,
  350. sizeof(SCSI_ADDRESS)
  351. );
  352. pBuffer->pScsiAddress = (PSCSI_ADDRESS) UlongToPtr(offset);
  353. offset += sizeof(SCSI_ADDRESS);
  354. }
  355. MYASSERT(offset <= nOutBufferSize);
  356. return ERROR_SUCCESS;
  357. }
  358. DWORD
  359. WINAPI
  360. AsrpGetLocalDiskInfo(
  361. IN LPSTR lpszDeviceName,
  362. IN LPSTR lpszContextString, // not used
  363. OUT PVOID lpOutBuffer,
  364. IN DWORD nOutBufferSize,
  365. OUT LPDWORD lpBytesReturned
  366. )
  367. {
  368. PASR_DISK_INFO pLocalDisk = NULL;
  369. HANDLE heapHandle = NULL;
  370. DWORD status = ERROR_SUCCESS;
  371. BOOL result = FALSE;
  372. ULONG MaxDeviceNumber = 0;
  373. DWORD cchReqdSize = 0;
  374. heapHandle = GetProcessHeap();
  375. //
  376. // Either the BytesReturned must be non-null (he's getting the required size),
  377. // or the lpOutBuffer must be non-null (he's getting the data).
  378. //
  379. _AsrpErrExitCode(!(lpOutBuffer || lpBytesReturned), status, ERROR_INVALID_PARAMETER);
  380. if (lpBytesReturned) {
  381. *lpBytesReturned = 0;
  382. }
  383. pLocalDisk = (PASR_DISK_INFO) HeapAlloc(
  384. heapHandle,
  385. HEAP_ZERO_MEMORY,
  386. sizeof (ASR_DISK_INFO)
  387. );
  388. _AsrpErrExitCode(!pLocalDisk, status, ERROR_NOT_ENOUGH_MEMORY);
  389. cchReqdSize = MultiByteToWideChar(CP_ACP,
  390. 0,
  391. lpszDeviceName,
  392. -1,
  393. NULL,
  394. 0
  395. );
  396. pLocalDisk->DevicePath = (PWSTR) HeapAlloc(
  397. heapHandle,
  398. HEAP_ZERO_MEMORY,
  399. (cchReqdSize + 1) * (sizeof(WCHAR))
  400. );
  401. _AsrpErrExitCode(!(pLocalDisk->DevicePath), status, ERROR_NOT_ENOUGH_MEMORY);
  402. result = MultiByteToWideChar(CP_ACP,
  403. 0,
  404. lpszDeviceName,
  405. -1,
  406. pLocalDisk->DevicePath,
  407. (cchReqdSize + 1)
  408. );
  409. _AsrpErrExitCode(!result, status, ERROR_INVALID_PARAMETER);
  410. //
  411. // Get the disk layout information
  412. //
  413. result = AsrpInitLayoutInformation(NULL, pLocalDisk, &MaxDeviceNumber, TRUE, TRUE);
  414. _AsrpErrExitCode(!result, status, GetLastError());
  415. // _AsrpErrExitCode(result && GetLastErr what if createfile fails?
  416. result = AsrpFreeNonFixedMedia(&pLocalDisk);
  417. _AsrpErrExitCode(!result, status, GetLastError());
  418. _AsrpErrExitCode(!pLocalDisk, status, ERROR_SUCCESS);
  419. //
  420. // Copy it to the out buffer without any pointers
  421. //
  422. status = AsrpPackDiskInfo(pLocalDisk, lpOutBuffer, nOutBufferSize, lpBytesReturned);
  423. EXIT:
  424. AsrpFreeStateInformation(&pLocalDisk, NULL);
  425. return status;
  426. }
  427. BOOL
  428. AsrpIsOfflineClusteredDisk(
  429. IN CONST HANDLE hDisk
  430. )
  431. /*++
  432. Routine Description:
  433. Utility to check if the current disk is a shared cluster disk that's owned
  434. by a different node (and is hence inaccessible).
  435. Based on code-snippet graciously donated by SteveDz.
  436. Arguments:
  437. hDisk - Supplies a handle (no access required) to the disk of interest.
  438. Return Value:
  439. If the function succeeds and the disk is a shared cluster disk that is
  440. offline on the current node, the return value is a nonzero value.
  441. If the function fails, or if the disk is not a shared cluster disk that
  442. is offline on the current node (ie, is a local unshared disk, or
  443. a shared disk that online to the current node) the return value
  444. is zero.
  445. --*/
  446. {
  447. BOOL result = FALSE;
  448. DWORD bytesReturned = 0;
  449. DiskState diskState = DiskOffline;
  450. if ((!hDisk) || (INVALID_HANDLE_VALUE == hDisk)) {
  451. //
  452. // We couldn't open the disk--let's assume that it's not an offline
  453. // clustered disk.
  454. //
  455. return FALSE;
  456. }
  457. //
  458. // To get current disk state, don't specify input buffer.
  459. // Current disk state returned in output buffer.
  460. //
  461. result = DeviceIoControl(hDisk,
  462. IOCTL_DISK_CLUSTER_GET_STATE,
  463. NULL,
  464. 0,
  465. &diskState,
  466. sizeof(DiskState),
  467. &bytesReturned,
  468. FALSE
  469. );
  470. if ((result) && (DiskOffline == diskState)) {
  471. return TRUE;
  472. }
  473. else {
  474. return FALSE;
  475. }
  476. }
  477. //
  478. // ---- AsrpInitClusterSharedDisks and related helper functions
  479. //
  480. BOOL
  481. AsrpIsClusteredDiskSame(
  482. IN PASR_DISK_INFO currentDisk,
  483. IN PASR_DISK_INFO clusterDisk
  484. )
  485. {
  486. if (!clusterDisk || !currentDisk) {
  487. MYASSERT(0 && L"Invalid parameter, Disk is NULL");
  488. return FALSE;
  489. }
  490. if (currentDisk->Style != clusterDisk->Style) {
  491. return FALSE;
  492. }
  493. if (PARTITION_STYLE_MBR == clusterDisk->Style) { // currently always true
  494. if (clusterDisk->pDriveLayoutEx) {
  495. if (currentDisk->pDriveLayoutEx) {
  496. return (currentDisk->pDriveLayoutEx->Mbr.Signature == clusterDisk->pDriveLayoutEx->Mbr.Signature);
  497. }
  498. else {
  499. return (currentDisk->TempSignature == clusterDisk->pDriveLayoutEx->Mbr.Signature);
  500. }
  501. }
  502. else {
  503. MYASSERT(0 && L"Cluster disk drive layout is NULL");
  504. return FALSE;
  505. }
  506. }
  507. else {
  508. if (clusterDisk->pDriveLayoutEx && currentDisk->pDriveLayoutEx) {
  509. return (IsEqualGUID(&(currentDisk->pDriveLayoutEx->Gpt.DiskId), &(clusterDisk->pDriveLayoutEx->Gpt.DiskId)));
  510. }
  511. else {
  512. return FALSE;
  513. }
  514. }
  515. return FALSE;
  516. }
  517. DWORD
  518. AsrpResourceCallBack(
  519. RESOURCE_HANDLE hOriginal,
  520. RESOURCE_HANDLE hResource,
  521. PVOID lpParams
  522. )
  523. {
  524. DISK_DLL_EXTENSION_INFO inBuffer;
  525. PBYTE outBuffer = NULL;
  526. DWORD sizeOutBuffer = 0,
  527. bytesReturned = 0;
  528. DWORD status = ERROR_SUCCESS;
  529. PASR_DISK_INFO currentDisk = (PASR_DISK_INFO) lpParams,
  530. clusterDisk = NULL,
  531. prevDisk = NULL;
  532. BOOL bResult = FALSE;
  533. HANDLE heapHandle = NULL;
  534. BOOL done = FALSE;
  535. if (!lpParams) {
  536. //
  537. // The system must have at least one disk that has been enumerated
  538. // already (the system disk, at least!), so our disk list shouldn't be NULL.
  539. //
  540. return ERROR_INVALID_PARAMETER;
  541. }
  542. heapHandle = GetProcessHeap();
  543. MYASSERT(heapHandle);
  544. //
  545. // Allocate a reasonably-sized memory for the out buffer. If this isn't
  546. // big enough, we'll re-allocate.
  547. //
  548. sizeOutBuffer = ASR_BUFFER_SIZE;
  549. outBuffer = (PBYTE) HeapAlloc(
  550. heapHandle,
  551. HEAP_ZERO_MEMORY,
  552. sizeOutBuffer
  553. );
  554. _AsrpErrExitCode(!outBuffer, status, ERROR_NOT_ENOUGH_MEMORY);
  555. //
  556. // Call AsrpGetLocalDiskInfo on the node owning this disk resource
  557. //
  558. ZeroMemory(&inBuffer, sizeof(inBuffer));
  559. inBuffer.MajorVersion = NT5_MAJOR_VERSION;
  560. strcpy(inBuffer.DllModuleName, ASR_CLUSTER_DLL_MODULE_NAME);
  561. strcpy(inBuffer.DllProcName, ASR_CLUSTER_DLL_PROC_NAME);
  562. status = (pfnClusterResourceControl) (hResource,
  563. NULL,
  564. CLUSCTL_RESOURCE_STORAGE_DLL_EXTENSION,
  565. &inBuffer,
  566. sizeof(DISK_DLL_EXTENSION_INFO),
  567. (PVOID) outBuffer,
  568. sizeOutBuffer,
  569. &bytesReturned
  570. );
  571. if (ERROR_INSUFFICIENT_BUFFER == status) {
  572. //
  573. // The buffer wasn't big enough, re-allocate as needed
  574. //
  575. _AsrpHeapFree(outBuffer);
  576. sizeOutBuffer = bytesReturned;
  577. outBuffer = (PBYTE) HeapAlloc(
  578. heapHandle,
  579. HEAP_ZERO_MEMORY,
  580. sizeOutBuffer
  581. );
  582. _AsrpErrExitCode(!outBuffer, status, ERROR_NOT_ENOUGH_MEMORY);
  583. status = (pfnClusterResourceControl) (
  584. hResource,
  585. NULL,
  586. CLUSCTL_RESOURCE_STORAGE_DLL_EXTENSION,
  587. &inBuffer,
  588. sizeof(DISK_DLL_EXTENSION_INFO),
  589. (PVOID) outBuffer,
  590. sizeOutBuffer,
  591. &bytesReturned
  592. );
  593. }
  594. _AsrpErrExitCode((ERROR_SUCCESS != status), status, status);
  595. //
  596. // outBuffer has a packed disk info struct (ie the pointers are offsets).
  597. //
  598. bResult = AsrpUnPackDiskInfo(outBuffer, sizeOutBuffer);
  599. _AsrpErrExitCode(!bResult, status, ERROR_INVALID_DATA);
  600. clusterDisk = (PASR_DISK_INFO) outBuffer;
  601. clusterDisk->IsClusterShared = TRUE;
  602. clusterDisk->IsPacked = TRUE; // so that we free this properly
  603. //
  604. // Check if clusterDisk already has info in our list (ie is owned
  605. // locally)
  606. //
  607. // Note that for now, clusterDisk is always MBR (since clusters don't
  608. // support shared GPT disks). We don't care here, we handle GPT as well.
  609. //
  610. done = FALSE;
  611. prevDisk = NULL;
  612. while (currentDisk && !done) {
  613. if (AsrpIsClusteredDiskSame(currentDisk, clusterDisk)) {
  614. if (currentDisk->pDriveLayoutEx) {
  615. //
  616. // This disk is owned by the local node (correct?), since
  617. // we would not have gotten the pDriveLayout otherwise
  618. //
  619. currentDisk->IsClusterShared = TRUE;
  620. currentDisk->IsPacked = FALSE;
  621. //
  622. // We don't need the info returned by clusterDisk, we have
  623. // it in currentDisk already.
  624. //
  625. _AsrpHeapFree(clusterDisk); // it's packed.
  626. }
  627. else {
  628. //
  629. // This disk is owned by a remote node. So we add clusterDisk
  630. // in to our list now. We'll remove currentDisk from our
  631. // list later (in RemoveNonFixedDevices).
  632. //
  633. // First though, we copy over DevicePath and DeviceNumber
  634. // from currentDisk, since these are relative to the local
  635. // machine
  636. //
  637. if (currentDisk->DevicePath) {
  638. clusterDisk->DevicePath = (PWSTR) HeapAlloc(
  639. heapHandle,
  640. HEAP_ZERO_MEMORY,
  641. sizeof(WCHAR) * (wcslen(currentDisk->DevicePath) + 1)
  642. );
  643. wcscpy(clusterDisk->DevicePath, currentDisk->DevicePath);
  644. }
  645. clusterDisk->DeviceNumber = currentDisk->DeviceNumber;
  646. //
  647. // Don't bother freeing currentDisk, it'll get taken care
  648. // of in RemoveNonFixedDevices.
  649. //
  650. clusterDisk->pNext = currentDisk->pNext;
  651. currentDisk->pNext = clusterDisk;
  652. 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)
  653. }
  654. done = TRUE;
  655. }
  656. prevDisk = currentDisk;
  657. currentDisk = currentDisk->pNext;
  658. }
  659. if (!done) {
  660. //
  661. // This disk was not found in our list (strange), let's add
  662. // it in at the end
  663. //
  664. // MYASSERT(0 && L"Clustered disk not found in OriginalDiskList, adding it to the end");
  665. clusterDisk->pNext = NULL;
  666. prevDisk->pNext = clusterDisk;
  667. }
  668. EXIT:
  669. //
  670. // Free up outBuffer on failure. On success, outBuffer shouldn't
  671. // be freed, it will either be part of OriginalDiskList or already
  672. // be freed.
  673. //
  674. if (ERROR_SUCCESS != status) {
  675. _AsrpHeapFree(outBuffer);
  676. }
  677. return status;
  678. }
  679. BOOL
  680. AsrpInitClusterSharedDisks(
  681. IN PASR_DISK_INFO OriginalDiskList
  682. )
  683. {
  684. DWORD status = ERROR_SUCCESS,
  685. dwOldError;
  686. HMODULE hClusApi = NULL,
  687. hResUtils = NULL;
  688. PFN_RES_UTIL_ENUM_RESOURCES pfnResUtilEnumResources = NULL;
  689. dwOldError = GetLastError();
  690. if (!OriginalDiskList) {
  691. SetLastError(ERROR_INVALID_PARAMETER);
  692. return FALSE;
  693. }
  694. hClusApi = LoadLibraryW(ASR_CLUSTER_CLUSAPI_DLL_NAME);
  695. _AsrpErrExitCode(!hClusApi, status, GetLastError());
  696. pfnClusterResourceControl = (PFN_CLUSTER_RESOURCE_CONTROL) GetProcAddress(
  697. hClusApi,
  698. ASR_CLUSTER_CLUSAPI_PROC_NAME
  699. );
  700. _AsrpErrExitCode(!pfnClusterResourceControl, status, GetLastError());
  701. hResUtils = LoadLibraryW(ASR_CLUSTER_RESUTILS_DLL_NAME);
  702. _AsrpErrExitCode(!hResUtils, status, GetLastError());
  703. pfnResUtilEnumResources = (PFN_RES_UTIL_ENUM_RESOURCES) GetProcAddress(
  704. hResUtils,
  705. ASR_CLUSTER_RESUTILS_PROC_NAME
  706. );
  707. _AsrpErrExitCode(!pfnResUtilEnumResources, status, GetLastError());
  708. status = (pfnResUtilEnumResources) (NULL,
  709. ASR_CLUSTER_PHYSICAL_DISK,
  710. AsrpResourceCallBack,
  711. OriginalDiskList
  712. );
  713. EXIT:
  714. if (hClusApi) {
  715. FreeLibrary(hClusApi);
  716. }
  717. if (hResUtils) {
  718. FreeLibrary(hResUtils);
  719. }
  720. // ResUtil will fail if we aren't on a cluster, but that's fine.
  721. SetLastError(dwOldError);
  722. return TRUE;
  723. }
  724. //
  725. // --- AsrpGetLocalVolumeInfo and related helper functions
  726. //
  727. //
  728. // The following two definitions are from asr_fmt:dr_state.cpp. This MUST be
  729. // kept in sync.
  730. //
  731. typedef struct _ASRFMT_CLUSTER_VOLUME_INFO {
  732. UINT driveType;
  733. DWORD PartitionNumber;
  734. ULONG FsNameOffset;
  735. USHORT FsNameLength;
  736. ULONG LabelOffset;
  737. USHORT LabelLength;
  738. ULONG SymbolicNamesOffset;
  739. USHORT SymbolicNamesLength;
  740. DWORD dwClusterSize;
  741. } ASRFMT_CLUSTER_VOLUME_INFO, *PASRFMT_CLUSTER_VOLUME_INFO;
  742. typedef struct _ASRFMT_CLUSTER_VOLUMES_TABLE {
  743. DWORD DiskSignature;
  744. DWORD NumberOfEntries;
  745. ASRFMT_CLUSTER_VOLUME_INFO VolumeInfoEntry[1];
  746. } ASRFMT_CLUSTER_VOLUMES_TABLE, *PASRFMT_CLUSTER_VOLUMES_TABLE;
  747. BOOL
  748. AsrpFmtGetVolumeDetails(
  749. IN PWSTR lpVolumeGuid,
  750. OUT PWSTR lpFsName,
  751. IN DWORD cchFsName,
  752. OUT PWSTR lpVolumeLabel,
  753. IN DWORD cchVolumeLabel,
  754. OUT LPDWORD lpClusterSize
  755. )
  756. {
  757. DWORD dwFSFlags = 0,
  758. dwSectorsPerCluster = 0,
  759. dwBytesPerSector = 0,
  760. dwNumFreeClusters = 0,
  761. dwTotalNumClusters = 0;
  762. BOOL result1 = TRUE,
  763. result2 = TRUE;
  764. *lpFsName = 0;
  765. *lpVolumeLabel = 0;
  766. *lpClusterSize = 0;
  767. SetErrorMode(SEM_FAILCRITICALERRORS);
  768. result1 = GetVolumeInformationW(lpVolumeGuid,
  769. lpVolumeLabel,
  770. cchVolumeLabel,
  771. NULL, // no need for serial number
  772. NULL, // max file name length
  773. &dwFSFlags, // !! we might need to store some of this ...
  774. lpFsName,
  775. cchFsName
  776. );
  777. result2 = GetDiskFreeSpaceW(lpVolumeGuid,
  778. &dwSectorsPerCluster,
  779. &dwBytesPerSector,
  780. &dwNumFreeClusters,
  781. &dwTotalNumClusters
  782. );
  783. *lpClusterSize = dwSectorsPerCluster * dwBytesPerSector;
  784. return (result1 && result2);
  785. }
  786. DWORD
  787. WINAPI
  788. AsrpGetLocalVolumeInfo(
  789. IN LPSTR lpszDeviceName,
  790. IN LPSTR lpszContextString, // not used
  791. OUT PVOID lpOutBuffer,
  792. IN DWORD nOutBufferSize,
  793. OUT LPDWORD lpBytesReturned
  794. )
  795. {
  796. PASR_DISK_INFO pLocalDisk = NULL;
  797. HANDLE heapHandle = NULL;
  798. DWORD status = ERROR_SUCCESS;
  799. BOOL result = FALSE;
  800. ULONG MaxDeviceNumber = 0;
  801. DWORD cchReqdSize = 0,
  802. cchGuid = 0,
  803. offset = 0,
  804. index = 0,
  805. i = 0;
  806. USHORT
  807. cbFsName = 0,
  808. cbLabel = 0,
  809. cbLinks = 0;
  810. PMOUNTMGR_MOUNT_POINTS mountPointsOut = NULL;
  811. WCHAR devicePath[MAX_PATH + 1];
  812. WCHAR volumeGuid[MAX_PATH + 1];
  813. WCHAR fileSystemName[MAX_PATH + 1];
  814. WCHAR volumeLabel[MAX_PATH + 1];
  815. UINT driveType = DRIVE_UNKNOWN;
  816. DWORD clusterSize = 0;
  817. BOOL bufferFull = FALSE,
  818. foundGuid = FALSE;
  819. PPARTITION_INFORMATION_EX currentPartitionEx = NULL;
  820. PASRFMT_CLUSTER_VOLUMES_TABLE pTable = NULL;
  821. heapHandle = GetProcessHeap();
  822. //
  823. // Either the BytesReturned must be non-null (he's getting the required size),
  824. // or the lpOutBuffer must be non-null (he's getting the data).
  825. //
  826. _AsrpErrExitCode(!(lpOutBuffer || lpBytesReturned), status, ERROR_INVALID_PARAMETER);
  827. if (lpBytesReturned) {
  828. *lpBytesReturned = 0;
  829. }
  830. //
  831. // Zero the out buffer
  832. //
  833. if ((lpOutBuffer) && (nOutBufferSize > 0)) {
  834. ZeroMemory(lpOutBuffer, nOutBufferSize);
  835. }
  836. pLocalDisk = (PASR_DISK_INFO) HeapAlloc(
  837. heapHandle,
  838. HEAP_ZERO_MEMORY,
  839. sizeof (ASR_DISK_INFO)
  840. );
  841. _AsrpErrExitCode(!pLocalDisk, status, ERROR_NOT_ENOUGH_MEMORY);
  842. cchReqdSize = MultiByteToWideChar(CP_ACP,
  843. 0,
  844. lpszDeviceName,
  845. -1,
  846. NULL,
  847. 0
  848. );
  849. pLocalDisk->DevicePath = (PWSTR) HeapAlloc(
  850. heapHandle,
  851. HEAP_ZERO_MEMORY,
  852. (cchReqdSize + 1) * (sizeof(WCHAR))
  853. );
  854. _AsrpErrExitCode(!(pLocalDisk->DevicePath), status, ERROR_NOT_ENOUGH_MEMORY);
  855. result = MultiByteToWideChar(CP_ACP,
  856. 0,
  857. lpszDeviceName,
  858. -1,
  859. pLocalDisk->DevicePath,
  860. (cchReqdSize + 1)
  861. );
  862. _AsrpErrExitCode(!result, status, ERROR_INVALID_PARAMETER);
  863. //
  864. // Get the disk layout information
  865. //
  866. result = AsrpInitLayoutInformation(NULL, pLocalDisk, &MaxDeviceNumber, FALSE, FALSE); // basic info will suffice
  867. _AsrpErrExitCode(!result, status, GetLastError());
  868. _AsrpErrExitCode(!(pLocalDisk->pDriveLayoutEx), status, ERROR_SUCCESS);
  869. //
  870. //
  871. //
  872. offset = sizeof(ASRFMT_CLUSTER_VOLUMES_TABLE) +
  873. (sizeof(ASRFMT_CLUSTER_VOLUME_INFO) * (pLocalDisk->pDriveLayoutEx->PartitionCount - 1));
  874. pTable = (PASRFMT_CLUSTER_VOLUMES_TABLE) lpOutBuffer;
  875. if ((!lpOutBuffer) || (offset > nOutBufferSize)) {
  876. bufferFull = TRUE;
  877. }
  878. if (!bufferFull) {
  879. if (PARTITION_STYLE_MBR == pLocalDisk->pDriveLayoutEx->PartitionStyle) {
  880. pTable->DiskSignature = pLocalDisk->pDriveLayoutEx->Mbr.Signature;
  881. }
  882. else {
  883. //
  884. // At the moment, only MBR disks are cluster shared disks, and so
  885. // we don't handle GPT disks here. If GPT disks are allowed to
  886. // be on a shared bus in a cluster, change this.
  887. //
  888. _AsrpErrExitCode(FALSE, status, ERROR_SUCCESS);
  889. }
  890. pTable->NumberOfEntries = pLocalDisk->pDriveLayoutEx->PartitionCount;
  891. }
  892. for (index = 0; index < pLocalDisk->pDriveLayoutEx->PartitionCount; index++) {
  893. currentPartitionEx = &(pLocalDisk->pDriveLayoutEx->PartitionEntry[index]);
  894. mountPointsOut = NULL;
  895. foundGuid = FALSE;
  896. //
  897. // For each partition, AsrpGetMountPoints gives a list of all mount points,
  898. // then use that to AsrpFmtGetVolumeDetails
  899. //
  900. // get the volumeGuid
  901. if (!(currentPartitionEx->PartitionNumber)) {
  902. //
  903. // Container partitions have partitionNumber = 0, and have no volume Guids.
  904. //
  905. continue;
  906. }
  907. memset(volumeGuid, 0, (MAX_PATH + 1) * sizeof(WCHAR));
  908. swprintf(devicePath,
  909. ASR_WSZ_DEVICE_PATH_FORMAT,
  910. pLocalDisk->DeviceNumber,
  911. currentPartitionEx->PartitionNumber
  912. );
  913. result = AsrpGetMountPoints(
  914. devicePath,
  915. (wcslen(devicePath) + 1)* sizeof(WCHAR), // including \0, in bytes
  916. &mountPointsOut
  917. );
  918. if (!result || !(mountPointsOut)) {
  919. continue;
  920. }
  921. //
  922. // Go through the list of mount points, and pick out one that
  923. // looks like a volume Guid (starts with \??\Volume)
  924. //
  925. cbLinks = sizeof(WCHAR); // \0 at the end
  926. for (i = 0; i < mountPointsOut->NumberOfMountPoints; i++) {
  927. PWSTR linkName = (PWSTR) (
  928. ((LPBYTE) mountPointsOut) +
  929. mountPointsOut->MountPoints[i].SymbolicLinkNameOffset
  930. );
  931. USHORT sizeLinkName = (UINT) (mountPointsOut->MountPoints[i].SymbolicLinkNameLength);
  932. if (!wcsncmp(ASR_WSZ_VOLUME_PREFIX, linkName, wcslen(ASR_WSZ_VOLUME_PREFIX)) &&
  933. !foundGuid) {
  934. wcsncpy(volumeGuid, linkName, sizeLinkName / sizeof(WCHAR));
  935. foundGuid = TRUE;
  936. }
  937. cbLinks += sizeLinkName + (USHORT) sizeof(WCHAR);
  938. }
  939. //
  940. // GetDriveType needs the volume guid in the dos-name-space, while the
  941. // mount manager gives the volume guid in the nt-name-space. Convert
  942. // the name by changing the \??\ at the beginning to \\?\, and adding
  943. // a back-slash at the end.
  944. //
  945. cchGuid = wcslen(volumeGuid);
  946. volumeGuid[1] = L'\\';
  947. volumeGuid[cchGuid] = L'\\'; // Trailing back-slash
  948. volumeGuid[cchGuid+1] = L'\0';
  949. driveType = GetDriveTypeW(volumeGuid);
  950. //
  951. // Get the FS Label, cluster size, and so on.
  952. //
  953. result = AsrpFmtGetVolumeDetails(volumeGuid,
  954. fileSystemName,
  955. MAX_PATH + 1,
  956. volumeLabel,
  957. MAX_PATH + 1,
  958. &clusterSize
  959. );
  960. if (!result) {
  961. continue;
  962. }
  963. cbFsName = wcslen(fileSystemName) * sizeof(WCHAR);
  964. cbLabel = wcslen(volumeLabel) * sizeof(WCHAR);
  965. if (bufferFull) {
  966. offset += (cbFsName + cbLabel + cbLinks);
  967. }
  968. else {
  969. if (offset + cbFsName + cbLabel + cbLinks > nOutBufferSize) {
  970. bufferFull = TRUE;
  971. }
  972. else {
  973. if (cbFsName) {
  974. CopyMemory(((LPBYTE)lpOutBuffer + offset),
  975. fileSystemName,
  976. cbFsName
  977. );
  978. pTable->VolumeInfoEntry[index].FsNameOffset = offset;
  979. pTable->VolumeInfoEntry[index].FsNameLength = cbFsName;
  980. offset += cbFsName;
  981. }
  982. if (cbLabel) {
  983. CopyMemory(((LPBYTE)lpOutBuffer + offset),
  984. volumeLabel,
  985. cbLabel
  986. );
  987. pTable->VolumeInfoEntry[index].LabelOffset = offset;
  988. pTable->VolumeInfoEntry[index].LabelLength = cbLabel;
  989. offset += cbLabel;
  990. }
  991. //
  992. // Copy the symbolic links, separated by zeroes
  993. //
  994. if (mountPointsOut->NumberOfMountPoints > 0) {
  995. pTable->VolumeInfoEntry[index].SymbolicNamesOffset = offset;
  996. }
  997. for (i = 0; i < mountPointsOut->NumberOfMountPoints; i++) {
  998. PWSTR linkName = (PWSTR) (
  999. ((LPBYTE) mountPointsOut) +
  1000. mountPointsOut->MountPoints[i].SymbolicLinkNameOffset
  1001. );
  1002. UINT sizeLinkName = (UINT) (mountPointsOut->MountPoints[i].SymbolicLinkNameLength);
  1003. CopyMemory(((LPBYTE)lpOutBuffer + offset),
  1004. linkName,
  1005. sizeLinkName
  1006. );
  1007. offset += (sizeLinkName + sizeof(WCHAR));
  1008. }
  1009. offset += sizeof(WCHAR); // second \0 at the end
  1010. pTable->VolumeInfoEntry[index].SymbolicNamesLength = cbLinks;
  1011. pTable->VolumeInfoEntry[index].driveType = driveType;
  1012. pTable->VolumeInfoEntry[index].PartitionNumber = currentPartitionEx->PartitionNumber;
  1013. pTable->VolumeInfoEntry[index].dwClusterSize = clusterSize;
  1014. }
  1015. }
  1016. _AsrpHeapFree(mountPointsOut);
  1017. }
  1018. if (lpBytesReturned) {
  1019. *lpBytesReturned = offset;
  1020. }
  1021. EXIT:
  1022. AsrpFreeStateInformation(&pLocalDisk, NULL);
  1023. return status;
  1024. }