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

2085 lines
54 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 <mountmgr.h>
  23. #include <winioctl.h>
  24. #include <ntddscsi.h>
  25. #include "clusdisk.h"
  26. #include "disksp.h"
  27. #include "newmount.h"
  28. #define LOG_CURRENT_MODULE LOG_MODULE_DISK
  29. extern PWCHAR DEVICE_HARDDISK_PARTITION_FMT; // L"\\Device\\Harddisk%u\\Partition%u" //
  30. extern PWCHAR GLOBALROOT_HARDDISK_PARTITION_FMT; // L"\\\\\?\\GLOBALROOT\\Device\\Harddisk%u\\Partition%u\\";
  31. #define MOUNTIE_VOLUME_INFO L"MountVolumeInfo"
  32. #define DISKS_DISK_INFO L"DiskInfo"
  33. #define BOGUS_BUFFER_LENGTH 512
  34. #define FIRST_SHOT_SIZE 512
  35. //
  36. // LETTER_ASSIGNMENT structure is used to store letter assignment
  37. // information from various information providers
  38. //
  39. typedef USHORT PARTITION_NUMBER_TYPE;
  40. typedef struct _LETTER_ASSIGNMENT {
  41. DWORD MatchCount;
  42. DWORD MismatchCount;
  43. DWORD DriveLetters;
  44. PARTITION_NUMBER_TYPE PartNumber[26];
  45. } LETTER_ASSIGNMENT, *PLETTER_ASSIGNMENT;
  46. DWORD
  47. MountMgr_Get(
  48. PMOUNTIE_INFO Info,
  49. PDISK_RESOURCE ResourceEntry,
  50. PLETTER_ASSIGNMENT Result);
  51. /*
  52. * DoIoctlAndAllocate - allocates a result buffer and
  53. * tries to perform DeviceIoControl, it it fails due to insufficient buffer,
  54. * it tries again with a bigger buffer.
  55. *
  56. * FIRST_SHOT_SIZE is a constant that regulates the size of the buffer
  57. * for the first attempt to do DeviceIoControl.
  58. *
  59. * Return a non-zero code for error.
  60. */
  61. PVOID
  62. DoIoctlAndAllocate(
  63. IN HANDLE FileHandle,
  64. IN DWORD IoControlCode,
  65. IN PVOID InBuf,
  66. IN ULONG InBufSize,
  67. OUT LPDWORD BytesReturned
  68. )
  69. {
  70. UCHAR firstShot[ FIRST_SHOT_SIZE ];
  71. DWORD status = ERROR_SUCCESS;
  72. BOOL success;
  73. DWORD outBufSize;
  74. PVOID outBuf = 0;
  75. DWORD bytesReturned;
  76. success = DeviceIoControl( FileHandle,
  77. IoControlCode,
  78. InBuf,
  79. InBufSize,
  80. &firstShot,
  81. sizeof(firstShot),
  82. &bytesReturned,
  83. (LPOVERLAPPED) NULL );
  84. if ( success ) {
  85. outBufSize = bytesReturned;
  86. outBuf = malloc( outBufSize );
  87. if (!outBuf) {
  88. status = ERROR_OUTOFMEMORY;
  89. } else {
  90. RtlCopyMemory(outBuf, &firstShot, outBufSize);
  91. status = ERROR_SUCCESS;
  92. }
  93. } else {
  94. outBufSize = sizeof(firstShot);
  95. for(;;) {
  96. status = GetLastError();
  97. //
  98. // If it is not a buffer size related error, then we cannot do much
  99. //
  100. if ( status != ERROR_INSUFFICIENT_BUFFER
  101. && status != ERROR_MORE_DATA
  102. && status != ERROR_BAD_LENGTH
  103. ) {
  104. break;
  105. }
  106. //
  107. // Otherwise, try an outbut buffer twice the previous size
  108. //
  109. outBufSize *= 2;
  110. outBuf = malloc( outBufSize );
  111. if ( !outBuf ) {
  112. status = ERROR_OUTOFMEMORY;
  113. break;
  114. }
  115. success = DeviceIoControl( FileHandle,
  116. IoControlCode,
  117. InBuf,
  118. InBufSize,
  119. outBuf,
  120. outBufSize,
  121. &bytesReturned,
  122. (LPOVERLAPPED) NULL );
  123. if (success) {
  124. status = ERROR_SUCCESS;
  125. break;
  126. }
  127. free( outBuf );
  128. }
  129. }
  130. if (status != ERROR_SUCCESS) {
  131. free( outBuf ); // free( 0 ) is legal //
  132. outBuf = 0;
  133. bytesReturned = 0;
  134. }
  135. SetLastError( status );
  136. *BytesReturned = bytesReturned;
  137. return outBuf;
  138. }
  139. /*
  140. * DevfileOpen - open a device file given a pathname
  141. *
  142. * Return a non-zero code for error.
  143. */
  144. NTSTATUS
  145. DevfileOpen(
  146. OUT HANDLE *Handle,
  147. IN wchar_t *pathname
  148. )
  149. {
  150. HANDLE fh;
  151. OBJECT_ATTRIBUTES objattrs;
  152. UNICODE_STRING cwspath;
  153. NTSTATUS status;
  154. IO_STATUS_BLOCK iostatus;
  155. RtlInitUnicodeString(&cwspath, pathname);
  156. InitializeObjectAttributes(&objattrs, &cwspath, OBJ_CASE_INSENSITIVE,
  157. NULL, NULL);
  158. fh = NULL;
  159. status = NtOpenFile(&fh,
  160. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  161. &objattrs, &iostatus,
  162. FILE_SHARE_READ | FILE_SHARE_WRITE,
  163. FILE_SYNCHRONOUS_IO_ALERT);
  164. if (status != STATUS_SUCCESS) {
  165. return status;
  166. }
  167. if ( !NT_SUCCESS(iostatus.Status) ) {
  168. if (fh) {
  169. NtClose(fh);
  170. }
  171. return iostatus.Status;
  172. }
  173. *Handle = fh;
  174. return STATUS_SUCCESS;
  175. } // DevfileOpen
  176. /*
  177. * DevfileClose - close a file
  178. */
  179. VOID
  180. DevfileClose(
  181. IN HANDLE Handle
  182. )
  183. {
  184. NtClose(Handle);
  185. } // DevFileClose
  186. /*
  187. * DevfileIoctl - issue an ioctl to a device
  188. */
  189. NTSTATUS
  190. DevfileIoctl(
  191. IN HANDLE Handle,
  192. IN DWORD Ioctl,
  193. IN PVOID InBuf,
  194. IN ULONG InBufSize,
  195. IN OUT PVOID OutBuf,
  196. IN DWORD OutBufSize,
  197. OUT LPDWORD returnLength
  198. )
  199. {
  200. NTSTATUS status;
  201. IO_STATUS_BLOCK ioStatus;
  202. status = NtDeviceIoControlFile(Handle,
  203. (HANDLE) NULL,
  204. (PIO_APC_ROUTINE) NULL,
  205. NULL,
  206. &ioStatus,
  207. Ioctl,
  208. InBuf, InBufSize,
  209. OutBuf, OutBufSize);
  210. if ( status == STATUS_PENDING ) {
  211. status = NtWaitForSingleObject( Handle, FALSE, NULL );
  212. }
  213. if ( NT_SUCCESS(status) ) {
  214. status = ioStatus.Status;
  215. }
  216. if ( ARGUMENT_PRESENT(returnLength) ) {
  217. *returnLength = (ULONG)ioStatus.Information;
  218. }
  219. return status;
  220. } // DevfileIoctl
  221. #define OUTPUT_BUFFER_LEN (1024)
  222. #define INPUT_BUFFER_LEN (sizeof(MOUNTMGR_MOUNT_POINT) + 2 * MAX_PATH * sizeof(WCHAR))
  223. DWORD
  224. DisksAssignDosDeviceM(
  225. HANDLE MountManager,
  226. PCHAR MountName,
  227. PWCHAR VolumeDevName
  228. )
  229. /*++
  230. Routine Description:
  231. Inputs:
  232. MountManager - Handle to MountMgr
  233. MountName -
  234. VolumeDevName -
  235. Return value:
  236. A Win32 error code.
  237. --*/
  238. {
  239. WCHAR mount_device[MAX_PATH];
  240. USHORT mount_point_len;
  241. USHORT dev_name_len;
  242. DWORD status;
  243. USHORT inputlength;
  244. PMOUNTMGR_CREATE_POINT_INPUT input;
  245. swprintf(mount_device, L"\\DosDevices\\%S\0", MountName);
  246. mount_point_len = wcslen(mount_device) * sizeof(WCHAR);
  247. dev_name_len = wcslen(VolumeDevName) * sizeof(WCHAR);
  248. inputlength = sizeof(MOUNTMGR_CREATE_POINT_INPUT) +
  249. mount_point_len + dev_name_len;
  250. input = (PMOUNTMGR_CREATE_POINT_INPUT)malloc(inputlength);
  251. if (!input) {
  252. return ERROR_NOT_ENOUGH_MEMORY;
  253. }
  254. input->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT);
  255. input->SymbolicLinkNameLength = mount_point_len;
  256. input->DeviceNameOffset = input->SymbolicLinkNameOffset +
  257. input->SymbolicLinkNameLength;
  258. input->DeviceNameLength = dev_name_len;
  259. RtlCopyMemory((PCHAR)input + input->SymbolicLinkNameOffset,
  260. mount_device, mount_point_len);
  261. RtlCopyMemory((PCHAR)input + input->DeviceNameOffset,
  262. VolumeDevName, dev_name_len);
  263. status = DevfileIoctl(MountManager, IOCTL_MOUNTMGR_CREATE_POINT,
  264. input, inputlength, NULL, 0, NULL);
  265. free(input);
  266. return status;
  267. } // DisksAssignDosDevice
  268. DWORD
  269. DisksRemoveDosDeviceM(
  270. HANDLE MountManager,
  271. PCHAR MountName
  272. )
  273. /*++
  274. Routine Description:
  275. Inputs:
  276. MountManager - Handle to MountMgr
  277. MountName -
  278. Return value:
  279. --*/
  280. {
  281. WCHAR mount_device[MAX_PATH];
  282. USHORT mount_point_len;
  283. USHORT dev_name_len;
  284. DWORD status;
  285. USHORT inputlength;
  286. PMOUNTMGR_MOUNT_POINT input;
  287. PUCHAR bogusBuffer; // this buffer should NOT be required!
  288. DWORD bogusBufferLength = BOGUS_BUFFER_LENGTH;
  289. //
  290. // Remove old mount points for this mount name.
  291. //
  292. swprintf(mount_device, L"\\DosDevices\\%S", MountName);
  293. mount_point_len = wcslen(mount_device) * sizeof(WCHAR);
  294. inputlength = sizeof(MOUNTMGR_MOUNT_POINT) + mount_point_len;
  295. input = (PMOUNTMGR_MOUNT_POINT)malloc(inputlength);
  296. if (!input) {
  297. return ERROR_NOT_ENOUGH_MEMORY;
  298. }
  299. bogusBuffer = malloc(bogusBufferLength);
  300. if (!bogusBuffer) {
  301. free(input);
  302. return ERROR_NOT_ENOUGH_MEMORY;
  303. }
  304. input->UniqueIdOffset = 0;
  305. input->UniqueIdLength = 0;
  306. input->DeviceNameOffset = 0;
  307. input->DeviceNameLength = 0;
  308. input->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  309. input->SymbolicLinkNameLength = mount_point_len;
  310. RtlCopyMemory((PCHAR)input + input->SymbolicLinkNameOffset,
  311. mount_device, mount_point_len);
  312. do {
  313. status = DevfileIoctl(MountManager, IOCTL_MOUNTMGR_DELETE_POINTS,
  314. input, inputlength, bogusBuffer, bogusBufferLength, NULL);
  315. free( bogusBuffer );
  316. if ( status == ERROR_MORE_DATA ) {
  317. bogusBufferLength += BOGUS_BUFFER_LENGTH;
  318. bogusBuffer = malloc(bogusBufferLength);
  319. if (!bogusBuffer) {
  320. status = ERROR_NOT_ENOUGH_MEMORY;
  321. }
  322. }
  323. } while ( status == ERROR_MORE_DATA );
  324. free(input);
  325. //
  326. // Use the 'old-style' name on error in case we got a 'half-built' stack.
  327. //
  328. if ( status != ERROR_SUCCESS ) {
  329. DefineDosDevice( DDD_REMOVE_DEFINITION | DDD_NO_BROADCAST_SYSTEM,
  330. MountName,
  331. NULL );
  332. }
  333. return status;
  334. } // DisksRemoveDosDevice
  335. static
  336. NTSTATUS
  337. GetAssignedLetterM (
  338. IN HANDLE MountMgrHandle,
  339. IN PWCHAR deviceName,
  340. OUT PCHAR driveLetter )
  341. /*++
  342. Routine Description:
  343. Get an assigned drive letter from MountMgr, if any
  344. Inputs:
  345. MountMgrHandle -
  346. deviceName -
  347. driveLetter - receives drive letter
  348. Return value:
  349. STATUS_SUCCESS - on success
  350. NTSTATUS code - on failure
  351. --*/
  352. {
  353. DWORD status = STATUS_SUCCESS;
  354. PMOUNTMGR_MOUNT_POINT input = NULL;
  355. PMOUNTMGR_MOUNT_POINTS output = NULL;
  356. PMOUNTMGR_MOUNT_POINT out;
  357. DWORD len = wcslen( deviceName ) * sizeof(WCHAR);
  358. DWORD bytesReturned;
  359. DWORD idx;
  360. DWORD outputLen;
  361. DWORD inputLen;
  362. WCHAR wc;
  363. inputLen = INPUT_BUFFER_LEN;
  364. input = LocalAlloc( LPTR, inputLen );
  365. if ( !input ) {
  366. goto FnExit;
  367. }
  368. input->SymbolicLinkNameOffset = 0;
  369. input->SymbolicLinkNameLength = 0;
  370. input->UniqueIdOffset = 0;
  371. input->UniqueIdLength = 0;
  372. input->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  373. input->DeviceNameLength = (USHORT) len;
  374. RtlCopyMemory((PCHAR)input + input->DeviceNameOffset,
  375. deviceName, len );
  376. if (len > sizeof(WCHAR) && deviceName[1] == L'\\') {
  377. // convert Dos name to NT name
  378. ((PWCHAR)(input + input->DeviceNameOffset))[1] = L'?';
  379. }
  380. outputLen = OUTPUT_BUFFER_LEN;
  381. output = LocalAlloc( LPTR, outputLen );
  382. if ( !output ) {
  383. goto FnExit;
  384. }
  385. status = DevfileIoctl(MountMgrHandle, IOCTL_MOUNTMGR_QUERY_POINTS,
  386. input, inputLen, output, outputLen, &bytesReturned);
  387. if ( STATUS_BUFFER_OVERFLOW == status ) {
  388. outputLen = output->Size;
  389. LocalFree( output );
  390. output = LocalAlloc( LPTR, outputLen );
  391. if ( !output ) {
  392. goto FnExit;
  393. }
  394. status = DevfileIoctl(MountMgrHandle, IOCTL_MOUNTMGR_QUERY_POINTS,
  395. input, inputLen, output, outputLen, &bytesReturned);
  396. }
  397. if ( !NT_SUCCESS(status) ) {
  398. goto FnExit;
  399. }
  400. if (driveLetter) {
  401. *driveLetter = 0;
  402. }
  403. for ( idx = 0; idx < output->NumberOfMountPoints; ++idx ) {
  404. out = &output->MountPoints[idx];
  405. if (out->SymbolicLinkNameLength/sizeof(WCHAR) == 14 &&
  406. (_wcsnicmp((PWCHAR)((PCHAR)output + out->SymbolicLinkNameOffset), L"\\DosDevices\\", 12) == 0) &&
  407. L':' == *((PCHAR)output + out->SymbolicLinkNameOffset + 13*sizeof(WCHAR)) )
  408. {
  409. wc = *((PCHAR)output + out->SymbolicLinkNameOffset + 12*sizeof(WCHAR));
  410. if (driveLetter && out->UniqueIdLength) {
  411. *driveLetter = (CHAR)toupper((UCHAR)wc);
  412. break;
  413. }
  414. }
  415. }
  416. FnExit:
  417. if ( output ) {
  418. LocalFree( output );
  419. }
  420. if ( input ) {
  421. LocalFree( input );
  422. }
  423. return status;
  424. }
  425. BOOL
  426. InterestingPartition(
  427. PPARTITION_INFORMATION info
  428. )
  429. /*++
  430. Routine Description:
  431. Quick check whether a partition is "interesting" for us
  432. Inputs:
  433. info - GetDriveLayout's partition information
  434. Return value:
  435. TRUE or FALSE
  436. --*/
  437. {
  438. return ( (info->RecognizedPartition)
  439. && ((info->PartitionType == PARTITION_IFS) ||
  440. IsContainerPartition(info->PartitionType)) );
  441. }
  442. PMOUNTIE_VOLUME
  443. CreateMountieVolumeFromDriveLayoutInfo (
  444. IN PDRIVE_LAYOUT_INFORMATION info,
  445. IN HANDLE ResourceHandle
  446. )
  447. /*++
  448. Routine Description:
  449. Collects all interesing partition from DriveLayoutInformation
  450. then it allocates and fills MountieVolume structure
  451. Inputs:
  452. info - GetDriveLayout's information
  453. ResourceHandle - for error logging - not used (may be NULL!)
  454. Return value:
  455. TRUE or FALSE
  456. --*/
  457. {
  458. DWORD i;
  459. DWORD nPartitions = 0;
  460. PMOUNTIE_VOLUME vol;
  461. PMOUNTIE_PARTITION mountie;
  462. DWORD size;
  463. //
  464. // Count Partitions
  465. //
  466. for (i = 0; i < info->PartitionCount; ++i) {
  467. if ( InterestingPartition( info->PartitionEntry + i ) ) {
  468. ++nPartitions;
  469. }
  470. }
  471. if (!nPartitions) {
  472. SetLastError(ERROR_INVALID_DATA);
  473. return 0;
  474. }
  475. //
  476. // Allocate memory for Mountie structure
  477. //
  478. size = sizeof(MOUNTIE_VOLUME) + sizeof(MOUNTIE_PARTITION) * (nPartitions - 1);
  479. vol = malloc( size );
  480. if (!vol) {
  481. SetLastError(ERROR_OUTOFMEMORY);
  482. return 0;
  483. }
  484. RtlZeroMemory(vol, size);
  485. vol->PartitionCount = nPartitions;
  486. vol->Signature = info->Signature;
  487. //
  488. // Copy all relevant Information from DriveLayout info
  489. //
  490. mountie = vol->Partition;
  491. for (i = 0; i < info->PartitionCount; ++i) {
  492. PPARTITION_INFORMATION entry = info->PartitionEntry + i;
  493. if ( InterestingPartition(entry) ) {
  494. mountie->StartingOffset = entry->StartingOffset;
  495. mountie->PartitionLength = entry->PartitionLength;
  496. mountie->PartitionNumber = entry->PartitionNumber;
  497. mountie->PartitionType = entry->PartitionType;
  498. ++mountie;
  499. }
  500. }
  501. return vol;
  502. }
  503. VOID
  504. MountieUpdateDriveLetters(
  505. IN OUT PMOUNTIE_INFO info
  506. )
  507. /*++
  508. Routine Description:
  509. Updates DriveLetter bitmap.
  510. This routine needs to be called every time
  511. drive letter information is changed in MountieInfo
  512. Inputs:
  513. info - MountieInfo
  514. --*/
  515. {
  516. DWORD i;
  517. DWORD driveLetters = 0;
  518. PMOUNTIE_VOLUME vol = info->Volume;
  519. if (vol) {
  520. for (i = 0; i < vol->PartitionCount; ++i) {
  521. UCHAR ch = vol->Partition[i].DriveLetter;
  522. if (ch) {
  523. driveLetters |= 1 << (ch - 'A');
  524. }
  525. }
  526. }
  527. info->DriveLetters = driveLetters;
  528. }
  529. PMOUNTIE_PARTITION
  530. MountiePartitionByOffsetAndLength(
  531. IN PMOUNTIE_INFO Info,
  532. LARGE_INTEGER Offset, LARGE_INTEGER Len)
  533. {
  534. DWORD PartitionCount;
  535. PMOUNTIE_PARTITION entry;
  536. if (!Info->Volume) {
  537. return 0;
  538. }
  539. PartitionCount = Info->Volume->PartitionCount;
  540. entry = Info->Volume->Partition;
  541. while ( PartitionCount-- ) {
  542. if (entry->StartingOffset.QuadPart == Offset.QuadPart
  543. && entry->PartitionLength.QuadPart == Len.QuadPart) {
  544. return entry;
  545. }
  546. ++entry;
  547. }
  548. return 0;
  549. }
  550. DWORD
  551. MountiePartitionCount(
  552. IN PMOUNTIE_INFO Info)
  553. {
  554. if (Info->Volume) {
  555. return Info->Volume->PartitionCount;
  556. } else {
  557. return 0;
  558. }
  559. }
  560. PMOUNTIE_PARTITION
  561. MountiePartition(
  562. IN PMOUNTIE_INFO Info,
  563. IN DWORD Index)
  564. {
  565. return Info->Volume->Partition + Index;
  566. }
  567. PMOUNTIE_PARTITION
  568. MountiePartitionByPartitionNo(
  569. IN PMOUNTIE_INFO Info,
  570. IN DWORD PartitionNumber
  571. )
  572. {
  573. DWORD i, n;
  574. PMOUNTIE_PARTITION entry;
  575. if (Info->Volume == 0) {
  576. return 0;
  577. }
  578. n = Info->Volume->PartitionCount;
  579. entry = Info->Volume->Partition;
  580. for (i = 0; i < n; ++i, ++entry) {
  581. if (entry->PartitionNumber == PartitionNumber)
  582. {
  583. return entry;
  584. }
  585. }
  586. return 0;
  587. }
  588. VOID
  589. MountiePrint(
  590. IN PMOUNTIE_INFO Info,
  591. IN HANDLE ResourceHandle
  592. )
  593. {
  594. DWORD i, n;
  595. PMOUNTIE_PARTITION entry;
  596. if (Info->Volume == 0) {
  597. return;
  598. }
  599. n = Info->Volume->PartitionCount;
  600. entry = Info->Volume->Partition;
  601. for (i = 0; i < n; ++i, ++entry) {
  602. (DiskpLogEvent)(
  603. ResourceHandle,
  604. LOG_INFORMATION,
  605. L"Mountie[%1!u!]: %2!u!, let=%3!c!, start=%4!X!, len=%5!X!.\n",
  606. i,
  607. entry->PartitionNumber,
  608. NICE_DRIVE_LETTER(entry->DriveLetter),
  609. entry->StartingOffset.LowPart,
  610. entry->PartitionLength.LowPart );
  611. }
  612. }
  613. DWORD
  614. DisksGetLettersForSignature(
  615. IN PDISK_RESOURCE ResourceEntry
  616. )
  617. {
  618. return ResourceEntry->MountieInfo.DriveLetters;
  619. }
  620. DWORD
  621. MountieRecreateVolumeInfoFromHandle(
  622. IN HANDLE FileHandle,
  623. IN DWORD HarddiskNo,
  624. IN HANDLE ResourceHandle,
  625. IN OUT PMOUNTIE_INFO Info
  626. )
  627. /*++
  628. Routine Description:
  629. Recreate a MountieInfo that has no
  630. DriveLetter assignments.
  631. IMPORTANT!!! The code assumes that Info->Volume
  632. either contains a valid pointer or NULL
  633. Inputs:
  634. ResourceHandle - may be NULL.
  635. Outputs:
  636. Info - MountieInfo
  637. --*/
  638. {
  639. PDRIVE_LAYOUT_INFORMATION layout;
  640. DWORD status;
  641. DWORD bytesReturned;
  642. free( Info->Volume ); // free(0) is OK //
  643. Info->HarddiskNo = HarddiskNo;
  644. Info->DriveLetters = 0;
  645. Info->Volume = 0;
  646. Info->VolumeStructSize = 0;
  647. layout = DoIoctlAndAllocate(
  648. FileHandle, IOCTL_DISK_GET_DRIVE_LAYOUT, 0,0, &bytesReturned);
  649. if (!layout) {
  650. return GetLastError();
  651. }
  652. status = ERROR_SUCCESS;
  653. try {
  654. Info->Volume = CreateMountieVolumeFromDriveLayoutInfo( layout , ResourceHandle );
  655. if (!Info->Volume) {
  656. status = GetLastError();
  657. leave;
  658. }
  659. Info->VolumeStructSize = sizeof(MOUNTIE_VOLUME) +
  660. sizeof(MOUNTIE_PARTITION) * (Info->Volume->PartitionCount - 1);
  661. } finally {
  662. free( layout );
  663. }
  664. if ( ResourceHandle ) MountiePrint(Info, ResourceHandle);
  665. return status;
  666. }
  667. DWORD
  668. MountieFindPartitionsForDisk(
  669. IN DWORD HarddiskNo,
  670. OUT PMOUNTIE_INFO MountieInfo
  671. )
  672. /*++
  673. Note that Caller of this routine is responsible for freeing Volume Information
  674. via call to MountieCleanup().
  675. --*/
  676. {
  677. UCHAR deviceName[MAX_PATH];
  678. HANDLE fileHandle;
  679. DWORD status;
  680. sprintf( deviceName,
  681. "\\\\.\\PhysicalDrive%u",
  682. HarddiskNo );
  683. ASSERT( strlen(deviceName) < sizeof( deviceName ));
  684. fileHandle = CreateFile( deviceName,
  685. GENERIC_READ | GENERIC_WRITE,
  686. FILE_SHARE_READ | FILE_SHARE_WRITE,
  687. NULL,
  688. OPEN_EXISTING,
  689. 0,
  690. NULL );
  691. if ( (fileHandle == NULL) ||
  692. (fileHandle == INVALID_HANDLE_VALUE) ) {
  693. status = GetLastError();
  694. return status;
  695. }
  696. RtlZeroMemory( MountieInfo, sizeof(MOUNTIE_INFO) );
  697. status = MountieRecreateVolumeInfoFromHandle(
  698. fileHandle,
  699. HarddiskNo,
  700. NULL,
  701. MountieInfo );
  702. if ( status != ERROR_SUCCESS ) {
  703. CloseHandle( fileHandle );
  704. return status;
  705. }
  706. CloseHandle( fileHandle );
  707. return(ERROR_SUCCESS);
  708. } // MountieFindPartitionsForDisk
  709. VOID
  710. MountieCleanup(
  711. IN OUT PMOUNTIE_INFO Info
  712. )
  713. /*++
  714. Routine Description:
  715. Deallocates Volume information
  716. Inputs:
  717. Info - MountieInfo
  718. --*/
  719. {
  720. PVOID volume;
  721. Info->VolumeStructSize = 0;
  722. volume = InterlockedExchangePointer(&(Info->Volume), 0);
  723. free(volume);
  724. }
  725. ////////////////////////////////////////////////////////////////////////////////////////
  726. ////////////////////////////////////////////////////////////////////////////////////////
  727. ////////////////////////////////////////////////////////////////////////////////////////
  728. ////////////////////////////////////////////////////////////////////////////////////////
  729. //
  730. // Disk information is specified in different formats in various places
  731. //
  732. // The following code is an attempt to provide some common denominator
  733. // to simplify verification of all disk information and keeping it in sync.
  734. //
  735. UCHAR
  736. AssignedLetterByPartitionNumber (
  737. PLETTER_ASSIGNMENT Assignment,
  738. DWORD PartitionNo)
  739. /*++
  740. Routine Description:
  741. Returns a drive letter assigned to a partition
  742. Inputs:
  743. Assignment - drive letter assignment info
  744. PartitionNo - partition number (As in Harddisk0\PartitionX)
  745. --*/
  746. {
  747. UCHAR i;
  748. for( i = 0; i < 26; ++i ) {
  749. if (Assignment->PartNumber[i] == PartitionNo) {
  750. return ('A' + i);
  751. }
  752. }
  753. return 0;
  754. }
  755. // For every different way to describe a disk information
  756. // there should be two functions defined GetInfo and SetInfo
  757. // which will read/write the information into/from LETTER_ASSIGNMENT structure
  758. typedef DWORD (*GetInfoFunc) (PMOUNTIE_INFO, PDISK_RESOURCE ResourceEntry, PLETTER_ASSIGNMENT Result);
  759. typedef DWORD (*SetInfoFunc) (PMOUNTIE_INFO, PDISK_RESOURCE ResourceEntry);
  760. //
  761. // The following structure is a description of disk information provider.
  762. //
  763. // It is used to bind a provider name (Used as a label in error logging)
  764. // and information access routines
  765. //
  766. typedef struct _INFO_PROVIDER {
  767. PWCHAR Name;
  768. GetInfoFunc GetInfo;
  769. SetInfoFunc SetInfo;
  770. } INFO_PROVIDER, *PINFO_PROVIDER;
  771. ////////////////////////////////////////////////////////////////////
  772. //
  773. // The following routine gets FtInfo, by reading existing one or
  774. // creating an empty one if there is no System\DISK in the registry)
  775. //
  776. // Then it adds/updates drive letter assignment for the specified drive,
  777. // using the information supplied in MOUNTIE_INFO structure.
  778. //
  779. PFT_INFO
  780. FtInfo_CreateFromMountie(
  781. PMOUNTIE_INFO Info,
  782. PDISK_RESOURCE ResourceEntry)
  783. {
  784. PFT_INFO ftInfo = 0;
  785. DWORD i, n;
  786. DWORD Status = ERROR_SUCCESS;
  787. PMOUNTIE_PARTITION entry;
  788. try {
  789. ftInfo = DiskGetFtInfo();
  790. if ( !ftInfo ) {
  791. (DiskpLogEvent)(ResourceEntry->ResourceHandle,
  792. LOG_ERROR,
  793. L"Failed to get FtInfo.\n");
  794. Status = ERROR_NOT_ENOUGH_MEMORY;
  795. ftInfo = 0;
  796. leave;
  797. }
  798. Status = DiskAddDiskInfoEx( ftInfo,
  799. ResourceEntry->DiskInfo.PhysicalDrive,
  800. ResourceEntry->DiskInfo.Params.Signature,
  801. DISKRTL_REPLACE_IF_EXISTS );
  802. if ( Status != ERROR_SUCCESS ) {
  803. (DiskpLogEvent)(ResourceEntry->ResourceHandle,
  804. LOG_ERROR,
  805. L"Error %1!d! adding DiskInfo.\n",
  806. Status);
  807. ftInfo = 0;
  808. leave;
  809. }
  810. n = Info->Volume->PartitionCount;
  811. entry = Info->Volume->Partition;
  812. //
  813. // Now add the partition info for each partition
  814. //
  815. for ( i = 0; i < n; ++i,++entry ) {
  816. UCHAR driveLetter;
  817. Status = DiskAddDriveLetterEx( ftInfo,
  818. ResourceEntry->DiskInfo.Params.Signature,
  819. entry->StartingOffset,
  820. entry->PartitionLength,
  821. entry->DriveLetter, 0);
  822. if ( Status != ERROR_SUCCESS ) {
  823. (DiskpLogEvent)(ResourceEntry->ResourceHandle,
  824. LOG_ERROR,
  825. L"Error %1!d! adding partition %2!x!:%3!x! letter %4!X! sig %5!x!.\n",
  826. Status, entry->StartingOffset.LowPart,
  827. entry->PartitionLength.LowPart,
  828. entry->DriveLetter,
  829. Info->Volume->Signature);
  830. break;
  831. }
  832. }
  833. } finally {
  834. if (Status != ERROR_SUCCESS) {
  835. SetLastError(Status);
  836. if (ftInfo) {
  837. DiskFreeFtInfo(ftInfo);
  838. ftInfo = 0;
  839. }
  840. }
  841. }
  842. return ftInfo;
  843. }
  844. DWORD FtInfo_GetFromFtInfo(
  845. IN PMOUNTIE_INFO Info,
  846. IN PDISK_RESOURCE ResourceEntry,
  847. IN PFT_INFO FtInfo,
  848. IN OUT PLETTER_ASSIGNMENT Result)
  849. {
  850. DWORD i, n;
  851. PFT_DISK_INFO FtDisk;
  852. FtDisk = FtInfo_GetFtDiskInfoBySignature(
  853. FtInfo, ResourceEntry->DiskInfo.Params.Signature);
  854. if ( !FtDisk ) {
  855. (DiskpLogEvent)(
  856. ResourceEntry->ResourceHandle,
  857. LOG_WARNING,
  858. L"FtInfo_GetFromFtInfo: GetFtDiskInfoBySignature failed.\n");
  859. ++Result->MismatchCount;
  860. return ERROR_NOT_FOUND;
  861. }
  862. n = FtDiskInfo_GetPartitionCount(FtDisk);
  863. if (n == 0) {
  864. (DiskpLogEvent)(
  865. ResourceEntry->ResourceHandle,
  866. LOG_WARNING,
  867. L"FtInfo_GetFromFtInfo: DiskInfo has no partitions.\n");
  868. ++Result->MismatchCount;
  869. return ERROR_NOT_FOUND;
  870. }
  871. // sanity check //
  872. // number 10 is completely arbitrary //
  873. if (n > Info->Volume->PartitionCount * 10) {
  874. (DiskpLogEvent)(
  875. ResourceEntry->ResourceHandle,
  876. LOG_ERROR,
  877. L"FtInfo_GetFromFtInfo: DiskInfo has %1!u! partitions!\n", n);
  878. n = Info->Volume->PartitionCount * 10;
  879. }
  880. for(i = 0; i < n; ++i) {
  881. DISK_PARTITION UNALIGNED *entry;
  882. PMOUNTIE_PARTITION mountie;
  883. entry = FtDiskInfo_GetPartitionInfoByIndex(FtDisk, i);
  884. mountie = MountiePartitionByOffsetAndLength(
  885. Info,
  886. entry->StartingOffset,
  887. entry->Length);
  888. if (mountie) {
  889. UCHAR ch = (UCHAR)toupper( entry->DriveLetter );
  890. if ( isalpha(ch) ) {
  891. ch -= 'A';
  892. Result->DriveLetters |= ( 1 << ch );
  893. Result->PartNumber[ch] = (PARTITION_NUMBER_TYPE) mountie->PartitionNumber;
  894. ++Result->MatchCount;
  895. }
  896. } else {
  897. //
  898. // Chittur Subbaraman (chitturs) - 11/5/98
  899. //
  900. // Added the following 4 statements for event logging in MountieVerify
  901. //
  902. UCHAR uch = (UCHAR)toupper( entry->DriveLetter );
  903. if ( isalpha(uch) ) {
  904. uch -= 'A';
  905. Result->DriveLetters |= ( 1 << uch );
  906. }
  907. ++Result->MismatchCount;
  908. (DiskpLogEvent)(
  909. ResourceEntry->ResourceHandle,
  910. LOG_WARNING,
  911. L"Strange partition: %1!X!, %2!X!, Type=%3!u!, letter=%4!c!.\n",
  912. entry->StartingOffset.LowPart, entry->Length.LowPart,
  913. entry->FtType, NICE_DRIVE_LETTER(entry->DriveLetter) );
  914. }
  915. }
  916. return ERROR_SUCCESS;
  917. }
  918. /////////////////////////////////////////////////////////////////
  919. //
  920. // NT4 style System\DISK and ClusReg\DiskInfo
  921. // accessing routines
  922. //
  923. // ClusDiskInfo_Get
  924. // ClusDiskInfo_Set
  925. // FtInfo_Get
  926. // FtInfo_Set
  927. //
  928. DWORD
  929. CluDiskInfo_Get(
  930. PMOUNTIE_INFO Info,
  931. PDISK_RESOURCE ResourceEntry,
  932. PLETTER_ASSIGNMENT Result)
  933. {
  934. DWORD Length;
  935. DWORD Status;
  936. DWORD errorLevel;
  937. PFULL_DISK_INFO DiskInfo = 0;
  938. try {
  939. //
  940. // Read out the diskinfo parameter from our resource.
  941. //
  942. Status = ClusterRegQueryValue(ResourceEntry->ResourceParametersKey,
  943. DISKS_DISK_INFO,
  944. NULL,
  945. NULL,
  946. &Length);
  947. if (Status == ERROR_SUCCESS ) {
  948. DiskInfo = malloc(Length);
  949. if (!DiskInfo) {
  950. Status = ERROR_OUTOFMEMORY;
  951. } else {
  952. Status = ClusterRegQueryValue(ResourceEntry->ResourceParametersKey,
  953. DISKS_DISK_INFO,
  954. NULL,
  955. (LPBYTE)DiskInfo,
  956. &Length);
  957. if (Status == ERROR_SUCCESS) {
  958. PFT_INFO ftInfo = DiskGetFtInfoFromFullDiskinfo(DiskInfo);
  959. if (ftInfo) {
  960. Status = FtInfo_GetFromFtInfo(Info,
  961. ResourceEntry,
  962. ftInfo,
  963. Result);
  964. DiskFreeFtInfo(ftInfo);
  965. } else {
  966. Status = GetLastError();
  967. }
  968. }
  969. }
  970. }
  971. } finally {
  972. if (Status != ERROR_SUCCESS) {
  973. if ( !DisksGetLettersForSignature( ResourceEntry ) ) {
  974. // No drive letters, we are using mount points and this is not an error.
  975. errorLevel = LOG_WARNING;
  976. } else {
  977. // Drive letters exist, this is likely an error.
  978. errorLevel = LOG_ERROR;
  979. }
  980. (DiskpLogEvent)(
  981. ResourceEntry->ResourceHandle,
  982. errorLevel,
  983. L"CluDiskInfo_Get: Status=%1!u!.\n", Status);
  984. ++Result->MismatchCount;
  985. }
  986. free(DiskInfo);
  987. }
  988. return ERROR_SUCCESS;
  989. }
  990. DWORD
  991. FtInfo_Get(
  992. PMOUNTIE_INFO Info,
  993. PDISK_RESOURCE ResourceEntry,
  994. PLETTER_ASSIGNMENT Result)
  995. {
  996. PFT_INFO FtInfo;
  997. DWORD Status;
  998. //
  999. // Get registry info.
  1000. //
  1001. FtInfo = DiskGetFtInfo();
  1002. if ( !FtInfo ) {
  1003. return ERROR_OUTOFMEMORY;
  1004. }
  1005. Status = FtInfo_GetFromFtInfo(Info, ResourceEntry, FtInfo, Result);
  1006. DiskFreeFtInfo(FtInfo);
  1007. if (Status != ERROR_SUCCESS) {
  1008. ++Result->MismatchCount;
  1009. }
  1010. return ERROR_SUCCESS;
  1011. }
  1012. DWORD
  1013. FtInfo_Set(
  1014. PMOUNTIE_INFO Info,
  1015. PDISK_RESOURCE ResourceEntry)
  1016. {
  1017. PFT_INFO ftInfo = FtInfo_CreateFromMountie(Info, ResourceEntry);
  1018. if (ftInfo) {
  1019. DWORD status = DiskCommitFtInfo(ftInfo);
  1020. if (status != ERROR_SUCCESS) {
  1021. (DiskpLogEvent)(
  1022. ResourceEntry->ResourceHandle,
  1023. LOG_ERROR,
  1024. L"FtInfo_Set: CommitFtInfo status = %1!u!.\n", status);
  1025. } else {
  1026. (DiskpLogEvent)(
  1027. ResourceEntry->ResourceHandle,
  1028. LOG_INFORMATION,
  1029. L"FtInfo_Set: Update successful.\n");
  1030. }
  1031. DiskFreeFtInfo(ftInfo);
  1032. return status;
  1033. } else {
  1034. DWORD status = GetLastError();
  1035. (DiskpLogEvent)(
  1036. ResourceEntry->ResourceHandle,
  1037. LOG_ERROR,
  1038. L"FtInfoSet: CreateFromMountie failed, status = %1!u!.\n", status);
  1039. return status;
  1040. }
  1041. }
  1042. DWORD
  1043. CluDiskInfo_Set(
  1044. PMOUNTIE_INFO Info,
  1045. PDISK_RESOURCE ResourceEntry)
  1046. {
  1047. PFT_INFO ftInfo = FtInfo_CreateFromMountie(Info, ResourceEntry);
  1048. if (ftInfo) {
  1049. PFULL_DISK_INFO DiskInfo;
  1050. DWORD Length;
  1051. DWORD Status;
  1052. DiskInfo = DiskGetFullDiskInfo( ftInfo,
  1053. ResourceEntry->DiskInfo.Params.Signature,
  1054. &Length );
  1055. if ( DiskInfo ) {
  1056. Status = ClusterRegSetValue(ResourceEntry->ResourceParametersKey,
  1057. DISKS_DISK_INFO,
  1058. REG_BINARY,
  1059. (CONST BYTE *)DiskInfo,
  1060. Length);
  1061. if (Status != ERROR_SUCCESS && Status != ERROR_SHARING_PAUSED) {
  1062. (DiskpLogEvent)(
  1063. ResourceEntry->ResourceHandle,
  1064. LOG_ERROR,
  1065. L"CluDiskInfo_Set: Data Length = %1!u!.\n", Length);
  1066. }
  1067. LocalFree( DiskInfo );
  1068. } else {
  1069. (DiskpLogEvent)(
  1070. ResourceEntry->ResourceHandle,
  1071. LOG_ERROR,
  1072. L"CluDiskInfo_Set: Disk with signature %1!x! is not found. Error=%2!u!\n", ResourceEntry->DiskInfo.Params.Signature, GetLastError());
  1073. Status = ERROR_FILE_NOT_FOUND;
  1074. }
  1075. DiskFreeFtInfo(ftInfo);
  1076. return Status;
  1077. } else {
  1078. (DiskpLogEvent)(
  1079. ResourceEntry->ResourceHandle,
  1080. LOG_ERROR,
  1081. L"CluDiskInfo_Set: Failed to create FtInfo.\n");
  1082. return GetLastError();
  1083. }
  1084. }
  1085. ////////////////////////////////////////////////////////
  1086. //
  1087. // New NT5 clusreg volume information access routines
  1088. //
  1089. // Mountie_Get
  1090. // Mountie_Set
  1091. //
  1092. //////////
  1093. DWORD
  1094. Mountie_Get(
  1095. PMOUNTIE_INFO Info,
  1096. PDISK_RESOURCE ResourceEntry,
  1097. PLETTER_ASSIGNMENT Result)
  1098. {
  1099. DWORD Length = 0; // Prefix bug 56153: initialize variable.
  1100. DWORD Status;
  1101. PMOUNTIE_VOLUME Volume = NULL;
  1102. DWORD i, n;
  1103. PMOUNTIE_PARTITION entry;
  1104. try {
  1105. //
  1106. // Read out the diskinfo parameter from our resource.
  1107. //
  1108. Status = ClusterRegQueryValue(ResourceEntry->ResourceParametersKey,
  1109. MOUNTIE_VOLUME_INFO,
  1110. NULL,
  1111. NULL,
  1112. &Length);
  1113. if (Status == ERROR_FILE_NOT_FOUND ) {
  1114. ++Result->MismatchCount;
  1115. Status = ERROR_SUCCESS;
  1116. leave;
  1117. }
  1118. //
  1119. // Prefix bug 56153: Make sure the length is valid before allocating
  1120. // memory.
  1121. //
  1122. if ( !Length ) {
  1123. Status = ERROR_BAD_LENGTH;
  1124. leave;
  1125. }
  1126. Volume = malloc(Length);
  1127. if (!Volume) {
  1128. Status = ERROR_OUTOFMEMORY;
  1129. leave;
  1130. }
  1131. Status = ClusterRegQueryValue(ResourceEntry->ResourceParametersKey,
  1132. MOUNTIE_VOLUME_INFO,
  1133. NULL,
  1134. (LPBYTE)Volume,
  1135. &Length);
  1136. if (Status != ERROR_SUCCESS) {
  1137. leave;
  1138. }
  1139. if (Length < sizeof(MOUNTIE_VOLUME) ) {
  1140. ++Result->MismatchCount;
  1141. (DiskpLogEvent)(
  1142. ResourceEntry->ResourceHandle,
  1143. LOG_ERROR,
  1144. L"Get: MountVolumeInfo key is truncated. Cannot read header, length %1!d!.\n", Length);
  1145. Status = ERROR_SUCCESS;
  1146. leave;
  1147. }
  1148. n = Volume->PartitionCount;
  1149. entry = Volume->Partition;
  1150. if (n == 0) {
  1151. ++Result->MismatchCount;
  1152. (DiskpLogEvent)(
  1153. ResourceEntry->ResourceHandle,
  1154. LOG_ERROR,
  1155. L"Get: MountVolumeInfo key is corrupted. No partitions.\n");
  1156. Status = ERROR_SUCCESS;
  1157. leave;
  1158. }
  1159. if ( Length < (sizeof(MOUNTIE_VOLUME) + (n-1) * sizeof(MOUNTIE_PARTITION)) ) {
  1160. DWORD delta = sizeof(MOUNTIE_VOLUME) + (n-1) * sizeof(MOUNTIE_PARTITION) - Length;
  1161. (DiskpLogEvent)(
  1162. ResourceEntry->ResourceHandle,
  1163. LOG_ERROR,
  1164. L"Get: MountVolumeInfo key is corrupted. "
  1165. L"Length %1!d!, PartitionCount %2!d!, delta %3!d!.\n", Length, n, delta);
  1166. ++Result->MismatchCount;
  1167. Status = ERROR_SUCCESS;
  1168. leave;
  1169. }
  1170. for (i = 0; i < n; ++i, ++entry) {
  1171. PMOUNTIE_PARTITION mountie;
  1172. mountie = MountiePartitionByOffsetAndLength(
  1173. Info,
  1174. entry->StartingOffset,
  1175. entry->PartitionLength);
  1176. if (mountie) {
  1177. UCHAR ch = (UCHAR)toupper( entry->DriveLetter );
  1178. if ( isalpha(ch) ) {
  1179. ch -= 'A';
  1180. Result->DriveLetters |= ( 1 << ch );
  1181. Result->PartNumber[ch] = (PARTITION_NUMBER_TYPE) mountie->PartitionNumber;
  1182. ++Result->MatchCount;
  1183. }
  1184. } else {
  1185. ++Result->MismatchCount;
  1186. }
  1187. }
  1188. } finally {
  1189. if (Status != ERROR_SUCCESS) {
  1190. ++Result->MismatchCount;
  1191. }
  1192. free(Volume);
  1193. }
  1194. return ERROR_SUCCESS;
  1195. }
  1196. DWORD
  1197. Mountie_Set(
  1198. PMOUNTIE_INFO Info,
  1199. PDISK_RESOURCE ResourceEntry)
  1200. {
  1201. DWORD Status = ClusterRegSetValue(ResourceEntry->ResourceParametersKey,
  1202. MOUNTIE_VOLUME_INFO,
  1203. REG_BINARY,
  1204. (LPBYTE)Info->Volume,
  1205. Info->VolumeStructSize);
  1206. return Status;
  1207. }
  1208. ///////////////////////////////////////////////////////////
  1209. //
  1210. // NT5 MountManager's volume information access routines
  1211. //
  1212. // MountMgr_Get
  1213. // MountMgr_Set
  1214. //
  1215. //////////
  1216. DWORD
  1217. MountMgr_Get(
  1218. PMOUNTIE_INFO Info,
  1219. PDISK_RESOURCE ResourceEntry,
  1220. PLETTER_ASSIGNMENT Result)
  1221. {
  1222. DWORD PartitionCount = Info->Volume->PartitionCount;
  1223. DWORD i;
  1224. DWORD error;
  1225. NTSTATUS ntStatus;
  1226. HANDLE MountManager;
  1227. ntStatus = DevfileOpen(&MountManager, MOUNTMGR_DEVICE_NAME);
  1228. if (!NT_SUCCESS(ntStatus)) {
  1229. if ( ResourceEntry ) {
  1230. (DiskpLogEvent)(
  1231. ResourceEntry->ResourceHandle,
  1232. LOG_ERROR,
  1233. L"Get: MountMgr open failed, status %1!X!.\n", ntStatus);
  1234. }
  1235. return RtlNtStatusToDosError(ntStatus);
  1236. }
  1237. error = ERROR_SUCCESS;
  1238. try {
  1239. for (i = 0; i < PartitionCount; ++i) {
  1240. PMOUNTIE_PARTITION entry = Info->Volume->Partition + i;
  1241. WCHAR DeviceName[MAX_PATH];
  1242. UCHAR ch;
  1243. swprintf(DeviceName, DEVICE_HARDDISK_PARTITION_FMT,
  1244. Info->HarddiskNo, entry->PartitionNumber);
  1245. ntStatus = GetAssignedLetterM(MountManager, DeviceName, &ch);
  1246. if ( NT_SUCCESS(ntStatus) ) {
  1247. if (Result && ch) {
  1248. ch -= 'A';
  1249. Result->DriveLetters |= ( 1 << ch );
  1250. Result->PartNumber[ch] = (PARTITION_NUMBER_TYPE) entry->PartitionNumber;
  1251. ++Result->MatchCount;
  1252. }
  1253. } else {
  1254. if ( ResourceEntry ) {
  1255. (DiskpLogEvent)(
  1256. ResourceEntry->ResourceHandle,
  1257. LOG_ERROR,
  1258. L"Get Assigned Letter for %1!ws! returned status %2!X!.\n", DeviceName, ntStatus);
  1259. }
  1260. error = RtlNtStatusToDosError(ntStatus);
  1261. leave;
  1262. }
  1263. }
  1264. } finally {
  1265. DevfileClose(MountManager);
  1266. }
  1267. return error;
  1268. }
  1269. DWORD
  1270. MountMgr_Set(
  1271. PMOUNTIE_INFO Info,
  1272. PDISK_RESOURCE ResourceEntry
  1273. )
  1274. {
  1275. HANDLE MountManager;
  1276. DWORD PartitionCount = Info->Volume->PartitionCount;
  1277. DWORD i, status;
  1278. UCHAR dosName[3];
  1279. NTSTATUS ntStatus;
  1280. (DiskpLogEvent)(
  1281. ResourceEntry->ResourceHandle,
  1282. LOG_INFORMATION,
  1283. L"MountMgr_Set: Entry\n");
  1284. ntStatus = DevfileOpen(&MountManager, MOUNTMGR_DEVICE_NAME);
  1285. if (!NT_SUCCESS(ntStatus)) {
  1286. (DiskpLogEvent)(
  1287. ResourceEntry->ResourceHandle,
  1288. LOG_ERROR,
  1289. L"Set: MountMgr open failed, status %1!X!.\n", ntStatus);
  1290. return RtlNtStatusToDosError(ntStatus);
  1291. }
  1292. try {
  1293. dosName[1] = ':';
  1294. dosName[2] = '\0';
  1295. //
  1296. // Remove old assignment of letters we are going to use
  1297. //
  1298. for (i = 0; i < 26; ++i) {
  1299. if ( (1 << i) & Info->DriveLetters ) {
  1300. dosName[0] = (UCHAR)('A' + i);
  1301. status = DisksRemoveDosDeviceM(MountManager, dosName);
  1302. (DiskpLogEvent)(
  1303. ResourceEntry->ResourceHandle,
  1304. LOG_INFORMATION,
  1305. L"MountMgr_Set: Remove Dos Device, letter=%1!c!, status=%2!u!\n",
  1306. NICE_DRIVE_LETTER(dosName[0]), status);
  1307. }
  1308. }
  1309. for (i = 0; i < PartitionCount; ++i) {
  1310. PMOUNTIE_PARTITION entry = Info->Volume->Partition + i;
  1311. WCHAR DeviceName[MAX_PATH];
  1312. UCHAR ch;
  1313. swprintf(DeviceName, DEVICE_HARDDISK_PARTITION_FMT,
  1314. Info->HarddiskNo, entry->PartitionNumber);
  1315. ntStatus = GetAssignedLetterM(MountManager, DeviceName, &ch);
  1316. if ( NT_SUCCESS(ntStatus) && ch) {
  1317. dosName[0] = ch;
  1318. status = DisksRemoveDosDeviceM(MountManager, dosName);
  1319. (DiskpLogEvent)(
  1320. ResourceEntry->ResourceHandle,
  1321. LOG_INFORMATION,
  1322. L"MountMgr_Set: Remove Dos Device 2, letter=%1!c!, status=%2!u!\n",
  1323. NICE_DRIVE_LETTER(dosName[0]), status);
  1324. }
  1325. if (entry->DriveLetter) {
  1326. dosName[0] = entry->DriveLetter;
  1327. status = DisksAssignDosDeviceM(MountManager, dosName, DeviceName);
  1328. (DiskpLogEvent)(
  1329. ResourceEntry->ResourceHandle,
  1330. LOG_INFORMATION,
  1331. L"MountMgr_Set: Assign Dos Device, letter=%1!c!, status=%2!u!\n",
  1332. NICE_DRIVE_LETTER(dosName[0]), status);
  1333. }
  1334. }
  1335. } finally {
  1336. DevfileClose( MountManager );
  1337. }
  1338. return ERROR_SUCCESS;
  1339. }
  1340. /////////////////////////////////////////////////////////////////////////
  1341. //
  1342. // information providers table
  1343. //
  1344. // Disk\Information has to be the last entry of the table
  1345. //
  1346. // Order of the entries is important
  1347. //
  1348. /////////////////////////////////////////////////////////////////
  1349. INFO_PROVIDER Providers[] = {
  1350. {L"ClusReg-DiskInfo", CluDiskInfo_Get, CluDiskInfo_Set},
  1351. {L"ClusReg-Mountie", Mountie_Get, Mountie_Set},
  1352. {L"MountMgr", MountMgr_Get, MountMgr_Set},
  1353. {L"Registry-System\\DISK", FtInfo_Get, FtInfo_Set}, // Disk\Information must be the last (Why?)
  1354. };
  1355. enum {
  1356. PROVIDER_COUNT = sizeof(Providers)/sizeof(Providers[0]),
  1357. MOUNT_MANAGER = PROVIDER_COUNT - 2,
  1358. };
  1359. DWORD
  1360. MountieUpdate(
  1361. PMOUNTIE_INFO info,
  1362. PDISK_RESOURCE ResourceEntry)
  1363. /*++
  1364. Routine Description:
  1365. Update disk information for all providers
  1366. marked in NeedsUpdate bitmask
  1367. Inputs:
  1368. Info - MountieInfo
  1369. --*/
  1370. {
  1371. DWORD NeedsUpdate = info->NeedsUpdate;
  1372. BOOLEAN SharingPausedError = FALSE;
  1373. DWORD LastError = ERROR_SUCCESS;
  1374. INT i;
  1375. if (!NeedsUpdate) {
  1376. return ERROR_SUCCESS;
  1377. }
  1378. for (i = 0; i < PROVIDER_COUNT; ++i) {
  1379. if ( (1 << i) & NeedsUpdate ) {
  1380. DWORD status;
  1381. status = Providers[i].SetInfo(info, ResourceEntry);
  1382. if (status != ERROR_SUCCESS) {
  1383. (DiskpLogEvent)(
  1384. ResourceEntry->ResourceHandle,
  1385. LOG_INFORMATION,
  1386. L"MountieUpdate: %1!ws!.SetInfo failed, error %2!u!.\n", Providers[i].Name, status);
  1387. if (status == ERROR_SHARING_PAUSED) {
  1388. SharingPausedError = TRUE;
  1389. } else {
  1390. LastError = status;
  1391. }
  1392. } else {
  1393. NeedsUpdate &= ~(1 << i);
  1394. }
  1395. }
  1396. }
  1397. (DiskpLogEvent)(
  1398. ResourceEntry->ResourceHandle,
  1399. LOG_INFORMATION,
  1400. L"MountieUpdate: Update needed for %1!02x!.\n", NeedsUpdate);
  1401. info->NeedsUpdate = NeedsUpdate;
  1402. if (NeedsUpdate) {
  1403. if (SharingPausedError) {
  1404. return ERROR_SHARING_PAUSED;
  1405. }
  1406. return LastError;
  1407. }
  1408. return ERROR_SUCCESS;
  1409. }
  1410. DWORD
  1411. MountieVerify(
  1412. PMOUNTIE_INFO info,
  1413. PDISK_RESOURCE ResourceEntry,
  1414. BOOL UseMountMgr
  1415. )
  1416. /*++
  1417. Routine Description:
  1418. 1. Compares information from all
  1419. providers and select one of them as source of
  1420. drive letter assignment.
  1421. 2. Update MountieInfo with this drive letter assignment
  1422. 3. Set NeedsUpdate for every provider whose information
  1423. differ from the MountieInfo
  1424. Inputs:
  1425. Info - MountieInfo
  1426. --*/
  1427. {
  1428. LETTER_ASSIGNMENT results[PROVIDER_COUNT + 1];
  1429. INT i;
  1430. INT GoodProvider = -1;
  1431. INT BestProvider = -1;
  1432. DWORD BestMatch = 0;
  1433. INT PartitionCount;
  1434. DWORD DriveLetters;
  1435. BOOLEAN UnassignedPartitions = FALSE;
  1436. DWORD NeedsUpdate = 0;
  1437. DWORD errorLevel;
  1438. if (!info->Volume || info->Volume->PartitionCount == 0) {
  1439. (DiskpLogEvent)(
  1440. ResourceEntry->ResourceHandle,
  1441. LOG_ERROR,
  1442. L"FatalError: Bad Mountie Info.\n");
  1443. return ERROR_INVALID_HANDLE;
  1444. }
  1445. PartitionCount = info->Volume->PartitionCount;
  1446. //
  1447. // Clear old DriveLetters in MOUNTIE_INFO
  1448. //
  1449. for (i = 0; i < PartitionCount; ++i) {
  1450. info->Volume->Partition[i].DriveLetter = 0;
  1451. }
  1452. //
  1453. // Collect Letter Assignments from Providers
  1454. //
  1455. RtlZeroMemory( results, sizeof(results) );
  1456. for (i = PROVIDER_COUNT; --i >= 0;) {
  1457. DWORD status;
  1458. status = Providers[i].GetInfo(info, ResourceEntry, results + i);
  1459. if (status != ERROR_SUCCESS) {
  1460. (DiskpLogEvent)(
  1461. ResourceEntry->ResourceHandle,
  1462. LOG_INFORMATION,
  1463. L"MountieVerify: %1!ws!.GetInfo returned %2!u! [%3!u!:%4!u!].\n",
  1464. Providers[i].Name, status, results[i].MatchCount, results[i].MismatchCount);
  1465. return status;
  1466. }
  1467. if (results[i].MatchCount && !results[i].MismatchCount) {
  1468. GoodProvider = i;
  1469. if (results[i].MatchCount >= BestMatch) {
  1470. BestProvider = i;
  1471. BestMatch = results[i].MatchCount;
  1472. }
  1473. } else {
  1474. (DiskpLogEvent)(
  1475. ResourceEntry->ResourceHandle,
  1476. LOG_INFORMATION,
  1477. L"MountieVerify: %1!ws!.GetInfo returned %2!u! [%3!u!:%4!u!].\n",
  1478. Providers[i].Name, status, results[i].MatchCount, results[i].MismatchCount);
  1479. }
  1480. }
  1481. if (GoodProvider < 0 || GoodProvider >= PROVIDER_COUNT) {
  1482. if ( !DisksGetLettersForSignature( ResourceEntry ) ) {
  1483. // No drive letters, we are using mount points and this is not an error.
  1484. errorLevel = LOG_WARNING;
  1485. } else {
  1486. // Drive letters exist, this is likely an error.
  1487. errorLevel = LOG_ERROR;
  1488. }
  1489. (DiskpLogEvent)(
  1490. ResourceEntry->ResourceHandle,
  1491. errorLevel,
  1492. L"MountieVerify: No good providers: %1!d!. \n", GoodProvider);
  1493. return ERROR_INVALID_HANDLE;
  1494. }
  1495. if (UseMountMgr) {
  1496. GoodProvider = MOUNT_MANAGER;
  1497. }
  1498. (DiskpLogEvent)(
  1499. ResourceEntry->ResourceHandle,
  1500. LOG_INFORMATION,
  1501. L"MountieVerify: %1!ws! selected.\n",
  1502. Providers[GoodProvider].Name);
  1503. if (GoodProvider != BestProvider) {
  1504. (DiskpLogEvent)(
  1505. ResourceEntry->ResourceHandle,
  1506. LOG_WARNING,
  1507. L"MountieVerify: %1!ws! is better.\n",
  1508. Providers[BestProvider].Name);
  1509. }
  1510. //
  1511. // Now GoodProvider now holds an index of the highest
  1512. // provider with non stale information.
  1513. //
  1514. // Copy its letter assignment to a MOUNTIE_INFO
  1515. //
  1516. for (i = 0; i < PartitionCount; ++i) {
  1517. UCHAR ch = AssignedLetterByPartitionNumber(
  1518. results + GoodProvider,
  1519. info->Volume->Partition[i].PartitionNumber);
  1520. info->Volume->Partition[i].DriveLetter = ch;
  1521. if (!ch) {
  1522. UnassignedPartitions = TRUE;
  1523. }
  1524. }
  1525. #if 0
  1526. // No need to assign drive letters, since now we understand
  1527. // PnP
  1528. if (UnassignedPartitions) {
  1529. //
  1530. // Now give some arbitrary letter assignment to all
  1531. // partitions without a drive letter
  1532. //
  1533. DriveLetters = GetLogicalDrives();
  1534. if (!DriveLetters) {
  1535. (DiskpLogEvent)(
  1536. ResourceEntry->ResourceHandle,
  1537. LOG_ERROR,
  1538. L"GetLogicalDrivers failed, error %u.\n", GetLastError() );
  1539. } else {
  1540. DWORD Letter = 0;
  1541. DriveLetters &= ~results[MOUNT_MANAGER].DriveLetters;
  1542. DriveLetters |= results[GoodProvider].DriveLetters;
  1543. DriveLetters |= 3; // Consider A and B drive letters busy //
  1544. for (i = 0; i < PartitionCount; ++i) {
  1545. PUCHAR pch = &info->Volume->Partition[i].DriveLetter;
  1546. if (!*pch) {
  1547. while( (1 << Letter) & DriveLetters ){
  1548. if (++Letter == 26) {
  1549. goto no_more_letters;
  1550. }
  1551. }
  1552. *pch = (UCHAR) ('A' + Letter);
  1553. if (++Letter == 26) {
  1554. break;
  1555. }
  1556. }
  1557. }
  1558. no_more_letters:;
  1559. }
  1560. }
  1561. #endif
  1562. // Update Drive Letters Mask //
  1563. MountieUpdateDriveLetters(info);
  1564. (DiskpLogEvent)(
  1565. ResourceEntry->ResourceHandle,
  1566. LOG_INFORMATION,
  1567. L"MountieVerify: DriveLetters mask is now %1!08x!.\n", info->DriveLetters );
  1568. //
  1569. // At this point MOUNTIE_INFO has a complete letter assignment
  1570. // for all partitions
  1571. //
  1572. // Now let's find which Providers needs to be updated
  1573. //
  1574. for (i = 0; i < PartitionCount; ++i) {
  1575. PMOUNTIE_PARTITION entry = info->Volume->Partition + i;
  1576. if (entry->DriveLetter) {
  1577. results[PROVIDER_COUNT].PartNumber[ entry->DriveLetter - 'A' ] =
  1578. (PARTITION_NUMBER_TYPE) entry->PartitionNumber;
  1579. }
  1580. }
  1581. results[PROVIDER_COUNT].DriveLetters = info->DriveLetters;
  1582. //
  1583. // All provides whose entries are different from results[PROVIDER_COUNT]
  1584. // need to be updated
  1585. //
  1586. for (i = 0; i < PROVIDER_COUNT; ++i) {
  1587. if (results[i].DriveLetters != results[PROVIDER_COUNT].DriveLetters
  1588. || results[i].MismatchCount
  1589. || 0 != memcmp(results[i].PartNumber,
  1590. results[PROVIDER_COUNT].PartNumber, sizeof(results[i].PartNumber) )
  1591. )
  1592. {
  1593. NeedsUpdate |= (1 << i);
  1594. }
  1595. }
  1596. info->NeedsUpdate = NeedsUpdate;
  1597. if (NeedsUpdate) {
  1598. (DiskpLogEvent)(
  1599. ResourceEntry->ResourceHandle,
  1600. LOG_INFORMATION,
  1601. L"MountieVerify: Update needed for %1!02x!.\n", NeedsUpdate);
  1602. //
  1603. // Chittur Subbaraman (chitturs) - 11/5/98
  1604. //
  1605. // If you plan to update the cluster registry values with info
  1606. // from the other providers, then log a warning to the event log.
  1607. //
  1608. if ( ( NeedsUpdate & 0x0003 ) && (GoodProvider == 2) && !UseMountMgr )
  1609. {
  1610. WCHAR szNewDriveLetterList[55];
  1611. WCHAR szOriginalDriveLetterList[55];
  1612. DWORD j = 0, k = 0;
  1613. for (i = 0; i < 26; ++i) {
  1614. if ( (1 << i) & results[PROVIDER_COUNT].DriveLetters ) {
  1615. szNewDriveLetterList[j] = (WCHAR)(L'A' + i);
  1616. szNewDriveLetterList[j+1] = L' ';
  1617. j += 2;
  1618. }
  1619. if ( (1 << i) & results[0].DriveLetters ) {
  1620. szOriginalDriveLetterList[k] = (WCHAR)(L'A' + i);
  1621. szOriginalDriveLetterList[k+1] = L' ';
  1622. k += 2;
  1623. }
  1624. }
  1625. szNewDriveLetterList[j] = L'\0';
  1626. szOriginalDriveLetterList[k] = L'\0';
  1627. //
  1628. // GorN. 8/25/99.
  1629. //
  1630. // Log the event only if OriginalDriveLetterList is empty.
  1631. //
  1632. if ( results[PROVIDER_COUNT].DriveLetters ) {
  1633. ClusResLogSystemEventByKey2( ResourceEntry->ResourceKey,
  1634. LOG_NOISE,
  1635. RES_DISK_WRITING_TO_CLUSREG,
  1636. szOriginalDriveLetterList,
  1637. szNewDriveLetterList
  1638. );
  1639. }
  1640. }
  1641. }
  1642. return ERROR_SUCCESS;
  1643. }
  1644. DWORD VolumesReady(
  1645. IN PMOUNTIE_INFO Info,
  1646. IN PDISK_RESOURCE ResourceEntry
  1647. )
  1648. /*++
  1649. Routine Description:
  1650. Checks whether each partition described in the MountieInfo can be seen by the
  1651. Mount Manager.
  1652. Inputs:
  1653. --*/
  1654. {
  1655. PMOUNTIE_PARTITION entry;
  1656. DWORD status = NO_ERROR;
  1657. DWORD nPartitions = MountiePartitionCount( Info );
  1658. DWORD i;
  1659. DWORD physicalDrive = ResourceEntry->DiskInfo.PhysicalDrive;
  1660. WCHAR szGlobalDiskPartName[MAX_PATH];
  1661. WCHAR szVolumeName[MAX_PATH];
  1662. for ( i = 0; i < nPartitions; ++i ) {
  1663. entry = MountiePartition( Info, i );
  1664. if ( !entry ) {
  1665. (DiskpLogEvent)(
  1666. ResourceEntry->ResourceHandle,
  1667. LOG_ERROR,
  1668. L"VolumesReady: no partition entry for partition %1!u! \n", i );
  1669. //
  1670. // Something bad happened to our data structures. Stop processing and
  1671. // return error.
  1672. //
  1673. status = ERROR_INVALID_DATA;
  1674. break;
  1675. }
  1676. //
  1677. // Given the DiskPartName, get the VolGuid name. This name must have a trailing
  1678. // backslash to work correctly.
  1679. //
  1680. _snwprintf( szGlobalDiskPartName,
  1681. MAX_PATH,
  1682. GLOBALROOT_HARDDISK_PARTITION_FMT,
  1683. physicalDrive,
  1684. entry->PartitionNumber );
  1685. if ( !GetVolumeNameForVolumeMountPointW( szGlobalDiskPartName,
  1686. szVolumeName,
  1687. sizeof(szVolumeName)/sizeof(WCHAR) )) {
  1688. status = GetLastError();
  1689. (DiskpLogEvent)(
  1690. ResourceEntry->ResourceHandle,
  1691. LOG_ERROR,
  1692. L"VolumesReady: GetVolumeNameForVolumeMountPoint for %1!ws! returned %2!u!\n",
  1693. szGlobalDiskPartName,
  1694. status );
  1695. //
  1696. // Something bad happened - stop checking this disk. Return the
  1697. // error status we received.
  1698. //
  1699. break;
  1700. }
  1701. //
  1702. // If we get here, this volume is recognized by the Mount Manager.
  1703. //
  1704. }
  1705. return status;
  1706. } // VolumesReady
  1707. NTSTATUS
  1708. GetAssignedLetter (
  1709. PWCHAR deviceName,
  1710. PCHAR driveLetter )
  1711. {
  1712. HANDLE MountMgrHandle = NULL;
  1713. DWORD status = DevfileOpen( &MountMgrHandle, MOUNTMGR_DEVICE_NAME );
  1714. if (driveLetter) {
  1715. *driveLetter = 0;
  1716. }
  1717. if ( NT_SUCCESS(status) && MountMgrHandle ) {
  1718. status = GetAssignedLetterM(MountMgrHandle, deviceName, driveLetter);
  1719. DevfileClose(MountMgrHandle);
  1720. }
  1721. return status;
  1722. }