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.

4933 lines
132 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. mountpoints.c
  5. Abstract:
  6. This module processes mount point information for the disk resource DLL.
  7. Author:
  8. Steve Dziok (stevedz) 15-May-2000
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #define UNICODE 1
  14. #include "disksp.h"
  15. #include "arbitrat.h"
  16. #include "newdisks.h"
  17. #include "newmount.h"
  18. #include <mountmgr.h>
  19. #include <strsafe.h> // Should be included last.
  20. #define SPACE_CHAR L' '
  21. #define MAX_OFFSET_CHARS 80 // Maximum number of chars allowed in offset string
  22. #define MP_ALLOC_SIZE 1024
  23. #define LOG_CURRENT_MODULE LOG_MODULE_DISK
  24. extern PWCHAR g_DiskResource; // L"rtPhysical Disk"
  25. #define RESOURCE_TYPE ((RESOURCE_HANDLE)g_DiskResource)
  26. #ifndef ClusterHashGuid
  27. //
  28. // Hash a GUID to a ULONG value.
  29. //
  30. #define ClusterHashGuid(_guid) ( ((PULONG) &(_guid))[0] ^ ((PULONG) &(_guid))[1] ^ \
  31. ((PULONG) &(_guid))[2] ^ ((PULONG) &(_guid))[3] )
  32. #endif
  33. #define MPS_ENABLED 0x00000001
  34. #define MPS_DELETE_INVALID_MPS 0x00000002 // Not currently used
  35. #define MPS_NONCLUSTERED_TO_CLUSTERED_MPS 0x00000010 // Not currently used
  36. #define MPS_KEEP_EXISTING_MPS 0x00000020 // Not currently used
  37. #define MPS_IGNORE_MAX_VOLGUIDS 0x00000100
  38. #define MAX_ALLOWED_VOLGUID_ENTRIES_PER_DISK 100
  39. #define STOP_CLUSTER_ENUMERATIONS ERROR_INVALID_PRINTER_COMMAND
  40. #define PHYSICAL_DISK_WSTR L"Physical Disk"
  41. #define CREATE_FILE_PREFIX L"\\\\.\\"
  42. #define MAX_GROUP_NAME_LENGTH MAX_PATH * 2
  43. #define VOL_GUID_STRING_LEN 48
  44. #define MOUNTDEV_WSZ_VOLUME_GUID_PREFIX L"\\??\\Volume{" // Forms: \??\Volume{
  45. #define MOUNTDEV_CWCHAR_VOLUME_GUID_PREFIX 11
  46. #define MOUNTDEV_CB_VOLUME_GUID_PREFIX MOUNTDEV_CWCHAR_VOLUME_GUID_PREFIX * sizeof(WCHAR)
  47. #define MOUNTDEV_LOOKS_LIKE_VOLUME_GUID( name, charCount ) \
  48. ( ( charCount > MOUNTDEV_CWCHAR_VOLUME_GUID_PREFIX ) && \
  49. ( !memcmp( name, MOUNTDEV_WSZ_VOLUME_GUID_PREFIX, MOUNTDEV_CB_VOLUME_GUID_PREFIX ) ) )
  50. #define MOUNTDEV_WSZ_ALT_VOLUME_GUID_PREFIX L"\\\\?\\Volume{" // Forms: \\?\Volume{
  51. #define MOUNTDEV_CWCHAR_ALT_VOLUME_GUID_PREFIX 11
  52. #define MOUNTDEV_CB_ALT_VOLUME_GUID_PREFIX MOUNTDEV_CWCHAR_ALT_VOLUME_GUID_PREFIX * sizeof(WCHAR)
  53. #define MOUNTDEV_LOOKS_LIKE_ALT_VOLUME_GUID( name, charCount ) \
  54. ( ( charCount > MOUNTDEV_CWCHAR_ALT_VOLUME_GUID_PREFIX ) && \
  55. ( !memcmp( name, MOUNTDEV_WSZ_ALT_VOLUME_GUID_PREFIX, MOUNTDEV_CB_ALT_VOLUME_GUID_PREFIX ) ) )
  56. #define MOUNTDEV_CWCHAR_DISK_PATH_PREFIX 3
  57. #define MOUNTDEV_CB_DISK_PATH_PREFIX MOUNTDEV_CWCHAR_DISK_PATH_PREFIX * sizeof(WCHAR)
  58. #define MOUNTDEV_LOOKS_LIKE_DISK_PATH( name, charCount ) \
  59. ( ( charCount > MOUNTDEV_CWCHAR_DISK_PATH_PREFIX ) && \
  60. ( (WCHAR)*( name + 1 ) == L':' ) && \
  61. ( (WCHAR)*( name + 2 ) == L'\\' ) )
  62. #define INPUT_BUFFER_LEN 2048
  63. #define OUTPUT_BUFFER_LEN 2048
  64. typedef struct _SIG_INFO {
  65. PDISK_RESOURCE ResourceEntry;
  66. DWORD Signature;
  67. BOOL Clustered;
  68. PWSTR GroupName;
  69. } SIG_INFO, *PSIG_INFO;
  70. typedef struct _DEPENDENCY_INFO {
  71. PDISK_RESOURCE ResourceEntry;
  72. DWORD SrcSignature;
  73. DWORD TargetSignature;
  74. BOOL DependencyCorrect;
  75. } DEPENDENCY_INFO, *PDEPENDENCY_INFO;
  76. typedef struct _STR_LIST {
  77. LPWSTR MultiSzList; // REG_MULTI_SZ string
  78. DWORD ListBytes; // Number of bytes, not number of WCHARs!
  79. } STR_LIST, *PSTR_LIST;
  80. typedef struct _OFFSET_LIST {
  81. LARGE_INTEGER Offset;
  82. struct _OFFSET_LIST *Next;
  83. } OFFSET_LIST, *POFFSET_LIST;
  84. DWORD
  85. AddStrToList(
  86. IN PDISK_RESOURCE ResourceEntry,
  87. IN PWSTR NewStr,
  88. IN DWORD PartitionNumber,
  89. IN OUT PSTR_LIST StrList
  90. );
  91. DWORD
  92. AssignDevice(
  93. HANDLE MountMgrHandle,
  94. PWCHAR MountName,
  95. PWCHAR VolumeDevName
  96. );
  97. DWORD
  98. CheckDependencies(
  99. PDISK_RESOURCE ResourceEntry,
  100. DWORD SrcSignature,
  101. DWORD TargetSignature,
  102. PBOOL DependencyCorrect
  103. );
  104. VOID
  105. CheckMPsForVolume(
  106. IN OUT PDISK_RESOURCE ResourceEntry,
  107. IN PWSTR VolumeName
  108. );
  109. DWORD
  110. CheckMPsOnVolume(
  111. IN OUT PDISK_RESOURCE ResourceEntry,
  112. IN PWSTR SrcVolName
  113. );
  114. DWORD
  115. CheckSignatureClustered(
  116. PDISK_RESOURCE ResourceEntry,
  117. DWORD Signature,
  118. PBOOL IsClustered,
  119. PWSTR *GroupName
  120. );
  121. DWORD
  122. CreateVolGuidList(
  123. IN OUT PDISK_RESOURCE ResourceEntry
  124. );
  125. DWORD
  126. DeleteVolGuidList(
  127. PDISK_RESOURCE ResourceEntry
  128. );
  129. DWORD
  130. DependencyCallback(
  131. RESOURCE_HANDLE hOriginal,
  132. RESOURCE_HANDLE hResource,
  133. PVOID lpParams
  134. );
  135. #if DBG
  136. VOID
  137. DumpDiskInfoParams(
  138. PDISK_RESOURCE ResourceEntry
  139. );
  140. #endif
  141. DWORD
  142. EnumSigDependencies(
  143. PDISK_RESOURCE ResourceEntry,
  144. RESOURCE_HANDLE DependentResource,
  145. DWORD DependsOnSignature,
  146. PBOOL DependencyCorrect
  147. );
  148. DWORD
  149. GetBestVolGuid(
  150. PDISK_RESOURCE ResourceEntry,
  151. PWSTR GlobalDiskPartName,
  152. PWSTR VolumeName,
  153. DWORD VolumeNameChars
  154. );
  155. DWORD
  156. GetMountPoints(
  157. PWSTR VolumeName,
  158. PWSTR *VolumePaths
  159. );
  160. BOOL
  161. GetOffsetFromPartNo(
  162. DWORD PartitionNo,
  163. PMOUNTIE_INFO Info,
  164. PLARGE_INTEGER Offset
  165. );
  166. BOOL
  167. GetPartNoFromOffset(
  168. PLARGE_INTEGER Offset,
  169. PMOUNTIE_INFO Info,
  170. PDWORD PartitionNumber
  171. );
  172. DWORD
  173. GetSignatureForVolume(
  174. PDISK_RESOURCE ResourceEntry,
  175. PWSTR Volume,
  176. PDWORD Signature
  177. );
  178. DWORD
  179. GetSignatureFromRegistry(
  180. PDISK_RESOURCE ResourceEntry,
  181. RESOURCE_HANDLE hResource,
  182. DWORD *dwSignature
  183. );
  184. BOOL
  185. IsMountPointAllowed(
  186. PWSTR MpName,
  187. PWSTR SourceVol,
  188. PWSTR TargetVol,
  189. PDISK_RESOURCE ResourceEntry
  190. );
  191. BOOL
  192. MPIsDriveLetter(
  193. IN PWSTR MountPoint
  194. );
  195. DWORD
  196. OffsetListAdd(
  197. POFFSET_LIST *OffsetList,
  198. PLARGE_INTEGER Offset
  199. );
  200. DWORD
  201. OffsetListCleanup(
  202. POFFSET_LIST OffsetList
  203. );
  204. VOID
  205. PrintStrList(
  206. PDISK_RESOURCE ResourceEntry,
  207. LPWSTR MultiSzList,
  208. DWORD ListBytes
  209. );
  210. DWORD
  211. ProcessVolGuidList(
  212. IN OUT PDISK_RESOURCE ResourceEntry
  213. );
  214. DWORD
  215. RemoveExcessVolGuids(
  216. HANDLE MountMgrHandle,
  217. PWCHAR MountName,
  218. PWCHAR VolumeDevName
  219. );
  220. DWORD
  221. RemoveVolGuid(
  222. HANDLE MountMgrHandle,
  223. PWCHAR VolGuid,
  224. USHORT VolGuidSize
  225. );
  226. static
  227. DWORD
  228. SetMPListThread(
  229. LPVOID lpThreadParameter
  230. );
  231. DWORD
  232. SetupVolGuids(
  233. IN OUT PDISK_RESOURCE ResourceEntry
  234. );
  235. DWORD
  236. SigInfoCallback(
  237. RESOURCE_HANDLE hOriginal,
  238. RESOURCE_HANDLE hResource,
  239. PVOID lpParams
  240. );
  241. DWORD
  242. ValidateListOffsets(
  243. IN OUT PDISK_RESOURCE ResourceEntry,
  244. IN PWSTR MasterList
  245. );
  246. DWORD
  247. ValidateMountPoints(
  248. IN OUT PDISK_RESOURCE ResourceEntry
  249. );
  250. DWORD
  251. DisksProcessMountPointInfo(
  252. IN OUT PDISK_RESOURCE ResourceEntry
  253. )
  254. /*++
  255. Routine Description:
  256. During online processing, find all mount points directed towards this volume
  257. (identified by the ResourceEntry), and process the VolGuid list for this
  258. volume.
  259. If the VolGuid list exists in the cluster database, use it. Otherwise,
  260. get the current VolGuid and add it to the VolGuid list. Each sector offset
  261. can only be listed once as the VolGuid will be the same on each node.
  262. VolGuid list is of the form:
  263. SectorOffset1 VolGuid1
  264. SectorOffset2 VolGuid2
  265. SectorOffset3 VolGuid3
  266. ... ...
  267. There are three possible mount point configurations involving clustered disks (we
  268. are not concerned about nonshared disks pointing to nonshared disks):
  269. Source --> Target
  270. ----------------- -----------------
  271. 1. clustered disk clustered disk
  272. 2. nonclustered disk clustered disk
  273. 3. clustered disk nonclustered disk
  274. Only configuration (1) is supported. Configurations (2) and (3) are not supported.
  275. Arguments:
  276. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  277. Return Value:
  278. ERROR_NOT_READY - MPInfo structure not yet initialized.
  279. Win32 error code.
  280. --*/
  281. {
  282. DWORD dwError = NO_ERROR;
  283. //
  284. // Mount point structures not initialized (i.e. critical section). Don't continue.
  285. //
  286. if ( !ResourceEntry->MPInfo.Initialized ) {
  287. (DiskpLogEvent)(
  288. ResourceEntry->ResourceHandle,
  289. LOG_WARNING,
  290. L"DisksProcessMountPointInfo: Mount point information not initialized. \n" );
  291. return ERROR_NOT_READY;
  292. }
  293. #if USEMOUNTPOINTS_KEY
  294. //
  295. // Mount point support disabled, don't do anything.
  296. //
  297. if ( !( ResourceEntry->DiskInfo.Params.UseMountPoints & MPS_ENABLED ) ) {
  298. (DiskpLogEvent)(
  299. ResourceEntry->ResourceHandle,
  300. LOG_INFORMATION,
  301. L"DisksProcessMountPointInfo: Mount point processing disabled via registry \n" );
  302. //
  303. // Delete the VolGuid list if it exists and remove this info
  304. // from the cluster database.
  305. //
  306. dwError = DeleteVolGuidList( ResourceEntry );
  307. if ( ERROR_SHARING_PAUSED == dwError ) {
  308. PostMPInfoIntoRegistry( ResourceEntry );
  309. }
  310. dwError = NO_ERROR;
  311. return dwError;
  312. }
  313. #endif
  314. //
  315. // Check if we are currently processing mount point info. If so, exit with an error.
  316. //
  317. if ( InterlockedCompareExchange(
  318. &ResourceEntry->MPInfo.MPListCreateInProcess,
  319. 1, 0 ) ) {
  320. (DiskpLogEvent)(
  321. ResourceEntry->ResourceHandle,
  322. LOG_WARNING,
  323. L"DisksProcessMountPointInfo: MPList creation in process, bypassing request \n" );
  324. return ERROR_BUSY;
  325. }
  326. __try {
  327. dwError = ProcessVolGuidList( ResourceEntry );
  328. ValidateMountPoints( ResourceEntry );
  329. // Fall through...
  330. #if 0
  331. // Add code similar to this when MPs from nonclustered to clustered disks is supported.
  332. if ( ( ResourceEntry->DiskInfo.Params.UseMountPoints & MPS_ENABLED ) &&
  333. ( ResourceEntry->DiskInfo.Params.UseMountPoints & MPS_NONCLUSTERED_TO_CLUSTERED_MPS ) ) {
  334. (DiskpLogEvent)(
  335. ResourceEntry->ResourceHandle,
  336. LOG_INFORMATION,
  337. L"DisksProcessMountPointInfo: ProcessMPList \n" );
  338. dwError = ProcessMPListConfig2( ResourceEntry );
  339. #endif
  340. } __finally {
  341. InterlockedExchange( &ResourceEntry->MPInfo.MPListCreateInProcess, 0 );
  342. }
  343. return dwError;
  344. } // DisksProcessMountPointInfo
  345. DWORD
  346. ProcessVolGuidList(
  347. IN OUT PDISK_RESOURCE ResourceEntry
  348. )
  349. /*++
  350. Routine Description:
  351. Main routine to create a new VolGuid list or to process an existing VolGuid list.
  352. Arguments:
  353. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  354. Return Value:
  355. Win32 error code.
  356. --*/
  357. {
  358. DWORD dwError = NO_ERROR;
  359. __try {
  360. //
  361. // If the list is empty, create it.
  362. //
  363. if ( !ResourceEntry->DiskInfo.Params.MPVolGuids ||
  364. 0 == ResourceEntry->DiskInfo.Params.MPVolGuidsSize ) {
  365. dwError = CreateVolGuidList( ResourceEntry );
  366. if ( NO_ERROR != dwError ) {
  367. (DiskpLogEvent)(
  368. ResourceEntry->ResourceHandle,
  369. LOG_WARNING,
  370. L"ProcessVolGuidList: Stop processing VolGuid list, Create failed %1!u! \n",
  371. dwError );
  372. __leave;
  373. }
  374. }
  375. //
  376. // If the list is still empty (it shouldn't be), then exit with an error.
  377. //
  378. if ( !ResourceEntry->DiskInfo.Params.MPVolGuids ||
  379. 0 == ResourceEntry->DiskInfo.Params.MPVolGuidsSize ) {
  380. dwError = ERROR_INVALID_DATA;
  381. __leave;
  382. }
  383. PrintStrList( ResourceEntry,
  384. ResourceEntry->DiskInfo.Params.MPVolGuids,
  385. ResourceEntry->DiskInfo.Params.MPVolGuidsSize );
  386. //
  387. // Make sure the offsets are correct in the VolGuid list.
  388. // Note that it is possible for the list to be deleted and
  389. // recreated after this validation, but that is not a problem (because
  390. // when they are recreated they will have the correct offsets).
  391. //
  392. dwError = ValidateListOffsets( ResourceEntry,
  393. ResourceEntry->DiskInfo.Params.MPVolGuids );
  394. if ( ERROR_INVALID_DATA == dwError ) {
  395. //
  396. // At least one of the offsets is invalid. Possibly, the partition
  397. // layout on the disk has been changed. Delete the existing
  398. // list, and create a new one.
  399. //
  400. // This code should run infrequently...
  401. //
  402. // The partition layout might change if ASR runs and creates new partitions
  403. // that don't match the previous system exactly. Since NTBACKUP saves the
  404. // cluster DB information, the mount point list will be restored but won't
  405. // match the actual "new" partition layout. ASR will insure that all the
  406. // mount points and VolGuids on the system are created, so we should be able
  407. // to simply delete and recreate the mount point list.
  408. //
  409. (DiskpLogEvent)(
  410. ResourceEntry->ResourceHandle,
  411. LOG_WARNING,
  412. L"ProcessVolGuidList: Problem with existing VolGuid list. Deleting and recreating. \n" );
  413. DeleteVolGuidList( ResourceEntry );
  414. dwError = CreateVolGuidList( ResourceEntry );
  415. if ( NO_ERROR != dwError ) {
  416. __leave;
  417. }
  418. // Fall through and call SetupVolGuids...
  419. } else if ( ERROR_INSUFFICIENT_BUFFER == dwError ) {
  420. //
  421. // The Volguid list is too large and likely corrupt. We cannot
  422. // proceed.
  423. //
  424. __leave;
  425. }
  426. //
  427. // For every VolGuid in the list, make sure they are assigned to the correct
  428. // volumes on this system.
  429. //
  430. dwError = SetupVolGuids( ResourceEntry );
  431. } __finally {
  432. }
  433. return dwError;
  434. } // ProcessVolGuidList
  435. DWORD
  436. CreateVolGuidList(
  437. IN OUT PDISK_RESOURCE ResourceEntry
  438. )
  439. /*++
  440. Routine Description:
  441. Create the VolGuid list. The list must be empty when this routine runs.
  442. For each partition on this disk (identified by the ResourceEntry), get the byte
  443. offset of that partition. Get the best VolGuid for that partition, and add
  444. it to the list.
  445. Arguments:
  446. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  447. Return Value:
  448. ERROR_INVALID_DATA - partition info in disk resource is invalid
  449. Win32 error code.
  450. --*/
  451. {
  452. PMOUNTIE_PARTITION entry;
  453. HANDLE mountMgrHandle = INVALID_HANDLE_VALUE;
  454. DWORD dwError = ERROR_SUCCESS;
  455. DWORD nPartitions = MountiePartitionCount( &ResourceEntry->MountieInfo );
  456. DWORD physicalDrive = ResourceEntry->DiskInfo.PhysicalDrive;
  457. DWORD idx;
  458. DWORD volumeNameLenChars; // Number of characters
  459. DWORD newStrListLenBytes; // Number of bytes
  460. WCHAR szGlobalDiskPartName[MAX_PATH];
  461. WCHAR szVolumeName[MAX_PATH];
  462. STR_LIST newStrList;
  463. __try {
  464. (DiskpLogEvent)(
  465. ResourceEntry->ResourceHandle,
  466. LOG_INFORMATION,
  467. L"CreateVolGuidList: Creating new VolGuid list \n" );
  468. EnterCriticalSection( &ResourceEntry->MPInfo.MPLock );
  469. if ( ResourceEntry->DiskInfo.Params.MPVolGuids ||
  470. 0 != ResourceEntry->DiskInfo.Params.MPVolGuidsSize ) {
  471. LeaveCriticalSection( &ResourceEntry->MPInfo.MPLock );
  472. dwError = ERROR_INVALID_PARAMETER;
  473. __leave;
  474. }
  475. LeaveCriticalSection( &ResourceEntry->MPInfo.MPLock );
  476. ZeroMemory( &newStrList, sizeof(STR_LIST) );
  477. dwError = DevfileOpen( &mountMgrHandle, MOUNTMGR_DEVICE_NAME );
  478. if ( dwError != NO_ERROR ) {
  479. (DiskpLogEvent)(
  480. ResourceEntry->ResourceHandle,
  481. LOG_WARNING,
  482. L"CreateVolGuidList: Failed to open MountMgr %1!u! \n",
  483. dwError );
  484. __leave;
  485. }
  486. //
  487. // Check each interesting partition. Since only "valid" partitions are
  488. // saved in the MountieInfo structure, we will only look at those (ignoring those
  489. // partitions that are not NTFS).
  490. //
  491. for ( idx = 0; idx < nPartitions; ++idx ) {
  492. entry = MountiePartition( &ResourceEntry->MountieInfo, idx );
  493. #if DBG
  494. (DiskpLogEvent)(
  495. ResourceEntry->ResourceHandle,
  496. LOG_INFORMATION,
  497. L"CreateVolGuidList: index %1!u! entry %2!x! \n", idx, entry );
  498. #endif
  499. if ( !entry ) {
  500. (DiskpLogEvent)(
  501. ResourceEntry->ResourceHandle,
  502. LOG_WARNING,
  503. L"CreateVolGuidList: no partition entry for index %1!u! \n", idx );
  504. //
  505. // Something bad happened to our data structures.
  506. //
  507. dwError = ERROR_INVALID_DATA;
  508. __leave;
  509. }
  510. //
  511. // Create the device name of the form:
  512. // \\?\GLOBALROOT\Device\HarddiskX\PartitionY\ (uses trailing backslash)
  513. //
  514. (VOID) StringCchPrintf( szGlobalDiskPartName,
  515. RTL_NUMBER_OF( szGlobalDiskPartName ),
  516. GLOBALROOT_HARDDISK_PARTITION_FMT,
  517. physicalDrive,
  518. entry->PartitionNumber );
  519. #if DBG
  520. (DiskpLogEvent)(
  521. ResourceEntry->ResourceHandle,
  522. LOG_INFORMATION,
  523. L"CreateVolGuidList: Using name (%1!ws!) \n",
  524. szGlobalDiskPartName );
  525. #endif
  526. dwError = GetBestVolGuid( ResourceEntry,
  527. szGlobalDiskPartName,
  528. szVolumeName,
  529. RTL_NUMBER_OF(szVolumeName) );
  530. if ( NO_ERROR != dwError ) {
  531. (DiskpLogEvent)(
  532. ResourceEntry->ResourceHandle,
  533. LOG_WARNING,
  534. L"CreateVolGuidList: Unable to get valid VolGuid for (%1!ws!), error %2!u!\n ",
  535. szGlobalDiskPartName,
  536. dwError );
  537. // Try next partition.
  538. continue;
  539. }
  540. //
  541. // Fix current VolGuid name.
  542. //
  543. // GetVolumeNameForVolumeMountPoint returns name of the form:
  544. // \\?\Volume{-GUID-}\
  545. //
  546. // But we need the name to be in the form:
  547. // \??\Volume{-GUID-}
  548. //
  549. volumeNameLenChars = wcslen( szVolumeName );
  550. if ( !(MOUNTDEV_LOOKS_LIKE_ALT_VOLUME_GUID( szVolumeName, volumeNameLenChars ) ) ) {
  551. (DiskpLogEvent)(
  552. ResourceEntry->ResourceHandle,
  553. LOG_WARNING,
  554. L"CreateVolGuidList: Improper volume name format (%1!ws!) \n",
  555. szVolumeName );
  556. // Try next partition.
  557. continue;
  558. }
  559. szVolumeName[1] = L'?';
  560. if ( L'\\' == szVolumeName[volumeNameLenChars-1]) {
  561. szVolumeName[volumeNameLenChars-1] = L'\0';
  562. }
  563. #if DBG
  564. (DiskpLogEvent)(
  565. ResourceEntry->ResourceHandle,
  566. LOG_INFORMATION,
  567. L"CreateVolGuidList: Fixed volume name (%1!ws!) \n",
  568. szVolumeName );
  569. #endif
  570. //
  571. // Add the new string to the list. If the new string is already in the list, this
  572. // routine won't do anything and will return NO_ERROR.
  573. //
  574. dwError = AddStrToList( ResourceEntry,
  575. szVolumeName,
  576. entry->PartitionNumber,
  577. &newStrList );
  578. if ( NO_ERROR != dwError ) {
  579. __leave;
  580. }
  581. }
  582. (DiskpLogEvent)(
  583. ResourceEntry->ResourceHandle,
  584. LOG_INFORMATION,
  585. L"CreateVolGuidList: Saving new VolGuid list \n" );
  586. //
  587. // Update the ResourceEntry with the new list information,
  588. // and update the cluster database.
  589. //
  590. EnterCriticalSection( &ResourceEntry->MPInfo.MPLock );
  591. if ( 0 == ResourceEntry->DiskInfo.Params.MPVolGuids &&
  592. 0 == ResourceEntry->DiskInfo.Params.MPVolGuidsSize ) {
  593. ResourceEntry->DiskInfo.Params.MPVolGuids = newStrList.MultiSzList;
  594. ResourceEntry->DiskInfo.Params.MPVolGuidsSize = newStrList.ListBytes;
  595. } else {
  596. (DiskpLogEvent)(
  597. ResourceEntry->ResourceHandle,
  598. LOG_WARNING,
  599. L"CreateVolGuidList: VolGuid list is not empty - not saving... \n" );
  600. LocalFree( newStrList.MultiSzList );
  601. }
  602. LeaveCriticalSection( &ResourceEntry->MPInfo.MPLock );
  603. PrintStrList( ResourceEntry,
  604. ResourceEntry->DiskInfo.Params.MPVolGuids,
  605. ResourceEntry->DiskInfo.Params.MPVolGuidsSize );
  606. dwError = PostMPInfoIntoRegistry( ResourceEntry );
  607. } __finally {
  608. if ( INVALID_HANDLE_VALUE != mountMgrHandle ) {
  609. CloseHandle( mountMgrHandle );
  610. }
  611. }
  612. return dwError;
  613. } // CreateVolGuidList
  614. DWORD
  615. GetBestVolGuid(
  616. PDISK_RESOURCE ResourceEntry,
  617. PWSTR GlobalDiskPartName,
  618. PWSTR VolumeName,
  619. DWORD VolumeNameChars
  620. )
  621. /*++
  622. Routine Description:
  623. Get the best VolGuid for the specified device.
  624. If the disk has no mountpoints, then just save the current VolGuid.
  625. If the disk has mountpoints on it, then save the VolGuid
  626. from the disk. All the mountpoints on the disk should have
  627. the same VolGuid.
  628. Arguments:
  629. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  630. GlobalDiskPartName - device to get the VolGuid from.
  631. \\?\GLOBALROOT\Device\HarddiskX\PartitionY\ (uses trailing backslash)
  632. VolumeName - buffer to return the VolGuid.
  633. VolumeNameChars - number of CHARS in VolumeName buffer.
  634. Return Value:
  635. NO_ERROR - valid VolGuid is returned.
  636. Win32 error code - VolGuid could not be retrieved.
  637. --*/
  638. {
  639. PWCHAR fullName = NULL;
  640. PWCHAR mpOnDisk = NULL;
  641. PWCHAR mpVolGuid = NULL;
  642. HANDLE hVol;
  643. DWORD dwError = NO_ERROR;
  644. DWORD fullNameChars;
  645. DWORD mpOnDiskChars;
  646. DWORD mpVolGuidChars;
  647. mpOnDiskChars = MAX_PATH * sizeof(WCHAR);
  648. mpOnDisk = LocalAlloc( LPTR, mpOnDiskChars );
  649. if ( !mpOnDisk ) {
  650. dwError = GetLastError();
  651. goto FnExit;
  652. }
  653. fullNameChars = MAX_PATH * sizeof(WCHAR) * 2;
  654. fullName = LocalAlloc( LPTR, fullNameChars );
  655. if ( !fullName ) {
  656. dwError = GetLastError();
  657. goto FnExit;
  658. }
  659. mpVolGuidChars = MAX_PATH * sizeof(WCHAR);
  660. mpVolGuid = LocalAlloc( LPTR, mpVolGuidChars );
  661. if ( !mpVolGuid ) {
  662. dwError = GetLastError();
  663. goto FnExit;
  664. }
  665. //
  666. // Get the current VolGuid for this partition.
  667. //
  668. if ( !GetVolumeNameForVolumeMountPointW( GlobalDiskPartName,
  669. VolumeName,
  670. VolumeNameChars )) {
  671. dwError = GetLastError();
  672. (DiskpLogEvent)(
  673. ResourceEntry->ResourceHandle,
  674. LOG_WARNING,
  675. L"GetBestVolGuid: GetVolumeNameForVolumeMountPoint for (%1!ws!) returned %2!u!\n",
  676. GlobalDiskPartName,
  677. dwError );
  678. goto FnExit;
  679. }
  680. //
  681. // See if there are mountpoints on the disk. Note
  682. // we use the volume name we just received for this
  683. // device.
  684. //
  685. hVol = FindFirstVolumeMountPoint( VolumeName,
  686. mpOnDisk,
  687. mpOnDiskChars );
  688. if ( INVALID_HANDLE_VALUE == hVol ) {
  689. //
  690. // No mountpoints, just use the standard VolGuid.
  691. //
  692. (DiskpLogEvent)(
  693. ResourceEntry->ResourceHandle,
  694. LOG_INFORMATION,
  695. L"GetBestVolGuid: Using standard volguid (%1!ws!) \n",
  696. VolumeName );
  697. goto FnExit;
  698. }
  699. //
  700. // Disk has mountpoints on it. Now get the VolGuid from this
  701. // mountpoint.
  702. //
  703. (VOID) StringCchCopy( fullName, fullNameChars, VolumeName );
  704. (VOID) StringCchCat( fullName, fullNameChars, mpOnDisk );
  705. if ( !GetVolumeNameForVolumeMountPointW( GlobalDiskPartName,
  706. mpVolGuid,
  707. mpVolGuidChars )) {
  708. dwError = GetLastError();
  709. (DiskpLogEvent)(
  710. ResourceEntry->ResourceHandle,
  711. LOG_WARNING,
  712. L"CreateVolGuidList: Can't get volguid for (%1!ws!), error %2!u! \n",
  713. fullName,
  714. dwError );
  715. (DiskpLogEvent)(
  716. ResourceEntry->ResourceHandle,
  717. LOG_INFORMATION,
  718. L"GetBestVolGuid: Using standard volguid (%1!ws!) \n",
  719. VolumeName );
  720. //
  721. // We couldn't get the VolGuid for the mountpoint, return success
  722. // and use the standard VolGuid we got earlier.
  723. //
  724. dwError = ERROR_SUCCESS;
  725. goto FnExit;
  726. }
  727. FindVolumeMountPointClose( hVol );
  728. //
  729. // Use the VolGuid based on the mountpoint.
  730. //
  731. (VOID) StringCchCopy( VolumeName, VolumeNameChars, mpVolGuid );
  732. (DiskpLogEvent)(
  733. ResourceEntry->ResourceHandle,
  734. LOG_INFORMATION,
  735. L"GetBestVolGuid: Using mountpoint volguid (%1!ws!) \n",
  736. VolumeName );
  737. FnExit:
  738. LocalFree( fullName );
  739. LocalFree( mpOnDisk );
  740. LocalFree( mpVolGuid );
  741. return dwError;
  742. } // GetBestVolGuid
  743. DWORD
  744. AddStrToList(
  745. IN PDISK_RESOURCE ResourceEntry,
  746. IN PWSTR NewStr,
  747. IN DWORD PartitionNumber,
  748. IN OUT PSTR_LIST StrList
  749. )
  750. /*++
  751. Routine Description:
  752. Add the string to the MULTI_SZ list. Convert the partition number to a byte offset
  753. so we don't rely on partition numbers.
  754. List format will be:
  755. ByteOffset1 Str1
  756. ByteOffset1 Str2
  757. ByteOffset1 Str3
  758. ByteOffset2 Str1
  759. ByteOffset2 Str2
  760. ByteOffset3 Str1
  761. ... ...
  762. Arguments:
  763. Return Value:
  764. --*/
  765. {
  766. PWCHAR listEntry = NULL;
  767. DWORD listEntrySizeChars;
  768. DWORD lenChars;
  769. DWORD newStrLenChars;
  770. DWORD listChars;
  771. DWORD remainingLen;
  772. DWORD dwError = ERROR_INVALID_DATA;
  773. LARGE_INTEGER offset;
  774. #if DBG
  775. (DiskpLogEvent)(
  776. ResourceEntry->ResourceHandle,
  777. LOG_INFORMATION,
  778. L"AddStrToList: Adding str (%1!ws!) \n", NewStr );
  779. #endif
  780. newStrLenChars = wcslen( NewStr );
  781. if ( 0 == newStrLenChars ) {
  782. //
  783. // Something wrong with the string length.
  784. //
  785. (DiskpLogEvent)(
  786. ResourceEntry->ResourceHandle,
  787. LOG_WARNING,
  788. L"AddStrToList: Invalid length: NewStrLen = %1!u! \n",
  789. newStrLenChars );
  790. goto FnExit;
  791. }
  792. //
  793. // Indicate an error unless we can allocate and copy the info
  794. // into the list. Calculate the minimum size needed, then get
  795. // larger buffer. This buffer is temporary and freed later.
  796. //
  797. listEntrySizeChars = ( newStrLenChars + // Char length of parameter string
  798. MAX_OFFSET_CHARS + // Char length of offset string
  799. 1 + // Room to change end of offset string to space and extend it
  800. 1 ) // Unicode NULL
  801. * 2; // Make sure buffer is large enough
  802. listEntry = LocalAlloc( LPTR, listEntrySizeChars * sizeof(WCHAR) );
  803. if ( !listEntry ) {
  804. dwError = GetLastError();
  805. goto FnExit;
  806. }
  807. //
  808. // Get the offset for the specified partition.
  809. //
  810. if ( !GetOffsetFromPartNo( PartitionNumber,
  811. &ResourceEntry->MountieInfo,
  812. &offset ) ) {
  813. //
  814. // Can't get the offset for the specified partition.
  815. //
  816. (DiskpLogEvent)(
  817. ResourceEntry->ResourceHandle,
  818. LOG_WARNING,
  819. L"AddStrToList: GetOffsetFromPartNo failed \n" );
  820. goto FnExit;
  821. }
  822. //
  823. // Convert the offset into a string. Put the offset into listEntry.
  824. //
  825. _ui64tow( offset.QuadPart, listEntry, 16 );
  826. lenChars = wcslen( listEntry );
  827. if ( 0 == lenChars || lenChars >= MAX_OFFSET_CHARS ) {
  828. //
  829. // The length of the offset string is invalid.
  830. //
  831. (DiskpLogEvent)(
  832. ResourceEntry->ResourceHandle,
  833. LOG_WARNING,
  834. L"AddStrToList: Invalid offset string length = %1!u! \n",
  835. lenChars );
  836. goto FnExit;
  837. }
  838. // Format will be:
  839. // ByteOffset1 Str1
  840. // ByteOffset1 Str2
  841. // ByteOffset1 Str3
  842. // ByteOffset2 Str1
  843. // ByteOffset2 Str2
  844. // ByteOffset3 Str1
  845. // ... ...
  846. //
  847. // Change the end of the offset string to another character. Move the end of string
  848. // out one character. This extra space was included when we allocated the buffer.
  849. //
  850. listEntry[lenChars+1] = UNICODE_NULL;
  851. listEntry[lenChars] = SPACE_CHAR;
  852. //
  853. // One more check. Make sure enough space remaining for adding string.
  854. //
  855. remainingLen = listEntrySizeChars - wcslen( listEntry ) - 1;
  856. #if DBG
  857. (DiskpLogEvent)(
  858. ResourceEntry->ResourceHandle,
  859. LOG_INFORMATION,
  860. L"AddStrToList: New string length %1!u! Remaining list entry length %2!u! \n",
  861. newStrLenChars,
  862. remainingLen );
  863. #endif
  864. if ( newStrLenChars >= remainingLen ) {
  865. (DiskpLogEvent)(
  866. ResourceEntry->ResourceHandle,
  867. LOG_WARNING,
  868. L"AddStrToList: New string length %1!u! larger than remaining list entry length %2!u! \n",
  869. newStrLenChars,
  870. remainingLen );
  871. goto FnExit;
  872. }
  873. //
  874. // Put the rest of the string in list entry.
  875. //
  876. wcsncat( listEntry, NewStr, remainingLen );
  877. //
  878. // If the string is already in the list, skip it.
  879. //
  880. if ( ClRtlMultiSzScan( ResourceEntry->DiskInfo.Params.MPVolGuids, listEntry ) ) {
  881. (DiskpLogEvent)(
  882. ResourceEntry->ResourceHandle,
  883. LOG_INFORMATION,
  884. L"AddStrToList: Skipping duplicate entry (%1!ws!) \n",
  885. listEntry );
  886. dwError = NO_ERROR;
  887. goto FnExit;
  888. }
  889. //
  890. // Note that ClRtlMultiSzAppend updates the number of CHARACTERS, but we
  891. // need to have the number of BYTES in the property table. We will adjust
  892. // this value later.
  893. //
  894. listChars = StrList->ListBytes / sizeof(WCHAR);
  895. #if DBG
  896. (DiskpLogEvent)(
  897. ResourceEntry->ResourceHandle,
  898. LOG_INFORMATION,
  899. L"AddStrToList: StrList->MultiSzList at %1!p!, numBytes %2!u! \n",
  900. StrList->MultiSzList,
  901. StrList->ListBytes );
  902. (DiskpLogEvent)(
  903. ResourceEntry->ResourceHandle,
  904. LOG_INFORMATION,
  905. L"AddStrToList: Adding str entry: (%1!ws!) numChars %2!u! \n",
  906. listEntry,
  907. listChars );
  908. #endif
  909. dwError = ClRtlMultiSzAppend( &(StrList->MultiSzList),
  910. &listChars,
  911. listEntry );
  912. //
  913. // Convert the number of CHARACTERS back to bytes.
  914. //
  915. StrList->ListBytes = listChars * sizeof(WCHAR);
  916. if ( ERROR_SUCCESS == dwError) {
  917. #if DBG
  918. (DiskpLogEvent)(
  919. ResourceEntry->ResourceHandle,
  920. LOG_INFORMATION,
  921. L"AddStrToList: Added str, numBytes %1!u! numChars %2!u! \n",
  922. StrList->ListBytes,
  923. listChars );
  924. #endif
  925. } else {
  926. (DiskpLogEvent)(
  927. ResourceEntry->ResourceHandle,
  928. LOG_WARNING,
  929. L"AddStrToList: Unable to append MultiSz string for (%1!ws!), failed %x \n",
  930. NewStr,
  931. dwError );
  932. }
  933. FnExit:
  934. if ( listEntry ) {
  935. LocalFree( listEntry );
  936. }
  937. return dwError;
  938. } // AddStrToList
  939. DWORD
  940. SetupVolGuids(
  941. IN OUT PDISK_RESOURCE ResourceEntry
  942. )
  943. /*++
  944. Routine Description:
  945. Add every VolGuid in the existing MULTI_SZ VolGuid list to the system.
  946. Each volume will only have one VolGuid, and the VolGuid will be the
  947. same for all nodes.
  948. Remove any other VolGuids currently assigned to the volumes.
  949. Arguments:
  950. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  951. Return Value:
  952. Win32 error code.
  953. --*/
  954. {
  955. PWCHAR currentStr;
  956. PWCHAR volGuid;
  957. HANDLE mountMgrHandle = INVALID_HANDLE_VALUE;
  958. DWORD physicalDrive = ResourceEntry->DiskInfo.PhysicalDrive;
  959. DWORD currentStrLenChars = 0;
  960. DWORD dwError = NO_ERROR;
  961. DWORD partitionNo;
  962. DWORD count;
  963. LARGE_INTEGER offset;
  964. WCHAR szDiskPartName[MAX_PATH];
  965. __try {
  966. (DiskpLogEvent)(
  967. ResourceEntry->ResourceHandle,
  968. LOG_INFORMATION,
  969. L"SetupVolGuids: Processing VolGuid list \n" );
  970. EnterCriticalSection( &ResourceEntry->MPInfo.MPLock );
  971. dwError = DevfileOpen( &mountMgrHandle, MOUNTMGR_DEVICE_NAME );
  972. if ( dwError != NO_ERROR ) {
  973. __leave;
  974. }
  975. //
  976. // Parse through the list.
  977. //
  978. for ( currentStr = (PWCHAR)ResourceEntry->DiskInfo.Params.MPVolGuids,
  979. currentStrLenChars = wcslen( currentStr ) ;
  980. currentStrLenChars ;
  981. currentStr += currentStrLenChars + 1,
  982. currentStrLenChars = wcslen( currentStr ) ) {
  983. offset.QuadPart = 0;
  984. #if DBG
  985. (DiskpLogEvent)(
  986. ResourceEntry->ResourceHandle,
  987. LOG_INFORMATION,
  988. L"SetupVolGuids: CurrentStr (%1!ws!), numChars %2!u! \n",
  989. currentStr,
  990. currentStrLenChars );
  991. #endif
  992. //
  993. // Convert the offset from a string to a large integer value.
  994. //
  995. count = swscanf( currentStr, L"%I64x ", &offset.QuadPart );
  996. if ( 0 == count ) {
  997. (DiskpLogEvent)(
  998. ResourceEntry->ResourceHandle,
  999. LOG_WARNING,
  1000. L"SetupVolGuids: Unable to parse offset from currentStr (%1!ws!) \n",
  1001. currentStr );
  1002. continue;
  1003. }
  1004. //
  1005. // Convert the offset to a partition number.
  1006. //
  1007. if ( !GetPartNoFromOffset( &offset, &ResourceEntry->MountieInfo, &partitionNo ) ) {
  1008. (DiskpLogEvent)(
  1009. ResourceEntry->ResourceHandle,
  1010. LOG_WARNING,
  1011. L"SetupVolGuids: Unable to convert offset ( %1!08X!%2!08X! ) to partition number \n",
  1012. offset.HighPart,
  1013. offset.LowPart ); // couldn't get !I64X! to work...
  1014. continue;
  1015. }
  1016. //
  1017. // Get a pointer to the VolGuid data, just after the byte offset.
  1018. //
  1019. volGuid = wcsstr( currentStr, MOUNTDEV_WSZ_VOLUME_GUID_PREFIX );
  1020. if ( !volGuid ) {
  1021. (DiskpLogEvent)(
  1022. ResourceEntry->ResourceHandle,
  1023. LOG_WARNING,
  1024. L"SetupVolGuids: Unable to find volume string in current list entry (%1!ws) \n",
  1025. currentStr );
  1026. continue;
  1027. }
  1028. #if DBG
  1029. (DiskpLogEvent)(
  1030. ResourceEntry->ResourceHandle,
  1031. LOG_INFORMATION,
  1032. L"SetupVolGuids: Using VolGuid (%1!ws!) \n",
  1033. volGuid );
  1034. #endif
  1035. //
  1036. // Create the device name of the form:
  1037. // \Device\HarddiskX\PartitionY (no trailing backslash)
  1038. //
  1039. (VOID) StringCchPrintf( szDiskPartName,
  1040. RTL_NUMBER_OF( szDiskPartName ),
  1041. DEVICE_HARDDISK_PARTITION_FMT,
  1042. physicalDrive,
  1043. partitionNo );
  1044. #if DBG
  1045. (DiskpLogEvent)(
  1046. ResourceEntry->ResourceHandle,
  1047. LOG_INFORMATION,
  1048. L"SetupVolGuids: Using device name (%1!ws!) \n",
  1049. szDiskPartName );
  1050. #endif
  1051. dwError = AssignDevice( mountMgrHandle, volGuid, szDiskPartName );
  1052. if ( NO_ERROR != dwError &&
  1053. STATUS_OBJECT_NAME_COLLISION != dwError ) {
  1054. // Assign device will return: 0xC0000035 STATUS_OBJECT_NAME_COLLISION
  1055. // if we are setting a VolGuid that was previously set. This is not
  1056. // a problem.
  1057. (DiskpLogEvent)(
  1058. ResourceEntry->ResourceHandle,
  1059. LOG_WARNING,
  1060. L"SetupVolGuids: Unable to assign VolGuid to device, error %1!u! \n",
  1061. dwError );
  1062. // Continue processing with error...
  1063. } else {
  1064. //
  1065. // Only remove the other VolGuids if this assignment worked.
  1066. //
  1067. RemoveExcessVolGuids( mountMgrHandle, volGuid, szDiskPartName );
  1068. }
  1069. dwError = STATUS_SUCCESS;
  1070. }
  1071. } __finally {
  1072. if ( INVALID_HANDLE_VALUE != mountMgrHandle ) {
  1073. CloseHandle( mountMgrHandle );
  1074. }
  1075. LeaveCriticalSection( &ResourceEntry->MPInfo.MPLock );
  1076. }
  1077. return dwError;
  1078. } // SetupVolGuids
  1079. DWORD
  1080. AssignDevice(
  1081. HANDLE MountMgrHandle,
  1082. PWCHAR MountName,
  1083. PWCHAR VolumeDevName
  1084. )
  1085. /*++
  1086. Routine Description:
  1087. Put the specified MountName (i.e. mount point name) into the mount manager's internal table
  1088. of mount points.
  1089. Inputs:
  1090. MountMgrHandle - Handle to the mount manager. The caller is responsible for
  1091. opening and closing this handle.
  1092. MountName - Mountpoint name of the form:
  1093. \??\Volume{-GUID-} - note prefix "\??\" and no trailing backslash.
  1094. \DosDevices\X: - works if a drive letter is not already assigned
  1095. VolumeDevName - Volume device name. Can be one of the following forms (note that case is
  1096. important). The "#" is a zero-based device number (and partition number
  1097. as appropriate).
  1098. \Device\CdRom#
  1099. \Device\Floppy#
  1100. \Device\HarddiskVolume#
  1101. \Device\Harddisk#\Partition#
  1102. Return value:
  1103. A Win32 error code.
  1104. --*/
  1105. {
  1106. PMOUNTMGR_CREATE_POINT_INPUT input;
  1107. DWORD status;
  1108. USHORT mountNameLenBytes;
  1109. USHORT volumeDevNameLenBytes;
  1110. USHORT inputlengthBytes;
  1111. if ( INVALID_HANDLE_VALUE == MountMgrHandle ) {
  1112. return ERROR_INVALID_PARAMETER;
  1113. }
  1114. mountNameLenBytes = wcslen( MountName ) * sizeof(WCHAR);
  1115. volumeDevNameLenBytes = wcslen( VolumeDevName ) * sizeof(WCHAR);
  1116. inputlengthBytes = sizeof(MOUNTMGR_CREATE_POINT_INPUT) + mountNameLenBytes + volumeDevNameLenBytes;
  1117. input = (PMOUNTMGR_CREATE_POINT_INPUT)LocalAlloc( LPTR, inputlengthBytes );
  1118. if ( !input ) {
  1119. return ERROR_NOT_ENOUGH_MEMORY;
  1120. }
  1121. input->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT);
  1122. input->SymbolicLinkNameLength = mountNameLenBytes;
  1123. input->DeviceNameOffset = input->SymbolicLinkNameOffset +
  1124. input->SymbolicLinkNameLength;
  1125. input->DeviceNameLength = volumeDevNameLenBytes;
  1126. RtlCopyMemory((PCHAR)input + input->SymbolicLinkNameOffset,
  1127. MountName, mountNameLenBytes);
  1128. RtlCopyMemory((PCHAR)input + input->DeviceNameOffset,
  1129. VolumeDevName, volumeDevNameLenBytes);
  1130. status = DevfileIoctl( MountMgrHandle,
  1131. IOCTL_MOUNTMGR_CREATE_POINT,
  1132. input,
  1133. inputlengthBytes,
  1134. NULL,
  1135. 0,
  1136. NULL );
  1137. LocalFree( input );
  1138. return status;
  1139. } // AssignDevice
  1140. DWORD
  1141. RemoveExcessVolGuids(
  1142. HANDLE MountMgrHandle,
  1143. PWCHAR MountName,
  1144. PWCHAR VolumeDevName
  1145. )
  1146. /*++
  1147. Routine Description:
  1148. Remove all VolGuids except the specified MountName (VolGuid) from the
  1149. mount manager's internal table of mount points.
  1150. Inputs:
  1151. MountMgrHandle - Handle to the mount manager. The caller is responsible for
  1152. opening and closing this handle.
  1153. MountName - VolGuid to keep. Format:
  1154. \??\Volume{-GUID-} - note prefix "\??\" and no trailing backslash.
  1155. VolumeDevName - Volume device name. Can be one of the following forms (note that case is
  1156. important). The "#" is a zero-based device number (and partition number
  1157. as appropriate).
  1158. \Device\CdRom#
  1159. \Device\Floppy#
  1160. \Device\HarddiskVolume#
  1161. \Device\Harddisk#\Partition#
  1162. Return value:
  1163. A Win32 error code.
  1164. --*/
  1165. {
  1166. DWORD dwError = NO_ERROR;
  1167. PMOUNTMGR_MOUNT_POINT input = NULL;
  1168. PMOUNTMGR_MOUNT_POINTS mountPoints = NULL;
  1169. PMOUNTMGR_MOUNT_POINT point;
  1170. DWORD len = wcslen( VolumeDevName ) * sizeof(WCHAR);
  1171. DWORD bytesReturned;
  1172. DWORD idx;
  1173. DWORD outputLen;
  1174. DWORD inputLen;
  1175. DWORD pointLen;
  1176. inputLen = INPUT_BUFFER_LEN + len;
  1177. input = LocalAlloc( LPTR, inputLen );
  1178. if ( !input ) {
  1179. dwError = GetLastError();
  1180. goto FnExit;
  1181. }
  1182. input->SymbolicLinkNameOffset = 0;
  1183. input->SymbolicLinkNameLength = 0;
  1184. input->UniqueIdOffset = 0;
  1185. input->UniqueIdLength = 0;
  1186. input->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  1187. input->DeviceNameLength = (USHORT) len;
  1188. CopyMemory((PCHAR)input + input->DeviceNameOffset, VolumeDevName, len );
  1189. if ( VolumeDevName[1] == L'\\' ) {
  1190. // convert Dos name to NT name
  1191. ((PWCHAR)(input + input->DeviceNameOffset))[1] = L'?';
  1192. }
  1193. outputLen = OUTPUT_BUFFER_LEN;
  1194. mountPoints = LocalAlloc( LPTR, outputLen );
  1195. if ( !mountPoints ) {
  1196. dwError = GetLastError();
  1197. goto FnExit;
  1198. }
  1199. if ( !DeviceIoControl( MountMgrHandle,
  1200. IOCTL_MOUNTMGR_QUERY_POINTS,
  1201. input,
  1202. inputLen,
  1203. mountPoints,
  1204. outputLen,
  1205. &bytesReturned,
  1206. NULL ) ) {
  1207. dwError = GetLastError();
  1208. if ( STATUS_BUFFER_OVERFLOW != dwError ) {
  1209. goto FnExit;
  1210. }
  1211. dwError = NO_ERROR;
  1212. outputLen = mountPoints->Size;
  1213. LocalFree( mountPoints );
  1214. mountPoints = LocalAlloc( LPTR, outputLen );
  1215. if ( !mountPoints ) {
  1216. dwError = GetLastError();
  1217. goto FnExit;
  1218. }
  1219. if ( !DeviceIoControl( MountMgrHandle,
  1220. IOCTL_MOUNTMGR_QUERY_POINTS,
  1221. input,
  1222. inputLen,
  1223. mountPoints,
  1224. outputLen,
  1225. &bytesReturned,
  1226. NULL ) ) {
  1227. dwError = GetLastError();
  1228. }
  1229. }
  1230. if ( NO_ERROR != dwError ) {
  1231. (DiskpLogEvent)(
  1232. RESOURCE_TYPE,
  1233. LOG_WARNING,
  1234. L"RemoveExcessVolGuids: mountmgr query returns error %1!u! \n",
  1235. dwError );
  1236. goto FnExit;
  1237. }
  1238. for ( idx = 0; idx < mountPoints->NumberOfMountPoints; ++idx ) {
  1239. point = &mountPoints->MountPoints[idx];
  1240. //
  1241. // Delete any VolGuids that mountmgr has that don't match the
  1242. // MountName (VolGuid) parameter.
  1243. //
  1244. if ( VOL_GUID_STRING_LEN * sizeof(WCHAR) == point->SymbolicLinkNameLength &&
  1245. 0 != memcmp( (PCHAR)mountPoints + point->SymbolicLinkNameOffset,
  1246. MountName,
  1247. point->SymbolicLinkNameLength ) ) {
  1248. RemoveVolGuid( MountMgrHandle,
  1249. (PWCHAR)((PCHAR)mountPoints + point->SymbolicLinkNameOffset),
  1250. point->SymbolicLinkNameLength );
  1251. }
  1252. }
  1253. FnExit:
  1254. LocalFree( mountPoints );
  1255. LocalFree( input );
  1256. return dwError;
  1257. } // RemoveExcessVolGuids
  1258. DWORD
  1259. RemoveVolGuid(
  1260. HANDLE MountMgrHandle,
  1261. PWCHAR VolGuid,
  1262. USHORT VolGuidSize
  1263. )
  1264. /*++
  1265. Routine Description:
  1266. Delete the specified VolGuid from mount manager's internal
  1267. table of mount points.
  1268. Inputs:
  1269. MountMgrHandle - Handle to the mount manager. The caller is responsible for
  1270. opening and closing this handle.
  1271. VolGuid - volume GUID to be deleted. Not NULL terminated.
  1272. \??\Volume{-GUID-} - note prefix "\??\" and no trailing backslash.
  1273. VolGuidSize - size (in bytes) of volume GUID.
  1274. Return value:
  1275. A Win32 error code.
  1276. --*/
  1277. {
  1278. DWORD dwError = NO_ERROR;
  1279. PMOUNTMGR_MOUNT_POINT input = NULL;
  1280. PMOUNTMGR_MOUNT_POINTS output = NULL;
  1281. DWORD bytesReturned;
  1282. DWORD inputLen;
  1283. DWORD outputLen;
  1284. //
  1285. // Allocate extra space so the VolGuid string will be null
  1286. // terminated in the input structure. This will allow us
  1287. // to display the VolGuid in the cluster log. We don't have
  1288. // to explictly null terminate the string because the input
  1289. // buffer is zeroed at allocation time.
  1290. //
  1291. inputLen = INPUT_BUFFER_LEN + VolGuidSize + sizeof(WCHAR);
  1292. input = LocalAlloc( LPTR, inputLen );
  1293. if ( !input ) {
  1294. dwError = GetLastError();
  1295. goto FnExit;
  1296. }
  1297. outputLen = sizeof(MOUNTMGR_MOUNT_POINTS) + 3*MAX_PATH*sizeof(WCHAR);
  1298. output = LocalAlloc( LPTR, outputLen );
  1299. input->UniqueIdOffset = 0;
  1300. input->UniqueIdLength = 0;
  1301. input->DeviceNameOffset = 0;
  1302. input->DeviceNameLength = 0;
  1303. input->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  1304. input->SymbolicLinkNameLength = VolGuidSize;
  1305. CopyMemory((PCHAR)input + input->SymbolicLinkNameOffset, VolGuid, VolGuidSize );
  1306. if ( !DeviceIoControl( MountMgrHandle,
  1307. IOCTL_MOUNTMGR_DELETE_POINTS,
  1308. input,
  1309. inputLen,
  1310. output,
  1311. outputLen,
  1312. &bytesReturned,
  1313. NULL ) ) {
  1314. dwError = GetLastError();
  1315. (DiskpLogEvent)(
  1316. RESOURCE_TYPE,
  1317. LOG_WARNING,
  1318. L"RemoveVolGuid: deleting VolGuid %1!ws! returns error %2!u! \n",
  1319. (PWCHAR)((PCHAR)input + input->SymbolicLinkNameOffset),
  1320. dwError );
  1321. } else {
  1322. (DiskpLogEvent)(
  1323. RESOURCE_TYPE,
  1324. LOG_INFORMATION,
  1325. L"RemoveVolGuid: deleted VolGuid %1!ws! \n",
  1326. (PWCHAR)((PCHAR)input + input->SymbolicLinkNameOffset) );
  1327. }
  1328. FnExit:
  1329. LocalFree( input );
  1330. LocalFree( output );
  1331. return dwError;
  1332. } // RemoveVolGuid
  1333. DWORD
  1334. DeleteVolGuidList(
  1335. PDISK_RESOURCE ResourceEntry
  1336. )
  1337. /*++
  1338. Routine Description:
  1339. Delete the list from the DISK_RESOURCE structure, if it exists (free the
  1340. memmory). Also deletes the information from the cluster database.
  1341. Arguments:
  1342. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  1343. Return Value:
  1344. NO_ERROR - The list was deleted.
  1345. ERROR_NOT_READY - The mount point information was not yet initialized.
  1346. Win32 error code.
  1347. --*/
  1348. {
  1349. DWORD dwError = NO_ERROR;
  1350. //
  1351. // Mount point structures not initialized (i.e. critical section). Don't continue.
  1352. //
  1353. if ( !ResourceEntry->MPInfo.Initialized ) {
  1354. (DiskpLogEvent)(
  1355. ResourceEntry->ResourceHandle,
  1356. LOG_WARNING,
  1357. L"DeleteVolGuidList: Mount point info not initialized. List not deleted. \n" );
  1358. dwError = ERROR_NOT_READY;
  1359. goto FnExit;
  1360. }
  1361. EnterCriticalSection( &ResourceEntry->MPInfo.MPLock );
  1362. //
  1363. // If existing list, free it.
  1364. //
  1365. if ( ResourceEntry->DiskInfo.Params.MPVolGuids ) {
  1366. LocalFree( ResourceEntry->DiskInfo.Params.MPVolGuids );
  1367. ResourceEntry->DiskInfo.Params.MPVolGuidsSize = 0;
  1368. ResourceEntry->DiskInfo.Params.MPVolGuids = NULL;
  1369. dwError = ClusterRegDeleteValue( ResourceEntry->ResourceParametersKey,
  1370. CLUSREG_NAME_PHYSDISK_MPVOLGUIDS );
  1371. //
  1372. // If the update failed and the disk is not yet online, it will fail with
  1373. // ERROR_SHARING_PAUSED. Just return the error. If the caller really,
  1374. // really, really wants the cluster database cleaned up, they can
  1375. // use the PostMPInfoIntoRegistry call to create a thread to do this
  1376. // work.
  1377. if ( NO_ERROR != dwError ) {
  1378. (DiskpLogEvent)(
  1379. ResourceEntry->ResourceHandle,
  1380. LOG_WARNING,
  1381. L"DeleteVolGuidList: Unable to delete VolGuid from cluster database %1!u! \n",
  1382. dwError );
  1383. }
  1384. }
  1385. LeaveCriticalSection( &ResourceEntry->MPInfo.MPLock );
  1386. FnExit:
  1387. #if DBG
  1388. (DiskpLogEvent)(
  1389. ResourceEntry->ResourceHandle,
  1390. LOG_INFORMATION,
  1391. L"DeleteVolGuidList: returns %1!u! \n",
  1392. dwError );
  1393. #endif
  1394. return dwError;
  1395. } // DeleteVolGuidList
  1396. BOOL
  1397. IsMountPointAllowed(
  1398. PWSTR MpName,
  1399. PWSTR SourceVol,
  1400. PWSTR TargetVol,
  1401. PDISK_RESOURCE ResourceEntry
  1402. )
  1403. /*++
  1404. Routine Description:
  1405. Verify that the mount point is allowed. There are several reasons why the mount
  1406. point would not be allowed.
  1407. At this point, the source volume will be accessible. If the source were offline,
  1408. we wouldn't even know about it, and we wouldn't even get to this routine. The
  1409. fact that the source is accessible allows us to do some things differently (i.e. we
  1410. can talk to the disk if needed).
  1411. Dependencies:
  1412. If source disk S has a mount point to target disk T ( S:\tdir --> T: ), then
  1413. target T is dependent on source S and source S must be brought online before
  1414. target T is online.
  1415. Quorum drive restrictions:
  1416. Generally, the quorum drive can have a mount point to target disk T as long as
  1417. target disk T is in same group as the quorum disk.
  1418. A mount point from clustered source S to quorum target Q is not allowed because
  1419. the quorum drive Q cannot be dependent on another resource.
  1420. A mount point from quorum source Q to a nonclustered target C is invalid.
  1421. Mount points to non-clustered disks:
  1422. These types of mountpoints should not be used.
  1423. Configurations supported:
  1424. C is a non-clustered disk.
  1425. X, Y are clustered disks, not quorum disks.
  1426. Q is quorum disk.
  1427. Source Target Status
  1428. ------ ------ ------------------------------------------------------------
  1429. C --> Q Not supported. Log error to system event log.
  1430. C --> X Not supported. Log error to system event log.
  1431. X --> C Not supported. We never process non-clustered target C.
  1432. X --> Q Invalid. Quorum drive cannot be dependent on another resource.
  1433. X --> Y Valid if drive Y is dependent on drive X (X online first).
  1434. Q --> X Valid if drive X is dependent on drive Q (Q online first).
  1435. Q --> C Not supported. We never process target C.
  1436. Arguments:
  1437. MpName - Possible mount point. This will either be a mount point or a drive letter
  1438. (which is actually a mount point). Format can be:
  1439. x:\ [Note trailing backslash!]
  1440. x:\some-mp-name\ [Note trailing backslash!]
  1441. x:\some-dir\some-mp-name\ [Note trailing backslash!]
  1442. \\?\Volume{GUID}\some-mp-name\ [Note trailing backslash!]
  1443. SourceVol - Mount point target volume name. Optional.
  1444. Format:
  1445. \\?\Volume{GUID}\ [Note trailing backslash!]
  1446. TargetVol - Mount point target volume name. Must always be specified.
  1447. Format:
  1448. \\?\Volume{GUID}\ [Note trailing backslash!]
  1449. ResourceEntry - Pointer to the DISK_RESOURCE structure for either the
  1450. source or target volume. If SourceVol is specified,
  1451. will be source structure. If SourceVol is not specified,
  1452. will be target structure.
  1453. Return Value:
  1454. TRUE if the mount point is allowed.
  1455. --*/
  1456. {
  1457. PWSTR srcGroup = NULL;
  1458. PWSTR targetGroup = NULL;
  1459. DWORD srcSignature = 0;
  1460. DWORD targetSignature = 0;
  1461. DWORD quorumSignature;
  1462. DWORD dwError = NO_ERROR;
  1463. DWORD messageId = 0;
  1464. DWORD srcGroupChars;
  1465. DWORD targetGroupChars;
  1466. BOOL mpAllowed = TRUE;
  1467. BOOL sigIsClustered;
  1468. BOOL dependencyCorrect;
  1469. BOOL sameGroup;
  1470. #if DBG
  1471. (DiskpLogEvent)(
  1472. ResourceEntry->ResourceHandle,
  1473. LOG_INFORMATION,
  1474. L"IsMountPointAllowed: MP Name (%1!ws!) \n",
  1475. MpName );
  1476. (DiskpLogEvent)(
  1477. ResourceEntry->ResourceHandle,
  1478. LOG_INFORMATION,
  1479. L"IsMountPointAllowed: SourceVolume (%1!ws!) \n",
  1480. SourceVol );
  1481. (DiskpLogEvent)(
  1482. ResourceEntry->ResourceHandle,
  1483. LOG_INFORMATION,
  1484. L"IsMountPointAllowed: TargetVolume (%1!ws!) \n",
  1485. TargetVol );
  1486. #endif
  1487. //
  1488. // Since the drive letter is also a mountpoint, a drive letter is valid.
  1489. //
  1490. if ( MPIsDriveLetter( MpName ) ) {
  1491. #if DBG
  1492. (DiskpLogEvent)(
  1493. ResourceEntry->ResourceHandle,
  1494. LOG_INFORMATION,
  1495. L"IsMountPointAllowed: Valid MP: MP is a drive letter \n" );
  1496. #endif
  1497. mpAllowed = TRUE;
  1498. goto FnExit;
  1499. }
  1500. if ( SourceVol ) {
  1501. srcSignature = ResourceEntry->DiskInfo.Params.Signature;
  1502. //
  1503. // Get the signature of the target drive.
  1504. // If this fails, we can't use the mountpoint.
  1505. //
  1506. dwError = GetSignatureForVolume( ResourceEntry, TargetVol, &targetSignature );
  1507. } else {
  1508. targetSignature = ResourceEntry->DiskInfo.Params.Signature;
  1509. //
  1510. // Get the signature of the source drive. This drive is accessible (or
  1511. // we wouldn't even have the mount point info yet) but we cannot assume it
  1512. // is a clustered drive. If this fails, we can't use the mountpoint.
  1513. //
  1514. dwError = GetSignatureForVolume( ResourceEntry, MpName, &srcSignature );
  1515. }
  1516. if ( NO_ERROR != dwError || !srcSignature || !targetSignature ) {
  1517. //
  1518. // If we are checking source mount points and target is not online (i.e. the
  1519. // dependency might be correct), we don't log an error if we can't get the
  1520. // signature. In this case, when we bring the target online, we'll check
  1521. // the dependencies at that time.
  1522. //
  1523. if ( SourceVol ) {
  1524. mpAllowed = TRUE;
  1525. } else {
  1526. mpAllowed = FALSE;
  1527. messageId = RES_DISK_INVALID_MP_SIG_UNAVAILABLE;
  1528. }
  1529. (DiskpLogEvent)(
  1530. ResourceEntry->ResourceHandle,
  1531. (mpAllowed ? LOG_INFORMATION : LOG_WARNING),
  1532. L"IsMountPointAllowed: Unable to get signature from volume, error %1!u! \n",
  1533. dwError );
  1534. goto FnExit;
  1535. }
  1536. //
  1537. // If source points back to target, this mount point is not allowed. Even though
  1538. // the mount point code seems to allow this, there are some strange circular
  1539. // dependencies that show up.
  1540. //
  1541. if ( srcSignature == targetSignature ) {
  1542. (DiskpLogEvent)(
  1543. ResourceEntry->ResourceHandle,
  1544. LOG_WARNING,
  1545. L"IsMountPointAllowed: Invalid MP: Source and target volumes are the same device \n" );
  1546. mpAllowed = FALSE;
  1547. messageId = RES_DISK_INVALID_MP_SOURCE_EQUAL_TARGET;
  1548. goto FnExit;
  1549. }
  1550. //
  1551. // Get quorum signature. If this fails, assume the mount point is not allowed.
  1552. //
  1553. dwError = GetQuorumSignature( &quorumSignature );
  1554. if ( NO_ERROR != dwError ) {
  1555. (DiskpLogEvent)(
  1556. ResourceEntry->ResourceHandle,
  1557. LOG_WARNING,
  1558. L"IsMountPointAllowed: Unable to get quorum signature, error %1!u! \n",
  1559. dwError );
  1560. mpAllowed = FALSE;
  1561. messageId = RES_DISK_INVALID_MP_QUORUM_SIG_UNAVAILABLE;
  1562. goto FnExit;
  1563. }
  1564. //
  1565. // If we can't enumerate the cluster disk signatures, assume that this mount
  1566. // point is not allowed. If SourceVol was specified, then we need to check if
  1567. // the target is clustered. If SourceVol was not specified, then we are
  1568. // processing the clustered target and need to insure the source is clustered.
  1569. //
  1570. if ( SourceVol ) {
  1571. dwError = CheckSignatureClustered( ResourceEntry,
  1572. targetSignature,
  1573. &sigIsClustered,
  1574. &targetGroup );
  1575. } else{
  1576. dwError = CheckSignatureClustered( ResourceEntry,
  1577. srcSignature,
  1578. &sigIsClustered,
  1579. &srcGroup );
  1580. }
  1581. if ( NO_ERROR != dwError ) {
  1582. (DiskpLogEvent)(
  1583. ResourceEntry->ResourceHandle,
  1584. LOG_WARNING,
  1585. L"IsMountPointAllowed: Unable to enumerate disk signatures, error %1!u! \n",
  1586. dwError );
  1587. mpAllowed = FALSE;
  1588. messageId = RES_DISK_INVALID_MP_SIG_ENUMERATION_FAILED;
  1589. goto FnExit;
  1590. }
  1591. //
  1592. // Insure that neither the source or target of the mount point is non-clustered.
  1593. // This check eliminates these configurations:
  1594. // C --> X
  1595. // C --> Q
  1596. // X --> C
  1597. // Q --> C
  1598. //
  1599. if ( !sigIsClustered ) {
  1600. if ( SourceVol ) {
  1601. (DiskpLogEvent)(
  1602. ResourceEntry->ResourceHandle,
  1603. LOG_WARNING,
  1604. L"IsMountPointAllowed: Invalid MP: Target volume is non-clustered \n" );
  1605. messageId = RES_DISK_INVALID_MP_TARGET_NOT_CLUSTERED;
  1606. } else {
  1607. (DiskpLogEvent)(
  1608. ResourceEntry->ResourceHandle,
  1609. LOG_WARNING,
  1610. L"IsMountPointAllowed: Invalid MP: Source volume is non-clustered \n" );
  1611. messageId = RES_DISK_INVALID_MP_SOURCE_NOT_CLUSTERED;
  1612. }
  1613. mpAllowed = FALSE;
  1614. goto FnExit;
  1615. }
  1616. //
  1617. // Have to check whether we retrieved the group names after checking
  1618. // whether signatures are clustered.
  1619. //
  1620. if ( (!targetGroup && !srcGroup) ) {
  1621. (DiskpLogEvent)(
  1622. ResourceEntry->ResourceHandle,
  1623. LOG_WARNING,
  1624. L"IsMountPointAllowed: Unable to enumerate disk signatures, error %1!u! \n",
  1625. dwError );
  1626. mpAllowed = FALSE;
  1627. messageId = RES_DISK_INVALID_MP_SIG_ENUMERATION_FAILED;
  1628. goto FnExit;
  1629. }
  1630. //
  1631. // If the target is the quorum drive, the mount point is not allowed because
  1632. // the quorum cannot be dependent on another disk resource. We already know
  1633. // that the source and target are different devices from an ealier check.
  1634. //
  1635. if ( quorumSignature == targetSignature ) {
  1636. (DiskpLogEvent)(
  1637. ResourceEntry->ResourceHandle,
  1638. LOG_WARNING,
  1639. L"IsMountPointAllowed: Invalid MP: target sig %1!x! is quorum disk, source sig %2!x! is clustered \n",
  1640. targetSignature,
  1641. srcSignature );
  1642. mpAllowed = FALSE;
  1643. messageId = RES_DISK_INVALID_MP_TARGET_IS_QUORUM;
  1644. goto FnExit;
  1645. }
  1646. //
  1647. // Check that the source and target are in the same group. If not, then we don't
  1648. // need to check the dependencies. If source/target is quorum, we can't go through
  1649. // the dependency check code because a deadlock can occur during quorum online.
  1650. //
  1651. // Similar to what we did previously, but note that if SourceVol was passed in,
  1652. // we specify srcSignature to CheckSignatureClustered. This will return the group
  1653. // name for the source volume. We do similar call for target volume.
  1654. //
  1655. if ( SourceVol ) {
  1656. dwError = CheckSignatureClustered( ResourceEntry,
  1657. srcSignature,
  1658. &sigIsClustered,
  1659. &srcGroup );
  1660. } else{
  1661. dwError = CheckSignatureClustered( ResourceEntry,
  1662. targetSignature,
  1663. &sigIsClustered,
  1664. &targetGroup );
  1665. }
  1666. if ( NO_ERROR != dwError || !targetGroup || !srcGroup ) {
  1667. (DiskpLogEvent)(
  1668. ResourceEntry->ResourceHandle,
  1669. LOG_WARNING,
  1670. L"IsMountPointAllowed: Unable to enumerate disk signatures, error %1!u! \n",
  1671. dwError );
  1672. mpAllowed = FALSE;
  1673. messageId = RES_DISK_INVALID_MP_SIG_ENUMERATION_FAILED;
  1674. goto FnExit;
  1675. }
  1676. #if DBG
  1677. (DiskpLogEvent)(
  1678. ResourceEntry->ResourceHandle,
  1679. LOG_INFORMATION,
  1680. L"IsMountPointAllowed: Source group: %1!ws! \n",
  1681. srcGroup );
  1682. (DiskpLogEvent)(
  1683. ResourceEntry->ResourceHandle,
  1684. LOG_INFORMATION,
  1685. L"IsMountPointAllowed: Target group: %1!ws! \n",
  1686. targetGroup );
  1687. #endif
  1688. //
  1689. // If source and target in different groups, we are done.
  1690. //
  1691. srcGroupChars = wcslen( srcGroup );
  1692. targetGroupChars = wcslen( targetGroup );
  1693. if ( srcGroupChars == targetGroupChars &&
  1694. 0 == wcsncmp( srcGroup, targetGroup, srcGroupChars ) ) {
  1695. sameGroup = TRUE;
  1696. } else {
  1697. sameGroup = FALSE;
  1698. }
  1699. //
  1700. // If source and target are not in the same group, just display
  1701. // the invalid dependency message and exit.
  1702. //
  1703. if ( !sameGroup ) {
  1704. (DiskpLogEvent)(
  1705. ResourceEntry->ResourceHandle,
  1706. LOG_WARNING,
  1707. L"IsMountPointAllowed: Invalid MP: Source and target are in different groups \n",
  1708. dwError );
  1709. mpAllowed = FALSE;
  1710. messageId = RES_DISK_INVALID_MP_INVALID_DEPENDENCIES;
  1711. goto FnExit;
  1712. }
  1713. //
  1714. // If source and target are in the same group and source is quorum disk,
  1715. // then the mount point is allowed since the quorum disk always comes
  1716. // online first. So even though dependencies might not be correct for
  1717. // quorum source pointed to clustered target (Q --> X) case, we won't
  1718. // display an error message.
  1719. //
  1720. if ( quorumSignature == srcSignature && sameGroup ) {
  1721. #if DBG
  1722. (DiskpLogEvent)(
  1723. ResourceEntry->ResourceHandle,
  1724. LOG_INFORMATION,
  1725. L"IsMountPointAllowed: Valid MP: source sig %1!x! is quorum, target sig %2!x! is clustered \n",
  1726. srcSignature,
  1727. targetSignature );
  1728. #endif
  1729. mpAllowed = TRUE;
  1730. goto FnExit;
  1731. }
  1732. //
  1733. // We have one possibility left:
  1734. // X --> Y
  1735. //
  1736. // This is valid only if the dependencies are set up correctly.
  1737. //
  1738. dependencyCorrect = FALSE;
  1739. dwError = CheckDependencies( ResourceEntry,
  1740. srcSignature,
  1741. targetSignature,
  1742. &dependencyCorrect );
  1743. if ( NO_ERROR != dwError ) {
  1744. (DiskpLogEvent)(
  1745. ResourceEntry->ResourceHandle,
  1746. LOG_WARNING,
  1747. L"IsMountPointAllowed: Unable to enumerate disk dependencies, error %1!u! \n",
  1748. dwError );
  1749. mpAllowed = FALSE;
  1750. messageId = RES_DISK_INVALID_MP_ENUM_DISK_DEP_FAILED;
  1751. goto FnExit;
  1752. }
  1753. if ( dependencyCorrect ) {
  1754. #if DBG
  1755. (DiskpLogEvent)(
  1756. ResourceEntry->ResourceHandle,
  1757. LOG_INFORMATION,
  1758. L"IsMountPointAllowed: Valid MP: Dependencies are correct \n" );
  1759. #endif
  1760. mpAllowed = TRUE;
  1761. goto FnExit;
  1762. }
  1763. (DiskpLogEvent)(
  1764. ResourceEntry->ResourceHandle,
  1765. LOG_WARNING,
  1766. L"IsMountPointAllowed: Invalid MP: Dependencies are incorrect \n",
  1767. MpName );
  1768. //
  1769. // If we get here, the mount point is not allowed.
  1770. //
  1771. mpAllowed = FALSE;
  1772. messageId = RES_DISK_INVALID_MP_INVALID_DEPENDENCIES;
  1773. FnExit:
  1774. if ( !mpAllowed && messageId ) {
  1775. // Log event...
  1776. ClusResLogSystemEventByKey2(ResourceEntry->ResourceKey,
  1777. LOG_UNUSUAL,
  1778. messageId,
  1779. MpName,
  1780. TargetVol);
  1781. }
  1782. if ( srcGroup ) {
  1783. LocalFree( srcGroup );
  1784. }
  1785. if ( targetGroup ) {
  1786. LocalFree( targetGroup );
  1787. }
  1788. return mpAllowed;
  1789. } // IsMountPointAllowed
  1790. DWORD
  1791. CheckDependencies(
  1792. PDISK_RESOURCE ResourceEntry,
  1793. DWORD SrcSignature,
  1794. DWORD TargetSignature,
  1795. PBOOL DependencyCorrect
  1796. )
  1797. /*++
  1798. Routine Description:
  1799. Determine if the dependency between the source volume and target volume is set up
  1800. correctly. Since we are using the cluster APIs, they should insure that the
  1801. resources are in the same group and have dependencies set.
  1802. Arguments:
  1803. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  1804. SrcSignature - Disk signature of the source volume.
  1805. TargetSignature - Disk signature of the targe volume.
  1806. DependencyCorrect - Indicates whether the dependency is set up correctly between the
  1807. source and target. If set up correctly, this will be returned
  1808. as TRUE.
  1809. Return Value:
  1810. Win32 error code.
  1811. --*/
  1812. {
  1813. DWORD dwError = NO_ERROR;
  1814. DEPENDENCY_INFO dependInfo;
  1815. ZeroMemory( &dependInfo, sizeof(DEPENDENCY_INFO) );
  1816. //
  1817. // We need to find the source's resources first.
  1818. //
  1819. dependInfo.ResourceEntry = ResourceEntry;
  1820. dependInfo.SrcSignature = SrcSignature;
  1821. dependInfo.TargetSignature = TargetSignature;
  1822. dependInfo.DependencyCorrect = FALSE;
  1823. //
  1824. // Worst case assume that the dependency is invalid.
  1825. //
  1826. *DependencyCorrect = FALSE;
  1827. dwError = ResUtilEnumResources( NULL,
  1828. PHYSICAL_DISK_WSTR,
  1829. DependencyCallback,
  1830. &dependInfo
  1831. );
  1832. //
  1833. // STOP_CLUSTER_ENUMERATIONS is our way to indicate that the
  1834. // enumerations stopped (possibly early). Check for this return
  1835. // value and also if the DependencyCorrect flag was set to indicate
  1836. // status to the caller.
  1837. //
  1838. if ( STOP_CLUSTER_ENUMERATIONS == dwError ) {
  1839. dwError = NO_ERROR;
  1840. if ( dependInfo.DependencyCorrect ) {
  1841. *DependencyCorrect = TRUE;
  1842. }
  1843. }
  1844. return dwError;
  1845. } // CheckDependencies
  1846. DWORD
  1847. DependencyCallback(
  1848. RESOURCE_HANDLE hOriginal,
  1849. RESOURCE_HANDLE hResource,
  1850. PVOID lpParams
  1851. )
  1852. /*++
  1853. Routine Description:
  1854. For each enumerated disk resource, get the signature and see if it matches the
  1855. mount point target signature (passed in the DEPENDENCY_INFO structure). If it
  1856. does not match, return success so that the disk enumeration continues.
  1857. If the enumerated resource signature matches the mount point target signature,
  1858. then check the cluster dependencies and make sure they are correct. Once we
  1859. have had a match on the signatures, we need to return an error to stop the
  1860. disk enumeration, so we use STOP_CLUSTER_ENUMERATIONS as that special error
  1861. value.
  1862. If the cluster dependencies are acceptable, the DependencyCorrect flag will be
  1863. set to TRUE in the DEPENDENCY_INFO structure.
  1864. Arguments:
  1865. hOriginal - Handle to the original resource. Not used.
  1866. hResource - Handle to a cluster resource of type PHYSICAL_DISK.
  1867. lpParams - Pointer to DEPENDENCY_INFO structure.
  1868. Return Value:
  1869. STOP_CLUSTER_ENUMERATIONS - Special flag to stop the enumeration process.
  1870. Win32 error code.
  1871. --*/
  1872. {
  1873. PDEPENDENCY_INFO dependInfo = lpParams;
  1874. DWORD dwSignature;
  1875. DWORD dwError = NO_ERROR;
  1876. //
  1877. // Get the disk info and parse the signature from it.
  1878. //
  1879. dwError = GetSignatureFromRegistry( dependInfo->ResourceEntry,
  1880. hResource,
  1881. &dwSignature );
  1882. if ( NO_ERROR != dwError ) {
  1883. return dwError;
  1884. }
  1885. //
  1886. // This code checks that the mount point SOURCE is online before
  1887. // the mount point TARGET.
  1888. //
  1889. // Check if we have a resource handle to the target disk or to
  1890. // a different disk. If the resource is the target disk,
  1891. // enumerate the dependencies and make sure they are correct.
  1892. //
  1893. if ( dwSignature == dependInfo->TargetSignature ) {
  1894. dwError = EnumSigDependencies( dependInfo->ResourceEntry,
  1895. hResource,
  1896. dependInfo->SrcSignature,
  1897. &dependInfo->DependencyCorrect );
  1898. //
  1899. // If the dependency check did not get an error, set a fake
  1900. // error to make the disk enumeration stop.
  1901. //
  1902. if ( NO_ERROR == dwError ) {
  1903. dwError = STOP_CLUSTER_ENUMERATIONS;
  1904. }
  1905. }
  1906. return dwError;
  1907. } // DependencyCallback
  1908. DWORD
  1909. EnumSigDependencies(
  1910. PDISK_RESOURCE ResourceEntry,
  1911. RESOURCE_HANDLE DependentResource,
  1912. DWORD DependsOnSignature,
  1913. PBOOL DependencyCorrect
  1914. )
  1915. /*++
  1916. Routine Description:
  1917. Check that the cluster disk dependencies are correct between the source and
  1918. target of the mount point.
  1919. To do this, we open the dependent resource and use the cluster APIs to enumerate
  1920. all the disk resources dependencies. For each dependency found, check for a
  1921. match of the DependsOnSignature. If the signatures match, the dependency is
  1922. correct and we are done. Otherwise, keep checking all the dependencies until
  1923. we exhaust the list or find a match.
  1924. Note: Dependency is brought online before the DependentResource.
  1925. Arguments:
  1926. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  1927. DependentResource - Resource Handle to check all the dependencies.
  1928. DependsOnSignature - Signature of a possibly dependent disk. This disk must be
  1929. brought online before the DependentResource.
  1930. DependencyCorrect - Flag set to TRUE when the cluster dependencies between
  1931. the DependentResource and it's dependency (identified by the
  1932. DependsOnSignature) are correct.
  1933. Return Value:
  1934. Win32 error code.
  1935. --*/
  1936. {
  1937. HRESENUM resEnum = NULL;
  1938. HCLUSTER hCluster = NULL;
  1939. HRESOURCE dependsOnResource = NULL;
  1940. DWORD idx;
  1941. DWORD dwError = NO_ERROR;
  1942. DWORD enumType;
  1943. DWORD nameLen;
  1944. DWORD signature;
  1945. WCHAR enumNameW[MAX_PATH * 2];
  1946. __try {
  1947. hCluster = OpenCluster( NULL );
  1948. if ( NULL == hCluster ) {
  1949. dwError = GetLastError();
  1950. __leave;
  1951. }
  1952. //
  1953. // Open an enumerator for iterating through the resources.
  1954. //
  1955. resEnum = ClusterResourceOpenEnum( DependentResource,
  1956. CLUSTER_RESOURCE_ENUM_DEPENDS );
  1957. if ( !resEnum ) {
  1958. dwError = GetLastError();
  1959. __leave;
  1960. }
  1961. //
  1962. // Iterate through the dependencies.
  1963. //
  1964. idx = 0;
  1965. while ( TRUE ) {
  1966. nameLen = MAX_PATH;
  1967. ZeroMemory( enumNameW, sizeof(enumNameW) );
  1968. dwError = ClusterResourceEnum( resEnum,
  1969. idx,
  1970. &enumType,
  1971. enumNameW,
  1972. &nameLen );
  1973. if ( ERROR_NO_MORE_ITEMS == dwError ) {
  1974. //
  1975. // The list is exhausted. Indicate no error and leave. This
  1976. // just means we checked all the dependencies and we didn't find
  1977. // a match.
  1978. //
  1979. dwError = NO_ERROR;
  1980. __leave;
  1981. }
  1982. if ( ERROR_SUCCESS != dwError ) {
  1983. //
  1984. // Some type of error, we have to stop processing.
  1985. //
  1986. __leave;
  1987. }
  1988. //
  1989. // Now we have the name (in the form of a string) of a resource we are
  1990. // dependent on. We need to get the signature and compare to the
  1991. // signature passed in.
  1992. //
  1993. dependsOnResource = OpenClusterResource( hCluster,
  1994. enumNameW );
  1995. if ( NULL == dependsOnResource ) {
  1996. dwError = GetLastError();
  1997. __leave;
  1998. }
  1999. //
  2000. // Get the disk signature from the resources disk info.
  2001. //
  2002. dwError = GetSignatureFromRegistry( ResourceEntry,
  2003. dependsOnResource,
  2004. &signature );
  2005. //
  2006. // If the signature passed in matches the signature we are dependent on,
  2007. // then the dependency is correct. Otherwise, we have to keep looking.
  2008. //
  2009. if ( NO_ERROR == dwError && signature == DependsOnSignature ) {
  2010. *DependencyCorrect = TRUE;
  2011. dwError = NO_ERROR;
  2012. __leave;
  2013. }
  2014. //
  2015. // Look at the next enumeration resource.
  2016. //
  2017. CloseClusterResource( dependsOnResource );
  2018. dependsOnResource = NULL;
  2019. idx++;
  2020. }
  2021. } __finally {
  2022. if ( dependsOnResource ) {
  2023. CloseClusterResource( dependsOnResource );
  2024. }
  2025. if ( resEnum ) {
  2026. ClusterResourceCloseEnum( resEnum );
  2027. }
  2028. if ( hCluster ) {
  2029. CloseCluster( hCluster );
  2030. }
  2031. }
  2032. return dwError;
  2033. } // EnumSigDependencies
  2034. DWORD
  2035. CheckSignatureClustered(
  2036. PDISK_RESOURCE ResourceEntry,
  2037. DWORD Signature,
  2038. PBOOL IsClustered,
  2039. PWSTR *GroupName
  2040. )
  2041. /*++
  2042. Routine Description:
  2043. Determine if the specified disk signature belongs to a clustered disk.
  2044. Enumerates the cluster physical disks and tries to find a signature
  2045. match.
  2046. The enumeration returns STOP_CLUSTER_ENUMERATIONS when it has found
  2047. a matching signature. This special error code is to stop the disk
  2048. enumeration.
  2049. If the disk is clustered, the disk name will be returned in the
  2050. GroupName parameter. The caller is responsible for freeing this
  2051. storage.
  2052. Arguments:
  2053. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  2054. Signature - Disk signature to be checked.
  2055. IsClustered - Flag indicating disk is clustered. If TRUE, disk is a
  2056. clustered disk.
  2057. GroupName - If signature represents a clustered disk, this parameter
  2058. will point to the group name (NULL terminated Unicode string).
  2059. The caller is responsible for freeing this buffer.
  2060. Return Value:
  2061. Win32 error code.
  2062. --*/
  2063. {
  2064. DWORD dwError = NO_ERROR;
  2065. SIG_INFO sigInfo;
  2066. ZeroMemory( &sigInfo, sizeof(SIG_INFO) );
  2067. sigInfo.ResourceEntry = ResourceEntry;
  2068. sigInfo.Signature = Signature;
  2069. sigInfo.Clustered = FALSE;
  2070. sigInfo.GroupName = NULL;
  2071. *IsClustered = FALSE;
  2072. *GroupName = NULL;
  2073. dwError = ResUtilEnumResources( NULL,
  2074. PHYSICAL_DISK_WSTR,
  2075. SigInfoCallback,
  2076. &sigInfo
  2077. );
  2078. if ( STOP_CLUSTER_ENUMERATIONS == dwError && sigInfo.Clustered ) {
  2079. dwError = NO_ERROR;
  2080. *IsClustered = TRUE;
  2081. *GroupName = sigInfo.GroupName;
  2082. }
  2083. return dwError;
  2084. } // CheckSignatureClustered
  2085. DWORD
  2086. SigInfoCallback(
  2087. RESOURCE_HANDLE hOriginal,
  2088. RESOURCE_HANDLE hResource,
  2089. PVOID lpParams
  2090. )
  2091. /*++
  2092. Routine Description:
  2093. For each enumerated disk resource, get the signature and see if it matches the
  2094. specified disk signature (passed in the SIG_INFO structure). If it does not
  2095. match, return success so that the disk enumeration continues.
  2096. If the enumerated resource signature matches the mount point source signature,
  2097. sets the Clustered flag in the SIG_INFO structure to TRUE.
  2098. Return the resource group name information.
  2099. Arguments:
  2100. hOriginal - Handle to the original resource. Not used.
  2101. hResource - Handle to a cluster resource of type PHYSICAL_DISK.
  2102. lpParams - Pointer to SIGN_INFO structure.
  2103. Return Value:
  2104. STOP_CLUSTER_ENUMERATIONS - Special flag to stop the enumeration process.
  2105. Win32 error code.
  2106. --*/
  2107. {
  2108. PSIG_INFO sigInfo = lpParams;
  2109. PWSTR groupName;
  2110. DWORD dwSignature;
  2111. DWORD dwError = NO_ERROR;
  2112. DWORD groupNameChars;
  2113. CLUSTER_RESOURCE_STATE resState;
  2114. //
  2115. // Get the disk info and parse the signature from it.
  2116. //
  2117. dwError = GetSignatureFromRegistry( sigInfo->ResourceEntry,
  2118. hResource,
  2119. &dwSignature );
  2120. if ( NO_ERROR != dwError ) {
  2121. return dwError;
  2122. }
  2123. if ( dwSignature == sigInfo->Signature ) {
  2124. sigInfo->Clustered = TRUE;
  2125. groupNameChars = MAX_GROUP_NAME_LENGTH;
  2126. groupName = LocalAlloc( LPTR, groupNameChars * sizeof(WCHAR) );
  2127. if ( groupName ) {
  2128. //
  2129. // Get the group name for this resource.
  2130. //
  2131. resState = GetClusterResourceState( hResource,
  2132. NULL,
  2133. 0,
  2134. groupName,
  2135. &groupNameChars );
  2136. //
  2137. // If we can't get the group name, we don't need to report
  2138. // an error. For error case, just free the group name
  2139. // buffer.
  2140. //
  2141. if ( ClusterResourceStateUnknown == resState ) {
  2142. LocalFree( groupName );
  2143. sigInfo->GroupName = NULL;
  2144. } else {
  2145. sigInfo->GroupName = groupName;
  2146. }
  2147. }
  2148. //
  2149. // Return an error to stop the enumeration.
  2150. //
  2151. dwError = STOP_CLUSTER_ENUMERATIONS;
  2152. }
  2153. return dwError;
  2154. } // SigInfoCallback
  2155. DWORD
  2156. GetSignatureFromRegistry(
  2157. PDISK_RESOURCE ResourceEntry,
  2158. RESOURCE_HANDLE hResource,
  2159. DWORD *dwSignature
  2160. )
  2161. /*++
  2162. Routine Description:
  2163. Get the signature for the given volume from the cluster from the registry.
  2164. Arguments:
  2165. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  2166. hResource - Handle to a cluster resource of type PHYSICAL_DISK.
  2167. Signature - On success, the signature is returned into this pointer.
  2168. Return Value:
  2169. Win32 error code.
  2170. --*/
  2171. {
  2172. DWORD dwError = NO_ERROR;
  2173. DWORD signature = 0;
  2174. HKEY hKey = NULL;
  2175. HKEY hParamKey = NULL;
  2176. *dwSignature = 0;
  2177. hKey = GetClusterResourceKey( hResource, KEY_READ );
  2178. if ( !hKey ) {
  2179. dwError = GetLastError();
  2180. goto FnExit;
  2181. }
  2182. dwError = ClusterRegOpenKey( hKey,
  2183. CLUSREG_KEYNAME_PARAMETERS,
  2184. KEY_READ,
  2185. &hParamKey );
  2186. if ( NO_ERROR != dwError ) {
  2187. (DiskpLogEvent)(
  2188. ResourceEntry->ResourceHandle,
  2189. LOG_WARNING,
  2190. L"GetSignatureFromRegistry: DiskRes %1!p! ClusterRegOpenKey failed %2!u! \n",
  2191. ResourceEntry,
  2192. dwError );
  2193. goto FnExit;
  2194. }
  2195. dwError = ResUtilGetDwordValue( hParamKey,
  2196. CLUSREG_NAME_PHYSDISK_SIGNATURE,
  2197. &signature,
  2198. 0 );
  2199. if ( NO_ERROR != dwError ) {
  2200. (DiskpLogEvent)(
  2201. ResourceEntry->ResourceHandle,
  2202. LOG_WARNING,
  2203. L"GetSignatureFromRegistry: DiskRes %1!p! ResUtilGetDwordValue failed %2!u! \n",
  2204. ResourceEntry,
  2205. dwError );
  2206. goto FnExit;
  2207. }
  2208. *dwSignature = signature;
  2209. FnExit:
  2210. if ( hParamKey ) {
  2211. ClusterRegCloseKey( hParamKey );
  2212. }
  2213. if ( hKey ) {
  2214. ClusterRegCloseKey( hKey );
  2215. }
  2216. return dwError;
  2217. } // GetSignatureFromRegistry
  2218. DWORD
  2219. GetSignatureForVolume(
  2220. PDISK_RESOURCE ResourceEntry,
  2221. PWSTR MpName,
  2222. PDWORD Signature
  2223. )
  2224. /*++
  2225. Routine Description:
  2226. Get the signature for the given volume. The signature is found by issuing
  2227. IOCTL_DISK_GET_DRIVE_LAYOUT_EX or IOCTL_DISK_GET_DRIVE_LAYOUT.
  2228. The volume must be online for this to work and not reserved by another node.
  2229. Arguments:
  2230. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  2231. MpName - Possible mount point. This will either be a mount point or a drive letter
  2232. (which is actually a mount point). Can also be a simple VolGUID.
  2233. Format can be:
  2234. x:\ [Note trailing backslash!]
  2235. x:\some-mp-name\ [Note trailing backslash!]
  2236. x:\some-dir\some-mp-name\ [Note trailing backslash!]
  2237. \\?\Volume{GUID}\some-mp-name\ [Note trailing backslash!]
  2238. \\?\Volume{GUID}\ [Note trailing backslash!]
  2239. Signature - On success, the signature is returned into this pointer.
  2240. Return Value:
  2241. Win32 error code.
  2242. --*/
  2243. {
  2244. PDRIVE_LAYOUT_INFORMATION_EX layoutEx = NULL;
  2245. PDRIVE_LAYOUT_INFORMATION layout = NULL;
  2246. PWCHAR deviceName = NULL;
  2247. HANDLE handle = NULL;
  2248. DWORD bytesReturned;
  2249. DWORD dwError = NO_ERROR;
  2250. DWORD deviceNameChars = 0;
  2251. if ( !MpName || !Signature ) {
  2252. dwError = ERROR_INVALID_PARAMETER;
  2253. goto FnExit;
  2254. }
  2255. *Signature = 0;
  2256. #if DBG
  2257. (DiskpLogEvent)(
  2258. ResourceEntry->ResourceHandle,
  2259. LOG_INFORMATION,
  2260. L"GetSignatureForVolume: Checking mount point (%1!ws!) \n",
  2261. MpName );
  2262. #endif
  2263. //
  2264. // Make copy of mount point for passing to CreateFile.
  2265. //
  2266. deviceNameChars = MAX_PATH;
  2267. deviceName = LocalAlloc( LPTR, deviceNameChars * sizeof(WCHAR) );
  2268. if ( !deviceName ) {
  2269. dwError = GetLastError();
  2270. goto FnExit;
  2271. }
  2272. //
  2273. // Create device name according to the mount point type.
  2274. //
  2275. if ( MOUNTDEV_LOOKS_LIKE_VOLUME_GUID( MpName, wcslen( MpName ) ) ) {
  2276. //
  2277. // Need to change the \??\Volume{ to \\?\Volume{ and truncate everything
  2278. // after the VolGUID. No trailing backslash.
  2279. //
  2280. wcsncpy( deviceName, MpName, VOL_GUID_STRING_LEN );
  2281. (WCHAR)*( deviceName + 1 ) = L'\\';
  2282. } else if ( MOUNTDEV_LOOKS_LIKE_ALT_VOLUME_GUID( MpName, wcslen( MpName ) ) ) {
  2283. //
  2284. // Form is acceptable as-is. Just truncate everything after the VolGUID.
  2285. // No trailing backslash.
  2286. //
  2287. wcsncpy( deviceName, MpName, VOL_GUID_STRING_LEN );
  2288. } else if ( MOUNTDEV_LOOKS_LIKE_DISK_PATH( MpName, wcslen( MpName ) ) ) {
  2289. //
  2290. // Make the name into the form: \\?\x: [Note: no trailing backslash!]
  2291. //
  2292. wcsncpy( deviceName, CREATE_FILE_PREFIX, wcslen( CREATE_FILE_PREFIX ) );
  2293. wcsncat( deviceName, MpName, 2 );
  2294. } else {
  2295. (DiskpLogEvent)(
  2296. ResourceEntry->ResourceHandle,
  2297. LOG_INFORMATION,
  2298. L"GetSignatureForVolume: Invalid mount point specified (%1!ws!) \n",
  2299. MpName );
  2300. dwError = ERROR_INVALID_PARAMETER;
  2301. goto FnExit;
  2302. }
  2303. #if DBG
  2304. (DiskpLogEvent)(
  2305. ResourceEntry->ResourceHandle,
  2306. LOG_INFORMATION,
  2307. L"GetSignatureForVolume: CreateFile using %1!ws! \n",
  2308. deviceName );
  2309. #endif
  2310. handle = CreateFileW( deviceName,
  2311. GENERIC_READ,
  2312. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2313. NULL,
  2314. OPEN_EXISTING,
  2315. FILE_ATTRIBUTE_NORMAL,
  2316. NULL );
  2317. if ( INVALID_HANDLE_VALUE == handle ) {
  2318. dwError = GetLastError();
  2319. (DiskpLogEvent)(
  2320. ResourceEntry->ResourceHandle,
  2321. LOG_WARNING,
  2322. L"GetSignatureForVolume: CreateFile for device (%1!ws!) failed, error %2!u! \n",
  2323. deviceName,
  2324. dwError );
  2325. goto FnExit;
  2326. }
  2327. //
  2328. // Try IOCTL_DISK_GET_DRIVE_LAYOUT_EX first. If it fails, try with
  2329. // IOCTL_DISK_GET_DRIVE_LAYOUT.
  2330. //
  2331. layoutEx = DoIoctlAndAllocate( handle,
  2332. IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  2333. 0,
  2334. 0,
  2335. &bytesReturned );
  2336. if ( layoutEx ) {
  2337. //
  2338. // Get the signature from the returned structure and return it to
  2339. // the caller.
  2340. //
  2341. if ( PARTITION_STYLE_MBR == layoutEx->PartitionStyle ) {
  2342. *Signature = layoutEx->Mbr.Signature;
  2343. } else if ( PARTITION_STYLE_GPT == layoutEx->PartitionStyle ) {
  2344. //
  2345. // Since our signatures won't handle the GPT GUID, we have to
  2346. // simulate a signature.
  2347. //
  2348. *Signature = ClusterHashGuid(layoutEx->Gpt.DiskId);
  2349. }
  2350. goto FnExit;
  2351. }
  2352. //
  2353. // Fall through and try the old IOCTL.
  2354. //
  2355. dwError = GetLastError();
  2356. (DiskpLogEvent)(
  2357. ResourceEntry->ResourceHandle,
  2358. LOG_WARNING,
  2359. L"GetSignatureForVolume: IOCTL_DISK_GET_DRIVE_LAYOUT_EX failed, error %1!u! \n",
  2360. dwError );
  2361. dwError = NO_ERROR;
  2362. layout = DoIoctlAndAllocate( handle,
  2363. IOCTL_DISK_GET_DRIVE_LAYOUT,
  2364. 0,
  2365. 0,
  2366. &bytesReturned );
  2367. if ( !layout ) {
  2368. dwError = GetLastError();
  2369. (DiskpLogEvent)(
  2370. ResourceEntry->ResourceHandle,
  2371. LOG_WARNING,
  2372. L"GetSignatureForVolume: IOCTL_DISK_GET_DRIVE_LAYOUT failed, error %1!u! \n",
  2373. dwError );
  2374. goto FnExit;
  2375. }
  2376. //
  2377. // Get the signature from the returned structure and return it to
  2378. // the caller.
  2379. //
  2380. *Signature = layout->Signature;
  2381. FnExit:
  2382. if ( layoutEx ) {
  2383. free( layoutEx );
  2384. }
  2385. if ( layout ) {
  2386. free( layout );
  2387. }
  2388. if ( deviceName ) {
  2389. LocalFree( deviceName );
  2390. }
  2391. if ( handle ) {
  2392. CloseHandle( handle );
  2393. }
  2394. #if DBG
  2395. (DiskpLogEvent)(
  2396. ResourceEntry->ResourceHandle,
  2397. LOG_INFORMATION,
  2398. L"GetSignatureForVolume: Returning signature %1!x! for mount point (%2!ws!) \n",
  2399. *Signature,
  2400. MpName );
  2401. #endif
  2402. return dwError;
  2403. } // GetSignatureForVolume
  2404. BOOL
  2405. GetOffsetFromPartNo(
  2406. DWORD PartitionNo,
  2407. PMOUNTIE_INFO Info,
  2408. PLARGE_INTEGER Offset
  2409. )
  2410. /*++
  2411. Routine Description:
  2412. Given the partition number and the drive layout, return the byte offset for the
  2413. specified partition.
  2414. Arguments:
  2415. PartitionNo - Supplies the partition number. Zero is invalid since partition zero
  2416. represents the entire disk.
  2417. Info - Pointer to MOUNTIE_INFO based on drive layout information.
  2418. Offset - Pointer to hold the returned byte offset for the partition. Space is
  2419. allocated by the caller.
  2420. Return Value:
  2421. TRUE if successful.
  2422. --*/
  2423. {
  2424. PMOUNTIE_PARTITION entry;
  2425. DWORD idx;
  2426. DWORD partitionCount;
  2427. BOOL retVal = FALSE;
  2428. if ( !PartitionNo || !Info || !Offset ) {
  2429. goto FnExit;
  2430. }
  2431. if ( 0 == Info->Volume ) {
  2432. goto FnExit;
  2433. }
  2434. #if DBG
  2435. (DiskpLogEvent)(
  2436. RESOURCE_TYPE,
  2437. LOG_INFORMATION,
  2438. L"GetOffsetFromPartNo: partition %1!u! \n",
  2439. PartitionNo );
  2440. #endif
  2441. Offset->QuadPart = 0; // Offset of zero is invalid. This will indicate an error.
  2442. partitionCount = Info->Volume->PartitionCount;
  2443. entry = Info->Volume->Partition;
  2444. for ( idx = 0; idx < partitionCount; ++idx, ++entry) {
  2445. #if DBG
  2446. (DiskpLogEvent)(
  2447. RESOURCE_TYPE,
  2448. LOG_INFORMATION,
  2449. L"GetOffsetFromPartNo: index %1!u! offset %2!x! \n",
  2450. idx,
  2451. entry->StartingOffset.LowPart );
  2452. #endif
  2453. if ( entry->PartitionNumber == PartitionNo ) {
  2454. Offset->QuadPart = entry->StartingOffset.QuadPart;
  2455. retVal = TRUE;
  2456. break;
  2457. }
  2458. }
  2459. FnExit:
  2460. return retVal;
  2461. } // GetOffsetFromPartNo
  2462. BOOL
  2463. GetPartNoFromOffset(
  2464. PLARGE_INTEGER Offset,
  2465. PMOUNTIE_INFO Info,
  2466. PDWORD PartitionNumber
  2467. )
  2468. /*++
  2469. Routine Description:
  2470. Given the offset and the drive layout, return the partition number for the specified offset.
  2471. Arguments:
  2472. Offset - Pointer to the byte offset.
  2473. Info - Pointer to MOUNTIE_INFO based on drive layout information.
  2474. PartitionNo - Pointer to hold the returned partition number. Space is allocated by the
  2475. caller.
  2476. Return Value:
  2477. TRUE if successful.
  2478. --*/
  2479. {
  2480. PMOUNTIE_PARTITION entry;
  2481. DWORD idx;
  2482. DWORD partitionCount;
  2483. BOOL retVal = FALSE;
  2484. if ( !Offset->QuadPart || !Info || !PartitionNumber) {
  2485. goto FnExit;
  2486. }
  2487. if ( 0 == Info->Volume ) {
  2488. goto FnExit;
  2489. }
  2490. *PartitionNumber = 0; // Partition zero is invalid. This will indicate an error.
  2491. partitionCount = Info->Volume->PartitionCount;
  2492. entry = Info->Volume->Partition;
  2493. for ( idx = 0; idx < partitionCount; ++idx, ++entry ) {
  2494. if ( entry->StartingOffset.QuadPart == Offset->QuadPart ) {
  2495. *PartitionNumber = entry->PartitionNumber;
  2496. retVal = TRUE;
  2497. break;
  2498. }
  2499. }
  2500. FnExit:
  2501. return retVal;
  2502. } // GetPartNoFromOffset
  2503. VOID
  2504. PrintStrList(
  2505. PDISK_RESOURCE ResourceEntry,
  2506. LPWSTR MultiSzList,
  2507. DWORD ListBytes
  2508. )
  2509. /*++
  2510. Routine Description:
  2511. Display the list in the cluster log.
  2512. Arguments:
  2513. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  2514. MultiSzList - REG_MULTI_SZ string
  2515. ListBytes - Number of bytes in MultiSzList, not number of WCHARs!
  2516. Return Value:
  2517. None.
  2518. --*/
  2519. {
  2520. PWSTR currentStr;
  2521. PWCHAR data;
  2522. LARGE_INTEGER offset;
  2523. DWORD currentStrLenChars = 0;
  2524. DWORD count;
  2525. if ( !ResourceEntry || !MultiSzList || 0 == ListBytes ) {
  2526. return;
  2527. }
  2528. (DiskpLogEvent)(
  2529. ResourceEntry->ResourceHandle,
  2530. LOG_INFORMATION,
  2531. L" Offset String \n" );
  2532. (DiskpLogEvent)(
  2533. ResourceEntry->ResourceHandle,
  2534. LOG_INFORMATION,
  2535. L"================ ====================================== \n" );
  2536. EnterCriticalSection( &ResourceEntry->MPInfo.MPLock );
  2537. currentStr = (PWCHAR)MultiSzList;
  2538. currentStrLenChars = wcslen( currentStr );
  2539. while ( currentStrLenChars ) {
  2540. data = NULL;
  2541. offset.QuadPart = 0;
  2542. //
  2543. // Convert the offset from a string to a large integer value.
  2544. //
  2545. count = swscanf( currentStr, L"%I64x ", &offset.QuadPart );
  2546. if ( 0 == count ) {
  2547. (DiskpLogEvent)(
  2548. ResourceEntry->ResourceHandle,
  2549. LOG_WARNING,
  2550. L"Error: Unable to parse offset from currentStr (%1!ws!) \n",
  2551. currentStr );
  2552. // Stop processing the list...
  2553. break;
  2554. }
  2555. //
  2556. // Data starts just after the first space.
  2557. //
  2558. data = wcschr( currentStr, SPACE_CHAR );
  2559. if ( !data || wcslen(data) < 3 ) {
  2560. (DiskpLogEvent)(
  2561. ResourceEntry->ResourceHandle,
  2562. LOG_INFORMATION,
  2563. L"Error: Unable to get mount point str from currentStr %1!ws! \n",
  2564. currentStr );
  2565. // Stop processing the list...
  2566. break;
  2567. }
  2568. //
  2569. // Skip past the space character. Note that the length was previously validated.
  2570. //
  2571. if ( SPACE_CHAR == *data ) {
  2572. data++;
  2573. }
  2574. (DiskpLogEvent)(
  2575. ResourceEntry->ResourceHandle,
  2576. LOG_INFORMATION,
  2577. L"%1!08X!%2!08X! %3!ws! \n", // couldn't get !I64X! to work...
  2578. offset.HighPart,
  2579. offset.LowPart,
  2580. data );
  2581. currentStr += currentStrLenChars + 1;
  2582. currentStrLenChars = wcslen( currentStr );
  2583. }
  2584. LeaveCriticalSection( &ResourceEntry->MPInfo.MPLock );
  2585. (DiskpLogEvent)(
  2586. ResourceEntry->ResourceHandle,
  2587. LOG_INFORMATION,
  2588. L"*** End of list *** \n" );
  2589. } // PrintStrList
  2590. static
  2591. DWORD
  2592. SetMPListThread(
  2593. LPVOID lpThreadParameter
  2594. )
  2595. /*++
  2596. Routine Description:
  2597. Mount point list update thread. Updates the cluster data base.
  2598. Arguments:
  2599. lpThreadParameter - stores ResourceEntry.
  2600. Return Value:
  2601. None
  2602. --*/
  2603. {
  2604. DWORD dwError;
  2605. PDISK_RESOURCE ResourceEntry = lpThreadParameter;
  2606. DWORD idx;
  2607. (DiskpLogEvent)(
  2608. ResourceEntry->ResourceHandle,
  2609. LOG_INFORMATION,
  2610. L"SetMPListThread: started.\n");
  2611. //
  2612. // Will die in 10 minutes if unsuccessful
  2613. //
  2614. for ( idx = 0; idx < 300; ++idx ) {
  2615. //
  2616. // Wait for either the terminate event or the timeout
  2617. //
  2618. dwError = WaitForSingleObject( DisksTerminateEvent, 2000 );
  2619. if ( WAIT_TIMEOUT == dwError ) {
  2620. EnterCriticalSection( &ResourceEntry->MPInfo.MPLock );
  2621. #if DBG
  2622. DumpDiskInfoParams( ResourceEntry );
  2623. #endif
  2624. //
  2625. // Bug in ResUtilSetPropertyParameterBlock. It will update the cluster
  2626. // database with updated MULTI_SZ data, but it doesn't clear the values
  2627. // appropriately. Use ClusterRegDeleteValue to make sure the lists are
  2628. // cleared if they have been deleted.
  2629. //
  2630. if ( !ResourceEntry->DiskInfo.Params.MPVolGuids &&
  2631. 0 == ResourceEntry->DiskInfo.Params.MPVolGuidsSize ) {
  2632. dwError = ClusterRegDeleteValue( ResourceEntry->ResourceParametersKey,
  2633. CLUSREG_NAME_PHYSDISK_MPVOLGUIDS );
  2634. }
  2635. //
  2636. // Timer expired. Update the cluster database.
  2637. //
  2638. dwError = ResUtilSetPropertyParameterBlock( ResourceEntry->ResourceParametersKey,
  2639. DiskResourcePrivateProperties,
  2640. NULL,
  2641. (LPBYTE) &ResourceEntry->DiskInfo.Params,
  2642. NULL,
  2643. 0,
  2644. NULL );
  2645. LeaveCriticalSection( &ResourceEntry->MPInfo.MPLock );
  2646. if ( ERROR_SUCCESS == dwError ) {
  2647. //
  2648. // We're done.
  2649. //
  2650. (DiskpLogEvent)(
  2651. ResourceEntry->ResourceHandle,
  2652. LOG_INFORMATION,
  2653. L"SetMPListThread: mount point info updated in cluster data base \n" );
  2654. break;
  2655. } else if ( ERROR_SHARING_PAUSED != dwError ) {
  2656. //
  2657. // If the drive is not yet online, we should have seen ERROR_SHARING_PAUSED. If
  2658. // we see any other error, something bad happened.
  2659. //
  2660. (DiskpLogEvent)(
  2661. ResourceEntry->ResourceHandle,
  2662. LOG_WARNING,
  2663. L"SetMPListThread: Failed to update cluster data base, error = %1!u! \n",
  2664. dwError );
  2665. break;
  2666. }
  2667. (DiskpLogEvent)(
  2668. ResourceEntry->ResourceHandle,
  2669. LOG_INFORMATION,
  2670. L"SetMPListThread: Wait again for event or timeout, count %1!u! \n",
  2671. idx );
  2672. } else {
  2673. //
  2674. // The terminate event is possibly set.
  2675. //
  2676. (DiskpLogEvent)(
  2677. ResourceEntry->ResourceHandle,
  2678. LOG_WARNING,
  2679. L"SetMPListThread: WaitForSingleObject returned error = %1!u! \n",
  2680. dwError );
  2681. break;
  2682. }
  2683. }
  2684. //
  2685. // Thread ending, clear the flag.
  2686. //
  2687. InterlockedExchange( &ResourceEntry->MPInfo.MPUpdateThreadIsActive, 0 );
  2688. return(ERROR_SUCCESS);
  2689. } // SetMPListThread
  2690. DWORD
  2691. PostMPInfoIntoRegistry(
  2692. PDISK_RESOURCE ResourceEntry
  2693. )
  2694. /*++
  2695. Routine Description:
  2696. Set the DiskResourcePrivateProperties in the cluster database. If the disk
  2697. is not yet online, create a thread to update the cluster database. The disk
  2698. might not be fully online if we are in the process of bringing the quorum disk
  2699. online and trying to update the mount point information.
  2700. Arguments:
  2701. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  2702. Return Value:
  2703. Win32 error code.
  2704. --*/
  2705. {
  2706. DWORD dwError;
  2707. //
  2708. // Update the cluster database.
  2709. //
  2710. EnterCriticalSection( &ResourceEntry->MPInfo.MPLock );
  2711. #if DBG
  2712. DumpDiskInfoParams( ResourceEntry );
  2713. #endif
  2714. //
  2715. // Bug in ResUtilSetPropertyParameterBlock. It will update the cluster
  2716. // database with updated MULTI_SZ data, but it doesn't clear the values
  2717. // appropriately. Use ClusterRegDeleteValue to make sure the lists are
  2718. // cleared if they have been deleted.
  2719. //
  2720. if ( !ResourceEntry->DiskInfo.Params.MPVolGuids &&
  2721. 0 == ResourceEntry->DiskInfo.Params.MPVolGuidsSize ) {
  2722. dwError = ClusterRegDeleteValue( ResourceEntry->ResourceParametersKey,
  2723. CLUSREG_NAME_PHYSDISK_MPVOLGUIDS );
  2724. }
  2725. dwError = ResUtilSetPropertyParameterBlock( ResourceEntry->ResourceParametersKey,
  2726. DiskResourcePrivateProperties,
  2727. NULL,
  2728. (LPBYTE) &ResourceEntry->DiskInfo.Params,
  2729. NULL,
  2730. 0,
  2731. NULL );
  2732. LeaveCriticalSection( &ResourceEntry->MPInfo.MPLock );
  2733. //
  2734. // If the update failed and the disk is not yet online, it will fail with
  2735. // ERROR_SHARING_PAUSED. In this case, create a thread to update the cluster
  2736. // data base. Any other error or success should simply continue.
  2737. //
  2738. if ( ERROR_SHARING_PAUSED == dwError ) {
  2739. //
  2740. // Check if the thread is already active. If it is, exit with an error.
  2741. //
  2742. if ( InterlockedCompareExchange(
  2743. &ResourceEntry->MPInfo.MPUpdateThreadIsActive,
  2744. 1, 0 ) ) {
  2745. (DiskpLogEvent)(
  2746. ResourceEntry->ResourceHandle,
  2747. LOG_WARNING,
  2748. L"PostMPInfoIntoRegistry: MountPoint thread is already running \n" );
  2749. dwError = ERROR_ALREADY_EXISTS;
  2750. } else {
  2751. HANDLE thread;
  2752. DWORD threadId;
  2753. thread = CreateThread( NULL,
  2754. 0,
  2755. SetMPListThread,
  2756. ResourceEntry,
  2757. 0,
  2758. &threadId );
  2759. if ( NULL == thread ) {
  2760. //
  2761. // Thread creation failed. Log error, clear thread active flag,
  2762. // and return.
  2763. //
  2764. dwError = GetLastError();
  2765. (DiskpLogEvent)(
  2766. ResourceEntry->ResourceHandle,
  2767. LOG_WARNING,
  2768. L"PostMPInfoIntoRegistry: CreateThread failed, error %1!u!\n",
  2769. dwError );
  2770. InterlockedExchange( &ResourceEntry->MPInfo.MPUpdateThreadIsActive, 0 );
  2771. } else {
  2772. (DiskpLogEvent)(
  2773. ResourceEntry->ResourceHandle,
  2774. LOG_INFORMATION,
  2775. L"PostMPInfoIntoRegistry: Thread created \n" );
  2776. //
  2777. // Thread created. Indicate no error.
  2778. //
  2779. CloseHandle( thread );
  2780. dwError = ERROR_SUCCESS;
  2781. }
  2782. }
  2783. } else {
  2784. (DiskpLogEvent)(
  2785. ResourceEntry->ResourceHandle,
  2786. ( NO_ERROR == dwError ? LOG_INFORMATION : LOG_WARNING ),
  2787. L"PostMPInfoIntoRegistry: ResUtilSetPropertyParameterBlock returned %1!u! \n",
  2788. dwError );
  2789. }
  2790. return dwError;
  2791. } // PostMpInfoIntoRegistry
  2792. VOID
  2793. DisksMountPointCleanup(
  2794. PDISK_RESOURCE ResourceEntry
  2795. )
  2796. /*++
  2797. Routine Description:
  2798. Cleanup everything the mount point code used.
  2799. This routine should be called in DisksClose.
  2800. Arguments:
  2801. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  2802. Return Value:
  2803. None.
  2804. --*/
  2805. {
  2806. (DiskpLogEvent)(
  2807. ResourceEntry->ResourceHandle,
  2808. LOG_INFORMATION,
  2809. L"DisksMountPointCleanup: Cleanup mount point information \n" );
  2810. //
  2811. // If existing MPVolGuids list, free it.
  2812. //
  2813. if ( ResourceEntry->DiskInfo.Params.MPVolGuids ) {
  2814. LocalFree( ResourceEntry->DiskInfo.Params.MPVolGuids );
  2815. ResourceEntry->DiskInfo.Params.MPVolGuidsSize = 0;
  2816. ResourceEntry->DiskInfo.Params.MPVolGuids = NULL;
  2817. }
  2818. ResourceEntry->MPInfo.Initialized = FALSE;
  2819. DeleteCriticalSection( &ResourceEntry->MPInfo.MPLock );
  2820. } // DisksMountPointCleanup
  2821. VOID
  2822. DisksMountPointInitialize(
  2823. PDISK_RESOURCE ResourceEntry
  2824. )
  2825. /*++
  2826. Routine Description:
  2827. Prepare the mount point structures in the ResourceEntry for use.
  2828. This routine should be called in DisksOpen.
  2829. Arguments:
  2830. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  2831. Return Value:
  2832. None.
  2833. --*/
  2834. {
  2835. InitializeCriticalSection( &ResourceEntry->MPInfo.MPLock );
  2836. ResourceEntry->MPInfo.Initialized = TRUE;
  2837. InterlockedExchange( &ResourceEntry->MPInfo.MPUpdateThreadIsActive, 0 );
  2838. InterlockedExchange( &ResourceEntry->MPInfo.MPListCreateInProcess, 0 );
  2839. } // DisksMountPointInitialize
  2840. DWORD
  2841. DisksUpdateMPList(
  2842. PDISK_RESOURCE ResourceEntry
  2843. )
  2844. /*++
  2845. Routine Description:
  2846. Validate the mount points.
  2847. Arguments:
  2848. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  2849. Return Value:
  2850. Win32 error code.
  2851. --*/
  2852. {
  2853. DWORD dwError = NO_ERROR;
  2854. (DiskpLogEvent)(
  2855. ResourceEntry->ResourceHandle,
  2856. LOG_INFORMATION,
  2857. L"DisksUpdateMPList: Processing PNP mountpoint notification \n" );
  2858. //
  2859. // Check if the MPList is in process of being updated. If it is, exit with an error.
  2860. //
  2861. if ( InterlockedCompareExchange(
  2862. &ResourceEntry->MPInfo.MPListCreateInProcess,
  2863. 1, 0 ) ) {
  2864. (DiskpLogEvent)(
  2865. ResourceEntry->ResourceHandle,
  2866. LOG_INFORMATION,
  2867. L"DisksUpdateMPList: Update in process, bypassing PNP notification \n" );
  2868. return ERROR_BUSY;
  2869. }
  2870. dwError = ValidateMountPoints( ResourceEntry );
  2871. InterlockedExchange( &ResourceEntry->MPInfo.MPListCreateInProcess, 0 );
  2872. return dwError;
  2873. } // DisksUpdateMPList
  2874. DWORD
  2875. DisksProcessMPControlCode(
  2876. PDISK_RESOURCE ResourceEntry,
  2877. DWORD ControlCode
  2878. )
  2879. /*++
  2880. Routine Description:
  2881. Process the disk mount point control code. Since we are in the thread
  2882. that handed us the control code (DisksResourceControl), we can't do
  2883. much except a separate thread to do the bulk of the mount point
  2884. processing.
  2885. Arguments:
  2886. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  2887. ControlCode - Cluster resource control for mount point processing.
  2888. Return Value:
  2889. --*/
  2890. {
  2891. HANDLE thread;
  2892. DWORD threadId;
  2893. DWORD dwError = NO_ERROR;
  2894. __try {
  2895. //
  2896. // Create a thread to update the mount point list. We don't need to
  2897. // copy the ResourceEntry as this pointer will be valid when the thread
  2898. // runs.
  2899. //
  2900. thread = CreateThread( NULL,
  2901. 0,
  2902. DisksUpdateMPList,
  2903. ResourceEntry,
  2904. 0,
  2905. &threadId );
  2906. if ( NULL == thread ) {
  2907. dwError = GetLastError();
  2908. (DiskpLogEvent)(
  2909. ResourceEntry->ResourceHandle,
  2910. LOG_WARNING,
  2911. L"DisksProcessMPControlCode: CreateThread failed %1!u! \n",
  2912. dwError );
  2913. __leave;
  2914. }
  2915. //
  2916. // Thread created. Indicate no error.
  2917. //
  2918. CloseHandle( thread );
  2919. dwError = NO_ERROR;
  2920. #if DBG
  2921. (DiskpLogEvent)(
  2922. ResourceEntry->ResourceHandle,
  2923. LOG_WARNING,
  2924. L"DisksProcessMPControlCode: Created thread to process control code \n" );
  2925. #endif
  2926. } __finally {
  2927. }
  2928. return dwError;
  2929. } // DisksProcessMPControlCode
  2930. DWORD
  2931. ValidateMountPoints(
  2932. IN OUT PDISK_RESOURCE ResourceEntry
  2933. )
  2934. /*++
  2935. Routine Description:
  2936. For each partition on this disk, get the mountpoints directed toward this
  2937. partition. Check each mountpoint to make sure it is allowed. For those
  2938. mountpoints not allowed, write a message to system event log indicating
  2939. why it is an invalid mountpoint.
  2940. Arguments:
  2941. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  2942. Return Value:
  2943. ERROR_INVALID_DATA - Partition info stored in MountieInfo is invalid.
  2944. Win32 error code.
  2945. --*/
  2946. {
  2947. PMOUNTIE_PARTITION entry;
  2948. DWORD dwError = ERROR_SUCCESS;
  2949. DWORD nPartitions = MountiePartitionCount( &ResourceEntry->MountieInfo );
  2950. DWORD physicalDrive = ResourceEntry->DiskInfo.PhysicalDrive;
  2951. DWORD idx;
  2952. WCHAR szGlobalDiskPartName[MAX_PATH];
  2953. WCHAR szVolumeName[MAX_PATH];
  2954. //
  2955. // Check each interesting partition. Since only "valid" partitions are
  2956. // saved in the MountieInfo structure, we will only look at those (ignoring those
  2957. // partitions that are not NTFS).
  2958. //
  2959. for ( idx = 0; idx < nPartitions; ++idx ) {
  2960. entry = MountiePartition( &ResourceEntry->MountieInfo, idx );
  2961. #if DBG
  2962. (DiskpLogEvent)(
  2963. ResourceEntry->ResourceHandle,
  2964. LOG_INFORMATION,
  2965. L"ValidateMountPoints: index %1!u! entry %2!x! \n", idx, entry );
  2966. #endif
  2967. if ( !entry ) {
  2968. (DiskpLogEvent)(
  2969. ResourceEntry->ResourceHandle,
  2970. LOG_WARNING,
  2971. L"ValidateMountPoints: no partition entry for index %1!u! \n", idx );
  2972. //
  2973. // Something bad happened to our data structures.
  2974. //
  2975. dwError = ERROR_INVALID_DATA;
  2976. break;
  2977. }
  2978. //
  2979. // Create the device name of the form:
  2980. // \\?\GLOBALROOT\Device\HarddiskX\PartitionY\ (uses trailing backslash)
  2981. //
  2982. (VOID) StringCchPrintf( szGlobalDiskPartName,
  2983. RTL_NUMBER_OF( szGlobalDiskPartName ),
  2984. GLOBALROOT_HARDDISK_PARTITION_FMT,
  2985. physicalDrive,
  2986. entry->PartitionNumber );
  2987. #if DBG
  2988. (DiskpLogEvent)(
  2989. ResourceEntry->ResourceHandle,
  2990. LOG_INFORMATION,
  2991. L"ValidateMountPoints: Using name (%1!ws!) \n",
  2992. szGlobalDiskPartName );
  2993. #endif
  2994. if ( !GetVolumeNameForVolumeMountPointW( szGlobalDiskPartName,
  2995. szVolumeName,
  2996. RTL_NUMBER_OF(szVolumeName) )) {
  2997. dwError = GetLastError();
  2998. (DiskpLogEvent)(
  2999. ResourceEntry->ResourceHandle,
  3000. LOG_WARNING,
  3001. L"ValidateMountPoints: GetVolumeNameForVolumeMountPoint for (%1!ws!) returned %2!u!\n",
  3002. szGlobalDiskPartName,
  3003. dwError );
  3004. break;
  3005. }
  3006. #if DBG
  3007. (DiskpLogEvent)(
  3008. ResourceEntry->ResourceHandle,
  3009. LOG_INFORMATION,
  3010. L"ValidateMountPoints: Returned volume name (%1!ws!) \n",
  3011. szVolumeName );
  3012. #endif
  3013. CheckMPsForVolume( ResourceEntry,
  3014. szVolumeName );
  3015. CheckMPsOnVolume( ResourceEntry,
  3016. szVolumeName );
  3017. }
  3018. return dwError;
  3019. } // ValidateMountPoints
  3020. DWORD
  3021. CheckMPsOnVolume(
  3022. IN OUT PDISK_RESOURCE ResourceEntry,
  3023. IN PWSTR SrcVolName
  3024. )
  3025. /*++
  3026. Routine Description:
  3027. For each the specified source volume, find all mount points hosted by this
  3028. volume. Find the target of each mount point, then make sure the depenedencies
  3029. are correct between the source and target volumes.
  3030. Arguments:
  3031. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  3032. SrcVolName - Volume GUID name with trailing backslash.
  3033. \\?\Volume{GUID}\ [Note trailing backslash!]
  3034. Return Value:
  3035. Win32 error code.
  3036. --*/
  3037. {
  3038. PWSTR mpBuffer = NULL;
  3039. PWSTR targetVolName = NULL;
  3040. PWSTR mpFullPath = NULL;
  3041. HANDLE hMP = INVALID_HANDLE_VALUE;
  3042. DWORD dwError = NO_ERROR;
  3043. DWORD mpBufferChars = MP_ALLOC_SIZE;
  3044. DWORD targetVolNameChars = MAX_PATH;
  3045. DWORD mpFullPathChars = MAX_PATH;
  3046. DWORD srcSignature = ResourceEntry->DiskInfo.Params.Signature;
  3047. //
  3048. // Buffer to hold mount points hosted on this volume.
  3049. //
  3050. mpBuffer = LocalAlloc( LPTR, mpBufferChars * sizeof(WCHAR) );
  3051. if ( !mpBuffer ) {
  3052. dwError = GetLastError();
  3053. (DiskpLogEvent)(
  3054. ResourceEntry->ResourceHandle,
  3055. LOG_WARNING,
  3056. L"CheckMPsOnVolume: Unable to allocate MP buffer for (%1!ws!), error %2!u!\n",
  3057. SrcVolName,
  3058. dwError );
  3059. goto FnExit;
  3060. }
  3061. hMP = FindFirstVolumeMountPoint( SrcVolName,
  3062. mpBuffer,
  3063. mpBufferChars );
  3064. if ( INVALID_HANDLE_VALUE == hMP ) {
  3065. //
  3066. // There might be no mount points on this volume, which is acceptable.
  3067. // Only log other types of errors.
  3068. //
  3069. dwError = GetLastError();
  3070. if ( ERROR_NO_MORE_FILES != dwError ) {
  3071. (DiskpLogEvent)(
  3072. ResourceEntry->ResourceHandle,
  3073. LOG_WARNING,
  3074. L"CheckMPsOnVolume: FindFirstVolumeMountPoint for (%1!ws!), error %2!u!\n",
  3075. SrcVolName,
  3076. dwError );
  3077. }
  3078. goto FnExit;
  3079. }
  3080. (DiskpLogEvent)(
  3081. ResourceEntry->ResourceHandle,
  3082. LOG_INFORMATION,
  3083. L"CheckMPsOnVolume: Checking volume (%1!ws!) source signature %2!08X! \n",
  3084. SrcVolName,
  3085. srcSignature );
  3086. //
  3087. // Buffer to hold the mount point target volume.
  3088. //
  3089. targetVolName = LocalAlloc( LPTR, targetVolNameChars * sizeof(WCHAR) );
  3090. if ( !targetVolName ) {
  3091. dwError = GetLastError();
  3092. (DiskpLogEvent)(
  3093. ResourceEntry->ResourceHandle,
  3094. LOG_WARNING,
  3095. L"CheckMPsOnVolume: Unable to allocate Volume Name buffer for (%1!ws!), error %2!u!\n",
  3096. SrcVolName,
  3097. dwError );
  3098. goto FnExit;
  3099. }
  3100. //
  3101. // Buffer to hold the full mount point name. This will be the source
  3102. // volume with the mount point appended to it.
  3103. // \\?\Volume{GUID}\some-mount-point\ [Note trailing backslash!]
  3104. //
  3105. mpFullPath = LocalAlloc( LPTR, mpFullPathChars * sizeof(WCHAR) );
  3106. if ( !mpFullPath ) {
  3107. dwError = GetLastError();
  3108. (DiskpLogEvent)(
  3109. ResourceEntry->ResourceHandle,
  3110. LOG_WARNING,
  3111. L"CheckMPsOnVolume: Unable to allocate Volume Name buffer for (%1!ws!), error %2!u!\n",
  3112. SrcVolName,
  3113. dwError );
  3114. goto FnExit;
  3115. }
  3116. while ( TRUE ) {
  3117. (VOID) StringCchCopy( mpFullPath, mpFullPathChars, SrcVolName );
  3118. (VOID) StringCchCat( mpFullPath, mpFullPathChars, mpBuffer );
  3119. //
  3120. // Given the source volume and mount point on the source volume,
  3121. // find the target of the mount point.
  3122. //
  3123. if ( !GetVolumeNameForVolumeMountPoint( mpFullPath,
  3124. targetVolName,
  3125. targetVolNameChars ) ) {
  3126. dwError = GetLastError();
  3127. (DiskpLogEvent)(
  3128. ResourceEntry->ResourceHandle,
  3129. LOG_WARNING,
  3130. L"CheckMPsOnVolume: GetVolumeNameForVolumeMountPoint failed for (%1!ws!), error %2!u!\n",
  3131. mpBuffer,
  3132. dwError );
  3133. //
  3134. // Fall through to get next mount point...
  3135. //
  3136. } else {
  3137. //
  3138. // Check dependencies between source and target volumes.
  3139. //
  3140. IsMountPointAllowed( mpFullPath,
  3141. SrcVolName, // Source VolGUID
  3142. targetVolName, // Target VolGUID
  3143. ResourceEntry );
  3144. }
  3145. //
  3146. // Keep looking for mount points on the source volume until there
  3147. // are no more.
  3148. //
  3149. if ( !FindNextVolumeMountPoint( hMP,
  3150. mpBuffer,
  3151. mpBufferChars ) ) {
  3152. dwError = GetLastError();
  3153. if ( ERROR_NO_MORE_FILES == dwError ) {
  3154. dwError = NO_ERROR;
  3155. } else {
  3156. (DiskpLogEvent)(
  3157. ResourceEntry->ResourceHandle,
  3158. LOG_WARNING,
  3159. L"CheckMPsOnVolume: FindNextVolumeMountPoint failed for (%1!ws!), error %2!u!\n",
  3160. SrcVolName,
  3161. dwError );
  3162. }
  3163. break;
  3164. }
  3165. }
  3166. FnExit:
  3167. if ( mpBuffer ) {
  3168. LocalFree( mpBuffer );
  3169. }
  3170. if ( targetVolName ) {
  3171. LocalFree( targetVolName );
  3172. }
  3173. if ( mpFullPath ) {
  3174. LocalFree( mpFullPath );
  3175. }
  3176. if ( INVALID_HANDLE_VALUE != hMP ) {
  3177. FindVolumeMountPointClose( hMP );
  3178. }
  3179. return dwError;
  3180. } // CheckMPsOnVolume
  3181. VOID
  3182. CheckMPsForVolume(
  3183. IN OUT PDISK_RESOURCE ResourceEntry,
  3184. IN PWSTR VolumeName
  3185. )
  3186. /*++
  3187. Routine Description:
  3188. For the specified volume, find all mount points directed towards this volume.
  3189. For each mountpoint, make sure it is allowed.
  3190. Arguments:
  3191. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  3192. VolumeName - Target volume for the mount point. Format is:
  3193. \\?\Volume{GUID}\ [Note trailing backslash!]
  3194. Return Value:
  3195. None.
  3196. --*/
  3197. {
  3198. PWSTR volumePaths = NULL;
  3199. PWSTR currentMP;
  3200. DWORD dwError;
  3201. __try {
  3202. //
  3203. // GetMountPoints will allocate a MultiSz buffer with
  3204. // all the mount points for this target volume.
  3205. //
  3206. dwError = GetMountPoints( VolumeName, &volumePaths );
  3207. if ( NO_ERROR != dwError || !volumePaths ) {
  3208. (DiskpLogEvent)(
  3209. ResourceEntry->ResourceHandle,
  3210. LOG_WARNING,
  3211. L"CheckMPsForVolume: GetMountPoints returns %1!u! \n", dwError );
  3212. __leave;
  3213. }
  3214. //
  3215. // Loop through each mount point in the list.
  3216. //
  3217. // Each mount point will either be a mount point or a drive letter
  3218. // (which is actually a mount point). Format can be:
  3219. //
  3220. // x:\ [Note trailing backslash!]
  3221. // x:\some-mp-name\ [Note trailing backslash!]
  3222. // x:\some-dir\some-mp-name\ [Note trailing backslash!]
  3223. //
  3224. currentMP = volumePaths;
  3225. for (;;) {
  3226. IsMountPointAllowed( currentMP,
  3227. NULL, // Source VolGUID
  3228. VolumeName, // Target VolGUID
  3229. ResourceEntry );
  3230. //
  3231. // Skip through current mount point to end of string.
  3232. //
  3233. while (*currentMP++);
  3234. //
  3235. // If next mount point is empty, the list is exhausted.
  3236. //
  3237. if (!*currentMP) {
  3238. break;
  3239. }
  3240. }
  3241. } __finally {
  3242. if ( volumePaths ) {
  3243. LocalFree( volumePaths );
  3244. }
  3245. }
  3246. } // CheckMPsForVolume
  3247. DWORD
  3248. GetMountPoints(
  3249. PWSTR VolumeName,
  3250. PWSTR *VolumePaths
  3251. )
  3252. /*++
  3253. Routine Description:
  3254. For the specified volume, find all mount points directed towards this volume.
  3255. The mount point buffer will be allocated by this routine and must be freed by
  3256. the caller.
  3257. Arguments:
  3258. VolumeName - Target volume for the mount point. Format is:
  3259. \\?\Volume{GUID}\ [Note trailing backslash!]
  3260. VolumePaths - Pointer to a MultiSz string containing all mount points directed
  3261. toward this volume. If there are no mount points, this pointer will
  3262. be set to NULL. The caller is responsible for freeing this buffer.
  3263. Return Value:
  3264. Win32 error code.
  3265. --*/
  3266. {
  3267. DWORD lenChars;
  3268. PWSTR paths = NULL;
  3269. DWORD dwError;
  3270. if ( !VolumeName || !VolumePaths ) {
  3271. return ERROR_INVALID_PARAMETER;
  3272. }
  3273. *VolumePaths = NULL;
  3274. //
  3275. // Determine the size of the buffer we need.
  3276. //
  3277. if ( !GetVolumePathNamesForVolumeName( VolumeName, NULL, 0, &lenChars ) ) {
  3278. dwError = GetLastError();
  3279. if ( ERROR_MORE_DATA != dwError ) {
  3280. return dwError;
  3281. }
  3282. }
  3283. //
  3284. // Allocate the mount point buffer.
  3285. //
  3286. paths = LocalAlloc( 0, lenChars * sizeof(WCHAR) );
  3287. if ( !paths ) {
  3288. dwError = GetLastError();
  3289. return dwError;
  3290. }
  3291. //
  3292. // Get the mount points.
  3293. //
  3294. if ( !GetVolumePathNamesForVolumeName( VolumeName, paths, lenChars, NULL ) ) {
  3295. dwError = GetLastError();
  3296. LocalFree( paths );
  3297. return dwError;
  3298. }
  3299. //
  3300. // If no mount points, free the buffer and return to the caller.
  3301. //
  3302. if ( !paths[0] ) {
  3303. LocalFree(paths);
  3304. //
  3305. // If no mount points for this volume, return no error and a NULL
  3306. // pointer to the mount point list.
  3307. //
  3308. return NO_ERROR;
  3309. }
  3310. *VolumePaths = paths;
  3311. return NO_ERROR;
  3312. } // GetMountPoints
  3313. DWORD
  3314. ValidateListOffsets(
  3315. IN OUT PDISK_RESOURCE ResourceEntry,
  3316. IN PWSTR MasterList
  3317. )
  3318. /*++
  3319. Routine Description:
  3320. Verify each entry in the list to make sure the byte offset
  3321. is valid. Also, count the number of entries to make sure
  3322. there are not too many entries saved (there should be one
  3323. VolGuid per node times the number of volumes on the disk).
  3324. Finally, make sure each offset is listed only once in the
  3325. list.
  3326. Arguments:
  3327. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  3328. MasterList - REG_MULTI_SZ list to be checked.
  3329. Return Value:
  3330. ERROR_INVALID_DATA - List contains at least one invalid byte offset
  3331. value, possibly more.
  3332. ERROR_INSUFFICIENT_BUFFER - List possibly corrupt as it contains too
  3333. many entries.
  3334. Win32 error code.
  3335. --*/
  3336. {
  3337. PWCHAR currentStr;
  3338. POFFSET_LIST offsetList = NULL;
  3339. DWORD currentStrLenChars = 0;
  3340. DWORD dwError = NO_ERROR;
  3341. DWORD partitionNo;
  3342. DWORD numberOfEntries = 0;
  3343. DWORD count;
  3344. LARGE_INTEGER offset;
  3345. BOOL invalidOffset = FALSE;
  3346. EnterCriticalSection( &ResourceEntry->MPInfo.MPLock );
  3347. //
  3348. // Parse through the list.
  3349. //
  3350. for ( currentStr = (PWCHAR)MasterList,
  3351. currentStrLenChars = wcslen( currentStr ) ;
  3352. currentStrLenChars ;
  3353. currentStr += currentStrLenChars + 1,
  3354. currentStrLenChars = wcslen( currentStr ) ) {
  3355. offset.QuadPart = 0;
  3356. #if DBG
  3357. (DiskpLogEvent)(
  3358. ResourceEntry->ResourceHandle,
  3359. LOG_INFORMATION,
  3360. L"ValidateListOffsets: CurrentStr (%1!ws!), numChars %2!u! \n",
  3361. currentStr,
  3362. currentStrLenChars );
  3363. #endif
  3364. //
  3365. // Convert the offset from a string to a large integer value.
  3366. //
  3367. count = swscanf( currentStr, L"%I64x ", &offset.QuadPart );
  3368. if ( 0 == count ) {
  3369. (DiskpLogEvent)(
  3370. ResourceEntry->ResourceHandle,
  3371. LOG_WARNING,
  3372. L"ValidateListOffsets: Unable to parse offset from currentStr (%1!ws!) \n",
  3373. currentStr );
  3374. numberOfEntries++;
  3375. continue;
  3376. }
  3377. //
  3378. // Check if offset was already seen. If seen, exit with error.
  3379. // If not seen, add it.
  3380. //
  3381. dwError = OffsetListAdd( &offsetList, &offset );
  3382. if ( ERROR_INVALID_DATA == dwError ) {
  3383. (DiskpLogEvent)(
  3384. ResourceEntry->ResourceHandle,
  3385. LOG_WARNING,
  3386. L"ValidateListOffsets: Offset ( %1!08X!%2!08X! ) in list multiple times \n",
  3387. offset.HighPart,
  3388. offset.LowPart ); // couldn't get !I64X! to work...
  3389. invalidOffset = TRUE;
  3390. // As soon as we find a duplicate offset, we are done.
  3391. break;
  3392. }
  3393. //
  3394. // Convert the offset to a partition number.
  3395. //
  3396. if ( !GetPartNoFromOffset( &offset, &ResourceEntry->MountieInfo, &partitionNo ) ) {
  3397. (DiskpLogEvent)(
  3398. ResourceEntry->ResourceHandle,
  3399. LOG_WARNING,
  3400. L"ValidateListOffsets: Unable to convert offset ( %1!08X!%2!08X! ) to partition number \n",
  3401. offset.HighPart,
  3402. offset.LowPart ); // couldn't get !I64X! to work...
  3403. invalidOffset = TRUE;
  3404. // As soon as we find an invalid partition number, we are done.
  3405. break;
  3406. }
  3407. numberOfEntries++;
  3408. }
  3409. if ( invalidOffset ) {
  3410. dwError = ERROR_INVALID_DATA;
  3411. } else if ( numberOfEntries > MAX_ALLOWED_VOLGUID_ENTRIES_PER_DISK ) {
  3412. (DiskpLogEvent)(
  3413. ResourceEntry->ResourceHandle,
  3414. LOG_WARNING,
  3415. L"ValidateListOffset: VolGuid list too large, %1!u! entries \n",
  3416. numberOfEntries );
  3417. //
  3418. // Return an error so the list is deleted and recreated.
  3419. //
  3420. dwError = ERROR_INVALID_DATA;
  3421. #if USEMOUNTPOINTS_KEY
  3422. //
  3423. // See if the user wants to ignore the number of entries in VolGuid list.
  3424. //
  3425. if ( !(ResourceEntry->DiskInfo.Params.UseMountPoints & MPS_IGNORE_MAX_VOLGUIDS) ) {
  3426. //
  3427. // Log an error to system event log.
  3428. //
  3429. ClusResLogSystemEventByKey(ResourceEntry->ResourceKey,
  3430. LOG_UNUSUAL,
  3431. RES_DISK_MP_VOLGUID_LIST_EXCESSIVE );
  3432. dwError = ERROR_INSUFFICIENT_BUFFER;
  3433. }
  3434. #endif
  3435. }
  3436. LeaveCriticalSection( &ResourceEntry->MPInfo.MPLock );
  3437. OffsetListCleanup( offsetList );
  3438. return dwError;
  3439. } // ValidateListOffsets
  3440. DWORD
  3441. OffsetListAdd(
  3442. POFFSET_LIST *OffsetList,
  3443. PLARGE_INTEGER Offset
  3444. )
  3445. /*++
  3446. Routine Description:
  3447. Add specified offset to the offset list.
  3448. Arguments:
  3449. OffsetList - pointer to offset list.
  3450. Offset - pointer to partition offset value.
  3451. Return Value:
  3452. NO_ERROR - Offset was not in list and was successfully added.
  3453. ERROR_INVALID_DATA - Offset was in the list previously.
  3454. Win32 error code - failed to add offset to the list.
  3455. --*/
  3456. {
  3457. POFFSET_LIST next = NULL;
  3458. POFFSET_LIST entry = *OffsetList;
  3459. DWORD dwError = NO_ERROR;
  3460. while ( entry ) {
  3461. next = entry->Next;
  3462. if ( Offset->LowPart == entry->Offset.LowPart &&
  3463. Offset->HighPart == entry->Offset.HighPart ) {
  3464. //
  3465. // Offset is already in the list. Return a
  3466. // unique error value.
  3467. //
  3468. dwError = ERROR_INVALID_DATA;
  3469. goto FnExit;
  3470. }
  3471. entry = next;
  3472. }
  3473. //
  3474. // If we got to this point, either the offset list was
  3475. // empty or we walked the entire list and the offset
  3476. // was not in the list. Add it now.
  3477. //
  3478. entry = LocalAlloc( LPTR, sizeof(OFFSET_LIST) );
  3479. if ( !entry ) {
  3480. dwError = GetLastError();
  3481. goto FnExit;
  3482. }
  3483. entry->Offset.LowPart = Offset->LowPart;
  3484. entry->Offset.HighPart = Offset->HighPart;
  3485. if ( *OffsetList ) {
  3486. entry->Next = *OffsetList;
  3487. }
  3488. *OffsetList = entry;
  3489. FnExit:
  3490. return dwError;
  3491. } // OffsetListAdd
  3492. DWORD
  3493. OffsetListCleanup(
  3494. POFFSET_LIST OffsetList
  3495. )
  3496. /*++
  3497. Routine Description:
  3498. Cleanup any storage allocated in the offset list.
  3499. Arguments:
  3500. OffsetList - pointer to offset list.
  3501. Return Value:
  3502. NO_ERROR
  3503. --*/
  3504. {
  3505. POFFSET_LIST next = NULL;
  3506. POFFSET_LIST entry = OffsetList;
  3507. while ( entry ) {
  3508. next = entry->Next;
  3509. LocalFree( entry );
  3510. entry = next;
  3511. }
  3512. return NO_ERROR;
  3513. } // OffsetListCleanup
  3514. BOOL
  3515. MPIsDriveLetter(
  3516. IN PWSTR MountPoint
  3517. )
  3518. /*++
  3519. Routine Description:
  3520. Determine if the mount point string is a drive letter. A drive letter will be
  3521. represented by a string of the form "x:\" with a length of 3.
  3522. Arguments:
  3523. MountPoint - Mount point string to be verified.
  3524. Return Value:
  3525. TRUE if the mount point string represents a drive letter.
  3526. --*/
  3527. {
  3528. DWORD lenChars;
  3529. lenChars = wcslen( MountPoint );
  3530. if ( 3 == lenChars &&
  3531. L':' == MountPoint[1] &&
  3532. L'\\' == MountPoint[2] &&
  3533. iswalpha( MountPoint[0] ) ) {
  3534. return TRUE;
  3535. }
  3536. return FALSE;
  3537. } // MPIsDriveLetter
  3538. #if DBG
  3539. //
  3540. // Debug helper routine
  3541. //
  3542. VOID
  3543. DumpDiskInfoParams(
  3544. PDISK_RESOURCE ResourceEntry
  3545. )
  3546. /*++
  3547. Routine Description:
  3548. Display in the cluster log interesting mountpoint information.
  3549. Arguments:
  3550. ResourceEntry - Pointer to the DISK_RESOURCE structure.
  3551. Return Value:
  3552. None.
  3553. --*/
  3554. {
  3555. #if 0 // Drive is not currently stored
  3556. (DiskpLogEvent)(
  3557. ResourceEntry->ResourceHandle,
  3558. LOG_INFORMATION,
  3559. L"SetMPListThread: Signature %1!x! Drive (%2!ws!) \n",
  3560. ResourceEntry->DiskInfo.Params.Signature,
  3561. ResourceEntry->DiskInfo.Params.Drive );
  3562. #endif
  3563. (DiskpLogEvent)(
  3564. ResourceEntry->ResourceHandle,
  3565. LOG_INFORMATION,
  3566. L"SetMPListThread: Signature %1!x! \n",
  3567. ResourceEntry->DiskInfo.Params.Signature );
  3568. #if USEMOUNTPOINTS_KEY
  3569. (DiskpLogEvent)(
  3570. ResourceEntry->ResourceHandle,
  3571. LOG_INFORMATION,
  3572. L"SetMPListThread: SkipChkdsk %1!x! ConditionalMount %2!x! UseMountPoints %3!x! \n",
  3573. ResourceEntry->DiskInfo.Params.SkipChkdsk,
  3574. ResourceEntry->DiskInfo.Params.ConditionalMount,
  3575. ResourceEntry->DiskInfo.Params.UseMountPoints );
  3576. #else
  3577. (DiskpLogEvent)(
  3578. ResourceEntry->ResourceHandle,
  3579. LOG_INFORMATION,
  3580. L"SetMPListThread: SkipChkdsk %1!x! ConditionalMount %2!x! \n",
  3581. ResourceEntry->DiskInfo.Params.SkipChkdsk,
  3582. ResourceEntry->DiskInfo.Params.ConditionalMount );
  3583. #endif
  3584. (DiskpLogEvent)(
  3585. ResourceEntry->ResourceHandle,
  3586. LOG_INFORMATION,
  3587. L"SetMPListThread: VolGuid list %1!x! VolGuid size %2!u! \n",
  3588. ResourceEntry->DiskInfo.Params.MPVolGuids,
  3589. ResourceEntry->DiskInfo.Params.MPVolGuidsSize );
  3590. } // DumpDiskInfoParams
  3591. #endif