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.

2741 lines
73 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. newmount.c
  5. Abstract:
  6. Replacement for mountie.c
  7. Author:
  8. Gor Nishanov (GorN) 31-July-1998
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include <nt.h>
  14. #include <ntdef.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include <windows.h>
  18. #include <devioctl.h>
  19. #include <stdio.h>
  20. #include <stddef.h>
  21. #include <stdlib.h>
  22. #include <mountdev.h> // This includes mountmgr.h
  23. #include <winioctl.h>
  24. #include <ntddscsi.h>
  25. #include "clusdisk.h"
  26. #include "disksp.h"
  27. #include "newmount.h"
  28. #include <strsafe.h> // Should be included last.
  29. #define LOG_CURRENT_MODULE LOG_MODULE_DISK
  30. #define MOUNTIE_VOLUME_INFO L"MountVolumeInfo"
  31. #define DISKS_DISK_INFO L"DiskInfo"
  32. #define BOGUS_BUFFER_LENGTH 512
  33. #define FIRST_SHOT_SIZE 512
  34. extern HANDLE DisksTerminateEvent;
  35. DWORD DiskInfoUpdateThreadIsActive = 0;
  36. //
  37. // LETTER_ASSIGNMENT structure is used to store letter assignment
  38. // information from various information providers
  39. //
  40. typedef USHORT PARTITION_NUMBER_TYPE;
  41. typedef struct _LETTER_ASSIGNMENT {
  42. DWORD MatchCount;
  43. DWORD MismatchCount;
  44. DWORD DriveLetters;
  45. PARTITION_NUMBER_TYPE PartNumber[26];
  46. } LETTER_ASSIGNMENT, *PLETTER_ASSIGNMENT;
  47. DWORD
  48. MountMgr_Get(
  49. PMOUNTIE_INFO Info,
  50. PDISK_RESOURCE ResourceEntry,
  51. PLETTER_ASSIGNMENT Result);
  52. /*
  53. * DoIoctlAndAllocate - allocates a result buffer and
  54. * tries to perform DeviceIoControl, it it fails due to insufficient buffer,
  55. * it tries again with a bigger buffer.
  56. *
  57. * FIRST_SHOT_SIZE is a constant that regulates the size of the buffer
  58. * for the first attempt to do DeviceIoControl.
  59. *
  60. * Return a non-zero code for error.
  61. */
  62. PVOID
  63. DoIoctlAndAllocate(
  64. IN HANDLE FileHandle,
  65. IN DWORD IoControlCode,
  66. IN PVOID InBuf,
  67. IN ULONG InBufSize,
  68. OUT LPDWORD BytesReturned
  69. )
  70. {
  71. UCHAR firstShot[ FIRST_SHOT_SIZE ];
  72. DWORD status = ERROR_SUCCESS;
  73. BOOL success;
  74. DWORD outBufSize;
  75. PVOID outBuf = 0;
  76. DWORD bytesReturned;
  77. success = DeviceIoControl( FileHandle,
  78. IoControlCode,
  79. InBuf,
  80. InBufSize,
  81. firstShot,
  82. sizeof(firstShot),
  83. &bytesReturned,
  84. (LPOVERLAPPED) NULL );
  85. if ( success ) {
  86. outBufSize = bytesReturned;
  87. outBuf = malloc( outBufSize );
  88. if (!outBuf) {
  89. status = ERROR_OUTOFMEMORY;
  90. } else {
  91. RtlCopyMemory(outBuf, firstShot, outBufSize);
  92. status = ERROR_SUCCESS;
  93. }
  94. } else {
  95. outBufSize = sizeof(firstShot);
  96. for(;;) {
  97. status = GetLastError();
  98. //
  99. // If it is not a buffer size related error, then we cannot do much
  100. //
  101. if ( status != ERROR_INSUFFICIENT_BUFFER
  102. && status != ERROR_MORE_DATA
  103. && status != ERROR_BAD_LENGTH
  104. ) {
  105. break;
  106. }
  107. //
  108. // Otherwise, try an outbut buffer twice the previous size
  109. //
  110. outBufSize *= 2;
  111. outBuf = malloc( outBufSize );
  112. if ( !outBuf ) {
  113. status = ERROR_OUTOFMEMORY;
  114. break;
  115. }
  116. success = DeviceIoControl( FileHandle,
  117. IoControlCode,
  118. InBuf,
  119. InBufSize,
  120. outBuf,
  121. outBufSize,
  122. &bytesReturned,
  123. (LPOVERLAPPED) NULL );
  124. if (success) {
  125. status = ERROR_SUCCESS;
  126. break;
  127. }
  128. free( outBuf );
  129. }
  130. }
  131. if (status != ERROR_SUCCESS) {
  132. free( outBuf ); // free( 0 ) is legal //
  133. outBuf = 0;
  134. bytesReturned = 0;
  135. }
  136. SetLastError( status );
  137. *BytesReturned = bytesReturned;
  138. return outBuf;
  139. }
  140. /*
  141. * DevfileOpen - open a device file given a pathname
  142. *
  143. * Return a non-zero code for error.
  144. */
  145. NTSTATUS
  146. DevfileOpen(
  147. OUT HANDLE *Handle,
  148. IN wchar_t *pathname
  149. )
  150. {
  151. return DevfileOpenEx( Handle,
  152. pathname,
  153. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA );
  154. }
  155. NTSTATUS
  156. DevfileOpenEx(
  157. OUT HANDLE *Handle,
  158. IN wchar_t *pathname,
  159. IN ACCESS_MASK Access
  160. )
  161. {
  162. HANDLE fh;
  163. OBJECT_ATTRIBUTES objattrs;
  164. UNICODE_STRING cwspath;
  165. NTSTATUS status;
  166. IO_STATUS_BLOCK iostatus;
  167. RtlInitUnicodeString(&cwspath, pathname);
  168. InitializeObjectAttributes(&objattrs, &cwspath, OBJ_CASE_INSENSITIVE,
  169. NULL, NULL);
  170. fh = NULL;
  171. status = NtOpenFile(&fh,
  172. Access,
  173. &objattrs, &iostatus,
  174. FILE_SHARE_READ | FILE_SHARE_WRITE,
  175. FILE_SYNCHRONOUS_IO_ALERT);
  176. if (status != STATUS_SUCCESS) {
  177. return status;
  178. }
  179. if ( !NT_SUCCESS(iostatus.Status) ) {
  180. if (fh) {
  181. NtClose(fh);
  182. }
  183. return iostatus.Status;
  184. }
  185. *Handle = fh;
  186. return STATUS_SUCCESS;
  187. } // DevfileOpen
  188. /*
  189. * DevfileClose - close a file
  190. */
  191. VOID
  192. DevfileClose(
  193. IN HANDLE Handle
  194. )
  195. {
  196. NtClose(Handle);
  197. } // DevFileClose
  198. /*
  199. * DevfileIoctl - issue an ioctl to a device
  200. */
  201. NTSTATUS
  202. DevfileIoctl(
  203. IN HANDLE Handle,
  204. IN DWORD Ioctl,
  205. IN PVOID InBuf,
  206. IN ULONG InBufSize,
  207. IN OUT PVOID OutBuf,
  208. IN DWORD OutBufSize,
  209. OUT LPDWORD returnLength
  210. )
  211. {
  212. NTSTATUS status;
  213. IO_STATUS_BLOCK ioStatus;
  214. status = NtDeviceIoControlFile(Handle,
  215. (HANDLE) NULL,
  216. (PIO_APC_ROUTINE) NULL,
  217. NULL,
  218. &ioStatus,
  219. Ioctl,
  220. InBuf, InBufSize,
  221. OutBuf, OutBufSize);
  222. if ( status == STATUS_PENDING ) {
  223. status = NtWaitForSingleObject( Handle, FALSE, NULL );
  224. }
  225. if ( NT_SUCCESS(status) ) {
  226. status = ioStatus.Status;
  227. }
  228. if ( ARGUMENT_PRESENT(returnLength) ) {
  229. *returnLength = (ULONG)ioStatus.Information;
  230. }
  231. return status;
  232. } // DevfileIoctl
  233. #define OUTPUT_BUFFER_LEN (1024)
  234. #define INPUT_BUFFER_LEN (sizeof(MOUNTMGR_MOUNT_POINT) + 2 * MAX_PATH * sizeof(WCHAR))
  235. DWORD
  236. DisksAssignDosDeviceM(
  237. HANDLE MountManager,
  238. PCHAR MountName,
  239. PWCHAR VolumeDevName
  240. )
  241. /*++
  242. Routine Description:
  243. Inputs:
  244. MountManager - Handle to MountMgr
  245. MountName -
  246. VolumeDevName -
  247. Return value:
  248. A Win32 error code.
  249. --*/
  250. {
  251. WCHAR mount_device[MAX_PATH];
  252. USHORT mount_point_len;
  253. USHORT dev_name_len;
  254. DWORD status;
  255. USHORT inputlength;
  256. PMOUNTMGR_CREATE_POINT_INPUT input;
  257. if ( FAILED( StringCchPrintf( mount_device,
  258. RTL_NUMBER_OF(mount_device),
  259. TEXT("\\DosDevices\\%S\0"),
  260. MountName ) ) ) {
  261. return ERROR_INSUFFICIENT_BUFFER;
  262. }
  263. mount_point_len = wcslen(mount_device) * sizeof(WCHAR);
  264. dev_name_len = wcslen(VolumeDevName) * sizeof(WCHAR);
  265. inputlength = sizeof(MOUNTMGR_CREATE_POINT_INPUT) +
  266. mount_point_len + dev_name_len;
  267. input = (PMOUNTMGR_CREATE_POINT_INPUT)malloc(inputlength);
  268. if (!input) {
  269. return ERROR_NOT_ENOUGH_MEMORY;
  270. }
  271. input->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT);
  272. input->SymbolicLinkNameLength = mount_point_len;
  273. input->DeviceNameOffset = input->SymbolicLinkNameOffset +
  274. input->SymbolicLinkNameLength;
  275. input->DeviceNameLength = dev_name_len;
  276. RtlCopyMemory((PCHAR)input + input->SymbolicLinkNameOffset,
  277. mount_device, mount_point_len);
  278. RtlCopyMemory((PCHAR)input + input->DeviceNameOffset,
  279. VolumeDevName, dev_name_len);
  280. status = DevfileIoctl(MountManager, IOCTL_MOUNTMGR_CREATE_POINT,
  281. input, inputlength, NULL, 0, NULL);
  282. free(input);
  283. return status;
  284. } // DisksAssignDosDevice
  285. DWORD
  286. DisksRemoveDosDeviceM(
  287. HANDLE MountManager,
  288. PCHAR MountName
  289. )
  290. /*++
  291. Routine Description:
  292. Inputs:
  293. MountManager - Handle to MountMgr
  294. MountName -
  295. Return value:
  296. --*/
  297. {
  298. WCHAR mount_device[MAX_PATH];
  299. USHORT mount_point_len;
  300. DWORD status;
  301. USHORT inputlength;
  302. PMOUNTMGR_MOUNT_POINT input;
  303. PUCHAR bogusBuffer; // this buffer should NOT be required!
  304. DWORD bogusBufferLength = BOGUS_BUFFER_LENGTH;
  305. //
  306. // Remove old mount points for this mount name.
  307. //
  308. if ( FAILED( StringCchPrintf( mount_device,
  309. RTL_NUMBER_OF(mount_device),
  310. TEXT("\\DosDevices\\%S"),
  311. MountName) ) ) {
  312. return ERROR_INSUFFICIENT_BUFFER;
  313. }
  314. mount_point_len = wcslen(mount_device) * sizeof(WCHAR);
  315. inputlength = sizeof(MOUNTMGR_MOUNT_POINT) + mount_point_len;
  316. input = (PMOUNTMGR_MOUNT_POINT)malloc(inputlength);
  317. if (!input) {
  318. return ERROR_NOT_ENOUGH_MEMORY;
  319. }
  320. bogusBuffer = malloc(bogusBufferLength);
  321. if (!bogusBuffer) {
  322. free(input);
  323. return ERROR_NOT_ENOUGH_MEMORY;
  324. }
  325. input->UniqueIdOffset = 0;
  326. input->UniqueIdLength = 0;
  327. input->DeviceNameOffset = 0;
  328. input->DeviceNameLength = 0;
  329. input->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  330. input->SymbolicLinkNameLength = mount_point_len;
  331. RtlCopyMemory((PCHAR)input + input->SymbolicLinkNameOffset,
  332. mount_device, mount_point_len);
  333. do {
  334. status = DevfileIoctl(MountManager, IOCTL_MOUNTMGR_DELETE_POINTS,
  335. input, inputlength, bogusBuffer, bogusBufferLength, NULL);
  336. free( bogusBuffer );
  337. if ( status == ERROR_MORE_DATA ) {
  338. bogusBufferLength += BOGUS_BUFFER_LENGTH;
  339. bogusBuffer = malloc(bogusBufferLength);
  340. if (!bogusBuffer) {
  341. status = ERROR_NOT_ENOUGH_MEMORY;
  342. }
  343. }
  344. } while ( status == ERROR_MORE_DATA );
  345. free(input);
  346. //
  347. // Use the 'old-style' name on error in case we got a 'half-built' stack.
  348. //
  349. if ( status != ERROR_SUCCESS ) {
  350. DefineDosDeviceA( DDD_REMOVE_DEFINITION | DDD_NO_BROADCAST_SYSTEM,
  351. MountName,
  352. NULL );
  353. }
  354. return status;
  355. } // DisksRemoveDosDevice
  356. static
  357. NTSTATUS
  358. GetAssignedLetterM (
  359. IN HANDLE MountMgrHandle,
  360. IN PWCHAR deviceName,
  361. OUT PCHAR driveLetter )
  362. /*++
  363. Routine Description:
  364. Get an assigned drive letter from MountMgr, if any
  365. Inputs:
  366. MountMgrHandle -
  367. deviceName -
  368. driveLetter - receives drive letter
  369. Return value:
  370. STATUS_SUCCESS - on success
  371. NTSTATUS code - on failure
  372. --*/
  373. {
  374. DWORD status = STATUS_SUCCESS;
  375. PMOUNTMGR_MOUNT_POINT input = NULL;
  376. PMOUNTMGR_MOUNT_POINTS output = NULL;
  377. PMOUNTMGR_MOUNT_POINT out;
  378. DWORD len = wcslen( deviceName ) * sizeof(WCHAR);
  379. DWORD bytesReturned;
  380. DWORD idx;
  381. DWORD outputLen;
  382. DWORD inputLen;
  383. WCHAR wc;
  384. // Input length has to include the MOUNTMGR_MOUNT_POINT
  385. // structure and the input device name string.
  386. inputLen = INPUT_BUFFER_LEN + len * 2;
  387. input = LocalAlloc( LPTR, inputLen );
  388. if ( !input ) {
  389. status = STATUS_INSUFFICIENT_RESOURCES;
  390. goto FnExit;
  391. }
  392. input->SymbolicLinkNameOffset = 0;
  393. input->SymbolicLinkNameLength = 0;
  394. input->UniqueIdOffset = 0;
  395. input->UniqueIdLength = 0;
  396. input->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  397. input->DeviceNameLength = (USHORT) len;
  398. RtlCopyMemory((PCHAR)input + input->DeviceNameOffset,
  399. deviceName, len );
  400. if (len > sizeof(WCHAR) && deviceName[1] == L'\\') {
  401. // convert Dos name to NT name
  402. ((PWCHAR)(input + input->DeviceNameOffset))[1] = L'?';
  403. }
  404. outputLen = OUTPUT_BUFFER_LEN;
  405. output = LocalAlloc( LPTR, outputLen );
  406. if ( !output ) {
  407. status = STATUS_INSUFFICIENT_RESOURCES;
  408. goto FnExit;
  409. }
  410. status = DevfileIoctl(MountMgrHandle, IOCTL_MOUNTMGR_QUERY_POINTS,
  411. input, inputLen, output, outputLen, &bytesReturned);
  412. if ( STATUS_BUFFER_OVERFLOW == status ) {
  413. outputLen = output->Size;
  414. LocalFree( output );
  415. output = LocalAlloc( LPTR, outputLen );
  416. if ( !output ) {
  417. status = STATUS_INSUFFICIENT_RESOURCES;
  418. goto FnExit;
  419. }
  420. status = DevfileIoctl(MountMgrHandle, IOCTL_MOUNTMGR_QUERY_POINTS,
  421. input, inputLen, output, outputLen, &bytesReturned);
  422. }
  423. if ( !NT_SUCCESS(status) ) {
  424. goto FnExit;
  425. }
  426. if (driveLetter) {
  427. *driveLetter = 0;
  428. }
  429. for ( idx = 0; idx < output->NumberOfMountPoints; ++idx ) {
  430. out = &output->MountPoints[idx];
  431. if (out->SymbolicLinkNameLength/sizeof(WCHAR) == 14 &&
  432. (ClRtlStrNICmp((PWCHAR)((PCHAR)output + out->SymbolicLinkNameOffset), L"\\DosDevices\\", 12) == 0) &&
  433. L':' == *((PCHAR)output + out->SymbolicLinkNameOffset + 13*sizeof(WCHAR)) )
  434. {
  435. wc = *((PCHAR)output + out->SymbolicLinkNameOffset + 12*sizeof(WCHAR));
  436. if (driveLetter && out->UniqueIdLength) {
  437. *driveLetter = (CHAR)toupper((UCHAR)wc);
  438. break;
  439. }
  440. }
  441. }
  442. FnExit:
  443. if ( output ) {
  444. LocalFree( output );
  445. }
  446. if ( input ) {
  447. LocalFree( input );
  448. }
  449. return status;
  450. }
  451. BOOL
  452. InterestingPartition(
  453. PPARTITION_INFORMATION info
  454. )
  455. /*++
  456. Routine Description:
  457. Quick check whether a partition is "interesting" for us
  458. Inputs:
  459. info - GetDriveLayout's partition information
  460. Return value:
  461. TRUE or FALSE
  462. --*/
  463. {
  464. return ( (info->RecognizedPartition)
  465. && ((info->PartitionType == PARTITION_IFS) ||
  466. IsContainerPartition(info->PartitionType)) );
  467. }
  468. PMOUNTIE_VOLUME
  469. CreateMountieVolumeFromDriveLayoutInfo (
  470. IN PDRIVE_LAYOUT_INFORMATION info,
  471. IN HANDLE ResourceHandle
  472. )
  473. /*++
  474. Routine Description:
  475. Collects all interesing partition from DriveLayoutInformation
  476. then it allocates and fills MountieVolume structure
  477. Inputs:
  478. info - GetDriveLayout's information
  479. ResourceHandle - for error logging - not used (may be NULL!)
  480. Return value:
  481. TRUE or FALSE
  482. --*/
  483. {
  484. DWORD i;
  485. DWORD nPartitions = 0;
  486. PMOUNTIE_VOLUME vol;
  487. PMOUNTIE_PARTITION mountie;
  488. DWORD size;
  489. //
  490. // Count Partitions
  491. //
  492. for (i = 0; i < info->PartitionCount; ++i) {
  493. if ( InterestingPartition( info->PartitionEntry + i ) ) {
  494. ++nPartitions;
  495. }
  496. }
  497. if (!nPartitions) {
  498. SetLastError(ERROR_INVALID_DATA);
  499. return 0;
  500. }
  501. //
  502. // Allocate memory for Mountie structure
  503. //
  504. size = sizeof(MOUNTIE_VOLUME) + sizeof(MOUNTIE_PARTITION) * (nPartitions - 1);
  505. vol = malloc( size );
  506. if (!vol) {
  507. SetLastError(ERROR_OUTOFMEMORY);
  508. return 0;
  509. }
  510. RtlZeroMemory(vol, size);
  511. vol->PartitionCount = nPartitions;
  512. vol->Signature = info->Signature;
  513. //
  514. // Copy all relevant Information from DriveLayout info
  515. //
  516. mountie = vol->Partition;
  517. for (i = 0; i < info->PartitionCount; ++i) {
  518. PPARTITION_INFORMATION entry = info->PartitionEntry + i;
  519. if ( InterestingPartition(entry) ) {
  520. mountie->StartingOffset = entry->StartingOffset;
  521. mountie->PartitionLength = entry->PartitionLength;
  522. mountie->PartitionNumber = entry->PartitionNumber;
  523. mountie->PartitionType = entry->PartitionType;
  524. ++mountie;
  525. }
  526. }
  527. return vol;
  528. }
  529. VOID
  530. MountieUpdateDriveLetters(
  531. IN OUT PMOUNTIE_INFO info
  532. )
  533. /*++
  534. Routine Description:
  535. Updates DriveLetter bitmap.
  536. This routine needs to be called every time
  537. drive letter information is changed in MountieInfo
  538. Inputs:
  539. info - MountieInfo
  540. --*/
  541. {
  542. DWORD i;
  543. DWORD driveLetters = 0;
  544. PMOUNTIE_VOLUME vol = info->Volume;
  545. if (vol) {
  546. for (i = 0; i < vol->PartitionCount; ++i) {
  547. UCHAR ch = vol->Partition[i].DriveLetter;
  548. if (ch) {
  549. driveLetters |= 1 << (ch - 'A');
  550. }
  551. }
  552. }
  553. info->DriveLetters = driveLetters;
  554. }
  555. PMOUNTIE_PARTITION
  556. MountiePartitionByOffsetAndLength(
  557. IN PMOUNTIE_INFO Info,
  558. LARGE_INTEGER Offset, LARGE_INTEGER Len)
  559. {
  560. DWORD PartitionCount;
  561. PMOUNTIE_PARTITION entry;
  562. if (!Info->Volume) {
  563. return 0;
  564. }
  565. PartitionCount = Info->Volume->PartitionCount;
  566. entry = Info->Volume->Partition;
  567. while ( PartitionCount-- ) {
  568. if (entry->StartingOffset.QuadPart == Offset.QuadPart
  569. && entry->PartitionLength.QuadPart == Len.QuadPart) {
  570. return entry;
  571. }
  572. ++entry;
  573. }
  574. return 0;
  575. }
  576. DWORD
  577. MountiePartitionCount(
  578. IN PMOUNTIE_INFO Info)
  579. {
  580. if (Info->Volume) {
  581. return Info->Volume->PartitionCount;
  582. } else {
  583. return 0;
  584. }
  585. }
  586. PMOUNTIE_PARTITION
  587. MountiePartition(
  588. IN PMOUNTIE_INFO Info,
  589. IN DWORD Index)
  590. {
  591. return Info->Volume->Partition + Index;
  592. }
  593. PMOUNTIE_PARTITION
  594. MountiePartitionByPartitionNo(
  595. IN PMOUNTIE_INFO Info,
  596. IN DWORD PartitionNumber
  597. )
  598. {
  599. DWORD i, n;
  600. PMOUNTIE_PARTITION entry;
  601. if (Info->Volume == 0) {
  602. return 0;
  603. }
  604. n = Info->Volume->PartitionCount;
  605. entry = Info->Volume->Partition;
  606. for (i = 0; i < n; ++i, ++entry) {
  607. if (entry->PartitionNumber == PartitionNumber)
  608. {
  609. return entry;
  610. }
  611. }
  612. return 0;
  613. }
  614. VOID
  615. MountiePrint(
  616. IN PMOUNTIE_INFO Info,
  617. IN HANDLE ResourceHandle
  618. )
  619. {
  620. DWORD i, n;
  621. PMOUNTIE_PARTITION entry;
  622. if (Info->Volume == 0) {
  623. return;
  624. }
  625. n = Info->Volume->PartitionCount;
  626. entry = Info->Volume->Partition;
  627. for (i = 0; i < n; ++i, ++entry) {
  628. (DiskpLogEvent)(
  629. ResourceHandle,
  630. LOG_INFORMATION,
  631. L"Mountie[%1!u!]: %2!u!, let=%3!c!, start=%4!X!, len=%5!X!.\n",
  632. i,
  633. entry->PartitionNumber,
  634. NICE_DRIVE_LETTER(entry->DriveLetter),
  635. entry->StartingOffset.LowPart,
  636. entry->PartitionLength.LowPart );
  637. }
  638. }
  639. DWORD
  640. DisksGetLettersForSignature(
  641. IN PDISK_RESOURCE ResourceEntry
  642. )
  643. {
  644. return ResourceEntry->MountieInfo.DriveLetters;
  645. }
  646. DWORD
  647. MountieRecreateVolumeInfoFromHandle(
  648. IN HANDLE FileHandle,
  649. IN DWORD HarddiskNo,
  650. IN HANDLE ResourceHandle,
  651. IN OUT PMOUNTIE_INFO Info
  652. )
  653. /*++
  654. Routine Description:
  655. Recreate a MountieInfo that has no
  656. DriveLetter assignments.
  657. IMPORTANT!!! The code assumes that Info->Volume
  658. either contains a valid pointer or NULL
  659. Inputs:
  660. ResourceHandle - may be NULL.
  661. Outputs:
  662. Info - MountieInfo
  663. --*/
  664. {
  665. PDRIVE_LAYOUT_INFORMATION layout;
  666. DWORD status;
  667. DWORD bytesReturned;
  668. free( Info->Volume ); // free(0) is OK //
  669. Info->HarddiskNo = HarddiskNo;
  670. Info->DriveLetters = 0;
  671. Info->Volume = 0;
  672. Info->VolumeStructSize = 0;
  673. //
  674. // Tell storage drivers to refresh their cached partition information.
  675. // Ignore the returned status. This IOCTL can only go to the physical
  676. // disk (partition0), not any of the partitions.
  677. //
  678. DeviceIoControl( FileHandle,
  679. IOCTL_DISK_UPDATE_PROPERTIES,
  680. NULL,
  681. 0,
  682. NULL,
  683. 0,
  684. &bytesReturned,
  685. NULL );
  686. layout = DoIoctlAndAllocate(
  687. FileHandle, IOCTL_DISK_GET_DRIVE_LAYOUT, 0,0, &bytesReturned);
  688. if (!layout) {
  689. return GetLastError();
  690. }
  691. status = ERROR_SUCCESS;
  692. try {
  693. Info->Volume = CreateMountieVolumeFromDriveLayoutInfo( layout , ResourceHandle );
  694. if (!Info->Volume) {
  695. status = GetLastError();
  696. leave;
  697. }
  698. Info->VolumeStructSize = sizeof(MOUNTIE_VOLUME) +
  699. sizeof(MOUNTIE_PARTITION) * (Info->Volume->PartitionCount - 1);
  700. } finally {
  701. free( layout );
  702. }
  703. if ( ResourceHandle ) MountiePrint(Info, ResourceHandle);
  704. return status;
  705. }
  706. DWORD
  707. MountieFindPartitionsForDisk(
  708. IN DWORD HarddiskNo,
  709. OUT PMOUNTIE_INFO MountieInfo
  710. )
  711. /*++
  712. Note that Caller of this routine is responsible for freeing Volume Information
  713. via call to MountieCleanup().
  714. --*/
  715. {
  716. WCHAR deviceName[MAX_PATH];
  717. HANDLE fileHandle;
  718. DWORD status;
  719. if ( FAILED( StringCchPrintf( deviceName,
  720. RTL_NUMBER_OF( deviceName ),
  721. TEXT("\\\\.\\PhysicalDrive%u"),
  722. HarddiskNo ) ) ) {
  723. return ERROR_INSUFFICIENT_BUFFER;
  724. }
  725. fileHandle = CreateFile( deviceName,
  726. GENERIC_READ | GENERIC_WRITE,
  727. FILE_SHARE_READ | FILE_SHARE_WRITE,
  728. NULL,
  729. OPEN_EXISTING,
  730. 0,
  731. NULL );
  732. if ( (fileHandle == NULL) ||
  733. (fileHandle == INVALID_HANDLE_VALUE) ) {
  734. status = GetLastError();
  735. return status;
  736. }
  737. RtlZeroMemory( MountieInfo, sizeof(MOUNTIE_INFO) );
  738. status = MountieRecreateVolumeInfoFromHandle(
  739. fileHandle,
  740. HarddiskNo,
  741. NULL,
  742. MountieInfo );
  743. if ( status != ERROR_SUCCESS ) {
  744. CloseHandle( fileHandle );
  745. return status;
  746. }
  747. CloseHandle( fileHandle );
  748. return(ERROR_SUCCESS);
  749. } // MountieFindPartitionsForDisk
  750. VOID
  751. MountieCleanup(
  752. IN OUT PMOUNTIE_INFO Info
  753. )
  754. /*++
  755. Routine Description:
  756. Deallocates Volume information
  757. Inputs:
  758. Info - MountieInfo
  759. --*/
  760. {
  761. PVOID volume;
  762. Info->VolumeStructSize = 0;
  763. volume = InterlockedExchangePointer(&(Info->Volume), 0);
  764. free(volume);
  765. }
  766. ////////////////////////////////////////////////////////////////////////////////////////
  767. ////////////////////////////////////////////////////////////////////////////////////////
  768. ////////////////////////////////////////////////////////////////////////////////////////
  769. ////////////////////////////////////////////////////////////////////////////////////////
  770. //
  771. // Disk information is specified in different formats in various places
  772. //
  773. // The following code is an attempt to provide some common denominator
  774. // to simplify verification of all disk information and keeping it in sync.
  775. //
  776. UCHAR
  777. AssignedLetterByPartitionNumber (
  778. PLETTER_ASSIGNMENT Assignment,
  779. DWORD PartitionNo)
  780. /*++
  781. Routine Description:
  782. Returns a drive letter assigned to a partition
  783. Inputs:
  784. Assignment - drive letter assignment info
  785. PartitionNo - partition number (As in Harddisk0\PartitionX)
  786. --*/
  787. {
  788. UCHAR i;
  789. for( i = 0; i < 26; ++i ) {
  790. if (Assignment->PartNumber[i] == PartitionNo) {
  791. return ('A' + i);
  792. }
  793. }
  794. return 0;
  795. }
  796. // For every different way to describe a disk information
  797. // there should be two functions defined GetInfo and SetInfo
  798. // which will read/write the information into/from LETTER_ASSIGNMENT structure
  799. typedef DWORD (*GetInfoFunc) (PMOUNTIE_INFO, PDISK_RESOURCE ResourceEntry, PLETTER_ASSIGNMENT Result);
  800. typedef DWORD (*SetInfoFunc) (PMOUNTIE_INFO, PDISK_RESOURCE ResourceEntry);
  801. //
  802. // The following structure is a description of disk information provider.
  803. //
  804. // It is used to bind a provider name (Used as a label in error logging)
  805. // and information access routines
  806. //
  807. typedef struct _INFO_PROVIDER {
  808. PWCHAR Name;
  809. GetInfoFunc GetInfo;
  810. SetInfoFunc SetInfo;
  811. } INFO_PROVIDER, *PINFO_PROVIDER;
  812. ////////////////////////////////////////////////////////////////////
  813. //
  814. // The following routine gets FtInfo, by reading existing one or
  815. // creating an empty one if there is no System\DISK in the registry)
  816. //
  817. // Then it adds/updates drive letter assignment for the specified drive,
  818. // using the information supplied in MOUNTIE_INFO structure.
  819. //
  820. PFT_INFO
  821. FtInfo_CreateFromMountie(
  822. PMOUNTIE_INFO Info,
  823. PDISK_RESOURCE ResourceEntry)
  824. {
  825. PFT_INFO ftInfo = 0;
  826. DWORD i, n;
  827. DWORD Status = ERROR_SUCCESS;
  828. PMOUNTIE_PARTITION entry;
  829. try {
  830. ftInfo = DiskGetFtInfo();
  831. if ( !ftInfo ) {
  832. (DiskpLogEvent)(ResourceEntry->ResourceHandle,
  833. LOG_ERROR,
  834. L"Failed to get FtInfo.\n");
  835. Status = ERROR_NOT_ENOUGH_MEMORY;
  836. ftInfo = 0;
  837. leave;
  838. }
  839. Status = DiskAddDiskInfoEx( ftInfo,
  840. ResourceEntry->DiskInfo.PhysicalDrive,
  841. ResourceEntry->DiskInfo.Params.Signature,
  842. DISKRTL_REPLACE_IF_EXISTS );
  843. if ( Status != ERROR_SUCCESS ) {
  844. (DiskpLogEvent)(ResourceEntry->ResourceHandle,
  845. LOG_ERROR,
  846. L"Error %1!d! adding DiskInfo.\n",
  847. Status);
  848. ftInfo = 0;
  849. leave;
  850. }
  851. n = Info->Volume->PartitionCount;
  852. entry = Info->Volume->Partition;
  853. //
  854. // Now add the partition info for each partition
  855. //
  856. for ( i = 0; i < n; ++i,++entry ) {
  857. Status = DiskAddDriveLetterEx( ftInfo,
  858. ResourceEntry->DiskInfo.Params.Signature,
  859. entry->StartingOffset,
  860. entry->PartitionLength,
  861. entry->DriveLetter, 0);
  862. if ( Status != ERROR_SUCCESS ) {
  863. (DiskpLogEvent)(ResourceEntry->ResourceHandle,
  864. LOG_ERROR,
  865. L"Error %1!d! adding partition %2!x!:%3!x! letter %4!X! sig %5!x!.\n",
  866. Status, entry->StartingOffset.LowPart,
  867. entry->PartitionLength.LowPart,
  868. entry->DriveLetter,
  869. Info->Volume->Signature);
  870. break;
  871. }
  872. }
  873. } finally {
  874. if (Status != ERROR_SUCCESS) {
  875. SetLastError(Status);
  876. if (ftInfo) {
  877. DiskFreeFtInfo(ftInfo);
  878. ftInfo = 0;
  879. }
  880. }
  881. }
  882. return ftInfo;
  883. }
  884. DWORD FtInfo_GetFromFtInfo(
  885. IN PMOUNTIE_INFO Info,
  886. IN PDISK_RESOURCE ResourceEntry,
  887. IN PFT_INFO FtInfo,
  888. IN OUT PLETTER_ASSIGNMENT Result)
  889. {
  890. DWORD i, n;
  891. PFT_DISK_INFO FtDisk;
  892. FtDisk = FtInfo_GetFtDiskInfoBySignature(
  893. FtInfo, ResourceEntry->DiskInfo.Params.Signature);
  894. if ( !FtDisk ) {
  895. (DiskpLogEvent)(
  896. ResourceEntry->ResourceHandle,
  897. LOG_WARNING,
  898. L"FtInfo_GetFromFtInfo: GetFtDiskInfoBySignature failed.\n");
  899. ++Result->MismatchCount;
  900. return ERROR_NOT_FOUND;
  901. }
  902. n = FtDiskInfo_GetPartitionCount(FtDisk);
  903. if (n == 0) {
  904. (DiskpLogEvent)(
  905. ResourceEntry->ResourceHandle,
  906. LOG_WARNING,
  907. L"FtInfo_GetFromFtInfo: DiskInfo has no partitions.\n");
  908. ++Result->MismatchCount;
  909. return ERROR_NOT_FOUND;
  910. }
  911. // sanity check //
  912. // number 10 is completely arbitrary //
  913. if (n > Info->Volume->PartitionCount * 10) {
  914. (DiskpLogEvent)(
  915. ResourceEntry->ResourceHandle,
  916. LOG_ERROR,
  917. L"FtInfo_GetFromFtInfo: DiskInfo has %1!u! partitions!\n", n);
  918. n = Info->Volume->PartitionCount * 10;
  919. }
  920. for(i = 0; i < n; ++i) {
  921. DISK_PARTITION UNALIGNED *entry;
  922. PMOUNTIE_PARTITION mountie;
  923. entry = FtDiskInfo_GetPartitionInfoByIndex(FtDisk, i);
  924. if (entry == NULL) {
  925. ++Result->MismatchCount;
  926. (DiskpLogEvent)(
  927. ResourceEntry->ResourceHandle,
  928. LOG_WARNING,
  929. L"FtDiskInfo_GetPartitionInfoByIndex(%1!d!) return NULL\n",
  930. i );
  931. continue;
  932. }
  933. mountie = MountiePartitionByOffsetAndLength(
  934. Info,
  935. entry->StartingOffset,
  936. entry->Length);
  937. if (mountie) {
  938. UCHAR ch = (UCHAR)toupper( entry->DriveLetter );
  939. // Match count no longer requires a drive letter.
  940. ++Result->MatchCount;
  941. if ( isalpha(ch) ) {
  942. ch -= 'A';
  943. Result->DriveLetters |= ( 1 << ch );
  944. Result->PartNumber[ch] = (PARTITION_NUMBER_TYPE) mountie->PartitionNumber;
  945. }
  946. } else {
  947. //
  948. // Chittur Subbaraman (chitturs) - 11/5/98
  949. //
  950. // Added the following 4 statements for event logging in MountieVerify
  951. //
  952. UCHAR uch = (UCHAR)toupper( entry->DriveLetter );
  953. if ( isalpha(uch) ) {
  954. uch -= 'A';
  955. Result->DriveLetters |= ( 1 << uch );
  956. }
  957. ++Result->MismatchCount;
  958. (DiskpLogEvent)(
  959. ResourceEntry->ResourceHandle,
  960. LOG_WARNING,
  961. L"Strange partition: %1!X!, %2!X!, Type=%3!u!, letter=%4!c!.\n",
  962. entry->StartingOffset.LowPart, entry->Length.LowPart,
  963. entry->FtType, NICE_DRIVE_LETTER(entry->DriveLetter) );
  964. }
  965. }
  966. return ERROR_SUCCESS;
  967. }
  968. /////////////////////////////////////////////////////////////////
  969. //
  970. // NT4 style System\DISK and ClusReg\DiskInfo
  971. // accessing routines
  972. //
  973. // ClusDiskInfo_Get
  974. // ClusDiskInfo_Set
  975. // FtInfo_Get
  976. // FtInfo_Set
  977. //
  978. DWORD
  979. CluDiskInfo_Get(
  980. PMOUNTIE_INFO Info,
  981. PDISK_RESOURCE ResourceEntry,
  982. PLETTER_ASSIGNMENT Result)
  983. /*++
  984. Routine Description:
  985. This routine does nothing now that we are no longer using the
  986. Cluster DiskInfo key.
  987. --*/
  988. {
  989. #if USE_CLUSTERDB_DISKINFO
  990. DWORD Length;
  991. DWORD Status;
  992. DWORD errorLevel;
  993. PFULL_DISK_INFO DiskInfo = 0;
  994. try {
  995. //
  996. // Read out the diskinfo parameter from our resource.
  997. //
  998. Status = ClusterRegQueryValue(ResourceEntry->ResourceParametersKey,
  999. DISKS_DISK_INFO,
  1000. NULL,
  1001. NULL,
  1002. &Length);
  1003. if (Status == ERROR_SUCCESS ) {
  1004. DiskInfo = malloc(Length);
  1005. if (!DiskInfo) {
  1006. Status = ERROR_OUTOFMEMORY;
  1007. } else {
  1008. Status = ClusterRegQueryValue(ResourceEntry->ResourceParametersKey,
  1009. DISKS_DISK_INFO,
  1010. NULL,
  1011. (LPBYTE)DiskInfo,
  1012. &Length);
  1013. if (Status == ERROR_SUCCESS) {
  1014. PFT_INFO ftInfo = DiskGetFtInfoFromFullDiskinfo(DiskInfo);
  1015. if (ftInfo) {
  1016. Status = FtInfo_GetFromFtInfo(Info,
  1017. ResourceEntry,
  1018. ftInfo,
  1019. Result);
  1020. DiskFreeFtInfo(ftInfo);
  1021. } else {
  1022. Status = GetLastError();
  1023. }
  1024. }
  1025. }
  1026. }
  1027. } finally {
  1028. if (Status != ERROR_SUCCESS) {
  1029. if ( !DisksGetLettersForSignature( ResourceEntry ) ) {
  1030. // No drive letters, we are using mount points and this is not an error.
  1031. errorLevel = LOG_WARNING;
  1032. } else {
  1033. // Drive letters exist, this is likely an error.
  1034. errorLevel = LOG_ERROR;
  1035. }
  1036. (DiskpLogEvent)(
  1037. ResourceEntry->ResourceHandle,
  1038. errorLevel,
  1039. L"CluDiskInfo_Get: Status=%1!u!.\n", Status);
  1040. ++Result->MismatchCount;
  1041. }
  1042. free(DiskInfo);
  1043. }
  1044. #endif
  1045. return ERROR_SUCCESS;
  1046. }
  1047. DWORD
  1048. FtInfo_Get(
  1049. PMOUNTIE_INFO Info,
  1050. PDISK_RESOURCE ResourceEntry,
  1051. PLETTER_ASSIGNMENT Result)
  1052. {
  1053. PFT_INFO FtInfo;
  1054. DWORD Status;
  1055. //
  1056. // Get registry info.
  1057. //
  1058. FtInfo = DiskGetFtInfo();
  1059. if ( !FtInfo ) {
  1060. return ERROR_OUTOFMEMORY;
  1061. }
  1062. Status = FtInfo_GetFromFtInfo(Info, ResourceEntry, FtInfo, Result);
  1063. DiskFreeFtInfo(FtInfo);
  1064. if (Status != ERROR_SUCCESS) {
  1065. ++Result->MismatchCount;
  1066. }
  1067. return ERROR_SUCCESS;
  1068. }
  1069. DWORD
  1070. FtInfo_Set(
  1071. PMOUNTIE_INFO Info,
  1072. PDISK_RESOURCE ResourceEntry)
  1073. {
  1074. PFT_INFO ftInfo = FtInfo_CreateFromMountie(Info, ResourceEntry);
  1075. if (ftInfo) {
  1076. DWORD status = DiskCommitFtInfo(ftInfo);
  1077. if (status != ERROR_SUCCESS) {
  1078. (DiskpLogEvent)(
  1079. ResourceEntry->ResourceHandle,
  1080. LOG_ERROR,
  1081. L"FtInfo_Set: CommitFtInfo status = %1!u!.\n", status);
  1082. } else {
  1083. (DiskpLogEvent)(
  1084. ResourceEntry->ResourceHandle,
  1085. LOG_INFORMATION,
  1086. L"FtInfo_Set: Update successful.\n");
  1087. }
  1088. DiskFreeFtInfo(ftInfo);
  1089. return status;
  1090. } else {
  1091. DWORD status = GetLastError();
  1092. (DiskpLogEvent)(
  1093. ResourceEntry->ResourceHandle,
  1094. LOG_ERROR,
  1095. L"FtInfoSet: CreateFromMountie failed, status = %1!u!.\n", status);
  1096. return status;
  1097. }
  1098. }
  1099. DWORD
  1100. CluDiskInfo_Set(
  1101. PMOUNTIE_INFO Info,
  1102. PDISK_RESOURCE ResourceEntry)
  1103. /*++
  1104. Routine Description:
  1105. Delete the Cluster DiskInfo key. If this is the quorum disk online
  1106. thread, we may have to create another thread to actually delete the
  1107. value from the cluster DB.
  1108. --*/
  1109. {
  1110. #if USE_CLUSTERDB_DISKINFO
  1111. PFT_INFO ftInfo = FtInfo_CreateFromMountie(Info, ResourceEntry);
  1112. if (ftInfo) {
  1113. PFULL_DISK_INFO DiskInfo;
  1114. DWORD Length;
  1115. DWORD Status;
  1116. DiskInfo = DiskGetFullDiskInfo( ftInfo,
  1117. ResourceEntry->DiskInfo.Params.Signature,
  1118. &Length );
  1119. if ( DiskInfo ) {
  1120. Status = ClusterRegSetValue(ResourceEntry->ResourceParametersKey,
  1121. DISKS_DISK_INFO,
  1122. REG_BINARY,
  1123. (CONST BYTE *)DiskInfo,
  1124. Length);
  1125. if (Status != ERROR_SUCCESS && Status != ERROR_SHARING_PAUSED) {
  1126. (DiskpLogEvent)(
  1127. ResourceEntry->ResourceHandle,
  1128. LOG_ERROR,
  1129. L"CluDiskInfo_Set: Data Length = %1!u!.\n", Length);
  1130. }
  1131. LocalFree( DiskInfo );
  1132. } else {
  1133. (DiskpLogEvent)(
  1134. ResourceEntry->ResourceHandle,
  1135. LOG_ERROR,
  1136. L"CluDiskInfo_Set: Disk with signature %1!x! is not found. Error=%2!u!\n", ResourceEntry->DiskInfo.Params.Signature, GetLastError());
  1137. Status = ERROR_FILE_NOT_FOUND;
  1138. }
  1139. DiskFreeFtInfo(ftInfo);
  1140. return Status;
  1141. } else {
  1142. (DiskpLogEvent)(
  1143. ResourceEntry->ResourceHandle,
  1144. LOG_ERROR,
  1145. L"CluDiskInfo_Set: Failed to create FtInfo.\n");
  1146. return GetLastError();
  1147. }
  1148. #else
  1149. HANDLE thread;
  1150. DWORD threadId;
  1151. DWORD dwError;
  1152. DWORD length;
  1153. //
  1154. // Try opening the key first. If it doesn't exist, we don't need to
  1155. // delete it.
  1156. //
  1157. dwError = ClusterRegQueryValue( ResourceEntry->ResourceParametersKey,
  1158. DISKS_DISK_INFO,
  1159. NULL,
  1160. NULL,
  1161. &length );
  1162. if ( ERROR_FILE_NOT_FOUND == dwError ||
  1163. ( ERROR_SUCCESS == dwError && 0 == length ) ) {
  1164. goto FnExit;
  1165. }
  1166. dwError = ClusterRegDeleteValue( ResourceEntry->ResourceParametersKey,
  1167. DISKS_DISK_INFO );
  1168. //
  1169. // If we successfully deleted the value or if the value is already
  1170. // deleted, we are done.
  1171. //
  1172. if ( ERROR_SUCCESS == dwError || ERROR_FILE_NOT_FOUND == dwError ) {
  1173. goto FnExit;
  1174. }
  1175. if ( ERROR_SHARING_PAUSED != dwError ) {
  1176. (DiskpLogEvent)( ResourceEntry->ResourceHandle,
  1177. LOG_WARNING,
  1178. L"CluDiskInfo_Set: Delete registry value failed, %1!u!.\n", dwError );
  1179. goto FnExit;
  1180. }
  1181. //
  1182. // Quorum disk will return error until online completes.
  1183. //
  1184. //
  1185. // Check if the thread is already active. If it is, don't do anything.
  1186. //
  1187. if ( InterlockedCompareExchange( &DiskInfoUpdateThreadIsActive,
  1188. 1,
  1189. 0 ) ) {
  1190. (DiskpLogEvent)( ResourceEntry->ResourceHandle,
  1191. LOG_WARNING,
  1192. L"CluDiskInfo_Set: DiskInfo update thread is already running \n" );
  1193. goto FnExit;
  1194. }
  1195. thread = CreateThread( NULL,
  1196. 0,
  1197. SetDiskInfoThread,
  1198. ResourceEntry,
  1199. 0,
  1200. &threadId );
  1201. if ( NULL == thread ) {
  1202. //
  1203. // Thread creation failed. Log error, clear thread active flag,
  1204. // and return.
  1205. //
  1206. dwError = GetLastError();
  1207. (DiskpLogEvent)(
  1208. ResourceEntry->ResourceHandle,
  1209. LOG_ERROR,
  1210. L"CluDiskInfo_Set: CreateThread failed, error %1!u!\n",
  1211. dwError );
  1212. InterlockedExchange( &DiskInfoUpdateThreadIsActive, 0 );
  1213. goto FnExit;
  1214. }
  1215. (DiskpLogEvent)(
  1216. ResourceEntry->ResourceHandle,
  1217. LOG_INFORMATION,
  1218. L"CluDiskInfo_Set: Thread created \n" );
  1219. //
  1220. // Thread created. Close the handle and return.
  1221. //
  1222. CloseHandle( thread );
  1223. FnExit:
  1224. return ERROR_SUCCESS;
  1225. #endif
  1226. }
  1227. ////////////////////////////////////////////////////////
  1228. //
  1229. // New NT5 clusreg volume information access routines
  1230. //
  1231. // Mountie_Get
  1232. // Mountie_Set
  1233. //
  1234. //////////
  1235. DWORD
  1236. Mountie_Get(
  1237. PMOUNTIE_INFO Info,
  1238. PDISK_RESOURCE ResourceEntry,
  1239. PLETTER_ASSIGNMENT Result)
  1240. {
  1241. DWORD Length = 0; // Prefix bug 56153: initialize variable.
  1242. DWORD Status;
  1243. PMOUNTIE_VOLUME Volume = NULL;
  1244. DWORD i, n;
  1245. PMOUNTIE_PARTITION entry;
  1246. try {
  1247. //
  1248. // Read out the diskinfo parameter from our resource.
  1249. //
  1250. Status = ClusterRegQueryValue(ResourceEntry->ResourceParametersKey,
  1251. MOUNTIE_VOLUME_INFO,
  1252. NULL,
  1253. NULL,
  1254. &Length);
  1255. if (Status == ERROR_FILE_NOT_FOUND ) {
  1256. ++Result->MismatchCount;
  1257. Status = ERROR_SUCCESS;
  1258. leave;
  1259. }
  1260. //
  1261. // Prefix bug 56153: Make sure the length is valid before allocating
  1262. // memory.
  1263. //
  1264. if ( !Length ) {
  1265. Status = ERROR_BAD_LENGTH;
  1266. leave;
  1267. }
  1268. Volume = malloc(Length);
  1269. if (!Volume) {
  1270. Status = ERROR_OUTOFMEMORY;
  1271. leave;
  1272. }
  1273. Status = ClusterRegQueryValue(ResourceEntry->ResourceParametersKey,
  1274. MOUNTIE_VOLUME_INFO,
  1275. NULL,
  1276. (LPBYTE)Volume,
  1277. &Length);
  1278. if (Status != ERROR_SUCCESS) {
  1279. leave;
  1280. }
  1281. if (Length < sizeof(MOUNTIE_VOLUME) ) {
  1282. ++Result->MismatchCount;
  1283. (DiskpLogEvent)(
  1284. ResourceEntry->ResourceHandle,
  1285. LOG_ERROR,
  1286. L"Get: MountVolumeInfo key is truncated. Cannot read header, length %1!d!.\n", Length);
  1287. Status = ERROR_SUCCESS;
  1288. leave;
  1289. }
  1290. n = Volume->PartitionCount;
  1291. entry = Volume->Partition;
  1292. if (n == 0) {
  1293. ++Result->MismatchCount;
  1294. (DiskpLogEvent)(
  1295. ResourceEntry->ResourceHandle,
  1296. LOG_ERROR,
  1297. L"Get: MountVolumeInfo key is corrupted. No partitions.\n");
  1298. Status = ERROR_SUCCESS;
  1299. leave;
  1300. }
  1301. if ( Length < (sizeof(MOUNTIE_VOLUME) + (n-1) * sizeof(MOUNTIE_PARTITION)) ) {
  1302. DWORD delta = sizeof(MOUNTIE_VOLUME) + (n-1) * sizeof(MOUNTIE_PARTITION) - Length;
  1303. (DiskpLogEvent)(
  1304. ResourceEntry->ResourceHandle,
  1305. LOG_ERROR,
  1306. L"Get: MountVolumeInfo key is corrupted. "
  1307. L"Length %1!d!, PartitionCount %2!d!, delta %3!d!.\n", Length, n, delta);
  1308. ++Result->MismatchCount;
  1309. Status = ERROR_SUCCESS;
  1310. leave;
  1311. }
  1312. for (i = 0; i < n; ++i, ++entry) {
  1313. PMOUNTIE_PARTITION mountie;
  1314. mountie = MountiePartitionByOffsetAndLength(
  1315. Info,
  1316. entry->StartingOffset,
  1317. entry->PartitionLength);
  1318. if (mountie) {
  1319. UCHAR ch = (UCHAR)toupper( entry->DriveLetter );
  1320. // Match count no longer requires a drive letter.
  1321. ++Result->MatchCount;
  1322. if ( isalpha(ch) ) {
  1323. ch -= 'A';
  1324. Result->DriveLetters |= ( 1 << ch );
  1325. Result->PartNumber[ch] = (PARTITION_NUMBER_TYPE) mountie->PartitionNumber;
  1326. }
  1327. } else {
  1328. ++Result->MismatchCount;
  1329. }
  1330. }
  1331. } finally {
  1332. if (Status != ERROR_SUCCESS) {
  1333. ++Result->MismatchCount;
  1334. }
  1335. free(Volume);
  1336. }
  1337. return ERROR_SUCCESS;
  1338. }
  1339. DWORD
  1340. Mountie_Set(
  1341. PMOUNTIE_INFO Info,
  1342. PDISK_RESOURCE ResourceEntry)
  1343. {
  1344. DWORD Status = ClusterRegSetValue(ResourceEntry->ResourceParametersKey,
  1345. MOUNTIE_VOLUME_INFO,
  1346. REG_BINARY,
  1347. (LPBYTE)Info->Volume,
  1348. Info->VolumeStructSize);
  1349. return Status;
  1350. }
  1351. ///////////////////////////////////////////////////////////
  1352. //
  1353. // NT5 MountManager's volume information access routines
  1354. //
  1355. // MountMgr_Get
  1356. // MountMgr_Set
  1357. //
  1358. //////////
  1359. DWORD
  1360. MountMgr_Get(
  1361. PMOUNTIE_INFO Info,
  1362. PDISK_RESOURCE ResourceEntry,
  1363. PLETTER_ASSIGNMENT Result)
  1364. {
  1365. DWORD PartitionCount = Info->Volume->PartitionCount;
  1366. DWORD i;
  1367. DWORD error;
  1368. NTSTATUS ntStatus;
  1369. HANDLE MountManager;
  1370. ntStatus = DevfileOpen(&MountManager, MOUNTMGR_DEVICE_NAME);
  1371. if (!NT_SUCCESS(ntStatus)) {
  1372. if ( ResourceEntry ) {
  1373. (DiskpLogEvent)(
  1374. ResourceEntry->ResourceHandle,
  1375. LOG_ERROR,
  1376. L"Get: MountMgr open failed, status %1!X!.\n", ntStatus);
  1377. }
  1378. return RtlNtStatusToDosError(ntStatus);
  1379. }
  1380. error = ERROR_SUCCESS;
  1381. try {
  1382. for (i = 0; i < PartitionCount; ++i) {
  1383. PMOUNTIE_PARTITION entry = Info->Volume->Partition + i;
  1384. WCHAR DeviceName[MAX_PATH];
  1385. UCHAR ch;
  1386. (VOID) StringCchPrintf( DeviceName,
  1387. RTL_NUMBER_OF( DeviceName ),
  1388. DEVICE_HARDDISK_PARTITION_FMT,
  1389. Info->HarddiskNo,
  1390. entry->PartitionNumber );
  1391. ntStatus = GetAssignedLetterM(MountManager, DeviceName, &ch);
  1392. if ( NT_SUCCESS(ntStatus) ) {
  1393. if ( Result ) {
  1394. // Match count no longer requres a drive letter.
  1395. ++Result->MatchCount;
  1396. }
  1397. if (Result && ch) {
  1398. ch -= 'A';
  1399. Result->DriveLetters |= ( 1 << ch );
  1400. Result->PartNumber[ch] = (PARTITION_NUMBER_TYPE) entry->PartitionNumber;
  1401. }
  1402. } else {
  1403. if ( ResourceEntry ) {
  1404. (DiskpLogEvent)(
  1405. ResourceEntry->ResourceHandle,
  1406. LOG_ERROR,
  1407. L"Get Assigned Letter for %1!ws! returned status %2!X!.\n", DeviceName, ntStatus);
  1408. }
  1409. error = RtlNtStatusToDosError(ntStatus);
  1410. leave;
  1411. }
  1412. }
  1413. } finally {
  1414. DevfileClose(MountManager);
  1415. }
  1416. return error;
  1417. }
  1418. DWORD
  1419. MountMgr_Set(
  1420. PMOUNTIE_INFO Info,
  1421. PDISK_RESOURCE ResourceEntry
  1422. )
  1423. {
  1424. HANDLE MountManager;
  1425. DWORD PartitionCount = Info->Volume->PartitionCount;
  1426. DWORD i, status;
  1427. UCHAR dosName[3];
  1428. NTSTATUS ntStatus;
  1429. (DiskpLogEvent)(
  1430. ResourceEntry->ResourceHandle,
  1431. LOG_INFORMATION,
  1432. L"MountMgr_Set: Entry\n");
  1433. ntStatus = DevfileOpen(&MountManager, MOUNTMGR_DEVICE_NAME);
  1434. if (!NT_SUCCESS(ntStatus)) {
  1435. (DiskpLogEvent)(
  1436. ResourceEntry->ResourceHandle,
  1437. LOG_ERROR,
  1438. L"Set: MountMgr open failed, status %1!X!.\n", ntStatus);
  1439. return RtlNtStatusToDosError(ntStatus);
  1440. }
  1441. try {
  1442. dosName[1] = ':';
  1443. dosName[2] = '\0';
  1444. //
  1445. // Remove old assignment of letters we are going to use
  1446. //
  1447. for (i = 0; i < 26; ++i) {
  1448. if ( (1 << i) & Info->DriveLetters ) {
  1449. dosName[0] = (UCHAR)('A' + i);
  1450. status = DisksRemoveDosDeviceM(MountManager, dosName);
  1451. (DiskpLogEvent)(
  1452. ResourceEntry->ResourceHandle,
  1453. LOG_INFORMATION,
  1454. L"MountMgr_Set: Remove Dos Device, letter=%1!c!, status=%2!u!\n",
  1455. NICE_DRIVE_LETTER(dosName[0]), status);
  1456. }
  1457. }
  1458. for (i = 0; i < PartitionCount; ++i) {
  1459. PMOUNTIE_PARTITION entry = Info->Volume->Partition + i;
  1460. WCHAR DeviceName[MAX_PATH];
  1461. UCHAR ch;
  1462. (VOID) StringCchPrintf( DeviceName,
  1463. RTL_NUMBER_OF( DeviceName ),
  1464. DEVICE_HARDDISK_PARTITION_FMT,
  1465. Info->HarddiskNo,
  1466. entry->PartitionNumber );
  1467. ntStatus = GetAssignedLetterM(MountManager, DeviceName, &ch);
  1468. if ( NT_SUCCESS(ntStatus) && ch) {
  1469. dosName[0] = ch;
  1470. status = DisksRemoveDosDeviceM(MountManager, dosName);
  1471. (DiskpLogEvent)(
  1472. ResourceEntry->ResourceHandle,
  1473. LOG_INFORMATION,
  1474. L"MountMgr_Set: Remove Dos Device 2, letter=%1!c!, status=%2!u!\n",
  1475. NICE_DRIVE_LETTER(dosName[0]), status);
  1476. }
  1477. if (entry->DriveLetter) {
  1478. dosName[0] = entry->DriveLetter;
  1479. status = DisksAssignDosDeviceM(MountManager, dosName, DeviceName);
  1480. (DiskpLogEvent)(
  1481. ResourceEntry->ResourceHandle,
  1482. LOG_INFORMATION,
  1483. L"MountMgr_Set: Assign Dos Device, letter=%1!c!, status=%2!u!\n",
  1484. NICE_DRIVE_LETTER(dosName[0]), status);
  1485. }
  1486. }
  1487. } finally {
  1488. DevfileClose( MountManager );
  1489. }
  1490. return ERROR_SUCCESS;
  1491. }
  1492. /////////////////////////////////////////////////////////////////////////
  1493. //
  1494. // information providers table
  1495. //
  1496. // Disk\Information has to be the last entry of the table
  1497. //
  1498. // Order of the entries is important
  1499. //
  1500. /////////////////////////////////////////////////////////////////
  1501. INFO_PROVIDER Providers[] = {
  1502. {L"ClusReg-DiskInfo", CluDiskInfo_Get, CluDiskInfo_Set},
  1503. {L"ClusReg-Mountie", Mountie_Get, Mountie_Set},
  1504. {L"MountMgr", MountMgr_Get, MountMgr_Set},
  1505. {L"Registry-System\\DISK", FtInfo_Get, FtInfo_Set}, // Disk\Information must be the last (Why?)
  1506. };
  1507. enum {
  1508. PROVIDER_COUNT = sizeof(Providers)/sizeof(Providers[0]),
  1509. MOUNT_MANAGER = PROVIDER_COUNT - 2,
  1510. };
  1511. DWORD
  1512. MountieUpdate(
  1513. PMOUNTIE_INFO info,
  1514. PDISK_RESOURCE ResourceEntry)
  1515. /*++
  1516. Routine Description:
  1517. Update disk information for all providers
  1518. marked in NeedsUpdate bitmask
  1519. Inputs:
  1520. Info - MountieInfo
  1521. --*/
  1522. {
  1523. DWORD NeedsUpdate = info->NeedsUpdate;
  1524. BOOLEAN SharingPausedError = FALSE;
  1525. DWORD LastError = ERROR_SUCCESS;
  1526. INT i;
  1527. if (!NeedsUpdate) {
  1528. return ERROR_SUCCESS;
  1529. }
  1530. for (i = 0; i < PROVIDER_COUNT; ++i) {
  1531. if ( (1 << i) & NeedsUpdate ) {
  1532. DWORD status;
  1533. status = Providers[i].SetInfo(info, ResourceEntry);
  1534. if (status != ERROR_SUCCESS) {
  1535. (DiskpLogEvent)(
  1536. ResourceEntry->ResourceHandle,
  1537. LOG_INFORMATION,
  1538. L"MountieUpdate: %1!ws!.SetInfo failed, error %2!u!.\n", Providers[i].Name, status);
  1539. if (status == ERROR_SHARING_PAUSED) {
  1540. SharingPausedError = TRUE;
  1541. } else {
  1542. LastError = status;
  1543. }
  1544. } else {
  1545. NeedsUpdate &= ~(1 << i);
  1546. }
  1547. }
  1548. }
  1549. (DiskpLogEvent)(
  1550. ResourceEntry->ResourceHandle,
  1551. LOG_INFORMATION,
  1552. L"MountieUpdate: Update needed for %1!02x!.\n", NeedsUpdate);
  1553. info->NeedsUpdate = NeedsUpdate;
  1554. if (NeedsUpdate) {
  1555. if (SharingPausedError) {
  1556. return ERROR_SHARING_PAUSED;
  1557. }
  1558. return LastError;
  1559. }
  1560. return ERROR_SUCCESS;
  1561. }
  1562. DWORD
  1563. MountieVerify(
  1564. PMOUNTIE_INFO info,
  1565. PDISK_RESOURCE ResourceEntry,
  1566. BOOL UseMountMgr
  1567. )
  1568. /*++
  1569. Routine Description:
  1570. 1. Compares information from all
  1571. providers and select one of them as source of
  1572. drive letter assignment.
  1573. 2. Update MountieInfo with this drive letter assignment
  1574. 3. Set NeedsUpdate for every provider whose information
  1575. differ from the MountieInfo
  1576. Inputs:
  1577. Info - MountieInfo
  1578. --*/
  1579. {
  1580. LETTER_ASSIGNMENT results[PROVIDER_COUNT + 1];
  1581. INT i;
  1582. INT GoodProvider = -1;
  1583. INT BestProvider = -1;
  1584. DWORD BestMatch = 0;
  1585. INT PartitionCount;
  1586. BOOLEAN UnassignedPartitions = FALSE;
  1587. DWORD NeedsUpdate = 0;
  1588. DWORD errorLevel;
  1589. if (!info->Volume || info->Volume->PartitionCount == 0) {
  1590. (DiskpLogEvent)(
  1591. ResourceEntry->ResourceHandle,
  1592. LOG_ERROR,
  1593. L"FatalError: Bad Mountie Info.\n");
  1594. return ERROR_INVALID_HANDLE;
  1595. }
  1596. PartitionCount = info->Volume->PartitionCount;
  1597. //
  1598. // Clear old DriveLetters in MOUNTIE_INFO
  1599. //
  1600. for (i = 0; i < PartitionCount; ++i) {
  1601. info->Volume->Partition[i].DriveLetter = 0;
  1602. }
  1603. //
  1604. // Collect Letter Assignments from Providers
  1605. //
  1606. RtlZeroMemory( results, sizeof(results) );
  1607. for (i = PROVIDER_COUNT; --i >= 0;) {
  1608. DWORD status;
  1609. status = Providers[i].GetInfo(info, ResourceEntry, results + i);
  1610. if (status != ERROR_SUCCESS) {
  1611. (DiskpLogEvent)(
  1612. ResourceEntry->ResourceHandle,
  1613. LOG_INFORMATION,
  1614. L"MountieVerify: %1!ws!.GetInfo returned %2!u! [%3!u!:%4!u!].\n",
  1615. Providers[i].Name, status, results[i].MatchCount, results[i].MismatchCount);
  1616. return status;
  1617. }
  1618. if (results[i].MatchCount && !results[i].MismatchCount) {
  1619. GoodProvider = i;
  1620. if (results[i].MatchCount >= BestMatch) {
  1621. BestProvider = i;
  1622. BestMatch = results[i].MatchCount;
  1623. }
  1624. } else {
  1625. (DiskpLogEvent)(
  1626. ResourceEntry->ResourceHandle,
  1627. LOG_INFORMATION,
  1628. L"MountieVerify: %1!ws!.GetInfo returned %2!u! [%3!u!:%4!u!].\n",
  1629. Providers[i].Name, status, results[i].MatchCount, results[i].MismatchCount);
  1630. }
  1631. }
  1632. if (GoodProvider < 0 || GoodProvider >= PROVIDER_COUNT) {
  1633. if ( !DisksGetLettersForSignature( ResourceEntry ) ) {
  1634. // No drive letters, we are using mount points and this is not an error.
  1635. errorLevel = LOG_WARNING;
  1636. } else {
  1637. // Drive letters exist, this is likely an error.
  1638. errorLevel = LOG_ERROR;
  1639. }
  1640. (DiskpLogEvent)(
  1641. ResourceEntry->ResourceHandle,
  1642. errorLevel,
  1643. L"MountieVerify: No good providers: %1!d!. \n", GoodProvider);
  1644. return ERROR_INVALID_HANDLE;
  1645. }
  1646. if (UseMountMgr) {
  1647. GoodProvider = MOUNT_MANAGER;
  1648. }
  1649. (DiskpLogEvent)(
  1650. ResourceEntry->ResourceHandle,
  1651. LOG_INFORMATION,
  1652. L"MountieVerify: %1!ws! selected.\n",
  1653. Providers[GoodProvider].Name);
  1654. if (GoodProvider != BestProvider) {
  1655. (DiskpLogEvent)(
  1656. ResourceEntry->ResourceHandle,
  1657. LOG_WARNING,
  1658. L"MountieVerify: %1!ws! is better.\n",
  1659. Providers[BestProvider].Name);
  1660. }
  1661. //
  1662. // Now GoodProvider now holds an index of the highest
  1663. // provider with non stale information.
  1664. //
  1665. // Copy its letter assignment to a MOUNTIE_INFO
  1666. //
  1667. for (i = 0; i < PartitionCount; ++i) {
  1668. UCHAR ch = AssignedLetterByPartitionNumber(
  1669. results + GoodProvider,
  1670. info->Volume->Partition[i].PartitionNumber);
  1671. info->Volume->Partition[i].DriveLetter = ch;
  1672. if (!ch) {
  1673. UnassignedPartitions = TRUE;
  1674. }
  1675. }
  1676. #if 0
  1677. // No need to assign drive letters, since now we understand
  1678. // PnP
  1679. if (UnassignedPartitions) {
  1680. //
  1681. // Now give some arbitrary letter assignment to all
  1682. // partitions without a drive letter
  1683. //
  1684. DriveLetters = GetLogicalDrives();
  1685. if (!DriveLetters) {
  1686. (DiskpLogEvent)(
  1687. ResourceEntry->ResourceHandle,
  1688. LOG_ERROR,
  1689. L"GetLogicalDrivers failed, error %u.\n", GetLastError() );
  1690. } else {
  1691. DWORD Letter = 0;
  1692. DriveLetters &= ~results[MOUNT_MANAGER].DriveLetters;
  1693. DriveLetters |= results[GoodProvider].DriveLetters;
  1694. DriveLetters |= 3; // Consider A and B drive letters busy //
  1695. for (i = 0; i < PartitionCount; ++i) {
  1696. PUCHAR pch = &info->Volume->Partition[i].DriveLetter;
  1697. if (!*pch) {
  1698. while( (1 << Letter) & DriveLetters ){
  1699. if (++Letter == 26) {
  1700. goto no_more_letters;
  1701. }
  1702. }
  1703. *pch = (UCHAR) ('A' + Letter);
  1704. if (++Letter == 26) {
  1705. break;
  1706. }
  1707. }
  1708. }
  1709. no_more_letters:;
  1710. }
  1711. }
  1712. #endif
  1713. // Update Drive Letters Mask //
  1714. MountieUpdateDriveLetters(info);
  1715. (DiskpLogEvent)(
  1716. ResourceEntry->ResourceHandle,
  1717. LOG_INFORMATION,
  1718. L"MountieVerify: DriveLetters mask is now %1!08x!.\n", info->DriveLetters );
  1719. //
  1720. // Verify that the MS-DOS namespace drive letters are OK.
  1721. //
  1722. MountieVerifyMsdosDrives( info, ResourceEntry );
  1723. //
  1724. // At this point MOUNTIE_INFO has a complete letter assignment
  1725. // for all partitions
  1726. //
  1727. // Now let's find which Providers needs to be updated
  1728. //
  1729. for (i = 0; i < PartitionCount; ++i) {
  1730. PMOUNTIE_PARTITION entry = info->Volume->Partition + i;
  1731. if (entry->DriveLetter) {
  1732. results[PROVIDER_COUNT].PartNumber[ entry->DriveLetter - 'A' ] =
  1733. (PARTITION_NUMBER_TYPE) entry->PartitionNumber;
  1734. }
  1735. }
  1736. results[PROVIDER_COUNT].DriveLetters = info->DriveLetters;
  1737. //
  1738. // All provides whose entries are different from results[PROVIDER_COUNT]
  1739. // need to be updated
  1740. //
  1741. for (i = 0; i < PROVIDER_COUNT; ++i) {
  1742. if (results[i].DriveLetters != results[PROVIDER_COUNT].DriveLetters
  1743. || results[i].MismatchCount
  1744. || 0 != memcmp(results[i].PartNumber,
  1745. results[PROVIDER_COUNT].PartNumber, sizeof(results[i].PartNumber) )
  1746. )
  1747. {
  1748. NeedsUpdate |= (1 << i);
  1749. }
  1750. }
  1751. info->NeedsUpdate = NeedsUpdate;
  1752. if (NeedsUpdate) {
  1753. (DiskpLogEvent)(
  1754. ResourceEntry->ResourceHandle,
  1755. LOG_INFORMATION,
  1756. L"MountieVerify: Update needed for %1!02x!.\n", NeedsUpdate);
  1757. //
  1758. // Chittur Subbaraman (chitturs) - 11/5/98
  1759. //
  1760. // If you plan to update the cluster registry values with info
  1761. // from the other providers, then log a warning to the event log.
  1762. //
  1763. if ( ( NeedsUpdate & 0x0003 ) && (GoodProvider == 2) && !UseMountMgr )
  1764. {
  1765. WCHAR szNewDriveLetterList[55];
  1766. WCHAR szOriginalDriveLetterList[55];
  1767. DWORD j = 0, k = 0;
  1768. for (i = 0; i < 26; ++i) {
  1769. if ( (1 << i) & results[PROVIDER_COUNT].DriveLetters ) {
  1770. szNewDriveLetterList[j] = (WCHAR)(L'A' + i);
  1771. szNewDriveLetterList[j+1] = L' ';
  1772. j += 2;
  1773. }
  1774. if ( (1 << i) & results[0].DriveLetters ) {
  1775. szOriginalDriveLetterList[k] = (WCHAR)(L'A' + i);
  1776. szOriginalDriveLetterList[k+1] = L' ';
  1777. k += 2;
  1778. }
  1779. }
  1780. szNewDriveLetterList[j] = L'\0';
  1781. szOriginalDriveLetterList[k] = L'\0';
  1782. //
  1783. // GorN. 8/25/99.
  1784. //
  1785. // Log the event only if OriginalDriveLetterList is empty.
  1786. //
  1787. if ( results[PROVIDER_COUNT].DriveLetters ) {
  1788. ClusResLogSystemEventByKey2( ResourceEntry->ResourceKey,
  1789. LOG_NOISE,
  1790. RES_DISK_WRITING_TO_CLUSREG,
  1791. szOriginalDriveLetterList,
  1792. szNewDriveLetterList
  1793. );
  1794. }
  1795. }
  1796. }
  1797. return ERROR_SUCCESS;
  1798. }
  1799. DWORD
  1800. MountieVerifyMsdosDrives(
  1801. IN PMOUNTIE_INFO Info,
  1802. IN PDISK_RESOURCE ResourceEntry
  1803. )
  1804. /*++
  1805. Routine Description:
  1806. Checks whether each drive letter has a drive letter set in the
  1807. MSDOS namespace. When someone deletes a drive letter via
  1808. DefineDosDevice, mountmgr does not update its internal tables.
  1809. So a drive letter will not be accessible until the drive letter is
  1810. recreated with a new call to DefineDosDevice.
  1811. Arguments:
  1812. Info - pointer to filled in MOUNTIE_INFO structure.
  1813. ResourceEntry - physical disk resource.
  1814. Return Value:
  1815. Win32 error value
  1816. --*/
  1817. {
  1818. HANDLE devHandle = INVALID_HANDLE_VALUE;
  1819. DWORD dwError = NO_ERROR;
  1820. DWORD msdosDrives;
  1821. DWORD driveBitmap;
  1822. DWORD idx;
  1823. DWORD partitionCount;
  1824. int result;
  1825. WCHAR szGlobalDiskPartName[MAX_PATH];
  1826. WCHAR szVolumeName[MAX_PATH];
  1827. WCHAR szDriveLetterW[6];
  1828. UCHAR szDriveLetterA[6];
  1829. UCHAR ch;
  1830. BOOL boolVal;
  1831. if ( !Info || !Info->Volume ) {
  1832. dwError = ERROR_INVALID_PARAMETER;
  1833. goto FnExit;
  1834. }
  1835. //
  1836. // If this disk is not supposed to have drive letters, there is nothing to do.
  1837. //
  1838. if ( 0 == Info->DriveLetters ) {
  1839. goto FnExit;
  1840. }
  1841. msdosDrives = GetLogicalDrives();
  1842. if ( !msdosDrives ) {
  1843. (DiskpLogEvent)(
  1844. ResourceEntry->ResourceHandle,
  1845. LOG_WARNING,
  1846. L"MountieVerifyMsdosDrives: GetLogicalDrives failed, error %1!u! \n",
  1847. GetLastError() );
  1848. goto FnExit;
  1849. }
  1850. partitionCount = Info->Volume->PartitionCount;
  1851. //
  1852. // Compare the MSDOS drive letters to those letters stored in
  1853. // the disk resource. If they are different, we have work to do.
  1854. //
  1855. if ( msdosDrives &&
  1856. ( msdosDrives & Info->DriveLetters ) != Info->DriveLetters ) {
  1857. //
  1858. // We have a mismatch between drive letters MSDOS namespace has
  1859. // and what mountmgr has. We need to update the MSDOS namespace.
  1860. // Assume mountmgr is always correct.
  1861. //
  1862. //
  1863. // Find out which drive letters we are missing.
  1864. //
  1865. msdosDrives = (~msdosDrives & Info->DriveLetters) & 0x3ffffff ;
  1866. (DiskpLogEvent)(
  1867. ResourceEntry->ResourceHandle,
  1868. LOG_WARNING,
  1869. L"MountieVerifyMsdosDrives: Missing MSDOS letters, mask %1!x! \n",
  1870. msdosDrives );
  1871. //
  1872. // Set flag to ignore pnp notifications.
  1873. //
  1874. ResourceEntry->IgnoreMPNotifications = TRUE;
  1875. //
  1876. // Walk through each partition until we find a missing
  1877. // drive letter.
  1878. //
  1879. for ( idx = 0; idx < partitionCount; ++idx ) {
  1880. //
  1881. // From the disk resource, get the current drive
  1882. // letter for the volume.
  1883. //
  1884. ch = Info->Volume->Partition[idx].DriveLetter;
  1885. //
  1886. // If this is no drive letter that is supposed to be assigned to
  1887. // this partition, skip it.
  1888. //
  1889. if ( 0 == ch ) {
  1890. continue;
  1891. }
  1892. if ( !isupper( ch ) ) {
  1893. (DiskpLogEvent)(
  1894. ResourceEntry->ResourceHandle,
  1895. LOG_ERROR,
  1896. L"MountieVerifyMsdosDrives: Drive letter is incorrect format %1!c! \n",
  1897. ch );
  1898. continue;
  1899. }
  1900. //
  1901. // Convert drive letter to drive bitmap.
  1902. //
  1903. driveBitmap = (DWORD)( 1 << (ch - 'A') );
  1904. //
  1905. // If the drive letter isn't set, then create the MSDOS
  1906. // device name again. We are going to use the mountmgr
  1907. // to do this work.
  1908. //
  1909. if ( driveBitmap & msdosDrives ) {
  1910. szDriveLetterA[0] = ch;
  1911. szDriveLetterA[1] = ':';
  1912. szDriveLetterA[2] = '\\';
  1913. szDriveLetterA[3] = '\0';
  1914. //
  1915. // Convert string to wide.
  1916. //
  1917. result = MultiByteToWideChar( CP_ACP,
  1918. 0,
  1919. szDriveLetterA,
  1920. -1,
  1921. szDriveLetterW,
  1922. RTL_NUMBER_OF(szDriveLetterW) - 1 );
  1923. if ( !result ) {
  1924. dwError = GetLastError();
  1925. (DiskpLogEvent)(
  1926. ResourceEntry->ResourceHandle,
  1927. LOG_ERROR,
  1928. L"MountieVerifyMsdosDrives: Unable to convert drive letter string, error %1!u! \n",
  1929. dwError );
  1930. continue;
  1931. }
  1932. //
  1933. // Get the current VolGuid name.
  1934. //
  1935. (VOID) StringCchPrintf( szGlobalDiskPartName,
  1936. RTL_NUMBER_OF( szGlobalDiskPartName ),
  1937. GLOBALROOT_HARDDISK_PARTITION_FMT,
  1938. Info->HarddiskNo,
  1939. Info->Volume->Partition[idx].PartitionNumber );
  1940. if ( !GetVolumeNameForVolumeMountPoint( szGlobalDiskPartName,
  1941. szVolumeName,
  1942. RTL_NUMBER_OF(szVolumeName) ) ) {
  1943. dwError = GetLastError();
  1944. (DiskpLogEvent)(
  1945. ResourceEntry->ResourceHandle,
  1946. LOG_ERROR,
  1947. L"MountieVerifyMsdosDrives: Unable to get mount point for %1!ws! returned %2!u! \n",
  1948. dwError );
  1949. continue;
  1950. }
  1951. //
  1952. // Remove the current mount point.
  1953. //
  1954. (DiskpLogEvent)(
  1955. ResourceEntry->ResourceHandle,
  1956. LOG_INFORMATION,
  1957. L"MountieVerifyMsdosDrives: deleting mount point %1!ws! \n",
  1958. szDriveLetterW );
  1959. if ( !DeleteVolumeMountPoint( szDriveLetterW ) ) {
  1960. dwError = GetLastError();
  1961. (DiskpLogEvent)(
  1962. ResourceEntry->ResourceHandle,
  1963. LOG_WARNING,
  1964. L"MountieVerifyMsdosDrives: deleting mount point %1!ws! failed %2!u! \n",
  1965. szDriveLetterW,
  1966. dwError );
  1967. //
  1968. // Fall through...
  1969. //
  1970. }
  1971. (DiskpLogEvent)(
  1972. ResourceEntry->ResourceHandle,
  1973. LOG_INFORMATION,
  1974. L"MountieVerifyMsdosDrives: recreating mount point %1!ws! \n",
  1975. szDriveLetterW );
  1976. //
  1977. // Recreate the mount point.
  1978. //
  1979. if ( !SetVolumeMountPoint( szDriveLetterW,
  1980. szVolumeName ) ) {
  1981. dwError = GetLastError();
  1982. } else {
  1983. dwError = NO_ERROR;
  1984. }
  1985. (DiskpLogEvent)(
  1986. ResourceEntry->ResourceHandle,
  1987. ( dwError == NO_ERROR ) ? LOG_INFORMATION : LOG_ERROR,
  1988. L"MountieVerifyMsdosDrives: recreating mount point %1!ws! returns %2!u! \n",
  1989. szDriveLetterW,
  1990. dwError );
  1991. }
  1992. }
  1993. }
  1994. FnExit:
  1995. //
  1996. // Clear flag to process pnp notifications again.
  1997. //
  1998. ResourceEntry->IgnoreMPNotifications = FALSE;
  1999. if ( INVALID_HANDLE_VALUE != devHandle ) {
  2000. DevfileClose( devHandle );
  2001. devHandle = INVALID_HANDLE_VALUE;
  2002. }
  2003. return dwError;
  2004. } // MountieVerifyMsdosDrives
  2005. DWORD VolumesReadyLoop(
  2006. IN PMOUNTIE_INFO Info,
  2007. IN PDISK_RESOURCE ResourceEntry
  2008. )
  2009. /*++
  2010. Routine Description:
  2011. Checks whether each partition described in the MountieInfo can be seen by the
  2012. Mount Manager. We call VolumesReady in a loop because mount manager might
  2013. not yet have created all volume names, even though all volumes are known
  2014. to pnp.
  2015. Inputs:
  2016. --*/
  2017. {
  2018. DWORD status = NO_ERROR;
  2019. DWORD retryCount;
  2020. for ( retryCount = 0; retryCount < 5; retryCount++) {
  2021. status = VolumesReady( Info, ResourceEntry );
  2022. //
  2023. // If the volume is ready, then exit. For only a couple
  2024. // specific errors will we retry waiting for the volume.
  2025. //
  2026. if ( ERROR_NOT_A_REPARSE_POINT != status &&
  2027. ERROR_NOT_READY != status ) {
  2028. break;
  2029. }
  2030. (DiskpLogEvent)(
  2031. ResourceEntry->ResourceHandle,
  2032. LOG_WARNING,
  2033. L"VolumesReady: sleep and retry \n" );
  2034. Sleep( 250 );
  2035. }
  2036. return status;
  2037. } // VolumesReadyLoop
  2038. DWORD VolumesReady(
  2039. IN PMOUNTIE_INFO Info,
  2040. IN PDISK_RESOURCE ResourceEntry
  2041. )
  2042. /*++
  2043. Routine Description:
  2044. Checks whether each partition described in the MountieInfo can be seen by the
  2045. Mount Manager.
  2046. Inputs:
  2047. --*/
  2048. {
  2049. PMOUNTIE_PARTITION entry;
  2050. DWORD status = NO_ERROR;
  2051. DWORD nPartitions = MountiePartitionCount( Info );
  2052. DWORD i;
  2053. DWORD physicalDrive = ResourceEntry->DiskInfo.PhysicalDrive;
  2054. WCHAR szGlobalDiskPartName[MAX_PATH];
  2055. WCHAR szVolumeName[MAX_PATH];
  2056. for ( i = 0; i < nPartitions; ++i ) {
  2057. entry = MountiePartition( Info, i );
  2058. if ( !entry ) {
  2059. (DiskpLogEvent)(
  2060. ResourceEntry->ResourceHandle,
  2061. LOG_ERROR,
  2062. L"VolumesReady: no partition entry for partition %1!u! \n", i );
  2063. //
  2064. // Something bad happened to our data structures. Stop processing and
  2065. // return error.
  2066. //
  2067. status = ERROR_INVALID_DATA;
  2068. break;
  2069. }
  2070. //
  2071. // Given the DiskPartName, get the VolGuid name. This name must have a trailing
  2072. // backslash to work correctly.
  2073. //
  2074. (VOID) StringCchPrintf( szGlobalDiskPartName,
  2075. RTL_NUMBER_OF( szGlobalDiskPartName ),
  2076. GLOBALROOT_HARDDISK_PARTITION_FMT,
  2077. physicalDrive,
  2078. entry->PartitionNumber );
  2079. if ( !GetVolumeNameForVolumeMountPointW( szGlobalDiskPartName,
  2080. szVolumeName,
  2081. RTL_NUMBER_OF(szVolumeName) )) {
  2082. status = GetLastError();
  2083. (DiskpLogEvent)(
  2084. ResourceEntry->ResourceHandle,
  2085. LOG_ERROR,
  2086. L"VolumesReady: GetVolumeNameForVolumeMountPoint for %1!ws! returned %2!u!\n",
  2087. szGlobalDiskPartName,
  2088. status );
  2089. //
  2090. // Something bad happened - stop checking this disk. Return the
  2091. // error status we received.
  2092. //
  2093. break;
  2094. }
  2095. //
  2096. // If we get here, this volume is recognized by the Mount Manager.
  2097. //
  2098. }
  2099. //
  2100. // If disk corrupt or file corrupt error returned, disk is ready and
  2101. // we need to run chkdsk. Change status to success and fall through.
  2102. //
  2103. if ( ERROR_DISK_CORRUPT == status || ERROR_FILE_CORRUPT == status ) {
  2104. (DiskpLogEvent)(
  2105. ResourceEntry->ResourceHandle,
  2106. LOG_WARNING,
  2107. L"VolumesReady, Allowing corrupt disk online for chkdsk processing \n" );
  2108. status = STATUS_SUCCESS;
  2109. }
  2110. return status;
  2111. } // VolumesReady
  2112. NTSTATUS
  2113. GetAssignedLetter (
  2114. PWCHAR deviceName,
  2115. PCHAR driveLetter )
  2116. {
  2117. HANDLE MountMgrHandle = NULL;
  2118. DWORD status = DevfileOpen( &MountMgrHandle, MOUNTMGR_DEVICE_NAME );
  2119. if (driveLetter) {
  2120. *driveLetter = 0;
  2121. }
  2122. if ( NT_SUCCESS(status) && MountMgrHandle ) {
  2123. status = GetAssignedLetterM(MountMgrHandle, deviceName, driveLetter);
  2124. DevfileClose(MountMgrHandle);
  2125. }
  2126. return status;
  2127. }
  2128. DWORD
  2129. SetDiskInfoThread(
  2130. LPVOID lpThreadParameter
  2131. )
  2132. /*++
  2133. Routine Description:
  2134. Mount point list update thread. Updates the cluster data base.
  2135. Arguments:
  2136. lpThreadParameter - stores ResourceEntry.
  2137. Return Value:
  2138. None
  2139. --*/
  2140. {
  2141. DWORD dwError;
  2142. PDISK_RESOURCE ResourceEntry = lpThreadParameter;
  2143. DWORD idx;
  2144. (DiskpLogEvent)(
  2145. ResourceEntry->ResourceHandle,
  2146. LOG_INFORMATION,
  2147. L"SetDiskInfoThread: started.\n");
  2148. //
  2149. // Will die in 10 minutes if unsuccessful
  2150. //
  2151. for ( idx = 0; idx < 300; ++idx ) {
  2152. //
  2153. // Wait for either the terminate event or the timeout
  2154. //
  2155. dwError = WaitForSingleObject( DisksTerminateEvent, 2000 );
  2156. if ( WAIT_TIMEOUT == dwError ) {
  2157. //
  2158. // Timer expired. Update the cluster database.
  2159. //
  2160. dwError = ClusterRegDeleteValue( ResourceEntry->ResourceParametersKey,
  2161. DISKS_DISK_INFO );
  2162. if ( ERROR_SUCCESS == dwError ) {
  2163. //
  2164. // We're done.
  2165. //
  2166. (DiskpLogEvent)(
  2167. ResourceEntry->ResourceHandle,
  2168. LOG_INFORMATION,
  2169. L"SetDiskInfoThread: DiskInfo updated in cluster data base \n" );
  2170. break;
  2171. } else if ( ERROR_SHARING_PAUSED != dwError ) {
  2172. //
  2173. // If the drive is not yet online, we should have seen ERROR_SHARING_PAUSED. If
  2174. // we see any other error, something bad happened.
  2175. //
  2176. (DiskpLogEvent)(
  2177. ResourceEntry->ResourceHandle,
  2178. LOG_WARNING,
  2179. L"SetDiskInfoThread: Failed to update cluster data base, error = %1!u! \n",
  2180. dwError );
  2181. break;
  2182. }
  2183. (DiskpLogEvent)(
  2184. ResourceEntry->ResourceHandle,
  2185. LOG_INFORMATION,
  2186. L"SetDiskInfoThread: Wait again for event or timeout, count %1!u! \n",
  2187. idx );
  2188. } else {
  2189. //
  2190. // The terminate event is possibly set.
  2191. //
  2192. (DiskpLogEvent)(
  2193. ResourceEntry->ResourceHandle,
  2194. LOG_WARNING,
  2195. L"SetDiskInfoThread: WaitForSingleObject returned error = %1!u! \n",
  2196. dwError );
  2197. break;
  2198. }
  2199. }
  2200. //
  2201. // Thread ending, clear the flag.
  2202. //
  2203. InterlockedExchange( &DiskInfoUpdateThreadIsActive, 0 );
  2204. return(ERROR_SUCCESS);
  2205. } // SetDiskInfoThread