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.

1479 lines
44 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. spdskreg.c
  5. Abstract:
  6. Code for building and manipulating the disk registry. Used in the Win9x Upgrade
  7. case.
  8. Author:
  9. Marc R. Whitten (marcw) 11-Mar-1997
  10. Revision History:
  11. --*/
  12. #include "spprecmp.h"
  13. #pragma hdrstop
  14. PUCHAR DiskRegistryKey = DISK_REGISTRY_KEY;
  15. PUCHAR DiskRegistryClass = "Disk and fault tolerance information.";
  16. PUCHAR DiskRegistryValue = DISK_REGISTRY_VALUE;
  17. #define WORK_BUFFER_SIZE 4096
  18. //
  19. // In spw9xupg.c - Should be moved to a header file.
  20. //
  21. PDISK_REGION
  22. SpFirstPartitionedRegion (
  23. IN PDISK_REGION Region,
  24. IN BOOLEAN Primary
  25. );
  26. PDISK_REGION
  27. SpNextPartitionedRegion (
  28. IN PDISK_REGION Region,
  29. IN BOOLEAN Primary
  30. );
  31. //
  32. // In spupgcfg.c
  33. //
  34. NTSTATUS
  35. SppCopyKeyRecursive(
  36. HANDLE hKeyRootSrc,
  37. HANDLE hKeyRootDst,
  38. PWSTR SrcKeyPath, OPTIONAL
  39. PWSTR DstKeyPath, OPTIONAL
  40. BOOLEAN CopyAlways,
  41. BOOLEAN ApplyACLsAlways
  42. );
  43. //
  44. // wrapper functions to allow linking with diskreg.lib.
  45. //
  46. //
  47. // Have to turn off this warning temporarily.
  48. //
  49. #define TESTANDFREE(Memory) {if (Memory) {SpMemFree(Memory);}}
  50. NTSTATUS
  51. FtCreateKey(
  52. PHANDLE HandlePtr,
  53. PUCHAR KeyName,
  54. PUCHAR KeyClass
  55. )
  56. {
  57. NTSTATUS status;
  58. STRING keyString;
  59. UNICODE_STRING unicodeKeyName;
  60. STRING classString;
  61. UNICODE_STRING unicodeClassName;
  62. OBJECT_ATTRIBUTES objectAttributes;
  63. ULONG disposition;
  64. HANDLE tempHandle;
  65. //
  66. // Initialize the object for the key.
  67. //
  68. RtlInitString(&keyString,
  69. KeyName);
  70. (VOID)RtlAnsiStringToUnicodeString(&unicodeKeyName,
  71. &keyString,
  72. TRUE);
  73. memset(&objectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
  74. InitializeObjectAttributes(&objectAttributes,
  75. &unicodeKeyName,
  76. OBJ_CASE_INSENSITIVE,
  77. NULL,
  78. NULL);
  79. //
  80. // Setup the unicode class value.
  81. //
  82. RtlInitString(&classString,
  83. KeyClass);
  84. (VOID)RtlAnsiStringToUnicodeString(&unicodeClassName,
  85. &classString,
  86. TRUE);
  87. //
  88. // Create the key.
  89. //
  90. status = ZwCreateKey(&tempHandle,
  91. KEY_READ | KEY_WRITE,
  92. &objectAttributes,
  93. 0,
  94. &unicodeClassName,
  95. REG_OPTION_NON_VOLATILE,
  96. &disposition);
  97. if (NT_SUCCESS(status)) {
  98. switch (disposition)
  99. {
  100. case REG_CREATED_NEW_KEY:
  101. break;
  102. case REG_OPENED_EXISTING_KEY:
  103. break;
  104. default:
  105. break;
  106. }
  107. }
  108. //
  109. // Free all allocated space.
  110. //
  111. RtlFreeUnicodeString(&unicodeKeyName);
  112. RtlFreeUnicodeString(&unicodeClassName);
  113. if (HandlePtr != NULL) {
  114. *HandlePtr = tempHandle;
  115. } else {
  116. NtClose(tempHandle);
  117. }
  118. return status;
  119. }
  120. NTSTATUS
  121. FtOpenKey(
  122. PHANDLE HandlePtr,
  123. PUCHAR KeyName,
  124. PUCHAR CreateKeyClass
  125. )
  126. {
  127. NTSTATUS status;
  128. STRING keyString;
  129. OBJECT_ATTRIBUTES objectAttributes;
  130. UNICODE_STRING unicodeKeyName;
  131. RtlInitString(&keyString,
  132. KeyName);
  133. (VOID)RtlAnsiStringToUnicodeString(&unicodeKeyName,
  134. &keyString,
  135. TRUE);
  136. memset(&objectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
  137. InitializeObjectAttributes(&objectAttributes,
  138. &unicodeKeyName,
  139. OBJ_CASE_INSENSITIVE,
  140. NULL,
  141. NULL);
  142. status = ZwOpenKey(HandlePtr,
  143. MAXIMUM_ALLOWED,
  144. &objectAttributes);
  145. RtlFreeUnicodeString(&unicodeKeyName);
  146. if ((!NT_SUCCESS(status)) && (CreateKeyClass)) {
  147. status = FtCreateKey(HandlePtr,
  148. KeyName,
  149. CreateKeyClass);
  150. }
  151. return status;
  152. }
  153. NTSTATUS
  154. FtRegistryQuery(
  155. IN PUCHAR ValueName,
  156. OUT PVOID *FreeToken,
  157. OUT PVOID *Buffer,
  158. OUT ULONG *LengthReturned,
  159. OUT PHANDLE HandlePtr
  160. )
  161. {
  162. NTSTATUS status;
  163. HANDLE handle;
  164. ULONG resultLength;
  165. STRING valueString;
  166. UNICODE_STRING unicodeValueName;
  167. PDISK_CONFIG_HEADER regHeader;
  168. PKEY_VALUE_FULL_INFORMATION keyValueInformation= NULL;
  169. *LengthReturned = 0;
  170. status = FtOpenKey(&handle,
  171. DiskRegistryKey,
  172. NULL);
  173. if (NT_SUCCESS(status)) {
  174. RtlInitString(&valueString,
  175. ValueName);
  176. RtlAnsiStringToUnicodeString(&unicodeValueName,
  177. &valueString,
  178. TRUE);
  179. resultLength = WORK_BUFFER_SIZE;
  180. while (1) {
  181. keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)
  182. SpMemAlloc(resultLength);
  183. status = ZwQueryValueKey(handle,
  184. &unicodeValueName,
  185. KeyValueFullInformation,
  186. keyValueInformation,
  187. resultLength,
  188. &resultLength);
  189. if (status == STATUS_BUFFER_OVERFLOW) {
  190. TESTANDFREE(keyValueInformation);
  191. //
  192. // Loop again and get a larger buffer.
  193. //
  194. } else {
  195. //
  196. // Either a real error or the information fit.
  197. //
  198. break;
  199. }
  200. }
  201. RtlFreeUnicodeString(&unicodeValueName);
  202. if (HandlePtr != NULL) {
  203. *HandlePtr = handle;
  204. } else {
  205. NtClose(handle);
  206. }
  207. if (NT_SUCCESS(status)) {
  208. if (keyValueInformation->DataLength == 0) {
  209. //
  210. // Treat this as if there was not disk information.
  211. //
  212. TESTANDFREE(keyValueInformation);
  213. *FreeToken = (PVOID) NULL;
  214. return STATUS_OBJECT_NAME_NOT_FOUND;
  215. } else {
  216. //
  217. // Set up the pointers for the caller.
  218. //
  219. regHeader = (PDISK_CONFIG_HEADER)
  220. ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset);
  221. *LengthReturned = regHeader->FtInformationOffset +
  222. regHeader->FtInformationSize;
  223. *Buffer = (PVOID) regHeader;
  224. }
  225. }
  226. *FreeToken = (PVOID) keyValueInformation;
  227. } else {
  228. *FreeToken = (PVOID) NULL;
  229. }
  230. return status;
  231. }
  232. NTSTATUS
  233. FtSetValue(
  234. HANDLE KeyHandle,
  235. PUCHAR ValueName,
  236. PVOID DataBuffer,
  237. ULONG DataLength,
  238. ULONG Type
  239. )
  240. {
  241. NTSTATUS status;
  242. STRING valueString;
  243. UNICODE_STRING unicodeValueName;
  244. RtlInitString(&valueString,
  245. ValueName);
  246. RtlAnsiStringToUnicodeString(&unicodeValueName,
  247. &valueString,
  248. TRUE);
  249. status = ZwSetValueKey(KeyHandle,
  250. &unicodeValueName,
  251. 0,
  252. Type,
  253. DataBuffer,
  254. DataLength);
  255. RtlFreeUnicodeString(&unicodeValueName);
  256. return status;
  257. }
  258. NTSTATUS
  259. FtDeleteValue(
  260. HANDLE KeyHandle,
  261. PUCHAR ValueName
  262. )
  263. {
  264. NTSTATUS status;
  265. STRING valueString;
  266. UNICODE_STRING unicodeValueName;
  267. RtlInitString(&valueString,
  268. ValueName);
  269. status = RtlAnsiStringToUnicodeString(&unicodeValueName,
  270. &valueString,
  271. TRUE);
  272. if (!NT_SUCCESS(status)) {
  273. return status;
  274. }
  275. status = ZwDeleteValueKey(KeyHandle,
  276. &unicodeValueName);
  277. RtlFreeUnicodeString(&unicodeValueName);
  278. return status;
  279. }
  280. VOID
  281. FtBackup(
  282. IN HANDLE KeyHandle
  283. )
  284. {
  285. //
  286. // For the time being (i.e. rename doesn't work), just attempt
  287. // to delete the value.
  288. //
  289. (VOID) FtDeleteValue(KeyHandle,
  290. DiskRegistryKey);
  291. }
  292. BOOLEAN
  293. SpDiskRegistryAssignDriveLetter(
  294. ULONG Signature,
  295. LARGE_INTEGER StartingOffset,
  296. LARGE_INTEGER Length,
  297. UCHAR DriveLetter
  298. )
  299. /*++
  300. Routine Description:
  301. This routine will get the information from the disk registry
  302. and update the drive letter assigned for the partition in
  303. the registry information. This includes any cleanup for FT
  304. sets when they change drive letter.
  305. Arguments:
  306. Signature - disk signature for disk containing partition for letter.
  307. StartingOffset - Starting offset of partition for the letter.
  308. Length - lenght of affected partition.
  309. DriveLetter - New drive letter for affected partition.
  310. Return Value:
  311. TRUE if all works.
  312. --*/
  313. {
  314. BOOLEAN writeRegistry= FALSE;
  315. PVOID freeToken = NULL;
  316. ULONG lengthReturned,
  317. i,
  318. j,
  319. k,
  320. l;
  321. NTSTATUS status;
  322. USHORT type,
  323. group;
  324. PDISK_CONFIG_HEADER regHeader;
  325. PDISK_REGISTRY diskRegistry;
  326. PDISK_DESCRIPTION diskDescription;
  327. PDISK_PARTITION diskPartition;
  328. PUCHAR endOfDiskInfo;
  329. HANDLE handle;
  330. PFT_REGISTRY ftRegistry;
  331. PFT_DESCRIPTION ftDescription;
  332. PFT_MEMBER_DESCRIPTION ftMember;
  333. //
  334. // Get the registry information.
  335. //
  336. status = FtRegistryQuery(DiskRegistryValue,
  337. &freeToken,
  338. (PVOID *) &regHeader,
  339. &lengthReturned,
  340. &handle);
  341. if (!NT_SUCCESS(status)) {
  342. //
  343. // Could be permission problem, or there is no registry information.
  344. //
  345. lengthReturned = 0;
  346. //
  347. // Try to open the key for later use when setting the new value.
  348. //
  349. status = FtOpenKey(&handle,
  350. DiskRegistryKey,
  351. NULL);
  352. }
  353. if (!NT_SUCCESS(status)) {
  354. //
  355. // There is no registry key for the disk information.
  356. // Return FALSE and force caller to create registry information.
  357. //
  358. return FALSE;
  359. }
  360. if (lengthReturned == 0) {
  361. //
  362. // There is currently no registry information.
  363. //
  364. NtClose(handle);
  365. TESTANDFREE(freeToken);
  366. return FALSE;
  367. }
  368. //
  369. // Search for the disk signature.
  370. //
  371. diskRegistry = (PDISK_REGISTRY)
  372. ((PUCHAR)regHeader + regHeader->DiskInformationOffset);
  373. diskDescription = &diskRegistry->Disks[0];
  374. for (i = 0; i < diskRegistry->NumberOfDisks; i++) {
  375. if (diskDescription->Signature == Signature) {
  376. //
  377. // Now locate the partition.
  378. //
  379. for (j = 0; j < diskDescription->NumberOfPartitions; j++) {
  380. diskPartition = &diskDescription->Partitions[j];
  381. if ((StartingOffset.QuadPart == diskPartition->StartingOffset.QuadPart) &&
  382. (Length.QuadPart == diskPartition->Length.QuadPart)) {
  383. if (diskPartition->FtType == NotAnFtMember) {
  384. //
  385. // Found the affected partition simple partition
  386. // i.e. not a part of an FT set.
  387. //
  388. writeRegistry= TRUE;
  389. if (DriveLetter == ' ') {
  390. diskPartition->AssignDriveLetter = FALSE;
  391. } else {
  392. diskPartition->AssignDriveLetter = TRUE;
  393. }
  394. diskPartition->DriveLetter = DriveLetter;
  395. } else {
  396. //
  397. // For FT sets work from the FT information area,
  398. // not from this partition location.
  399. //
  400. type = diskPartition->FtType;
  401. group = diskPartition->FtGroup;
  402. if (!regHeader->FtInformationOffset) {
  403. //
  404. // This is really a corrupt hive! The partition
  405. // affected is part of an FT set, but there is no
  406. // FT information.
  407. //
  408. NtClose(handle);
  409. TESTANDFREE(freeToken);
  410. return FALSE;
  411. }
  412. //
  413. // This is an FT set member, must correct the
  414. // drive letter for all FT set members in the
  415. // registry.
  416. //
  417. ftRegistry = (PFT_REGISTRY)
  418. ((PUCHAR)regHeader + regHeader->FtInformationOffset);
  419. ftDescription = &ftRegistry->FtDescription[0];
  420. for (k = 0; k < ftRegistry->NumberOfComponents; k++) {
  421. if (ftDescription->Type == type) {
  422. //
  423. // For each member, chase back to the diskPartition
  424. // information and if this is the correct FtGroup
  425. // update the drive letter.
  426. //
  427. for (l = 0; l < ftDescription->NumberOfMembers; l++) {
  428. ftMember = &ftDescription->FtMemberDescription[l];
  429. diskPartition = (PDISK_PARTITION)
  430. ((PUCHAR)regHeader + ftMember->OffsetToPartitionInfo);
  431. //
  432. // This could be a different FtGroup for the
  433. // same FT type. Check the group before
  434. // changing.
  435. //
  436. if (diskPartition->FtGroup == group) {
  437. writeRegistry= TRUE;
  438. diskPartition->DriveLetter = DriveLetter;
  439. //
  440. // Maintain the AssignDriveLetter flag on
  441. // the zero member of the set only.
  442. //
  443. if (diskPartition->FtMember == 0) {
  444. if (DriveLetter == ' ') {
  445. diskPartition->AssignDriveLetter = FALSE;
  446. } else {
  447. diskPartition->AssignDriveLetter = TRUE;
  448. }
  449. }
  450. } else {
  451. //
  452. // Not the same group, go to the next
  453. // FT set description.
  454. //
  455. break;
  456. }
  457. }
  458. //
  459. // break out to write the registry information
  460. // once the correct set has been found.
  461. //
  462. if (writeRegistry) {
  463. break;
  464. }
  465. }
  466. ftDescription = (PFT_DESCRIPTION)
  467. &ftDescription->FtMemberDescription[ftDescription->NumberOfMembers];
  468. }
  469. //
  470. // If this actually falls through as opposed to the
  471. // break statement in the for loop above, it indicates a
  472. // bad disk information structure.
  473. //
  474. }
  475. //
  476. // Only write this back out if it is believed that things
  477. // worked correctly.
  478. //
  479. if (writeRegistry) {
  480. //
  481. // All done with setting new drive letter in registry.
  482. // Backup the previous value.
  483. //
  484. FtBackup(handle);
  485. //
  486. // Set the new value.
  487. //
  488. status = FtSetValue(handle,
  489. DiskRegistryValue,
  490. regHeader,
  491. sizeof(DISK_CONFIG_HEADER) +
  492. regHeader->DiskInformationSize +
  493. regHeader->FtInformationSize,
  494. REG_BINARY);
  495. NtClose(handle);
  496. TESTANDFREE(freeToken);
  497. return TRUE;
  498. }
  499. }
  500. }
  501. }
  502. //
  503. // Look at the next disk
  504. //
  505. diskDescription = (PDISK_DESCRIPTION)
  506. &diskDescription->Partitions[diskDescription->NumberOfPartitions];
  507. }
  508. return TRUE;
  509. }
  510. NTSTATUS
  511. SpDiskRegistryAssignCdRomLetter(
  512. IN PWSTR CdromName,
  513. IN WCHAR DriveLetter
  514. )
  515. {
  516. NTSTATUS status;
  517. HANDLE handle;
  518. WCHAR newValue[4];
  519. UNICODE_STRING unicodeValueName;
  520. //
  521. // Try to open the key for later use when setting the new value.
  522. //
  523. status = FtOpenKey(&handle,
  524. DiskRegistryKey,
  525. DiskRegistryClass);
  526. if (NT_SUCCESS(status)) {
  527. unicodeValueName.MaximumLength =
  528. unicodeValueName.Length = (wcslen(CdromName) * sizeof(WCHAR)) + sizeof(WCHAR);
  529. unicodeValueName.Buffer = CdromName;
  530. unicodeValueName.Length -= sizeof(WCHAR); // don't count the eos
  531. newValue[0] = DriveLetter;
  532. newValue[1] = (WCHAR) ':';
  533. newValue[2] = 0;
  534. status = ZwSetValueKey(handle,
  535. &unicodeValueName,
  536. 0,
  537. REG_SZ,
  538. &newValue,
  539. 3 * sizeof(WCHAR));
  540. NtClose(handle);
  541. }
  542. return status;
  543. }
  544. //
  545. // This is a modified SppMigrateFtKeys.
  546. //
  547. NTSTATUS
  548. SpMigrateDiskRegistry(
  549. IN HANDLE hDestSystemHive
  550. )
  551. /*++
  552. Routine Description:
  553. Arguments:
  554. hDestSystemHive - Handle to the root of the system hive on the system
  555. being upgraded.
  556. Return Value:
  557. Status value indicating outcome of operation.
  558. --*/
  559. {
  560. NTSTATUS Status;
  561. NTSTATUS SavedStatus;
  562. OBJECT_ATTRIBUTES Obja;
  563. UNICODE_STRING UnicodeString;
  564. PWSTR FtDiskKeys[] = {
  565. L"Disk"
  566. };
  567. WCHAR KeyPath[MAX_PATH];
  568. HANDLE SrcKey;
  569. ULONG i;
  570. SavedStatus = STATUS_SUCCESS;
  571. for( i = 0; i < sizeof(FtDiskKeys)/sizeof(PWSTR); i++ ) {
  572. //
  573. // Open the source key
  574. //
  575. swprintf( KeyPath, L"\\registry\\machine\\system\\%ls", FtDiskKeys[i] );
  576. INIT_OBJA(&Obja,&UnicodeString,KeyPath);
  577. Obja.RootDirectory = NULL;
  578. Status = ZwOpenKey(&SrcKey,KEY_ALL_ACCESS,&Obja);
  579. if( !NT_SUCCESS( Status ) ) {
  580. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open %ls on the setup hive. Status = %lx \n", KeyPath, Status));
  581. if( SavedStatus == STATUS_SUCCESS ) {
  582. SavedStatus = Status;
  583. }
  584. continue;
  585. }
  586. Status = SppCopyKeyRecursive( SrcKey,
  587. hDestSystemHive,
  588. NULL,
  589. FtDiskKeys[i],
  590. TRUE,
  591. FALSE
  592. );
  593. if( !NT_SUCCESS( Status ) ) {
  594. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to migrate %ls to SYSTEM\\%ls. Status = %lx\n", KeyPath, FtDiskKeys[i], Status));
  595. if( SavedStatus == STATUS_SUCCESS ) {
  596. SavedStatus = Status;
  597. }
  598. }
  599. ZwClose( SrcKey );
  600. }
  601. return( SavedStatus );
  602. }
  603. VOID
  604. SpGetPartitionStartingOffsetAndLength(
  605. IN DWORD DiskIndex,
  606. IN PDISK_REGION Region,
  607. IN BOOL ExtendedPartition,
  608. OUT PLARGE_INTEGER Offset,
  609. OUT PLARGE_INTEGER Length
  610. )
  611. {
  612. ULONGLONG bytesPerSector;
  613. bytesPerSector = (ULONGLONG)PartitionedDisks[DiskIndex].HardDisk->Geometry.BytesPerSector;
  614. //
  615. // Calculate Offset and Legnth.
  616. //
  617. Offset -> QuadPart = Region->StartSector * bytesPerSector;
  618. Length -> QuadPart = Region->SectorCount * bytesPerSector;
  619. }
  620. BOOL
  621. SpFillInDiskPartitionStructure (
  622. IN DWORD DiskIndex,
  623. IN PDISK_REGION Region,
  624. IN USHORT LogicalNumber,
  625. IN BOOL ExtendedPartition,
  626. OUT PDISK_PARTITION Partition
  627. )
  628. {
  629. LARGE_INTEGER ftLength;
  630. ftLength.QuadPart = 0;
  631. RtlZeroMemory(Partition, sizeof(DISK_PARTITION));
  632. Partition -> FtType = NotAnFtMember;
  633. //
  634. // Set the offset and length.
  635. //
  636. SpGetPartitionStartingOffsetAndLength(
  637. DiskIndex,
  638. Region,
  639. ExtendedPartition,
  640. &(Partition -> StartingOffset),
  641. &(Partition -> Length)
  642. );
  643. //
  644. // set the Drive Letter to an uninitialized drive letter (for now)
  645. // Note that this is *NOT* Unicode.
  646. //
  647. Partition -> DriveLetter = ' ';
  648. Partition -> AssignDriveLetter = TRUE;
  649. Partition -> Modified = TRUE;
  650. Partition -> ReservedChars[0] = 0;
  651. Partition -> ReservedChars[1] = 0;
  652. Partition -> ReservedChars[2] = 0;
  653. Partition -> ReservedTwoLongs[0] = 0;
  654. Partition -> ReservedTwoLongs[1] = 0;
  655. Partition -> LogicalNumber = LogicalNumber;
  656. return TRUE;
  657. }
  658. //
  659. // cut/copied and modified from SpMigrateFtKeys in spupgcfg.c
  660. //
  661. NTSTATUS
  662. SpCopySetupDiskRegistryToTargetDiskRegistry(
  663. IN HANDLE hDestSystemHive
  664. )
  665. {
  666. NTSTATUS Status;
  667. NTSTATUS SavedStatus;
  668. OBJECT_ATTRIBUTES Obja;
  669. UNICODE_STRING UnicodeString;
  670. PWSTR FtDiskKeys[] = {L"Disk"};
  671. WCHAR KeyPath[MAX_PATH];
  672. HANDLE SrcKey;
  673. ULONG i;
  674. SavedStatus = STATUS_SUCCESS;
  675. for( i = 0; i < ARRAYSIZE(FtDiskKeys); i++ ) {
  676. int ReturnValue;
  677. //
  678. // Open the source key
  679. //
  680. #pragma prefast(suppress:53, "Buffer is MAX_PATH in length and loop takes care of overflow")
  681. ReturnValue = _snwprintf( KeyPath,
  682. ARRAYSIZE(KeyPath),
  683. L"\\registry\\machine\\system\\%ls",
  684. FtDiskKeys[i]);
  685. if((ReturnValue < 0) || (ReturnValue >= ARRAYSIZE(KeyPath))){
  686. continue;
  687. }
  688. INIT_OBJA(&Obja,&UnicodeString,KeyPath);
  689. Obja.RootDirectory = NULL;
  690. Status = ZwOpenKey(&SrcKey,KEY_ALL_ACCESS,&Obja);
  691. if( !NT_SUCCESS( Status ) ) {
  692. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open %ls on the setup hive. Status = %lx \n", KeyPath, Status));
  693. if( SavedStatus == STATUS_SUCCESS ) {
  694. SavedStatus = Status;
  695. }
  696. continue;
  697. }
  698. Status = SppCopyKeyRecursive( SrcKey,
  699. hDestSystemHive,
  700. NULL,
  701. FtDiskKeys[i],
  702. TRUE,
  703. FALSE
  704. );
  705. if( !NT_SUCCESS( Status ) ) {
  706. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to migrate %ls to SYSTEM\\%ls. Status = %lx\n", KeyPath, FtDiskKeys[i], Status));
  707. if( SavedStatus == STATUS_SUCCESS ) {
  708. SavedStatus = Status;
  709. }
  710. }
  711. ZwClose( SrcKey );
  712. }
  713. return( SavedStatus );
  714. }
  715. DWORD
  716. SpDetermineNecessarySizeForDiskRegistry(
  717. VOID
  718. )
  719. {
  720. DWORD rSize;
  721. PDISK_REGION region;
  722. DWORD index;
  723. DWORD partitionCount;
  724. //
  725. // Need one overall DISK_REGISTRY.
  726. //
  727. rSize = sizeof(DISK_REGISTRY);
  728. //
  729. // Need HardDiskCount DISK_DESCRIPTIONS.
  730. //
  731. rSize += sizeof(DISK_DESCRIPTION) * HardDiskCount;
  732. //
  733. // Need One DISK_PARTITION per partition for every disk.
  734. //
  735. for (index = 0, partitionCount = 0;index < HardDiskCount; index++) {
  736. region = SpFirstPartitionedRegion(PartitionedDisks[index].PrimaryDiskRegions, TRUE);
  737. while(region) {
  738. partitionCount++;
  739. region = SpNextPartitionedRegion(region, TRUE);
  740. }
  741. region = SpFirstPartitionedRegion(PartitionedDisks[index].PrimaryDiskRegions, FALSE);
  742. while(region) {
  743. partitionCount++;
  744. region = SpNextPartitionedRegion(region, FALSE);
  745. }
  746. }
  747. rSize += sizeof(DISK_PARTITION) * partitionCount;
  748. return rSize;
  749. }
  750. NTSTATUS
  751. SpDiskRegistrySet(
  752. IN PDISK_REGISTRY Registry
  753. )
  754. {
  755. typedef struct _MEMCHAIN {
  756. PDISK_DESCRIPTION Disk;
  757. PDISK_PARTITION Partition;
  758. ULONG MemberNumber;
  759. PVOID NextMember;
  760. } MEMCHAIN, *PMEMCHAIN;
  761. typedef struct _COMPONENT {
  762. PVOID NextComponent;
  763. PMEMCHAIN MemberChain;
  764. FT_TYPE Type;
  765. ULONG Group;
  766. } COMPONENT, *PCOMPONENT;
  767. NTSTATUS status;
  768. HANDLE handle;
  769. DISK_CONFIG_HEADER regHeader;
  770. PDISK_DESCRIPTION disk;
  771. PDISK_PARTITION partition;
  772. ULONG outer; // outer loop index
  773. ULONG i; // inner loop index
  774. PCOMPONENT ftBase = NULL;
  775. PCOMPONENT ftComponent = NULL;
  776. PCOMPONENT ftLastComponent = NULL;
  777. PMEMCHAIN ftMemChain;
  778. PVOID outBuffer = NULL;
  779. ULONG countFtComponents = 0;
  780. ULONG ftMemberCount = 0;
  781. ULONG ftComponentCount = 0;
  782. PFT_REGISTRY ftRegistry = NULL;
  783. PFT_DESCRIPTION ftComponentDescription = NULL;
  784. PFT_MEMBER_DESCRIPTION ftMember = NULL;
  785. status = FtOpenKey(&handle,
  786. DiskRegistryKey,
  787. DiskRegistryClass);
  788. if (NT_SUCCESS(status)) {
  789. //
  790. // Initialize the registry header.
  791. //
  792. regHeader.Version = DISK_INFORMATION_VERSION;
  793. regHeader.CheckSum = 0;
  794. regHeader.Reserved[0] = 0;
  795. regHeader.Reserved[1] = 0;
  796. regHeader.Reserved[2] = 0;
  797. regHeader.NameOffset = 0;
  798. regHeader.NameSize = 0;
  799. regHeader.FtInformationOffset = 0;
  800. regHeader.FtInformationSize = 0;
  801. regHeader.DiskInformationOffset = sizeof(DISK_CONFIG_HEADER);
  802. //
  803. // Walk through the disk information provided and count FT items.
  804. //
  805. disk = &Registry->Disks[0];
  806. for (outer = 0; outer < Registry->NumberOfDisks; outer++) {
  807. //
  808. // Walk through the partition information.
  809. //
  810. for (i = 0; i < disk->NumberOfPartitions; i++) {
  811. partition = &disk->Partitions[i];
  812. if (partition->FtType != NotAnFtMember) {
  813. //
  814. // Have a member of an FT item.
  815. //
  816. if (ftBase == NULL) {
  817. ftBase = (PCOMPONENT) SpMemAlloc(sizeof(COMPONENT));
  818. if (ftBase == NULL) {
  819. return STATUS_NO_MEMORY;
  820. }
  821. ftBase->Type = partition->FtType;
  822. ftBase->Group = partition->FtGroup;
  823. ftBase->NextComponent = NULL;
  824. ftMemChain = (PMEMCHAIN) SpMemAlloc(sizeof(MEMCHAIN));
  825. if (ftMemChain == NULL) {
  826. return STATUS_NO_MEMORY;
  827. }
  828. ftBase->MemberChain = ftMemChain;
  829. ftMemChain->Disk = disk;
  830. ftMemChain->Partition = partition;
  831. ftMemChain->MemberNumber = partition->FtMember;
  832. ftMemChain->NextMember = NULL;
  833. ftComponentCount++;
  834. ftMemberCount++;
  835. } else {
  836. //
  837. // Search the existing chain to see if this is
  838. // a member of a previously encountered FT component.
  839. //
  840. ftComponent = ftBase;
  841. while (ftComponent) {
  842. if ((ftComponent->Type == partition->FtType) &&
  843. (ftComponent->Group == partition->FtGroup)){
  844. //
  845. // Member of same group.
  846. //
  847. ftMemChain = ftComponent->MemberChain;
  848. //
  849. // Go to end of chain.
  850. //
  851. while (ftMemChain->NextMember != NULL) {
  852. ftMemChain = ftMemChain->NextMember;
  853. }
  854. //
  855. // Add new member at end.
  856. //
  857. ftMemChain->NextMember = (PMEMCHAIN) SpMemAlloc(sizeof(MEMCHAIN));
  858. if (ftMemChain->NextMember == NULL) {
  859. return STATUS_NO_MEMORY;
  860. }
  861. ftMemChain = ftMemChain->NextMember;
  862. ftMemChain->NextMember = NULL;
  863. ftMemChain->Disk = disk;
  864. ftMemChain->Partition = partition;
  865. ftMemChain->MemberNumber = partition->FtMember;
  866. ftMemberCount++;
  867. break;
  868. }
  869. ftLastComponent = ftComponent;
  870. ftComponent = ftComponent->NextComponent;
  871. }
  872. if (ftComponent == NULL) {
  873. //
  874. // New FT component volume.
  875. //
  876. ftComponent = (PCOMPONENT)SpMemAlloc(sizeof(COMPONENT));
  877. if (ftComponent == NULL) {
  878. return STATUS_NO_MEMORY;
  879. }
  880. if (ftLastComponent != NULL) {
  881. ftLastComponent->NextComponent = ftComponent;
  882. }
  883. ftComponent->Type = partition->FtType;
  884. ftComponent->Group = partition->FtGroup;
  885. ftComponent->NextComponent = NULL;
  886. ftMemChain = (PMEMCHAIN) SpMemAlloc(sizeof(MEMCHAIN));
  887. if (ftMemChain == NULL) {
  888. return STATUS_NO_MEMORY;
  889. }
  890. ftComponent->MemberChain = ftMemChain;
  891. ftMemChain->Disk = disk;
  892. ftMemChain->Partition = partition;
  893. ftMemChain->MemberNumber = partition->FtMember;
  894. ftMemChain->NextMember = NULL;
  895. ftComponentCount++;
  896. ftMemberCount++;
  897. }
  898. }
  899. }
  900. }
  901. //
  902. // The next disk description occurs immediately after the
  903. // last partition infomation.
  904. //
  905. disk =(PDISK_DESCRIPTION)&disk->Partitions[i];
  906. }
  907. //
  908. // Update the registry header with the length of the disk information.
  909. //
  910. regHeader.DiskInformationSize = ((PUCHAR)disk - (PUCHAR)Registry);
  911. regHeader.FtInformationOffset = sizeof(DISK_CONFIG_HEADER) +
  912. regHeader.DiskInformationSize;
  913. //
  914. // Now walk the ftBase chain constructed above and build
  915. // the FT component of the registry.
  916. //
  917. if (ftBase != NULL) {
  918. //
  919. // Calculate size needed for the FT portion of the
  920. // registry information.
  921. //
  922. i = (ftMemberCount * sizeof(FT_MEMBER_DESCRIPTION)) +
  923. (ftComponentCount * sizeof(FT_DESCRIPTION)) +
  924. sizeof(FT_REGISTRY);
  925. ftRegistry = (PFT_REGISTRY) SpMemAlloc(i);
  926. if (ftRegistry == NULL) {
  927. return STATUS_NO_MEMORY;
  928. }
  929. ftRegistry->NumberOfComponents = 0;
  930. regHeader.FtInformationSize = i;
  931. //
  932. // Construct FT entries.
  933. //
  934. ftComponentDescription = &ftRegistry->FtDescription[0];
  935. ftComponent = ftBase;
  936. while (ftComponent != NULL) {
  937. ftRegistry->NumberOfComponents++;
  938. ftComponentDescription->FtVolumeState = FtStateOk;
  939. ftComponentDescription->Type = ftComponent->Type;
  940. ftComponentDescription->Reserved = 0;
  941. //
  942. // Sort the member list into the ft registry section.
  943. //
  944. i = 0;
  945. while (1) {
  946. ftMemChain = ftComponent->MemberChain;
  947. while (ftMemChain->MemberNumber != i) {
  948. ftMemChain = ftMemChain->NextMember;
  949. if (ftMemChain == NULL) {
  950. break;
  951. }
  952. }
  953. if (ftMemChain == NULL) {
  954. break;
  955. }
  956. ftMember = &ftComponentDescription->FtMemberDescription[i];
  957. ftMember->State = 0;
  958. ftMember->ReservedShort = 0;
  959. ftMember->Signature = ftMemChain->Disk->Signature;
  960. ftMember->OffsetToPartitionInfo = (ULONG)
  961. ((PUCHAR) ftMemChain->Partition -
  962. (PUCHAR) Registry) +
  963. sizeof(DISK_CONFIG_HEADER);
  964. ftMember->LogicalNumber =
  965. ftMemChain->Partition->LogicalNumber;
  966. i++;
  967. }
  968. ftComponentDescription->NumberOfMembers = (USHORT)i;
  969. //
  970. // Set up base for next registry component.
  971. //
  972. ftComponentDescription = (PFT_DESCRIPTION)
  973. &ftComponentDescription->FtMemberDescription[i];
  974. //
  975. // Move forward on the chain.
  976. //
  977. ftLastComponent = ftComponent;
  978. ftComponent = ftComponent->NextComponent;
  979. //
  980. // Free the member chain and component.
  981. //
  982. ftMemChain = ftLastComponent->MemberChain;
  983. while (ftMemChain != NULL) {
  984. PMEMCHAIN nextChain;
  985. nextChain = ftMemChain->NextMember;
  986. TESTANDFREE(ftMemChain);
  987. ftMemChain = nextChain;
  988. }
  989. TESTANDFREE(ftLastComponent);
  990. }
  991. }
  992. i = regHeader.FtInformationSize +
  993. regHeader.DiskInformationSize +
  994. sizeof(DISK_CONFIG_HEADER);
  995. outBuffer = SpMemAlloc(i);
  996. if (outBuffer == NULL) {
  997. TESTANDFREE(ftRegistry);
  998. return STATUS_NO_MEMORY;
  999. }
  1000. //
  1001. // Move all of the pieces together.
  1002. //
  1003. RtlMoveMemory(outBuffer,
  1004. &regHeader,
  1005. sizeof(DISK_CONFIG_HEADER));
  1006. RtlMoveMemory((PUCHAR)outBuffer + sizeof(DISK_CONFIG_HEADER),
  1007. Registry,
  1008. regHeader.DiskInformationSize);
  1009. RtlMoveMemory((PUCHAR)outBuffer + regHeader.FtInformationOffset,
  1010. ftRegistry,
  1011. regHeader.FtInformationSize);
  1012. TESTANDFREE(ftRegistry);
  1013. //
  1014. // Backup the previous value.
  1015. //
  1016. FtBackup(handle);
  1017. //
  1018. // Set the new value.
  1019. //
  1020. status = FtSetValue(handle,
  1021. DiskRegistryValue,
  1022. outBuffer,
  1023. sizeof(DISK_CONFIG_HEADER) +
  1024. regHeader.DiskInformationSize +
  1025. regHeader.FtInformationSize,
  1026. REG_BINARY);
  1027. TESTANDFREE(outBuffer);
  1028. ZwFlushKey(handle);
  1029. ZwClose(handle);
  1030. }
  1031. return status;
  1032. }
  1033. BOOL
  1034. SpBuildDiskRegistry(
  1035. VOID
  1036. )
  1037. {
  1038. PDISK_DESCRIPTION curDisk;
  1039. DWORD diskRegistrySize;
  1040. PBYTE curOffset;
  1041. PDISK_REGISTRY diskRegistry;
  1042. PDISK_REGION region;
  1043. DWORD diskIndex;
  1044. USHORT logicalNumber;
  1045. NTSTATUS ntStatus;
  1046. //
  1047. // First, allocate enough space for the DiskRegistry structure.
  1048. //
  1049. diskRegistrySize = SpDetermineNecessarySizeForDiskRegistry();
  1050. diskRegistry = SpMemAlloc(diskRegistrySize);
  1051. if (!diskRegistry) {
  1052. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Could not allocate enough space to create a disk registry.\n"));
  1053. return FALSE;
  1054. }
  1055. //
  1056. // Set the number of disks in the system into the header.
  1057. //
  1058. diskRegistry -> NumberOfDisks = (USHORT) HardDiskCount;
  1059. diskRegistry -> ReservedShort = 0;
  1060. //
  1061. // Initialize curOffset to the Disks element of diskRegistry.
  1062. //
  1063. curOffset = (PBYTE) diskRegistry -> Disks;
  1064. //
  1065. // Now, enumerate all of these hard disks filling in the information for each of them.
  1066. //
  1067. for (diskIndex = 0;diskIndex < diskRegistry -> NumberOfDisks; diskIndex++) {
  1068. //
  1069. // Claim PDISK_DESCRIPTION worth of data.
  1070. //
  1071. curDisk = (PDISK_DESCRIPTION) curOffset;
  1072. //
  1073. // Set the disk signature and clear the reserved data.
  1074. //
  1075. curDisk -> Signature = PartitionedDisks[diskIndex].HardDisk -> Signature;
  1076. curDisk -> ReservedShort = 0;
  1077. //
  1078. // Initialize the NumberOfPartitions member to 0. This will be bumped for
  1079. // each partition found.
  1080. //
  1081. curDisk -> NumberOfPartitions = 0;
  1082. //
  1083. // Initialize curOffset to the Partitions element of the current disk description.
  1084. //
  1085. curOffset = (PBYTE) curDisk -> Partitions;
  1086. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Creating Disk Description structure in registry.\n"));
  1087. //
  1088. // Initialize the logical number var for this disk.
  1089. //
  1090. logicalNumber = 1;
  1091. //
  1092. // Enumerate the Primary regions, creating a DISK_PARTITION structure for
  1093. // each partition.
  1094. //
  1095. region = SpFirstPartitionedRegion(PartitionedDisks[diskIndex].PrimaryDiskRegions, TRUE);
  1096. while(region) {
  1097. SpFillInDiskPartitionStructure(
  1098. diskIndex,
  1099. region,
  1100. logicalNumber,
  1101. FALSE,
  1102. (PDISK_PARTITION) curOffset
  1103. );
  1104. //
  1105. // Increment the partition count and set the curOffset to the next
  1106. // free spot.
  1107. //
  1108. curDisk -> NumberOfPartitions++;
  1109. curOffset += sizeof(DISK_PARTITION);
  1110. region = SpNextPartitionedRegion(region, TRUE);
  1111. logicalNumber++;
  1112. }
  1113. //
  1114. // Enumerate the Extended regions, creating a DISK_PARTITION structure for
  1115. // each partition.
  1116. //
  1117. region = SpFirstPartitionedRegion(PartitionedDisks[diskIndex].PrimaryDiskRegions, FALSE);
  1118. while(region) {
  1119. SpFillInDiskPartitionStructure(
  1120. diskIndex,
  1121. region,
  1122. logicalNumber,
  1123. TRUE,
  1124. (PDISK_PARTITION) curOffset
  1125. );
  1126. //
  1127. // Increment the partition count and set the curOffset to the next
  1128. // free spot.
  1129. //
  1130. curDisk -> NumberOfPartitions++;
  1131. curOffset += sizeof(DISK_PARTITION);
  1132. region = SpNextPartitionedRegion(region, FALSE);
  1133. logicalNumber++;
  1134. }
  1135. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Disk contained %u partitions.\n",curDisk -> NumberOfPartitions));
  1136. }
  1137. //
  1138. // Now that the structure has been built, create its registry key and
  1139. // save it. Then free the associated memory.
  1140. //
  1141. ntStatus = SpDiskRegistrySet(diskRegistry);
  1142. if (!NT_SUCCESS(ntStatus)) {
  1143. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "Could not set the Disk Registry information. %u (%x)\n",ntStatus,ntStatus));
  1144. }
  1145. return NT_SUCCESS(ntStatus);
  1146. }