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

587 lines
16 KiB

  1. /*++
  2. Copyright (c) 1991-1993 Microsoft Corporation
  3. Module Name:
  4. diskreg.c
  5. Abstract:
  6. This is a tool to interface between applications and the configuration
  7. registry.
  8. The format of the registry information is described in the two
  9. include files ntdskreg.h and ntddft.h. The registry information
  10. is stored in a single value within the key \registry\machine\system\disk.
  11. The value name is "information". The format of this single value is
  12. a collection of "compressed" structures. Compressed structures are
  13. multi element structures where the following structure starts at the
  14. end of the preceeding structure. The picture below attempts to display
  15. this:
  16. +---------------------------------------+
  17. | |
  18. | DISK_CONFIG_HEADER |
  19. | contains the offset to the |
  20. | DISK_REGISTRY header and the |
  21. | FT_REGISTRY header. |
  22. +---------------------------------------+
  23. | |
  24. | DISK_REGISTRY |
  25. | contains a count of disks |
  26. +---------------------------------------+
  27. | |
  28. | DISK_DESCRIPTION |
  29. | contains a count of partitions |
  30. +---------------------------------------+
  31. | |
  32. | PARTITION_DESCRIPTION |
  33. | entry for each partition |
  34. +---------------------------------------+
  35. | |
  36. = More DISK_DESCRIPTION plus =
  37. = PARTITION_DESCRIPTIONS for =
  38. = the number of disks in the =
  39. = system. Note, the second disk =
  40. = description starts in the "n"th =
  41. = partition location of the memory =
  42. = area. This is the meaning of =
  43. = "compressed" format. =
  44. | |
  45. +---------------------------------------+
  46. | |
  47. | FT_REGISTRY |
  48. | contains a count of FT components |
  49. | this is located by an offset in |
  50. | the DISK_CONFIG_HEADER |
  51. +---------------------------------------+
  52. | |
  53. | FT_DESCRIPTION |
  54. | contains a count of FT members |
  55. +---------------------------------------+
  56. | |
  57. | FT_MEMBER |
  58. | entry for each member |
  59. +---------------------------------------+
  60. | |
  61. = More FT_DESCRIPTION plus =
  62. = FT_MEMBER entries for the number =
  63. = of FT compenents in the system =
  64. | |
  65. +---------------------------------------+
  66. This packing of structures is done for two reasons:
  67. 1. to conserve space in the registry. If there are only two partitions
  68. on a disk then there are only two PARTITION_DESCRIPTIONs in the
  69. registry for that disk.
  70. 2. to not impose a maximum on the number of items that can be described
  71. in the registry. For example if the number of members in a stripe
  72. set were to change from 32 to 64 there would be no effect on the
  73. registry format, only on the UI that presents it to the user.
  74. Author:
  75. Bob Rinne (bobri) 2-Apr-1992
  76. Environment:
  77. User process. Library written for DiskMan use.
  78. Notes:
  79. Revision History:
  80. 8-Dec-93 (bobri) Added double space and cdrom registry manipulation routines.
  81. --*/
  82. #include <nt.h>
  83. #include <ntrtl.h>
  84. #include <nturtl.h>
  85. #include <stdio.h>
  86. #include <stdlib.h>
  87. #include <conio.h>
  88. #include <ctype.h>
  89. #include <string.h>
  90. //#include <io.h>
  91. #include <ntdskreg.h>
  92. #include <ntddft.h>
  93. #include <ntdddisk.h>
  94. #include <windef.h>
  95. #include <winbase.h>
  96. //
  97. // Size of memory area to allocate for configuration registry use.
  98. //
  99. #define DISKS_PRINT printf
  100. //
  101. // Constant strings.
  102. //
  103. PUCHAR DiskRegistryKey = DISK_REGISTRY_KEY;
  104. PUCHAR DiskRegistryValue = DISK_REGISTRY_VALUE;
  105. NTSTATUS
  106. FtCreateKey(
  107. PHANDLE HandlePtr,
  108. PUCHAR KeyName,
  109. PUCHAR KeyClass
  110. )
  111. /*++
  112. Routine Description:
  113. Given an asciiz name, this routine will create a key in the configuration
  114. registry.
  115. Arguments:
  116. HandlePtr - pointer to handle if create is successful.
  117. KeyName - asciiz string, the name of the key to create.
  118. KeyClass - registry class for the new key.
  119. DiskInfo - disk information for the associated partition.
  120. Return Value:
  121. NTSTATUS - from the config registry calls.
  122. --*/
  123. {
  124. NTSTATUS status;
  125. STRING keyString;
  126. UNICODE_STRING unicodeKeyName;
  127. STRING classString;
  128. UNICODE_STRING unicodeClassName;
  129. OBJECT_ATTRIBUTES objectAttributes;
  130. ULONG disposition;
  131. HANDLE tempHandle;
  132. #if DBG
  133. if ((KeyName == NULL) ||
  134. (KeyClass == NULL)) {
  135. DISKS_PRINT("FtCreateKey: Invalid parameter 0x%1!x!, 0x%2!x!\n",
  136. KeyName,
  137. KeyClass);
  138. ASSERT(0);
  139. }
  140. #endif
  141. //
  142. // Initialize the object for the key.
  143. //
  144. RtlInitString(&keyString,
  145. KeyName);
  146. (VOID)RtlAnsiStringToUnicodeString(&unicodeKeyName,
  147. &keyString,
  148. TRUE);
  149. memset(&objectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
  150. InitializeObjectAttributes(&objectAttributes,
  151. &unicodeKeyName,
  152. OBJ_CASE_INSENSITIVE,
  153. NULL,
  154. NULL);
  155. //
  156. // Setup the unicode class value.
  157. //
  158. RtlInitString(&classString,
  159. KeyClass);
  160. (VOID)RtlAnsiStringToUnicodeString(&unicodeClassName,
  161. &classString,
  162. TRUE);
  163. //
  164. // Create the key.
  165. //
  166. status = NtCreateKey(&tempHandle,
  167. KEY_READ | KEY_WRITE,
  168. &objectAttributes,
  169. 0,
  170. &unicodeClassName,
  171. REG_OPTION_NON_VOLATILE,
  172. &disposition);
  173. if (NT_SUCCESS(status)) {
  174. switch (disposition)
  175. {
  176. case REG_CREATED_NEW_KEY:
  177. break;
  178. case REG_OPENED_EXISTING_KEY:
  179. DISKS_PRINT("Warning: Creation was for an existing key!\n");
  180. break;
  181. default:
  182. DISKS_PRINT("New disposition returned == 0x%x\n", disposition);
  183. break;
  184. }
  185. }
  186. //
  187. // Free all allocated space.
  188. //
  189. RtlFreeUnicodeString(&unicodeKeyName);
  190. RtlFreeUnicodeString(&unicodeClassName);
  191. if (HandlePtr != NULL) {
  192. *HandlePtr = tempHandle;
  193. } else {
  194. NtClose(tempHandle);
  195. }
  196. return status;
  197. }
  198. NTSTATUS
  199. FtOpenKey(
  200. PHANDLE HandlePtr,
  201. PUCHAR KeyName,
  202. PUCHAR CreateKeyClass
  203. )
  204. /*++
  205. Routine Description:
  206. Given an asciiz string, this routine will open a key in the configuration
  207. registry and return the HANDLE to the caller.
  208. Arguments:
  209. HandlePtr - location for HANDLE on success.
  210. KeyName - asciiz string for the key to be opened.
  211. CreateKeyClass - if NULL do not create key name.
  212. If !NULL call create if open fails.
  213. Return Value:
  214. NTSTATUS - from the config registry calls.
  215. --*/
  216. {
  217. NTSTATUS status;
  218. STRING keyString;
  219. OBJECT_ATTRIBUTES objectAttributes;
  220. UNICODE_STRING unicodeKeyName;
  221. RtlInitString(&keyString,
  222. KeyName);
  223. (VOID)RtlAnsiStringToUnicodeString(&unicodeKeyName,
  224. &keyString,
  225. TRUE);
  226. memset(&objectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
  227. InitializeObjectAttributes(&objectAttributes,
  228. &unicodeKeyName,
  229. OBJ_CASE_INSENSITIVE,
  230. NULL,
  231. NULL);
  232. status = NtOpenKey(HandlePtr,
  233. MAXIMUM_ALLOWED,
  234. &objectAttributes);
  235. RtlFreeUnicodeString(&unicodeKeyName);
  236. if ((!NT_SUCCESS(status)) && (CreateKeyClass)) {
  237. status = FtCreateKey(HandlePtr,
  238. KeyName,
  239. CreateKeyClass);
  240. }
  241. return status;
  242. }
  243. NTSTATUS
  244. FtRegistryQuery(
  245. IN PUCHAR ValueName,
  246. OUT PVOID *FreeToken,
  247. OUT PVOID *Buffer,
  248. OUT ULONG *LengthReturned,
  249. OUT PHANDLE HandlePtr
  250. )
  251. /*++
  252. Routine Description:
  253. This routine opens the Disk Registry key and gets the contents of the
  254. disk information value. It returns this contents to the caller.
  255. Arguments:
  256. ValueName - asciiz string for the value name to query.
  257. FreeToken - A pointer to a buffer to be freed by the caller. This is the
  258. buffer pointer allocated to obtain the registry information
  259. via the registry APIs. To the caller it is an opaque value.
  260. Buffer - pointer to a pointer for a buffer containing the desired
  261. registry value contents. This is allocated by this routine and
  262. is part of the "FreeToken" buffer allocated once the actual
  263. size of the registry information is known.
  264. LengthReturned - pointer to location for the size of the contents returned.
  265. HandlePtr - pointer to a handle pointer if the caller wishes to keep it
  266. open for later use.
  267. Return Value:
  268. NTSTATUS - from the configuration registry.
  269. --*/
  270. {
  271. NTSTATUS status;
  272. HANDLE handle;
  273. ULONG resultLength;
  274. STRING valueString;
  275. UNICODE_STRING unicodeValueName;
  276. PDISK_CONFIG_HEADER regHeader;
  277. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  278. *LengthReturned = 0;
  279. status = FtOpenKey(&handle,
  280. DiskRegistryKey,
  281. NULL);
  282. if (NT_SUCCESS(status)) {
  283. RtlInitString(&valueString,
  284. ValueName);
  285. RtlAnsiStringToUnicodeString(&unicodeValueName,
  286. &valueString,
  287. TRUE);
  288. resultLength = 0;
  289. while (1) {
  290. if ( resultLength != 0 ) {
  291. keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)
  292. LocalAlloc(LMEM_FIXED, resultLength);
  293. }
  294. //
  295. // PREFIX bug: 47610
  296. // If the memory can't be allocated, stop processing. This code will
  297. // correctly fall through and return NULL to FreeToken (because
  298. // keyValueInformation is NULL).
  299. //
  300. if ( !keyValueInformation ) {
  301. status = STATUS_NO_MEMORY;
  302. break;
  303. }
  304. status = NtQueryValueKey(handle,
  305. &unicodeValueName,
  306. KeyValueFullInformation,
  307. keyValueInformation,
  308. resultLength,
  309. &resultLength);
  310. if ( status != STATUS_BUFFER_TOO_SMALL ) {
  311. //
  312. // Either a real error or the information fit.
  313. //
  314. break;
  315. }
  316. }
  317. RtlFreeUnicodeString(&unicodeValueName);
  318. if (HandlePtr != NULL) {
  319. *HandlePtr = handle;
  320. } else {
  321. NtClose(handle);
  322. }
  323. if (NT_SUCCESS(status)) {
  324. if (keyValueInformation->DataLength == 0) {
  325. //
  326. // Treat this as if there was not disk information.
  327. //
  328. LocalFree(keyValueInformation);
  329. *FreeToken = (PVOID) NULL;
  330. return STATUS_OBJECT_NAME_NOT_FOUND;
  331. } else {
  332. //
  333. // Set up the pointers for the caller.
  334. //
  335. regHeader = (PDISK_CONFIG_HEADER)
  336. ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset);
  337. *LengthReturned = regHeader->FtInformationOffset +
  338. regHeader->FtInformationSize;
  339. *Buffer = (PVOID) regHeader;
  340. }
  341. }
  342. *FreeToken = (PVOID) keyValueInformation;
  343. } else {
  344. *FreeToken = (PVOID) NULL;
  345. }
  346. return status;
  347. }
  348. BOOLEAN
  349. GetAssignedDriveLetter(
  350. ULONG Signature,
  351. LARGE_INTEGER StartingOffset,
  352. LARGE_INTEGER Length,
  353. PUCHAR DriveLetter,
  354. PULONG Partition
  355. )
  356. /*++
  357. Routine Description:
  358. This routine will get the information from the disk registry
  359. and return the drive letter assigned for the partition in
  360. the registry information.
  361. Arguments:
  362. Signature - disk signature for disk containing partition for letter.
  363. StartingOffset - Starting offset of partition for the letter.
  364. Length - length of specified partition.
  365. DriveLetter - Place to return drive letter for partition.
  366. Partition - Found partition number.
  367. Return Value:
  368. TRUE if all works.
  369. --*/
  370. {
  371. PVOID freeToken = NULL;
  372. ULONG lengthReturned,
  373. i,
  374. j;
  375. NTSTATUS status;
  376. PDISK_CONFIG_HEADER regHeader;
  377. PDISK_REGISTRY diskRegistry;
  378. PDISK_DESCRIPTION diskDescription;
  379. PDISK_PARTITION diskPartition;
  380. HANDLE handle;
  381. *DriveLetter = ' ';
  382. //
  383. // Get the registry information.
  384. //
  385. status = FtRegistryQuery(DiskRegistryValue,
  386. &freeToken,
  387. (PVOID *) &regHeader,
  388. &lengthReturned,
  389. &handle);
  390. if (!NT_SUCCESS(status)) {
  391. //
  392. // Could be permission problem, or there is no registry information.
  393. //
  394. lengthReturned = 0;
  395. //
  396. // Try to open the key for later use when setting the new value.
  397. //
  398. status = FtOpenKey(&handle,
  399. DiskRegistryKey,
  400. NULL);
  401. }
  402. if (!NT_SUCCESS(status)) {
  403. //
  404. // There is no registry key for the disk information.
  405. // Return FALSE and force caller to create registry information.
  406. //
  407. return FALSE;
  408. }
  409. if (lengthReturned == 0) {
  410. //
  411. // There is currently no registry information.
  412. //
  413. NtClose(handle);
  414. LocalFree(freeToken);
  415. return FALSE;
  416. }
  417. //
  418. // Search all disks.
  419. //
  420. diskRegistry = (PDISK_REGISTRY)
  421. ((PUCHAR)regHeader + regHeader->DiskInformationOffset);
  422. diskDescription = &diskRegistry->Disks[0];
  423. for (i = 0; i < diskRegistry->NumberOfDisks; i++) {
  424. if ( diskDescription->Signature != Signature ) {
  425. goto next_disk;
  426. }
  427. //
  428. // Now locate the partition.
  429. //
  430. for (j = 0; j < diskDescription->NumberOfPartitions; j++) {
  431. diskPartition = &diskDescription->Partitions[j];
  432. if ( (diskPartition->StartingOffset.QuadPart == StartingOffset.QuadPart) &&
  433. (diskPartition->Length.QuadPart == Length.QuadPart) ) {
  434. *DriveLetter = diskPartition->DriveLetter;
  435. *Partition = j;
  436. NtClose(handle);
  437. LocalFree( freeToken );
  438. return TRUE;
  439. }
  440. }
  441. next_disk:
  442. //
  443. // Look at the next disk
  444. //
  445. diskDescription = (PDISK_DESCRIPTION)
  446. &diskDescription->Partitions[diskDescription->NumberOfPartitions];
  447. }
  448. NtClose(handle);
  449. LocalFree(freeToken);
  450. return TRUE;
  451. }