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.

3314 lines
79 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. editreg.c
  5. Abstract:
  6. This program acts as an interactive shell allowing a user to view
  7. and manipulate the configuration registry. Also, it has some specific
  8. commands for support of the NTFT component of the registry.
  9. Author:
  10. Mike Glass
  11. Bob Rinne
  12. Environment:
  13. User process.
  14. Notes:
  15. The commands "disk", "fix", "restore" are commands that know where
  16. the configuration information is for the NTFT component of the NT
  17. system.
  18. Revision History:
  19. --*/
  20. #include "cmp.h"
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <ctype.h>
  25. #include "ntdskreg.h"
  26. #include "ntddft.h"
  27. //
  28. // Tempory stuff to get types and values to print in help.
  29. //
  30. PUCHAR TypeNames[] =
  31. {
  32. "REG_NONE",
  33. "REG_SZ",
  34. "REG_BINARY",
  35. "REG_DWORD",
  36. "REG_DWORD_LITTLE_ENDIAN",
  37. "REG_DWORD_BIG_ENDIAN",
  38. "REG_LINK",
  39. "REG_MULTI_SZ",
  40. "REG_RESOURCE_LIST",
  41. NULL
  42. };
  43. ULONG TypeNumbers[] =
  44. {
  45. REG_NONE,
  46. REG_SZ,
  47. REG_BINARY,
  48. REG_DWORD,
  49. REG_DWORD_LITTLE_ENDIAN,
  50. REG_DWORD_BIG_ENDIAN,
  51. REG_LINK,
  52. REG_MULTI_SZ,
  53. REG_RESOURCE_LIST
  54. };
  55. //
  56. // Special support for the driver load lists in the registry.
  57. //
  58. PUCHAR StartDescription[] =
  59. {
  60. "Boot loader",
  61. "System",
  62. "2",
  63. "3",
  64. //
  65. // Anything above 3 is not loaded.
  66. //
  67. NULL
  68. };
  69. PUCHAR TypeDescription[] =
  70. {
  71. "System driver",
  72. "File system",
  73. "Service",
  74. NULL
  75. };
  76. //
  77. // Constants and defines.
  78. //
  79. #define WORK_BUFFER_SIZE 4096
  80. //
  81. // Amount to fudge when mallocing for strings.
  82. //
  83. #define FUDGE 8
  84. //
  85. // Registry base.
  86. //
  87. #define REGISTRY_BASE "\\REGISTRY\\MACHINE"
  88. //
  89. // Default type value when key value set.
  90. //
  91. #define DEFAULT_TYPE REG_SZ
  92. //
  93. // Base location for component descriptions of FT elements.
  94. //
  95. #define FT_REGISTRY_ROOT "\\REGISTRY\\MACHINE\\SYSTEM\\NTFT"
  96. //
  97. // Subkey name located in the FT_REGISTRY_ROOT for stripes.
  98. //
  99. #define FT_STRIPE_BASE "Stripe%d"
  100. //
  101. // Subkey name located in the FT_REGISTRY_ROOT for mirrors.
  102. //
  103. #define FT_MIRROR_BASE "Mirror%d"
  104. //
  105. // Subkey name located in the FT_REGISTRY_ROOT for volume sets.
  106. //
  107. #define FT_VOLSET_BASE "VolSet%d"
  108. //
  109. // Constants for the command values.
  110. //
  111. #define INVALID -1
  112. #define DIR 0
  113. #define CREATE 1
  114. #define LIST 2
  115. #define CHDIR 3
  116. #define HELP 4
  117. #define QUIT 5
  118. #define DDEBUG 6
  119. #define SETVALUE 7
  120. #define DELKEY 8
  121. #define DELVALUE 9
  122. #define DIRLONG 10
  123. #define INLONG 11
  124. #define INSHORT 12
  125. #define INBYTE 13
  126. #define DUMP 14
  127. #define DISKREG 15
  128. #define FIXDISK 16
  129. #define RESTORE 17
  130. #define DRIVERS 18
  131. #define ORPHAN 19
  132. #define REGEN 20
  133. #define INIT 21
  134. #define MAKEFT 22
  135. #define CTRL_C 0x03
  136. //
  137. // Table of recognized commands.
  138. //
  139. PUCHAR Commands[] = {
  140. "dir",
  141. "keys",
  142. "lc",
  143. "ls",
  144. "create",
  145. "set",
  146. "unset",
  147. "erase",
  148. "delete",
  149. "rm",
  150. "list",
  151. "values",
  152. "display",
  153. "cd",
  154. "chdir",
  155. "help",
  156. "?",
  157. "quit",
  158. "exit",
  159. "debug",
  160. "longs",
  161. "shorts",
  162. "bytes",
  163. "dump",
  164. "disks",
  165. "fix",
  166. "restore",
  167. "drivers",
  168. "orphan",
  169. "regenerate",
  170. "initialize",
  171. "makeft",
  172. NULL
  173. };
  174. //
  175. // Using the index from the match on the commands in Commands[], this
  176. // table gives the proper command value to be executed. This allows
  177. // for multiple entries in Commands[] for the same command code.
  178. //
  179. int CommandMap[] = {
  180. DIRLONG,
  181. DIR,
  182. DIR,
  183. DIR,
  184. CREATE,
  185. SETVALUE,
  186. DELVALUE,
  187. DELVALUE,
  188. DELKEY,
  189. DELKEY,
  190. LIST,
  191. LIST,
  192. LIST,
  193. CHDIR,
  194. CHDIR,
  195. HELP,
  196. HELP,
  197. QUIT,
  198. QUIT,
  199. DDEBUG,
  200. INLONG,
  201. INSHORT,
  202. INBYTE,
  203. DUMP,
  204. DISKREG,
  205. FIXDISK,
  206. RESTORE,
  207. DRIVERS,
  208. ORPHAN,
  209. REGEN,
  210. INIT,
  211. MAKEFT
  212. };
  213. //
  214. // CommandHelp is an array of help strings for each of the commands.
  215. // The array is indexed by the result of CommandMap[i] for the Commands[]
  216. // array. This way the same help message will print for each of the
  217. // commands aliases.
  218. //
  219. PUCHAR CommandHelp[] = {
  220. "Displays keys.",
  221. "Create a new key.",
  222. "Displays values withing a key.",
  223. "Change current location in registry.",
  224. "This help information.",
  225. "Exit the program.",
  226. "Set internal debug on for this program.",
  227. "Set a new value within a key.",
  228. "Delete a key.",
  229. "Unset (erase) a key value.",
  230. "Unset (erase) a key value.",
  231. "Change dump format to Longs (default).",
  232. "Change dump format to Shorts.",
  233. "Change dump format to Bytes.",
  234. "Toggle dump mode (force hex dump for all value types).",
  235. "Display the disk registry.",
  236. "Set disk signatures in registry.",
  237. "Restore an FT orphan to working state.",
  238. "List the information on the drivers from the registry.",
  239. "Orphan a member of an FT set.",
  240. "Mark a FT set member for regeneration on next boot.",
  241. "Mark a stripe with parity for initialization on next boot.",
  242. "Construct an FT set from existing partitions",
  243. NULL
  244. };
  245. //
  246. // Space for working location string in registry.
  247. //
  248. UCHAR WorkingDirectory[512];
  249. //
  250. // Space for current location string in registry.
  251. //
  252. UCHAR CurrentDirectory[512];
  253. //
  254. // Space for command input.
  255. //
  256. UCHAR CommandLine[512];
  257. //
  258. // Prompt strings for getting definition for an FT_COPY request.
  259. //
  260. PUCHAR SetPrompts[] = {
  261. "Name => ",
  262. "Value => ",
  263. "Index => ",
  264. NULL
  265. };
  266. //
  267. // Version indicator. Should be changed every time a major edit occurs.
  268. //
  269. PUCHAR Version = "Version 1.30";
  270. //
  271. // Debug print level.
  272. //
  273. ULONG Debug = 0;
  274. //
  275. // Dump control values.
  276. //
  277. typedef enum _DUMP_CONTROL {
  278. InBytes,
  279. InShorts,
  280. InLongs
  281. } DUMP_CONTROL, *PDUMP_CONTROL;
  282. ULONG ForceDump = 0;
  283. DUMP_CONTROL DumpControl = InLongs;
  284. NTSTATUS
  285. FtOpenKey(
  286. PHANDLE HandlePtr,
  287. PUCHAR KeyName
  288. )
  289. /*++
  290. Routine Description:
  291. Arguments:
  292. Return Value:
  293. --*/
  294. {
  295. NTSTATUS status;
  296. STRING keyString;
  297. OBJECT_ATTRIBUTES objectAttributes;
  298. UNICODE_STRING unicodeKeyName;
  299. RtlInitString(&keyString,
  300. KeyName);
  301. (VOID)RtlAnsiStringToUnicodeString(&unicodeKeyName,
  302. &keyString,
  303. (BOOLEAN) TRUE);
  304. memset(&objectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
  305. InitializeObjectAttributes(&objectAttributes,
  306. &unicodeKeyName,
  307. OBJ_CASE_INSENSITIVE,
  308. NULL,
  309. NULL);
  310. status = NtOpenKey(HandlePtr,
  311. MAXIMUM_ALLOWED,
  312. &objectAttributes);
  313. RtlFreeUnicodeString(&unicodeKeyName);
  314. if (Debug == 1) {
  315. if (!NT_SUCCESS(status)) {
  316. printf("Failed NtOpenKey for %s => %x\n",
  317. KeyName,
  318. status);
  319. }
  320. }
  321. return status;
  322. }
  323. NTSTATUS
  324. FtDeleteKey(
  325. PUCHAR KeyName
  326. )
  327. /*++
  328. Routine Description:
  329. Arguments:
  330. Return Value:
  331. --*/
  332. {
  333. NTSTATUS status;
  334. HANDLE keyToDelete;
  335. status = FtOpenKey(&keyToDelete,
  336. KeyName);
  337. if (!NT_SUCCESS(status)) {
  338. printf("Key %s not found (0x%x).\n", KeyName, status);
  339. return status;
  340. }
  341. status = NtDeleteKey(keyToDelete);
  342. if (Debug == 1) {
  343. if (!NT_SUCCESS(status)) {
  344. printf("Could not delete key %s => %x\n",
  345. KeyName,
  346. status);
  347. }
  348. }
  349. NtClose(keyToDelete);
  350. return status;
  351. }
  352. NTSTATUS
  353. FtCreateKey(
  354. PUCHAR KeyName,
  355. PUCHAR KeyClass,
  356. ULONG Index
  357. )
  358. /*++
  359. Routine Description:
  360. Arguments:
  361. Return Value:
  362. --*/
  363. {
  364. NTSTATUS status;
  365. STRING keyString;
  366. UNICODE_STRING unicodeKeyName;
  367. STRING classString;
  368. UNICODE_STRING unicodeClassName;
  369. OBJECT_ATTRIBUTES objectAttributes;
  370. ULONG disposition;
  371. HANDLE tempHandle;
  372. #if DBG
  373. if ((KeyName == NULL) ||
  374. (KeyClass == NULL)) {
  375. printf("FtCreateKey: Invalid parameter 0x%x, 0x%x\n",
  376. KeyName,
  377. KeyClass);
  378. ASSERT(0);
  379. }
  380. #endif
  381. //
  382. // Initialize the object for the key.
  383. //
  384. RtlInitString(&keyString,
  385. KeyName);
  386. (VOID)RtlAnsiStringToUnicodeString(&unicodeKeyName,
  387. &keyString,
  388. (BOOLEAN) TRUE);
  389. memset(&objectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
  390. InitializeObjectAttributes(&objectAttributes,
  391. &unicodeKeyName,
  392. OBJ_CASE_INSENSITIVE,
  393. NULL,
  394. NULL);
  395. //
  396. // Setup the unicode class value.
  397. //
  398. RtlInitString(&classString,
  399. KeyClass);
  400. (VOID)RtlAnsiStringToUnicodeString(&unicodeClassName,
  401. &classString,
  402. (BOOLEAN) TRUE);
  403. //
  404. // Create the key.
  405. //
  406. status = NtCreateKey(&tempHandle,
  407. MAXIMUM_ALLOWED,
  408. &objectAttributes,
  409. Index,
  410. &unicodeClassName,
  411. REG_OPTION_NON_VOLATILE,
  412. &disposition);
  413. if (NT_SUCCESS(status)) {
  414. switch (disposition)
  415. {
  416. case REG_CREATED_NEW_KEY:
  417. break;
  418. case REG_OPENED_EXISTING_KEY:
  419. printf("Warning: Creation was for an existing key!\n");
  420. break;
  421. default:
  422. printf("New disposition returned == 0x%x\n", disposition);
  423. break;
  424. }
  425. }
  426. //
  427. // Free all allocated space.
  428. //
  429. RtlFreeUnicodeString(&unicodeKeyName);
  430. RtlFreeUnicodeString(&unicodeClassName);
  431. NtClose(tempHandle);
  432. return status;
  433. }
  434. NTSTATUS
  435. FtDeleteValue(
  436. HANDLE KeyHandle,
  437. PUCHAR ValueName
  438. )
  439. /*++
  440. Routine Description:
  441. Arguments:
  442. Return Value:
  443. --*/
  444. {
  445. NTSTATUS status;
  446. STRING valueString;
  447. UNICODE_STRING unicodeValueName;
  448. RtlInitString(&valueString,
  449. ValueName);
  450. status = RtlAnsiStringToUnicodeString(&unicodeValueName,
  451. &valueString,
  452. (BOOLEAN) TRUE);
  453. if (!NT_SUCCESS(status)) {
  454. printf("FtDeleteValue: internal conversion error 0x%x\n", status);
  455. return status;
  456. }
  457. status = NtDeleteValueKey(KeyHandle,
  458. &unicodeValueName);
  459. if (Debug == 1) {
  460. if (!NT_SUCCESS(status)) {
  461. printf("Could not delete value %s => %x\n",
  462. ValueName,
  463. status);
  464. }
  465. }
  466. RtlFreeUnicodeString(&unicodeValueName);
  467. return status;
  468. }
  469. NTSTATUS
  470. FtSetValue(
  471. HANDLE KeyHandle,
  472. PUCHAR ValueName,
  473. PVOID DataBuffer,
  474. ULONG DataLength,
  475. ULONG Type
  476. )
  477. /*++
  478. Routine Description:
  479. Arguments:
  480. Return Value:
  481. --*/
  482. {
  483. NTSTATUS status;
  484. STRING valueString;
  485. UNICODE_STRING unicodeValueName;
  486. RtlInitString(&valueString,
  487. ValueName);
  488. RtlAnsiStringToUnicodeString(&unicodeValueName,
  489. &valueString,
  490. (BOOLEAN) TRUE);
  491. status = NtSetValueKey(KeyHandle,
  492. &unicodeValueName,
  493. 0,
  494. Type,
  495. DataBuffer,
  496. DataLength);
  497. if (Debug == 1) {
  498. if (!NT_SUCCESS(status)) {
  499. printf("Could not set value %s => %x\n",
  500. ValueName,
  501. status);
  502. }
  503. }
  504. RtlFreeUnicodeString(&unicodeValueName);
  505. return status;
  506. }
  507. PUCHAR
  508. FindTypeString(
  509. ULONG Type
  510. )
  511. /*++
  512. Routine Description:
  513. Arguments:
  514. Return Value:
  515. --*/
  516. {
  517. int i;
  518. for (i = 0; TypeNames[i] != NULL; i++) {
  519. if (TypeNumbers[i] == Type) {
  520. return TypeNames[i];
  521. }
  522. }
  523. return "(Unknown)";
  524. }
  525. BOOLEAN
  526. ProcessHex(
  527. PUCHAR String,
  528. PULONG Value
  529. )
  530. /*++
  531. Routine Description:
  532. Arguments:
  533. Return Value:
  534. --*/
  535. {
  536. ULONG workValue;
  537. int i;
  538. PUCHAR cp;
  539. if (String == NULL) {
  540. return FALSE;
  541. }
  542. cp = String;
  543. //
  544. // 'i' is an index value. It contains the maximum index into the String.
  545. // Therefore it is initialized to -1.
  546. //
  547. i = -1;
  548. while ((*cp) && (*cp != '\n')) {
  549. i++;
  550. cp++;
  551. }
  552. if (i >= 8) {
  553. //
  554. // String to long for a long.
  555. //
  556. return FALSE;
  557. }
  558. workValue = 0;
  559. cp = String;
  560. while (*cp) {
  561. *cp = (UCHAR) tolower(*cp);
  562. switch (*cp) {
  563. case '0':
  564. case '1':
  565. case '2':
  566. case '3':
  567. case '4':
  568. case '5':
  569. case '6':
  570. case '7':
  571. case '8':
  572. case '9':
  573. workValue |= (((*cp) - '0') << (i * 4));
  574. break;
  575. case 'a':
  576. case 'b':
  577. case 'c':
  578. case 'd':
  579. case 'e':
  580. case 'f':
  581. workValue |= ((((*cp) - 'a') + 10) << (i * 4));
  582. break;
  583. default:
  584. //
  585. // Illegal value, just punt.
  586. //
  587. return FALSE;
  588. break;
  589. }
  590. cp++;
  591. i--;
  592. }
  593. *Value = workValue;
  594. return TRUE;
  595. }
  596. VOID
  597. Dump(
  598. PVOID Buffer,
  599. ULONG Length
  600. )
  601. /*++
  602. Routine Description:
  603. Dump the value data from a buffer in the format specified.
  604. Arguments:
  605. Buffer - pointer to the data.
  606. Length - length of the data.
  607. Return Value:
  608. None.
  609. --*/
  610. {
  611. PUCHAR location;
  612. PUCHAR internalBuffer;
  613. int i;
  614. int j;
  615. int numberLines;
  616. UCHAR outHexLine[128];
  617. UCHAR outPrintable[64];
  618. numberLines = (Length + 15) / 16;
  619. //
  620. // Since the amount of data displayed has been rounded up, this
  621. // routine mallocs enough space and copies the data in. This way
  622. // it won't fault if the data is at the end of memory.
  623. //
  624. internalBuffer = (PUCHAR) malloc(numberLines * 16);
  625. RtlMoveMemory(internalBuffer, Buffer, Length);
  626. location = (PUCHAR) internalBuffer;
  627. for (i = 0; i < numberLines; i++) {
  628. sprintf(outHexLine, "%8x: ", (i * 16));
  629. sprintf(outPrintable, "*");
  630. switch (DumpControl) {
  631. case InBytes:
  632. for (j = 0; j < 16; j++) {
  633. sprintf(outHexLine, "%s%2X ", outHexLine, *location);
  634. sprintf(outPrintable, "%s%c", outPrintable,
  635. (isprint(location[0])) ? location[0] : '.');
  636. location++;
  637. }
  638. break;
  639. case InShorts:
  640. for (j = 0; j < 8; j++) {
  641. sprintf(outHexLine, "%s%4X ", outHexLine,
  642. *((PUSHORT)location));
  643. sprintf(outPrintable, "%s%c%c", outPrintable,
  644. (isprint(location[0])) ? location[0] : '.',
  645. (isprint(location[1])) ? location[1] : '.');
  646. location += 2;
  647. }
  648. break;
  649. default:
  650. case InLongs:
  651. for (j = 0; j < 4; j++) {
  652. sprintf(outHexLine, "%s%8X ", outHexLine,
  653. *((PULONG)location));
  654. sprintf(outPrintable, "%s%c%c%c%c", outPrintable,
  655. (isprint(location[0])) ? location[0] : '.',
  656. (isprint(location[1])) ? location[1] : '.',
  657. (isprint(location[2])) ? location[2] : '.',
  658. (isprint(location[3])) ? location[3] : '.');
  659. location += 4;
  660. }
  661. break;
  662. }
  663. printf("%s %s*\n", outHexLine, outPrintable);
  664. }
  665. printf("\n");
  666. free(internalBuffer);
  667. }
  668. void
  669. UnicodePrint(
  670. PUNICODE_STRING UnicodeString
  671. )
  672. /*++
  673. Routine Description:
  674. Print a unicode string.
  675. Arguments:
  676. UnicodeString - pointer to the string.
  677. Return Value:
  678. None.
  679. --*/
  680. {
  681. ANSI_STRING ansiString;
  682. PUCHAR tempbuffer = (PUCHAR) malloc(WORK_BUFFER_SIZE);
  683. ansiString.MaximumLength = WORK_BUFFER_SIZE;
  684. ansiString.Length = 0L;
  685. ansiString.Buffer = tempbuffer;
  686. RtlUnicodeStringToAnsiString(&ansiString,
  687. UnicodeString,
  688. (BOOLEAN) FALSE);
  689. printf("%s", ansiString.Buffer);
  690. free(tempbuffer);
  691. return;
  692. }
  693. NTSTATUS
  694. Directory(
  695. HANDLE KeyHandle,
  696. BOOLEAN LongListing
  697. )
  698. /*++
  699. Routine Description:
  700. Arguments:
  701. Return Value:
  702. --*/
  703. {
  704. NTSTATUS status;
  705. ULONG index;
  706. ULONG resultLength;
  707. UNICODE_STRING unicodeValueName;
  708. PKEY_BASIC_INFORMATION keyInformation;
  709. keyInformation = (PKEY_BASIC_INFORMATION) malloc(WORK_BUFFER_SIZE);
  710. for (index = 0; TRUE; index++) {
  711. RtlZeroMemory(keyInformation, WORK_BUFFER_SIZE);
  712. status = NtEnumerateKey(KeyHandle,
  713. index,
  714. KeyBasicInformation,
  715. keyInformation,
  716. WORK_BUFFER_SIZE,
  717. &resultLength);
  718. if (status == STATUS_NO_MORE_ENTRIES) {
  719. break;
  720. } else if (!NT_SUCCESS(status)) {
  721. printf("readreg: Error on Enumerate status = %x\n", status);
  722. break;
  723. }
  724. unicodeValueName.Length = (USHORT)keyInformation->NameLength;
  725. unicodeValueName.MaximumLength = (USHORT)keyInformation->NameLength;
  726. unicodeValueName.Buffer = (PWSTR)&keyInformation->Name[0];
  727. UnicodePrint(&unicodeValueName);
  728. printf("\n");
  729. if (LongListing) {
  730. }
  731. }
  732. free(keyInformation);
  733. return status;
  734. }
  735. NTSTATUS
  736. List(
  737. HANDLE KeyHandle,
  738. PUCHAR ItemName
  739. )
  740. /*++
  741. Routine Description:
  742. Arguments:
  743. Return Value:
  744. --*/
  745. {
  746. NTSTATUS status;
  747. ULONG index;
  748. ULONG resultLength;
  749. ULONG type;
  750. PUCHAR typeString;
  751. UNICODE_STRING unicodeValueName;
  752. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  753. UNREFERENCED_PARAMETER(ItemName);
  754. resultLength = WORK_BUFFER_SIZE;
  755. keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)malloc(WORK_BUFFER_SIZE);
  756. for (index = 0; TRUE; index++) {
  757. while (1) {
  758. RtlZeroMemory(keyValueInformation, resultLength);
  759. status = NtEnumerateValueKey(KeyHandle,
  760. index,
  761. KeyValueFullInformation,
  762. keyValueInformation,
  763. resultLength,
  764. &resultLength);
  765. if (status == STATUS_BUFFER_OVERFLOW) {
  766. free(keyValueInformation);
  767. keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)
  768. malloc(resultLength + 10);
  769. } else {
  770. break;
  771. }
  772. }
  773. if (status == STATUS_NO_MORE_ENTRIES) {
  774. break;
  775. } else if (!NT_SUCCESS(status)) {
  776. printf("readreg: Cannot list (%x)\n", status);
  777. break;
  778. }
  779. type = keyValueInformation->Type;
  780. typeString = FindTypeString(type);
  781. unicodeValueName.Length = (USHORT)keyValueInformation->NameLength;
  782. unicodeValueName.MaximumLength =(USHORT)keyValueInformation->NameLength;
  783. unicodeValueName.Buffer = (PWSTR)&keyValueInformation->Name[0];
  784. printf("Name-> """);
  785. UnicodePrint(&unicodeValueName);
  786. printf("""\n");
  787. printf("\ttype = %s (%d)\ttitle index = %d\tdata length = %d\n",
  788. typeString,
  789. type,
  790. keyValueInformation->TitleIndex,
  791. keyValueInformation->DataLength);
  792. printf("\tData:\n");
  793. if (ForceDump) {
  794. type = REG_BINARY;
  795. }
  796. switch (type) {
  797. case REG_DWORD:
  798. // case REG_DWORD_LITTLE_ENDIAN:
  799. printf("\tDWORD value == %d, (0x%x)\n",
  800. *((PULONG)((PUCHAR)keyValueInformation +
  801. keyValueInformation->DataOffset)),
  802. *((PULONG)((PUCHAR)keyValueInformation +
  803. keyValueInformation->DataOffset)));
  804. break;
  805. case REG_SZ:
  806. unicodeValueName.Length = (USHORT)keyValueInformation->DataLength;
  807. unicodeValueName.MaximumLength = (USHORT)
  808. keyValueInformation->DataLength;
  809. unicodeValueName.Buffer = (PWSTR) ((PUCHAR) keyValueInformation +
  810. keyValueInformation->DataOffset);
  811. UnicodePrint(&unicodeValueName);
  812. break;
  813. case REG_BINARY:
  814. default:
  815. Dump(((PUCHAR)keyValueInformation +keyValueInformation->DataOffset),
  816. keyValueInformation->DataLength);
  817. }
  818. printf("\n");
  819. }
  820. free(keyValueInformation);
  821. return status;
  822. }
  823. UCHAR
  824. GetCharacter(
  825. BOOLEAN Batch
  826. )
  827. /*++
  828. Routine Description:
  829. This routine returns a single character from the input stream.
  830. It discards leading blanks if the input is not from the console.
  831. Arguments:
  832. Batch - a boolean indicating if the input it coming from the console.
  833. Return Value:
  834. A character
  835. --*/
  836. {
  837. UCHAR c;
  838. if (Batch) {
  839. while ((c = (UCHAR) getchar()) == ' ')
  840. ;
  841. } else {
  842. c = (UCHAR) getchar();
  843. }
  844. return c;
  845. } // GetCharacter
  846. PUCHAR
  847. GetArgumentString(
  848. BOOLEAN Batch,
  849. PUCHAR Prompt,
  850. BOOLEAN ConvertToLower
  851. )
  852. /*++
  853. Routine Description:
  854. This routine prints the prompt if the input is coming from the console,
  855. then proceeds to collect the user input until a carraige return is typed.
  856. Arguments:
  857. Batch - a boolean indicating if the input is coming from the console.
  858. Prompt - String to prompt with.
  859. Return Value:
  860. A pointer to the input string.
  861. NULL if the user escaped.
  862. --*/
  863. {
  864. //
  865. // The command line data area is used to store the argument string.
  866. //
  867. PUCHAR argument = CommandLine;
  868. int i;
  869. UCHAR c;
  870. if (!Batch) {
  871. printf("%s", Prompt);
  872. }
  873. while ((c = GetCharacter(Batch)) == ' ') {
  874. //
  875. // Ignore leading spaces.
  876. //
  877. }
  878. i = 0;
  879. while (c) {
  880. putchar(c);
  881. if (c == CTRL_C) {
  882. return NULL;
  883. }
  884. if ((c == '\n') || (c == '\r')) {
  885. putchar('\n');
  886. if (i == 0) {
  887. return NULL;
  888. } else {
  889. break;
  890. }
  891. }
  892. if (c == '\b') {
  893. if (i > 0) {
  894. //
  895. // blank over last char
  896. //
  897. putchar(' ');
  898. putchar('\b');
  899. i--;
  900. } else {
  901. //
  902. // space forward to keep prompt in the same place.
  903. //
  904. putchar(' ');
  905. }
  906. } else {
  907. //
  908. // Collect the argument.
  909. //
  910. if (ConvertToLower == TRUE) {
  911. argument[i] = (UCHAR) tolower(c);
  912. } else {
  913. argument[i] = (UCHAR) c;
  914. }
  915. i++;
  916. }
  917. c = GetCharacter(Batch);
  918. }
  919. argument[i] = '\0';
  920. return CommandLine;
  921. } // GetArgumentString
  922. ULONG
  923. ParseArgumentNumeric(
  924. PUCHAR *ArgumentPtr
  925. )
  926. /*++
  927. Routine Description:
  928. This routine prints the prompt if the input is coming from the console.
  929. Arguments:
  930. Batch - a boolean indicating if the input is coming from the console.
  931. Return Value:
  932. None
  933. --*/
  934. {
  935. UCHAR c;
  936. ULONG number;
  937. int i;
  938. BOOLEAN complete = FALSE;
  939. PUCHAR argument = *ArgumentPtr;
  940. while (*argument == ' ') {
  941. //
  942. // skip spaces.
  943. //
  944. argument++;
  945. }
  946. //
  947. // Assume there is only one option to parse until proven
  948. // otherwise.
  949. //
  950. *ArgumentPtr = NULL;
  951. i = 0;
  952. while (complete == FALSE) {
  953. c = argument[i];
  954. switch (c) {
  955. case '\n':
  956. case '\r':
  957. case '\t':
  958. case ' ':
  959. //
  960. // Update the caller argument pointer to the remaining string.
  961. //
  962. *ArgumentPtr = &argument[i + 1];
  963. //
  964. // fall through.
  965. //
  966. case '\0':
  967. argument[i] = '\0';
  968. complete = TRUE;
  969. break;
  970. default:
  971. i++;
  972. break;
  973. }
  974. }
  975. if (i > 0) {
  976. number = (ULONG) atoi(argument);
  977. } else {
  978. number = (ULONG) -1;
  979. }
  980. return number;
  981. } // ParseArgumentNumeric
  982. VOID
  983. PromptUser(
  984. BOOLEAN Batch
  985. )
  986. /*++
  987. Routine Description:
  988. This routine prints the prompt if the input is coming from the console.
  989. Arguments:
  990. Batch - a boolean indicating if the input is coming from the console.
  991. Return Value:
  992. None
  993. --*/
  994. {
  995. if (!Batch) {
  996. printf("\n%s> ", CurrentDirectory);
  997. }
  998. } // PromptUser
  999. int
  1000. GetCommand(
  1001. BOOLEAN Batch,
  1002. PUCHAR *ArgumentPtr
  1003. )
  1004. /*++
  1005. Routine Description:
  1006. This routine processes the user input and returns the code for the
  1007. command entered. If the command has an argument, either the default
  1008. value for the argument (if none is given) or the value provided by the
  1009. user is returned.
  1010. Arguments:
  1011. Batch - a boolean indicating if the input it coming from the console.
  1012. Return Value:
  1013. A command code
  1014. --*/
  1015. {
  1016. int i;
  1017. int commandIndex;
  1018. int commandCode;
  1019. UCHAR c;
  1020. PUCHAR commandPtr;
  1021. PUCHAR command = CommandLine;
  1022. int argumentIndex = -1;
  1023. PUCHAR argument = NULL;
  1024. PromptUser(Batch);
  1025. while ((c = GetCharacter(Batch)) == ' ') {
  1026. //
  1027. // Ignore leading spaces.
  1028. //
  1029. }
  1030. i = 0;
  1031. while (c) {
  1032. putchar(c);
  1033. if ((c == '\n') || (c == '\r')) {
  1034. putchar('\n');
  1035. if (i == 0) {
  1036. PromptUser(Batch);
  1037. c = GetCharacter(Batch);
  1038. continue;
  1039. }
  1040. break;
  1041. }
  1042. if (c == '\b') {
  1043. if (i > 0) {
  1044. //
  1045. // blank over last char
  1046. //
  1047. putchar(' ');
  1048. putchar('\b');
  1049. i--;
  1050. if (argumentIndex == i) {
  1051. argumentIndex = -1;
  1052. argument = NULL;
  1053. }
  1054. } else {
  1055. //
  1056. // space forward to keep prompt in the same place.
  1057. //
  1058. putchar(' ');
  1059. }
  1060. } else {
  1061. //
  1062. // Collect the command.
  1063. //
  1064. command[i] = (UCHAR)tolower(c);
  1065. i++;
  1066. }
  1067. if ((c == ' ') && (argument == NULL)) {
  1068. argument = &command[i];
  1069. argumentIndex = i;
  1070. command[i - 1] = '\0';
  1071. }
  1072. c = GetCharacter(Batch);
  1073. }
  1074. //
  1075. // add end of string.
  1076. //
  1077. command[i] = '\0';
  1078. if (Debug) {
  1079. printf("command => %s$\n", command);
  1080. }
  1081. //
  1082. // Identify the command and return its code.
  1083. //
  1084. commandIndex = 0;
  1085. for (commandPtr = Commands[commandIndex];
  1086. commandPtr != NULL;
  1087. commandPtr = Commands[commandIndex]) {
  1088. if (Debug) {
  1089. printf("Testing => %s$ ... ", commandPtr);
  1090. }
  1091. i = 0;
  1092. while (commandPtr[i] == command[i]) {
  1093. if (command[i] == '\0') {
  1094. break;
  1095. }
  1096. i++;
  1097. }
  1098. if (Debug) {
  1099. printf(" i == %d, command[i] == 0x%x\n", i, command[i]);
  1100. }
  1101. if (command[i]) {
  1102. //
  1103. // Not complete there was a mismatch on the command.
  1104. //
  1105. commandIndex++;
  1106. continue;
  1107. }
  1108. //
  1109. // Have a match on the command.
  1110. //
  1111. if (Debug) {
  1112. printf("Command match %d, argument %s\n",
  1113. commandIndex,
  1114. (argument == NULL) ? "(none)" : argument);
  1115. }
  1116. commandCode = CommandMap[commandIndex];
  1117. *ArgumentPtr = argument;
  1118. return commandCode;
  1119. }
  1120. printf("Command was invalid\n");
  1121. return INVALID;
  1122. } // GetCommand
  1123. VOID
  1124. NotImplemented()
  1125. /*++
  1126. --*/
  1127. {
  1128. printf("Sorry, function not implemented yet.\n");
  1129. }
  1130. NTSTATUS
  1131. FtReturnValue(
  1132. IN HANDLE Handle,
  1133. IN PUCHAR ValueName,
  1134. IN PUCHAR Buffer,
  1135. IN ULONG BufferLength
  1136. )
  1137. /*++
  1138. Routine Description:
  1139. Formatted display of the disk registry information.
  1140. Arguments:
  1141. None.
  1142. Return Values:
  1143. None.
  1144. --*/
  1145. {
  1146. NTSTATUS status;
  1147. ULONG resultLength;
  1148. ULONG length;
  1149. STRING valueString;
  1150. UNICODE_STRING unicodeValueName;
  1151. PUCHAR internalBuffer;
  1152. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  1153. keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)malloc(WORK_BUFFER_SIZE);
  1154. if (keyValueInformation == NULL) {
  1155. printf("FtReturnValue: cannot allocate memory.\n");
  1156. return STATUS_NO_MEMORY;
  1157. }
  1158. RtlInitString(&valueString,
  1159. ValueName);
  1160. RtlAnsiStringToUnicodeString(&unicodeValueName,
  1161. &valueString,
  1162. (BOOLEAN) TRUE);
  1163. status = NtQueryValueKey(Handle,
  1164. &unicodeValueName,
  1165. KeyValueFullInformation,
  1166. keyValueInformation,
  1167. WORK_BUFFER_SIZE,
  1168. &resultLength);
  1169. RtlFreeUnicodeString(&unicodeValueName);
  1170. if (NT_SUCCESS(status)) {
  1171. length = (resultLength > BufferLength) ? BufferLength : resultLength;
  1172. internalBuffer =
  1173. ((PUCHAR)keyValueInformation + keyValueInformation->DataOffset);
  1174. RtlMoveMemory(Buffer, internalBuffer, length);
  1175. }
  1176. free(keyValueInformation);
  1177. return status;
  1178. }
  1179. VOID
  1180. DiskDump()
  1181. /*++
  1182. Routine Description:
  1183. Formatted display of the disk registry information.
  1184. Arguments:
  1185. None.
  1186. Return Values:
  1187. None.
  1188. --*/
  1189. {
  1190. ULONG outerLoop;
  1191. ULONG innerLoop;
  1192. HANDLE handle;
  1193. NTSTATUS status;
  1194. PDISK_CONFIG_HEADER configHeader;
  1195. PDISK_REGISTRY diskRegistry;
  1196. PDISK_DESCRIPTION diskDescription;
  1197. PDISK_PARTITION diskPartition;
  1198. PFT_REGISTRY ftRegistry;
  1199. PFT_DESCRIPTION ftDescription;
  1200. PFT_MEMBER_DESCRIPTION ftMember;
  1201. status = FtOpenKey(&handle,
  1202. DISK_REGISTRY_KEY);
  1203. if (!NT_SUCCESS(status)) {
  1204. printf("Currently there is no key in the registry"
  1205. " for the disk information.\n");
  1206. return;
  1207. }
  1208. configHeader = (PDISK_CONFIG_HEADER) malloc(WORK_BUFFER_SIZE);
  1209. if (configHeader == NULL) {
  1210. printf("Unable to allocate memory for the disk registy information.\n");
  1211. return;
  1212. }
  1213. RtlZeroMemory(configHeader, WORK_BUFFER_SIZE);
  1214. status = FtReturnValue(handle,
  1215. (PUCHAR) DISK_REGISTRY_VALUE,
  1216. (PUCHAR) configHeader,
  1217. WORK_BUFFER_SIZE);
  1218. NtClose(handle);
  1219. if (!NT_SUCCESS(status)) {
  1220. printf("There is no disk registry information (%x)\n", status);
  1221. free(configHeader);
  1222. return;
  1223. }
  1224. //
  1225. // Print the header.
  1226. //
  1227. printf("Registry header information:\n");
  1228. printf("\tVersion = 0x%x, Checksum = 0x%x\n",
  1229. configHeader->Version,
  1230. configHeader->CheckSum);
  1231. printf("\tDisk info Offset = 0x%x, Size = 0x%x\n",
  1232. configHeader->DiskInformationOffset,
  1233. configHeader->DiskInformationSize);
  1234. printf("\tFT info Offset = 0x%x, Size = 0x%x\n",
  1235. configHeader->FtInformationOffset,
  1236. configHeader->FtInformationSize);
  1237. //
  1238. // Print the information on disks.
  1239. //
  1240. diskRegistry = (PDISK_REGISTRY)
  1241. ((PUCHAR) configHeader + configHeader->DiskInformationOffset);
  1242. printf("\nDisk information for %d disks:\n",
  1243. diskRegistry->NumberOfDisks);
  1244. diskDescription = &diskRegistry->Disks[0];
  1245. for (outerLoop = 0;
  1246. outerLoop < diskRegistry->NumberOfDisks;
  1247. outerLoop++) {
  1248. printf("\nDisk %d signature 0x%08x has %d partitions:\n",
  1249. outerLoop,
  1250. diskDescription->Signature,
  1251. diskDescription->NumberOfPartitions);
  1252. printf(" Ln Type Start Length FtGrp Member\n");
  1253. for (innerLoop = 0;
  1254. innerLoop < diskDescription->NumberOfPartitions;
  1255. innerLoop++) {
  1256. diskPartition = &diskDescription->Partitions[innerLoop];
  1257. printf(" %c: %c %1d %3d %08x:%08x %08x:%08x %5d %4d %s\n",
  1258. (diskPartition->DriveLetter != '\0') ?
  1259. diskPartition->DriveLetter : ' ',
  1260. (diskPartition->AssignDriveLetter) ? 'A' : ' ',
  1261. diskPartition->LogicalNumber,
  1262. diskPartition->FtType,
  1263. diskPartition->StartingOffset.HighPart,
  1264. diskPartition->StartingOffset.LowPart,
  1265. diskPartition->Length.HighPart,
  1266. diskPartition->Length.LowPart,
  1267. diskPartition->FtGroup,
  1268. diskPartition->FtMember,
  1269. (diskPartition->FtState == Orphaned) ? "Orphan" :
  1270. (diskPartition->FtState == Regenerating) ? "Regen" :
  1271. (diskPartition->FtState == Initializing) ? "Init" : "");
  1272. }
  1273. diskDescription = (PDISK_DESCRIPTION)
  1274. &diskDescription->Partitions[diskDescription->NumberOfPartitions];
  1275. }
  1276. //
  1277. // Print the information for FT.
  1278. //
  1279. if (configHeader->FtInformationSize == 0) {
  1280. printf("There is no FT configuration.\n");
  1281. free(configHeader);
  1282. return;
  1283. }
  1284. ftRegistry = (PFT_REGISTRY)
  1285. ((PUCHAR) configHeader + configHeader->FtInformationOffset);
  1286. printf("\nNumber of FT components = %d\n",
  1287. ftRegistry->NumberOfComponents);
  1288. ftDescription = &ftRegistry->FtDescription[0];
  1289. for (outerLoop = 0;
  1290. outerLoop < ftRegistry->NumberOfComponents;
  1291. outerLoop++) {
  1292. printf("Component %d has %d members and is type %d\n",
  1293. outerLoop,
  1294. ftDescription->NumberOfMembers,
  1295. ftDescription->Type);
  1296. printf(" State Signature Start Length #\n");
  1297. for (innerLoop = 0;
  1298. innerLoop < ftDescription->NumberOfMembers;
  1299. innerLoop++) {
  1300. ftMember = &ftDescription->FtMemberDescription[innerLoop];
  1301. diskPartition = (PDISK_PARTITION)
  1302. ((PUCHAR) configHeader + ftMember->OffsetToPartitionInfo);
  1303. printf("%5x %2x %08x %08x:%08x %08x:%08x %d\n",
  1304. ftMember->OffsetToPartitionInfo,
  1305. ftMember->State,
  1306. ftMember->Signature,
  1307. diskPartition->StartingOffset.HighPart,
  1308. diskPartition->StartingOffset.LowPart,
  1309. diskPartition->Length.HighPart,
  1310. diskPartition->Length.LowPart,
  1311. ftMember->LogicalNumber);
  1312. }
  1313. ftDescription = (PFT_DESCRIPTION)
  1314. &ftDescription->FtMemberDescription[ftDescription->NumberOfMembers];
  1315. }
  1316. }
  1317. VOID
  1318. ChangeMemberState(
  1319. IN ULONG Type,
  1320. IN ULONG Group,
  1321. IN ULONG Member,
  1322. IN FT_PARTITION_STATE NewState
  1323. )
  1324. /*++
  1325. Routine Description:
  1326. Set the FT state for a partition.
  1327. Arguments:
  1328. Type - the FT type.
  1329. Group - the FT Group number for that type.
  1330. Member - the member number within the group.
  1331. Return Values:
  1332. None.
  1333. --*/
  1334. {
  1335. BOOLEAN writeBackRegistry = FALSE;
  1336. HANDLE handle;
  1337. ULONG outerLoop;
  1338. ULONG innerLoop;
  1339. NTSTATUS status;
  1340. PDISK_CONFIG_HEADER configHeader;
  1341. PDISK_REGISTRY diskRegistry;
  1342. PDISK_DESCRIPTION diskDescription;
  1343. PDISK_PARTITION partitionDescription;
  1344. status = FtOpenKey(&handle,
  1345. DISK_REGISTRY_KEY);
  1346. if (!NT_SUCCESS(status)) {
  1347. printf("Currently there is no key in the registry"
  1348. " for the disk information.\n");
  1349. return;
  1350. }
  1351. configHeader = (PDISK_CONFIG_HEADER) malloc(WORK_BUFFER_SIZE);
  1352. if (configHeader == NULL) {
  1353. printf("Unable to allocate memory for the disk registy information.\n");
  1354. NtClose(handle);
  1355. return;
  1356. }
  1357. RtlZeroMemory(configHeader, WORK_BUFFER_SIZE);
  1358. status = FtReturnValue(handle,
  1359. (PUCHAR) DISK_REGISTRY_VALUE,
  1360. (PUCHAR) configHeader,
  1361. WORK_BUFFER_SIZE);
  1362. if (!NT_SUCCESS(status)) {
  1363. printf("There is no disk registry information (%x)\n", status);
  1364. free(configHeader);
  1365. NtClose(handle);
  1366. return;
  1367. }
  1368. diskRegistry = (PDISK_REGISTRY)
  1369. ((PUCHAR) configHeader + configHeader->DiskInformationOffset);
  1370. diskDescription = &diskRegistry->Disks[0];
  1371. for (outerLoop = 0;
  1372. outerLoop < diskRegistry->NumberOfDisks;
  1373. outerLoop++) {
  1374. for (innerLoop = 0;
  1375. innerLoop < diskDescription->NumberOfPartitions;
  1376. innerLoop++) {
  1377. partitionDescription = &diskDescription->Partitions[innerLoop];
  1378. if ((partitionDescription->FtType == (FT_TYPE) Type) &&
  1379. (partitionDescription->FtGroup == (USHORT) Group) &&
  1380. (partitionDescription->FtMember == (USHORT) Member)) {
  1381. partitionDescription->FtState = NewState;
  1382. writeBackRegistry = TRUE;
  1383. break;
  1384. }
  1385. }
  1386. if (writeBackRegistry == TRUE) {
  1387. ULONG size;
  1388. if (configHeader->FtInformationSize == 0) {
  1389. printf("Seems a little odd to be setting FT state " // no comma
  1390. "with no FT information...\n");
  1391. size = configHeader->DiskInformationOffset +
  1392. configHeader->DiskInformationSize;
  1393. } else {
  1394. size = configHeader->FtInformationOffset +
  1395. configHeader->FtInformationSize;
  1396. }
  1397. (VOID) FtSetValue(handle,
  1398. (PUCHAR) DISK_REGISTRY_VALUE,
  1399. (PUCHAR) configHeader,
  1400. size,
  1401. REG_BINARY);
  1402. break;
  1403. }
  1404. diskDescription = (PDISK_DESCRIPTION)
  1405. &diskDescription->Partitions[diskDescription->NumberOfPartitions];
  1406. }
  1407. NtClose(handle);
  1408. free(configHeader);
  1409. }
  1410. VOID
  1411. RestoreOrphan(
  1412. IN ULONG Type,
  1413. IN ULONG Group,
  1414. IN ULONG Member
  1415. )
  1416. /*++
  1417. Routine Description:
  1418. Set the FT state for a partition back to Healthy.
  1419. Arguments:
  1420. Type - the FT type.
  1421. Group - the FT Group number for that type.
  1422. Member - the member number within the group.
  1423. Return Values:
  1424. None.
  1425. --*/
  1426. {
  1427. ChangeMemberState(Type,
  1428. Group,
  1429. Member,
  1430. Healthy);
  1431. }
  1432. VOID
  1433. OrphanMember(
  1434. IN ULONG Type,
  1435. IN ULONG Group,
  1436. IN ULONG Member
  1437. )
  1438. /*++
  1439. Routine Description:
  1440. Set the FT state for a partition to Orphaned.
  1441. Arguments:
  1442. Type - the FT type.
  1443. Group - the FT Group number for that type.
  1444. Member - the member number within the group.
  1445. Return Values:
  1446. None.
  1447. --*/
  1448. {
  1449. ChangeMemberState(Type,
  1450. Group,
  1451. Member,
  1452. Orphaned);
  1453. }
  1454. VOID
  1455. RegenerateMember(
  1456. IN ULONG Type,
  1457. IN ULONG Group,
  1458. IN ULONG Member
  1459. )
  1460. /*++
  1461. Routine Description:
  1462. Set the FT state for a partition to regenerate.
  1463. Arguments:
  1464. Type - the FT type.
  1465. Group - the FT Group number for that type.
  1466. Member - the member number within the group.
  1467. Return Values:
  1468. None.
  1469. --*/
  1470. {
  1471. ChangeMemberState(Type,
  1472. Group,
  1473. Member,
  1474. Regenerating);
  1475. }
  1476. VOID
  1477. FixDisk()
  1478. /*++
  1479. Routine Description:
  1480. Fix the disk signatures in the registry.
  1481. Arguments:
  1482. None.
  1483. Return Values:
  1484. None.
  1485. --*/
  1486. {
  1487. ULONG outerLoop;
  1488. ULONG innerLoop;
  1489. ULONG length;
  1490. HANDLE handle;
  1491. NTSTATUS status;
  1492. PDISK_CONFIG_HEADER configHeader;
  1493. PDISK_REGISTRY diskRegistry;
  1494. PDISK_DESCRIPTION diskDescription;
  1495. PFT_REGISTRY ftRegistry;
  1496. PFT_DESCRIPTION ftDescription;
  1497. PFT_MEMBER_DESCRIPTION ftMember;
  1498. UCHAR prompt[128];
  1499. PUCHAR hexString;
  1500. BOOLEAN changed = FALSE;
  1501. status = FtOpenKey(&handle,
  1502. DISK_REGISTRY_KEY);
  1503. if (!NT_SUCCESS(status)) {
  1504. printf("Currently there is no key in the registry"
  1505. " for the disk information.\n");
  1506. return;
  1507. }
  1508. configHeader = (PDISK_CONFIG_HEADER) malloc(WORK_BUFFER_SIZE);
  1509. if (configHeader == NULL) {
  1510. printf("Unable to allocate memory for the disk registy information.\n");
  1511. NtClose(handle);
  1512. return;
  1513. }
  1514. RtlZeroMemory(configHeader, WORK_BUFFER_SIZE);
  1515. status = FtReturnValue(handle,
  1516. (PUCHAR) DISK_REGISTRY_VALUE,
  1517. (PUCHAR) configHeader,
  1518. WORK_BUFFER_SIZE);
  1519. if (!NT_SUCCESS(status)) {
  1520. printf("There is no disk registry information (%x)\n", status);
  1521. free(configHeader);
  1522. NtClose(handle);
  1523. return;
  1524. }
  1525. diskRegistry = (PDISK_REGISTRY)
  1526. ((PUCHAR) configHeader + configHeader->DiskInformationOffset);
  1527. printf("\nDisk information for %d disks:\n",
  1528. diskRegistry->NumberOfDisks);
  1529. diskDescription = &diskRegistry->Disks[0];
  1530. for (outerLoop = 0;
  1531. outerLoop < diskRegistry->NumberOfDisks;
  1532. outerLoop++) {
  1533. sprintf(prompt,
  1534. "\nDisk %d signature 0x%08x = ",
  1535. outerLoop,
  1536. diskDescription->Signature);
  1537. hexString = GetArgumentString((BOOLEAN) FALSE,
  1538. prompt,
  1539. (BOOLEAN) TRUE);
  1540. if (hexString != NULL) {
  1541. changed = ProcessHex(hexString, &diskDescription->Signature);
  1542. }
  1543. diskDescription = (PDISK_DESCRIPTION)
  1544. &diskDescription->Partitions[diskDescription->NumberOfPartitions];
  1545. }
  1546. //
  1547. // Print the information for FT.
  1548. //
  1549. if (configHeader->FtInformationSize == 0) {
  1550. printf("There is no FT configuration.\n");
  1551. free(configHeader);
  1552. NtClose(handle);
  1553. return;
  1554. }
  1555. ftRegistry = (PFT_REGISTRY)
  1556. ((PUCHAR) configHeader + configHeader->FtInformationOffset);
  1557. printf("\nNumber of FT components = %d\n",
  1558. ftRegistry->NumberOfComponents);
  1559. ftDescription = &ftRegistry->FtDescription[0];
  1560. for (outerLoop = 0;
  1561. outerLoop < ftRegistry->NumberOfComponents;
  1562. outerLoop++) {
  1563. printf("Component %d has %d members and is type %d\n",
  1564. outerLoop,
  1565. ftDescription->NumberOfMembers,
  1566. ftDescription->Type);
  1567. for (innerLoop = 0;
  1568. innerLoop < ftDescription->NumberOfMembers;
  1569. innerLoop++) {
  1570. ftMember = &ftDescription->FtMemberDescription[innerLoop];
  1571. sprintf(prompt,
  1572. "FT Member Signature 0x%x = ",
  1573. ftMember->Signature);
  1574. hexString = GetArgumentString((BOOLEAN) FALSE,
  1575. prompt,
  1576. (BOOLEAN) TRUE);
  1577. if (hexString != NULL) {
  1578. changed = ProcessHex(hexString, &ftMember->Signature);
  1579. }
  1580. }
  1581. ftDescription = (PFT_DESCRIPTION)
  1582. &ftDescription->FtMemberDescription[ftDescription->NumberOfMembers];
  1583. }
  1584. if (changed == TRUE) {
  1585. printf("Attempting to update registry information.\n");
  1586. //
  1587. // Delete the current registry value and write the new one.
  1588. //
  1589. status = FtDeleteValue(handle,
  1590. DISK_REGISTRY_VALUE);
  1591. if (!NT_SUCCESS(status)) {
  1592. printf("Could not delete value (0x%x).\n", status);
  1593. } else {
  1594. length = (ULONG) ((PCHAR)ftDescription - (PUCHAR)configHeader);
  1595. status = FtSetValue(handle,
  1596. DISK_REGISTRY_VALUE,
  1597. configHeader,
  1598. length,
  1599. REG_BINARY);
  1600. if (!NT_SUCCESS(status)) {
  1601. printf("Could not write value (0x%x)\n.", status);
  1602. }
  1603. }
  1604. }
  1605. NtClose(handle);
  1606. }
  1607. PDISK_CONFIG_HEADER
  1608. GetDiskInfo()
  1609. /*++
  1610. --*/
  1611. {
  1612. HANDLE handle;
  1613. ULONG length;
  1614. NTSTATUS status;
  1615. PDISK_CONFIG_HEADER configHeader;
  1616. status = FtOpenKey(&handle,
  1617. DISK_REGISTRY_KEY);
  1618. if (!NT_SUCCESS(status)) {
  1619. printf("Currently there is no key in the registry"
  1620. " for the disk information.\n");
  1621. return NULL;
  1622. }
  1623. configHeader = (PDISK_CONFIG_HEADER) malloc(WORK_BUFFER_SIZE);
  1624. if (configHeader == NULL) {
  1625. printf("Unable to allocate memory for the disk registy information.\n");
  1626. NtClose(handle);
  1627. return NULL;
  1628. }
  1629. RtlZeroMemory(configHeader, WORK_BUFFER_SIZE);
  1630. status = FtReturnValue(handle,
  1631. (PUCHAR) DISK_REGISTRY_VALUE,
  1632. (PUCHAR) configHeader,
  1633. WORK_BUFFER_SIZE);
  1634. NtClose(handle);
  1635. if (!NT_SUCCESS(status)) {
  1636. printf("There is no disk registry information (%x)\n", status);
  1637. free(configHeader);
  1638. return NULL;
  1639. }
  1640. return configHeader;
  1641. }
  1642. BOOLEAN
  1643. CreateFtMember(
  1644. IN PDISK_CONFIG_HEADER ConfigHeader,
  1645. IN ULONG Disk,
  1646. IN ULONG Partition,
  1647. IN ULONG Type,
  1648. IN ULONG Group,
  1649. IN ULONG Member
  1650. )
  1651. /*++
  1652. --*/
  1653. {
  1654. ULONG innerLoop;
  1655. ULONG outerLoop;
  1656. ULONG length;
  1657. NTSTATUS status;
  1658. PDISK_REGISTRY diskRegistry;
  1659. PDISK_DESCRIPTION diskDescription;
  1660. PDISK_PARTITION diskPartition;
  1661. diskRegistry = (PDISK_REGISTRY)
  1662. ((PUCHAR) ConfigHeader + ConfigHeader->DiskInformationOffset);
  1663. diskDescription = &diskRegistry->Disks[0];
  1664. //
  1665. // Have to walk the disk information by hand to find a match on
  1666. // disk number and partition
  1667. //
  1668. for (outerLoop = 0;
  1669. outerLoop < diskRegistry->NumberOfDisks;
  1670. outerLoop++) {
  1671. if (outerLoop == Disk) {
  1672. for (innerLoop = 0;
  1673. innerLoop < diskDescription->NumberOfPartitions;
  1674. innerLoop++) {
  1675. diskPartition = &diskDescription->Partitions[innerLoop];
  1676. if (diskPartition->LogicalNumber == Partition) {
  1677. //
  1678. // Found a match.
  1679. //
  1680. diskPartition->FtType = Type;
  1681. diskPartition->FtMember = Member;
  1682. diskPartition->FtGroup = Group;
  1683. diskPartition->FtState = Healthy;
  1684. diskPartition->AssignDriveLetter = FALSE;
  1685. return TRUE;
  1686. }
  1687. }
  1688. }
  1689. diskDescription = (PDISK_DESCRIPTION)
  1690. &diskDescription->Partitions[diskDescription->NumberOfPartitions];
  1691. }
  1692. //
  1693. // Didn't find it.
  1694. //
  1695. return FALSE;
  1696. }
  1697. #define DRIVER_KEY "\\REGISTRY\\MACHINE\\System\\CurrentControlSet\\Services"
  1698. #define TYPE_KEY "Type"
  1699. #define START_KEY "Start"
  1700. #define GROUP_KEY "Group"
  1701. #define DEPENDENCIES "DependOnGroup"
  1702. #if 0
  1703. VOID
  1704. DisplayLoadInformation(
  1705. IN PUNICODE_STRING DriverKey
  1706. )
  1707. /*++
  1708. Routine Description:
  1709. Arguments:
  1710. DriverKey - a Unicode string pointer for the driver key name.
  1711. Return Value:
  1712. None.
  1713. --*/
  1714. {
  1715. HANDLE keyHandle;
  1716. UNICODE_STRING unicodeKeyName;
  1717. UNICODE_STRING unicodeValueName;
  1718. ULONG resultLength;
  1719. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  1720. resultLength = WORK_BUFFER_SIZE;
  1721. keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)malloc(WORK_BUFFER_SIZE);
  1722. //
  1723. // Type
  1724. //
  1725. //
  1726. // Start
  1727. //
  1728. //
  1729. // Group
  1730. //
  1731. //
  1732. // DependOnGroup
  1733. //
  1734. while (1) {
  1735. RtlZeroMemory(keyValueInformation, resultLength);
  1736. status = NtEnumerateValueKey(KeyHandle,
  1737. 0,
  1738. KeyValueFullInformation,
  1739. keyValueInformation,
  1740. resultLength,
  1741. &resultLength);
  1742. if (status == STATUS_BUFFER_OVERFLOW) {
  1743. free(keyValueInformation);
  1744. keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)
  1745. malloc(resultLength + 10);
  1746. } else {
  1747. break;
  1748. }
  1749. }
  1750. free(keyValueInformation);
  1751. NtClose(keyHandle);
  1752. }
  1753. #else
  1754. VOID
  1755. DisplayLoadInformation(
  1756. IN PUCHAR DriverKey
  1757. )
  1758. {
  1759. UNREFERENCED_PARAMETER(DriverKey);
  1760. }
  1761. #endif
  1762. #define TEMP_BUFFER_SIZE 256
  1763. VOID
  1764. ListDrivers()
  1765. /*++
  1766. Routine Description:
  1767. Got to the load list for the drivers, interpret and display what is there.
  1768. Arguments:
  1769. None.
  1770. Return Value:
  1771. NONE
  1772. --*/
  1773. {
  1774. int index;
  1775. NTSTATUS status;
  1776. HANDLE keyHandle;
  1777. ULONG resultLength;
  1778. UCHAR tempBuffer[TEMP_BUFFER_SIZE];
  1779. ANSI_STRING ansiString;
  1780. UNICODE_STRING unicodeValueName;
  1781. PKEY_BASIC_INFORMATION keyInformation;
  1782. keyInformation = (PKEY_BASIC_INFORMATION)malloc(WORK_BUFFER_SIZE);
  1783. status = FtOpenKey(&keyHandle, DRIVER_KEY);
  1784. if (!NT_SUCCESS(status)) {
  1785. printf("Could not open Services key (0x%x).\n", status);
  1786. return;
  1787. }
  1788. for (index = 0; TRUE; index++) {
  1789. RtlZeroMemory(keyInformation, WORK_BUFFER_SIZE);
  1790. status = NtEnumerateKey(keyHandle,
  1791. index,
  1792. KeyBasicInformation,
  1793. keyInformation,
  1794. WORK_BUFFER_SIZE,
  1795. &resultLength);
  1796. if (status == STATUS_NO_MORE_ENTRIES) {
  1797. break;
  1798. } else if (!NT_SUCCESS(status)) {
  1799. printf("readreg: Error on Enumerate status = %x\n", status);
  1800. break;
  1801. }
  1802. unicodeValueName.Length = (USHORT)keyInformation->NameLength;
  1803. unicodeValueName.MaximumLength = (USHORT)keyInformation->NameLength;
  1804. unicodeValueName.Buffer = (PWSTR)&keyInformation->Name[0];
  1805. ansiString.MaximumLength = TEMP_BUFFER_SIZE;
  1806. ansiString.Length = 0L;
  1807. ansiString.Buffer = &tempBuffer[0];
  1808. RtlUnicodeStringToAnsiString(&ansiString,
  1809. &unicodeValueName,
  1810. (BOOLEAN) FALSE);
  1811. //
  1812. // Now have the key name for the driver - concatenate it and
  1813. // call the routine to display what is in the key.
  1814. //
  1815. sprintf(WorkingDirectory,
  1816. "%s\\%s",
  1817. DRIVER_KEY,
  1818. tempBuffer);
  1819. DisplayLoadInformation(WorkingDirectory);
  1820. }
  1821. free(keyInformation);
  1822. NtClose(keyHandle);
  1823. }
  1824. VOID
  1825. main()
  1826. /*++
  1827. Routine Description:
  1828. The main entry point for the user process.
  1829. This process will prompt the user for the action desired. This
  1830. includes starting performance, stopping performance, and retreiving
  1831. performance data collected by the FT driver.
  1832. Arguments:
  1833. Command line:
  1834. No options.
  1835. Return Value:
  1836. NONE
  1837. --*/
  1838. {
  1839. NTSTATUS status;
  1840. BOOLEAN batch;
  1841. PUCHAR argumentString;
  1842. int commandCode;
  1843. HANDLE keyHandle;
  1844. status = FtOpenKey(&keyHandle, REGISTRY_BASE);
  1845. if (!NT_SUCCESS(status)) {
  1846. printf("readreg: Unable to open registry base (0x%x)\n", status);
  1847. exit(1);
  1848. }
  1849. sprintf(CurrentDirectory,
  1850. REGISTRY_BASE);
  1851. //
  1852. // See if we are connected to CON
  1853. //
  1854. batch = FALSE;
  1855. // batch = (BOOLEAN)(!isatty(0));
  1856. if (!batch) {
  1857. printf("FT registry edit utility. %s:\n", Version);
  1858. }
  1859. while(1) {
  1860. while ((commandCode = GetCommand(batch,
  1861. &argumentString)) == INVALID) {
  1862. //
  1863. // Continue until we get a valid command.
  1864. //
  1865. }
  1866. if (Debug) {
  1867. printf("Command code == %d, argumentString = %s\n",
  1868. commandCode,
  1869. (argumentString == NULL) ? "(none)" : argumentString);
  1870. }
  1871. switch (commandCode) {
  1872. case DIRLONG:
  1873. Directory(keyHandle, (BOOLEAN) TRUE);
  1874. break;
  1875. case DIR:
  1876. Directory(keyHandle, (BOOLEAN) FALSE);
  1877. break;
  1878. case CREATE:
  1879. {
  1880. ULONG index;
  1881. PUCHAR keyClass;
  1882. BOOLEAN classAllocated = FALSE;
  1883. if (argumentString == NULL) {
  1884. argumentString = GetArgumentString(batch,
  1885. "Key Name = ",
  1886. (BOOLEAN) FALSE);
  1887. }
  1888. if (argumentString == NULL) {
  1889. break;
  1890. }
  1891. sprintf(WorkingDirectory,
  1892. "%s\\%s",
  1893. CurrentDirectory,
  1894. argumentString);
  1895. argumentString = GetArgumentString(batch,
  1896. "Key Class = ",
  1897. (BOOLEAN) FALSE);
  1898. if (argumentString == NULL) {
  1899. keyClass = "Default Class";
  1900. } else {
  1901. keyClass = (PUCHAR) malloc(strlen(argumentString) + FUDGE);
  1902. classAllocated = TRUE;
  1903. sprintf(keyClass,
  1904. "%s",
  1905. argumentString);
  1906. }
  1907. argumentString = GetArgumentString(batch,
  1908. "Index = ",
  1909. (BOOLEAN) TRUE);
  1910. if (argumentString == NULL) {
  1911. index = 1;
  1912. } else {
  1913. index = ParseArgumentNumeric(&argumentString);
  1914. }
  1915. if (Debug) {
  1916. printf("Creating key %s, index %d with class %s\n",
  1917. WorkingDirectory,
  1918. index,
  1919. keyClass);
  1920. }
  1921. status = FtCreateKey(WorkingDirectory,
  1922. keyClass,
  1923. index);
  1924. if (!NT_SUCCESS(status)) {
  1925. printf("Could not create key %s (0x%x).\n",
  1926. WorkingDirectory,
  1927. status);
  1928. }
  1929. if (classAllocated == TRUE) {
  1930. free(keyClass);
  1931. }
  1932. break;
  1933. }
  1934. case LIST:
  1935. List(keyHandle,
  1936. argumentString);
  1937. break;
  1938. case CHDIR:
  1939. NtClose(keyHandle);
  1940. if (argumentString == NULL) {
  1941. argumentString = GetArgumentString(batch,
  1942. "New location = ",
  1943. (BOOLEAN) TRUE);
  1944. }
  1945. if (argumentString != NULL) {
  1946. if (*argumentString == '\\') {
  1947. //
  1948. // Root relative string.
  1949. // Use text provided (i.e. %s is to avoid user crashing
  1950. // by putting %s in the string).
  1951. //
  1952. sprintf(WorkingDirectory,
  1953. "%s",
  1954. argumentString);
  1955. } else {
  1956. while ((*argumentString == '.') &&
  1957. (*(argumentString + 1) == '.')) {
  1958. if ((*(argumentString + 2) == '\\') ||
  1959. (*(argumentString + 2) == '\0')) {
  1960. PUCHAR cptr = CurrentDirectory;
  1961. //
  1962. // move argumentString past ".."
  1963. //
  1964. argumentString += 2;
  1965. //
  1966. // Find end of current directory.
  1967. //
  1968. while (*cptr != '\0') {
  1969. cptr++;
  1970. }
  1971. //
  1972. // Backup to last component.
  1973. //
  1974. while (*cptr != '\\') {
  1975. cptr--;
  1976. }
  1977. if (cptr == CurrentDirectory) {
  1978. //
  1979. // Cannot backup anymore. Continue parsing
  1980. // argument.
  1981. //
  1982. continue;
  1983. }
  1984. //
  1985. // Remove component from path.
  1986. //
  1987. *cptr = '\0';
  1988. if (*argumentString == '\0') {
  1989. //
  1990. // All done with argument.
  1991. //
  1992. break;
  1993. }
  1994. //
  1995. // Step around backslash.
  1996. //
  1997. argumentString++;
  1998. } else {
  1999. //
  2000. // Assume it is a real name.
  2001. //
  2002. break;
  2003. }
  2004. }
  2005. if (*argumentString != '\0') {
  2006. sprintf(WorkingDirectory,
  2007. "%s\\%s",
  2008. CurrentDirectory,
  2009. argumentString);
  2010. } else {
  2011. sprintf(WorkingDirectory,
  2012. "%s",
  2013. CurrentDirectory);
  2014. }
  2015. }
  2016. status = FtOpenKey(&keyHandle,
  2017. WorkingDirectory);
  2018. if (NT_SUCCESS(status)) {
  2019. sprintf(CurrentDirectory,
  2020. "%s",
  2021. WorkingDirectory);
  2022. } else {
  2023. (VOID) FtOpenKey(&keyHandle,
  2024. CurrentDirectory);
  2025. //
  2026. // No error checks because this was opened once before.
  2027. //
  2028. }
  2029. }
  2030. break;
  2031. case HELP:
  2032. {
  2033. int i;
  2034. printf("Valid commands are:\n");
  2035. for (i = 0; Commands[i] != NULL; i++) {
  2036. printf(" %10s - %s\n",
  2037. Commands[i],
  2038. CommandHelp[CommandMap[i]]);
  2039. }
  2040. break;
  2041. }
  2042. case QUIT:
  2043. exit(0);
  2044. break;
  2045. case DDEBUG:
  2046. if (argumentString == NULL) {
  2047. if (Debug) {
  2048. printf("Debug turned off.\n");
  2049. Debug = 0;
  2050. } else {
  2051. Debug = 1;
  2052. }
  2053. } else {
  2054. Debug = atoi(argumentString);
  2055. printf("Debug set to %d\n", Debug);
  2056. }
  2057. break;
  2058. case SETVALUE:
  2059. {
  2060. int i;
  2061. BOOLEAN convertToUnicode = FALSE;
  2062. PUCHAR valueName;
  2063. PUCHAR valueData;
  2064. ULONG valueLength;
  2065. ULONG valueWord;
  2066. PVOID valuePtr;
  2067. ULONG type = DEFAULT_TYPE;
  2068. STRING valueString;
  2069. UNICODE_STRING unicodeValue;
  2070. BOOLEAN dataAllocated = FALSE;
  2071. BOOLEAN unicodeAllocated = FALSE;
  2072. if (argumentString == NULL) {
  2073. argumentString = GetArgumentString(batch,
  2074. "Value Name = ",
  2075. (BOOLEAN) FALSE);
  2076. }
  2077. if (argumentString == NULL) {
  2078. break;
  2079. }
  2080. valueName = (PUCHAR) malloc(strlen(argumentString) + FUDGE);
  2081. sprintf(valueName,
  2082. "%s",
  2083. argumentString);
  2084. //
  2085. // print a help banner on type and get the type.
  2086. //
  2087. for (i = 0; TypeNames[i] != NULL; i++) {
  2088. printf("%d - %s\n", TypeNumbers[i], TypeNames[i]);
  2089. }
  2090. printf("# - Other numbers are user defined\n");
  2091. argumentString = GetArgumentString(batch,
  2092. "Numeric value for type = ",
  2093. (BOOLEAN) TRUE);
  2094. if (argumentString != NULL) {
  2095. type = ParseArgumentNumeric(&argumentString);
  2096. }
  2097. switch(type)
  2098. {
  2099. default:
  2100. case REG_SZ:
  2101. if (type == REG_SZ) {
  2102. convertToUnicode = TRUE;
  2103. printf("Typed in string will be converted to unicode...\n");
  2104. argumentString = GetArgumentString(batch,
  2105. "Value Data = ",
  2106. (BOOLEAN) FALSE);
  2107. } else {
  2108. printf("For now the data must be typed in...\n");
  2109. argumentString = GetArgumentString(batch,
  2110. "Value Data = ",
  2111. (BOOLEAN) FALSE);
  2112. }
  2113. if (argumentString == NULL) {
  2114. valueData = "Default Data";
  2115. valueLength = strlen(valueData);
  2116. } else {
  2117. valueData = (PUCHAR) malloc(strlen(argumentString) + FUDGE);
  2118. dataAllocated = TRUE;
  2119. sprintf(valueData,
  2120. "%s",
  2121. argumentString);
  2122. if (convertToUnicode == TRUE) {
  2123. RtlInitString(&valueString,
  2124. valueData);
  2125. RtlAnsiStringToUnicodeString(&unicodeValue,
  2126. &valueString,
  2127. (BOOLEAN) TRUE);
  2128. unicodeAllocated = TRUE;
  2129. valueLength = unicodeValue.Length + 2;
  2130. } else {
  2131. valueLength = strlen(valueData);
  2132. }
  2133. }
  2134. break;
  2135. case REG_DWORD:
  2136. argumentString = GetArgumentString(batch,
  2137. "Value Data Word = ",
  2138. (BOOLEAN) TRUE);
  2139. if (argumentString == NULL) {
  2140. valueWord = 0;
  2141. } else {
  2142. valueWord = ParseArgumentNumeric(&argumentString);
  2143. }
  2144. valueLength = sizeof(ULONG);
  2145. break;
  2146. }
  2147. switch (type) {
  2148. case REG_DWORD:
  2149. valuePtr = (PVOID) &valueWord;
  2150. break;
  2151. case REG_SZ:
  2152. valuePtr = (PVOID) unicodeValue.Buffer;
  2153. break;
  2154. default:
  2155. valuePtr = (PVOID) valueData;
  2156. break;
  2157. }
  2158. status = FtSetValue(keyHandle,
  2159. valueName,
  2160. valuePtr,
  2161. valueLength,
  2162. type);
  2163. if (!NT_SUCCESS(status)) {
  2164. printf("Could not set value %s (0x%x).\n", valueName, status);
  2165. }
  2166. free(valueName);
  2167. if (dataAllocated == TRUE) {
  2168. free(valueData);
  2169. }
  2170. if (unicodeAllocated == TRUE) {
  2171. RtlFreeUnicodeString(&unicodeValue);
  2172. }
  2173. break;
  2174. }
  2175. case DELKEY:
  2176. {
  2177. if (argumentString == NULL) {
  2178. argumentString = GetArgumentString(batch,
  2179. "Key Name = ",
  2180. (BOOLEAN) TRUE);
  2181. }
  2182. if (argumentString == NULL) {
  2183. break;
  2184. }
  2185. sprintf(WorkingDirectory,
  2186. "%s\\%s",
  2187. CurrentDirectory,
  2188. argumentString);
  2189. status = FtDeleteKey(WorkingDirectory);
  2190. if (!NT_SUCCESS(status)) {
  2191. printf("Unable to delete key %s (0x%x)\n",
  2192. WorkingDirectory,
  2193. status);
  2194. }
  2195. break;
  2196. }
  2197. case DELVALUE:
  2198. {
  2199. if (argumentString == NULL) {
  2200. argumentString = GetArgumentString(batch,
  2201. "Key Name = ",
  2202. (BOOLEAN) TRUE);
  2203. }
  2204. if (argumentString == NULL) {
  2205. break;
  2206. }
  2207. status = FtDeleteValue(keyHandle,
  2208. argumentString);
  2209. if (!NT_SUCCESS(status)) {
  2210. printf("Unable to delete value %s (0x%x)\n",
  2211. argumentString,
  2212. status);
  2213. }
  2214. break;
  2215. }
  2216. case INLONG:
  2217. DumpControl = InLongs;
  2218. break;
  2219. case INSHORT:
  2220. DumpControl = InShorts;
  2221. break;
  2222. case INBYTE:
  2223. DumpControl = InBytes;
  2224. break;
  2225. case DUMP:
  2226. if (ForceDump) {
  2227. ForceDump = 0;
  2228. } else {
  2229. ForceDump++;
  2230. }
  2231. break;
  2232. case DISKREG:
  2233. DiskDump();
  2234. break;
  2235. case FIXDISK:
  2236. FixDisk();
  2237. break;
  2238. case RESTORE:
  2239. {
  2240. ULONG type;
  2241. ULONG group;
  2242. ULONG member;
  2243. printf("FT types that can be restored are:\n");
  2244. printf("\t%d - for Mirrors\n", Mirror);
  2245. printf("\t%d - for Stripes with parity\n", StripeWithParity);
  2246. //
  2247. // Get the type
  2248. //
  2249. if (argumentString == NULL) {
  2250. argumentString = GetArgumentString(batch,
  2251. "FT volume type = ",
  2252. (BOOLEAN) TRUE);
  2253. }
  2254. if (argumentString != NULL) {
  2255. type = ParseArgumentNumeric(&argumentString);
  2256. } else {
  2257. break;
  2258. }
  2259. //
  2260. // Get the group
  2261. //
  2262. if (argumentString == NULL) {
  2263. argumentString = GetArgumentString(batch,
  2264. "FT group number = ",
  2265. (BOOLEAN) TRUE);
  2266. }
  2267. if (argumentString != NULL) {
  2268. group = ParseArgumentNumeric(&argumentString);
  2269. } else {
  2270. break;
  2271. }
  2272. //
  2273. // Get the member
  2274. //
  2275. if (argumentString == NULL) {
  2276. argumentString = GetArgumentString(batch,
  2277. "FT member number = ",
  2278. (BOOLEAN) TRUE);
  2279. }
  2280. if (argumentString != NULL) {
  2281. member = ParseArgumentNumeric(&argumentString);
  2282. } else {
  2283. break;
  2284. }
  2285. RestoreOrphan(type, group, member);
  2286. break;
  2287. }
  2288. case DRIVERS:
  2289. NotImplemented();
  2290. // ListDrivers();
  2291. break;
  2292. case ORPHAN:
  2293. {
  2294. ULONG type;
  2295. ULONG group;
  2296. ULONG member;
  2297. printf("FT types that can be orphaned are:\n");
  2298. printf("\t%d - for Mirrors\n", Mirror);
  2299. printf("\t%d - for Stripes with parity\n", StripeWithParity);
  2300. //
  2301. // Get the type
  2302. //
  2303. if (argumentString == NULL) {
  2304. argumentString = GetArgumentString(batch,
  2305. "FT volume type = ",
  2306. (BOOLEAN) TRUE);
  2307. }
  2308. if (argumentString != NULL) {
  2309. type = ParseArgumentNumeric(&argumentString);
  2310. } else {
  2311. break;
  2312. }
  2313. //
  2314. // Get the group
  2315. //
  2316. if (argumentString == NULL) {
  2317. argumentString = GetArgumentString(batch,
  2318. "FT group number = ",
  2319. (BOOLEAN) TRUE);
  2320. }
  2321. if (argumentString != NULL) {
  2322. group = ParseArgumentNumeric(&argumentString);
  2323. } else {
  2324. break;
  2325. }
  2326. //
  2327. // Get the member
  2328. //
  2329. if (argumentString == NULL) {
  2330. argumentString = GetArgumentString(batch,
  2331. "FT member number = ",
  2332. (BOOLEAN) TRUE);
  2333. }
  2334. if (argumentString != NULL) {
  2335. member = ParseArgumentNumeric(&argumentString);
  2336. } else {
  2337. break;
  2338. }
  2339. OrphanMember(type, group, member);
  2340. break;
  2341. }
  2342. case REGEN:
  2343. {
  2344. ULONG type;
  2345. ULONG group;
  2346. ULONG member;
  2347. printf("FT types that can be regenerated are:\n");
  2348. printf("\t%d - for Mirrors\n", Mirror);
  2349. printf("\t%d - for Stripes with parity\n", StripeWithParity);
  2350. //
  2351. // Get the type
  2352. //
  2353. if (argumentString == NULL) {
  2354. argumentString = GetArgumentString(batch,
  2355. "FT volume type = ",
  2356. (BOOLEAN) TRUE);
  2357. }
  2358. if (argumentString != NULL) {
  2359. type = ParseArgumentNumeric(&argumentString);
  2360. } else {
  2361. break;
  2362. }
  2363. //
  2364. // Get the group
  2365. //
  2366. if (argumentString == NULL) {
  2367. argumentString = GetArgumentString(batch,
  2368. "FT group number = ",
  2369. (BOOLEAN) TRUE);
  2370. }
  2371. if (argumentString != NULL) {
  2372. group = ParseArgumentNumeric(&argumentString);
  2373. } else {
  2374. break;
  2375. }
  2376. //
  2377. // Get the member
  2378. //
  2379. if (argumentString == NULL) {
  2380. argumentString = GetArgumentString(batch,
  2381. "FT member number = ",
  2382. (BOOLEAN) TRUE);
  2383. }
  2384. if (argumentString != NULL) {
  2385. member = ParseArgumentNumeric(&argumentString);
  2386. } else {
  2387. break;
  2388. }
  2389. RegenerateMember(type, group, member);
  2390. break;
  2391. }
  2392. case INIT:
  2393. {
  2394. ULONG type;
  2395. ULONG group;
  2396. ULONG member;
  2397. printf("Only stripes with parity are initialized.\n");
  2398. //
  2399. // Get the group
  2400. //
  2401. if (argumentString == NULL) {
  2402. argumentString = GetArgumentString(batch,
  2403. "Parity stripe group number = ",
  2404. (BOOLEAN) TRUE);
  2405. }
  2406. if (argumentString != NULL) {
  2407. group = ParseArgumentNumeric(&argumentString);
  2408. } else {
  2409. break;
  2410. }
  2411. ChangeMemberState(StripeWithParity,
  2412. group,
  2413. 0,
  2414. Initializing);
  2415. break;
  2416. }
  2417. case MAKEFT:
  2418. {
  2419. ULONG type;
  2420. ULONG group;
  2421. ULONG member;
  2422. ULONG disk;
  2423. ULONG partition;
  2424. PDISK_CONFIG_HEADER configHeader;
  2425. BOOLEAN doUpdate = TRUE;
  2426. configHeader = GetDiskInfo();
  2427. if (configHeader == NULL) {
  2428. break;
  2429. }
  2430. printf("\t%d for Mirrors\n", Mirror);
  2431. printf("\t%d for Stripe Set\n", Stripe);
  2432. printf("\t%d for Stripe with parity\n", StripeWithParity);
  2433. printf("\t%d for Volume Set\n", VolumeSet);
  2434. if (argumentString == NULL) {
  2435. argumentString = GetArgumentString(batch,
  2436. "Which FT set to create? ",
  2437. (BOOLEAN) TRUE);
  2438. }
  2439. if (argumentString != NULL) {
  2440. type = ParseArgumentNumeric(&argumentString);
  2441. } else {
  2442. break;
  2443. }
  2444. if (argumentString == NULL) {
  2445. argumentString = GetArgumentString(batch,
  2446. "Please give an FT group # - ",
  2447. (BOOLEAN) TRUE);
  2448. }
  2449. if (argumentString != NULL) {
  2450. group = ParseArgumentNumeric(&argumentString);
  2451. } else {
  2452. break;
  2453. }
  2454. for (member = 0; TRUE; member++) {
  2455. printf("Information for member %d\n", member);
  2456. if (argumentString == NULL) {
  2457. argumentString = GetArgumentString(batch,
  2458. "Disk Number = ",
  2459. (BOOLEAN) TRUE);
  2460. }
  2461. if (argumentString != NULL) {
  2462. disk = ParseArgumentNumeric(&argumentString);
  2463. } else {
  2464. break;
  2465. }
  2466. if (argumentString == NULL) {
  2467. argumentString = GetArgumentString(batch,
  2468. "Partition Number = ",
  2469. (BOOLEAN) TRUE);
  2470. }
  2471. if (argumentString != NULL) {
  2472. partition = ParseArgumentNumeric(&argumentString);
  2473. } else {
  2474. break;
  2475. }
  2476. if (CreateFtMember(configHeader, disk, partition, type, group, member) == FALSE) {
  2477. printf("Failed to change member state\n");
  2478. printf("No update will be made\n");
  2479. doUpdate = FALSE;
  2480. break;
  2481. }
  2482. }
  2483. if (doUpdate == TRUE) {
  2484. PDISK_REGISTRY diskRegistry;
  2485. diskRegistry = (PDISK_REGISTRY)
  2486. ((PUCHAR) configHeader + configHeader->DiskInformationOffset);
  2487. DiskRegistrySet(diskRegistry);
  2488. }
  2489. free(configHeader);
  2490. break;
  2491. }
  2492. default:
  2493. printf("WDF homer?!?\n");
  2494. break;
  2495. }
  2496. }
  2497. } // main