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.

525 lines
15 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation
  4. //
  5. // File: regsups.c
  6. //
  7. // Contents: Support routines for registry - mainly wrappers for NtAPI.
  8. // The native NT registry API deal with unweildy OBJECT_ATTRIBUTES
  9. // structures to simply name a registry entry, and also deal
  10. // with open-ended structures. This module wraps around the native
  11. // NT api and presents a more logical interface tot the registry.
  12. //
  13. // The routines all have a uniform theme:
  14. //
  15. // o Declare a KEY_XXX (NT defined) structure on the stack,
  16. // with an "arbitrary guess" for size of data.
  17. //
  18. // o Make the NT call.
  19. //
  20. // o If NT call returns STATUS_BUFFER_OVERFLOW, allocate a
  21. // KEY_XXX structure of the correct size from heap, and make
  22. // NT call again.
  23. //
  24. // o If success, copy data to caller's data buffer, and free
  25. // anything we allocated on the heap.
  26. //
  27. // With a generous initial guess for data buffer size, most of
  28. // the time these calls will make a single NT call. Only for
  29. // large data will we pay the overhead of memory allocation.
  30. //
  31. // Classes:
  32. //
  33. // Functions: KRegpAttributes
  34. // KRegpGetValueByName
  35. // KRegpGetKeyInfo
  36. // KRegpEnumKeyValues
  37. // KRegpEnumSubKeys
  38. //
  39. // History: 18 Sep 92 Milans created.
  40. //
  41. //-----------------------------------------------------------------------------
  42. #include "registry.h"
  43. #include "regsups.h"
  44. #ifdef ALLOC_PRAGMA
  45. #pragma alloc_text( PAGE, KRegpAttributes )
  46. #pragma alloc_text( PAGE, KRegpGetValueByName )
  47. #pragma alloc_text( PAGE, KRegpGetKeyInfo )
  48. #pragma alloc_text( PAGE, KRegpEnumKeyValues )
  49. #pragma alloc_text( PAGE, KRegpEnumSubKeys )
  50. #endif // ALLOC_PRAGMA
  51. //-----------------------------------------------------------------------------
  52. //
  53. // The NT Reg API uses a few open ended structs for info related calls. This
  54. // defines the max size of our structs.
  55. //
  56. // This is just an "optimization". When the NT API's want an open ended data
  57. // buffer, we will initially supply one of MAX_INFO_LENGTH. If this is not
  58. // sufficient, the NT API will return STATUS_BUFFER_OVERFLOW. At that point,
  59. // we will allocate on the heap the proper size buffer, and call again.
  60. //
  61. //-----------------------------------------------------------------------------
  62. #define MAX_INFO_LENGTH 512 // Maximum length of info bufs
  63. //-----------------------------------------------------------------------------
  64. //
  65. // Struct for Value information (ie, value name, data, etc.)
  66. //
  67. typedef struct tag_KEY_VALUE_INFORMATION {
  68. KEY_VALUE_FULL_INFORMATION vi;
  69. BYTE buffer[MAX_INFO_LENGTH];
  70. } KEY_VALUE_INFORMATION;
  71. #define KEY_VALUE_INFORMATION_LENGTH sizeof(KEY_VALUE_FULL_INFORMATION) + \
  72. MAX_INFO_LENGTH
  73. //-----------------------------------------------------------------------------
  74. //
  75. // Struct for Key information (ie, # of subkeys, # of values, etc.)
  76. //
  77. typedef struct tag_KEY_INFORMATION {
  78. KEY_FULL_INFORMATION ki;
  79. BYTE buffer[MAX_INFO_LENGTH];
  80. } KEY_INFORMATION;
  81. #define KEY_INFORMATION_LENGTH sizeof(KEY_FULL_INFORMATION) + MAX_INFO_LENGTH
  82. //-----------------------------------------------------------------------------
  83. //
  84. // Struct for a particular subkey's information
  85. //
  86. typedef struct tag_KEY_SUBKEY_INFORMATION {
  87. KEY_NODE_INFORMATION ni;
  88. BYTE buffer[MAX_INFO_LENGTH];
  89. } KEY_SUBKEY_INFORMATION;
  90. #define KEY_SUBKEY_INFORMATION_LENGTH sizeof(KEY_NODE_INFORMATION) + \
  91. MAX_INFO_LENGTH
  92. //+----------------------------------------------------------------------------
  93. //
  94. // Function: KRegpAttributes
  95. //
  96. // Synopsis: The NT reg API often calls for an Object Attributes structure
  97. // for things like names etc. This routine bundles a name and its
  98. // parent into such a structure.
  99. //
  100. // Arguments: [hParent] Handle to parent of object
  101. // [wszName] Name of object
  102. //
  103. // Returns: Address of initialized object attributes structure.
  104. //
  105. // Notes: Return value is address to static variable.
  106. //
  107. //-----------------------------------------------------------------------------
  108. OBJECT_ATTRIBUTES *
  109. KRegpAttributes(
  110. IN HANDLE hParent,
  111. IN PWSTR wszName)
  112. {
  113. static OBJECT_ATTRIBUTES objAttributes;
  114. static UNICODE_STRING usName;
  115. RtlInitUnicodeString(&usName, wszName);
  116. InitializeObjectAttributes(
  117. &objAttributes, // Destination
  118. &usName, // Name
  119. OBJ_CASE_INSENSITIVE, // Attributes
  120. hParent, // Parent
  121. NULL); // Security
  122. return(&objAttributes);
  123. }
  124. //+----------------------------------------------------------------------------
  125. //
  126. // Function: KRegpGetValueByName
  127. //
  128. // Synopsis: Given a Value Name, returns the value's data.
  129. //
  130. // Arguments: [hkey] Handle of key
  131. // [wszValueName] Value Name to query
  132. // [pbData] Pointer to data buffer
  133. // [pcbSize] Pointer to ULONG. On entry, it must show size of
  134. // data buffer. On successful exit, it will be set to
  135. // actual length of data retrieved.
  136. //
  137. // Returns: STATUS_BUFFER_TOO_SMALL, Status from NT Reg API.
  138. //
  139. //-----------------------------------------------------------------------------
  140. NTSTATUS
  141. KRegpGetValueByName(
  142. IN HKEY hKey,
  143. IN PWSTR wszValueName,
  144. OUT PBYTE pbData,
  145. IN OUT PULONG pcbSize)
  146. {
  147. KEY_VALUE_INFORMATION viValue, *pviValue;
  148. UNICODE_STRING ustrValueName;
  149. ULONG cbActualLength, cbRequiredSize;
  150. NTSTATUS Status;
  151. RtlInitUnicodeString(&ustrValueName, wszValueName);
  152. pviValue = &viValue;
  153. Status = NtQueryValueKey(
  154. hKey,
  155. &ustrValueName,
  156. KeyValueFullInformation,
  157. (PVOID) pviValue,
  158. KEY_VALUE_INFORMATION_LENGTH,
  159. &cbActualLength
  160. );
  161. if (Status == STATUS_BUFFER_OVERFLOW) {
  162. //
  163. // Our default buffer of MAX_INFO_LENGTH size didn't quite cut it
  164. // Forced to allocate from heap and make call again.
  165. //
  166. pviValue = (KEY_VALUE_INFORMATION *) ExAllocatePoolWithTag(
  167. PagedPool,
  168. cbActualLength,
  169. ' sfD');
  170. if (!pviValue) {
  171. return(STATUS_NO_MEMORY);
  172. }
  173. Status = NtQueryValueKey(
  174. hKey,
  175. &ustrValueName,
  176. KeyValueFullInformation,
  177. (PVOID) pviValue,
  178. cbActualLength,
  179. &cbActualLength);
  180. }
  181. if (!NT_SUCCESS(Status)) {
  182. goto Cleanup;
  183. }
  184. if (pviValue->vi.Type == REG_SZ) {
  185. cbRequiredSize = pviValue->vi.DataLength + sizeof(UNICODE_NULL);
  186. } else {
  187. cbRequiredSize = pviValue->vi.DataLength;
  188. }
  189. if (cbRequiredSize > *pcbSize) {
  190. Status = STATUS_BUFFER_TOO_SMALL;
  191. goto Cleanup;
  192. }
  193. RtlMoveMemory(pbData, ((BYTE *) pviValue) + pviValue->vi.DataOffset,
  194. pviValue->vi.DataLength);
  195. if (pviValue->vi.Type == REG_SZ) {
  196. ((PWSTR) pbData)[cbRequiredSize/sizeof(WCHAR) - 1] = UNICODE_NULL;
  197. }
  198. *pcbSize = cbRequiredSize;
  199. Cleanup:
  200. if (pviValue != &viValue) {
  201. //
  202. // Must have had to allocate from heap, so free the heap
  203. //
  204. DfsFree(pviValue);
  205. }
  206. return(Status);
  207. }
  208. //+----------------------------------------------------------------------------
  209. //
  210. // Function: KRegpGetKeyInfo
  211. //
  212. // Synopsis: Given a key, return the number of subkeys, values, and their
  213. // max sizes.
  214. //
  215. // Arguments: [hkey] Handle to key.
  216. // [pcNumSubKeys] Receives # of subkeys that hkey has
  217. // [pcbMaxSubKeyLength] Receives max length of subkey name
  218. // [pcNumValues] Receives # of values that hkey has
  219. // [pcbMaxValueLength] Receives max length of value name
  220. // [pcbMaxValueData] Receives max length of value data
  221. //
  222. // Returns:
  223. //
  224. //-----------------------------------------------------------------------------
  225. NTSTATUS
  226. KRegpGetKeyInfo(
  227. IN HKEY hKey,
  228. OUT PULONG pcNumSubKeys,
  229. OUT PULONG pcbMaxSubKeyLength,
  230. OUT PULONG pcNumValues,
  231. OUT PULONG pcbMaxValueName,
  232. OUT PULONG pcbMaxValueData)
  233. {
  234. KEY_INFORMATION kiInfo, *pkiInfo;
  235. ULONG lActualLength;
  236. NTSTATUS Status;
  237. pkiInfo = &kiInfo;
  238. Status = NtQueryKey(
  239. hKey,
  240. KeyFullInformation,
  241. pkiInfo,
  242. KEY_INFORMATION_LENGTH,
  243. &lActualLength);
  244. if (Status == STATUS_BUFFER_OVERFLOW) {
  245. //
  246. // Our default buffer of MAX_INFO_LENGTH size didn't quite cut it
  247. // Forced to allocate from heap and make call again.
  248. //
  249. pkiInfo = (KEY_INFORMATION *) ExAllocatePoolWithTag(
  250. PagedPool,
  251. lActualLength,
  252. ' sfD');
  253. if (!pkiInfo) {
  254. return(STATUS_NO_MEMORY);
  255. }
  256. Status = NtQueryKey(
  257. hKey,
  258. KeyFullInformation,
  259. pkiInfo,
  260. lActualLength,
  261. &lActualLength);
  262. }
  263. if (NT_SUCCESS(Status)) {
  264. *pcNumSubKeys = pkiInfo->ki.SubKeys;
  265. *pcbMaxSubKeyLength = pkiInfo->ki.MaxNameLen;
  266. *pcNumValues = pkiInfo->ki.Values;
  267. *pcbMaxValueName = pkiInfo->ki.MaxValueNameLen;
  268. *pcbMaxValueData = pkiInfo->ki.MaxValueDataLen;
  269. }
  270. if (pkiInfo != &kiInfo) {
  271. DfsFree(pkiInfo);
  272. }
  273. return(Status);
  274. }
  275. //+----------------------------------------------------------------------------
  276. //
  277. // Function: KRegpEnumKeyValues
  278. //
  279. // Synopsis: Given a key, return the name and data of the i'th value, where
  280. // the first value has an index of 0.
  281. //
  282. // Arguments: [hkey] -- Handle to key
  283. // [i] -- Index of value to get
  284. // [wszValueName] -- Pointer to buffer to hold value name.
  285. // [pcbMaxValueName] -- on entry, size in bytes of wszValueName.
  286. // On exit, will hold size of wszValueName.
  287. // [pbData] -- pointer to buffer to hold value data.
  288. // [pcbMaxDataSize] -- on entry, size of pbData. On successful
  289. // return, size of pbData.
  290. //
  291. // Returns:
  292. //
  293. //-----------------------------------------------------------------------------
  294. NTSTATUS
  295. KRegpEnumKeyValues(
  296. HKEY hKey,
  297. ULONG iValue,
  298. PWSTR wszValueName,
  299. PULONG pcbMaxValueName,
  300. PBYTE pbData,
  301. PULONG pcbMaxDataSize)
  302. {
  303. KEY_VALUE_INFORMATION viValue, *pviValue;
  304. ULONG dwActualLength;
  305. NTSTATUS Status;
  306. pviValue = &viValue;
  307. Status = NtEnumerateValueKey(
  308. hKey,
  309. iValue,
  310. KeyValueFullInformation,
  311. pviValue,
  312. KEY_VALUE_INFORMATION_LENGTH,
  313. &dwActualLength);
  314. if (Status == STATUS_BUFFER_OVERFLOW) {
  315. //
  316. // Our default buffer of MAX_INFO_LENGTH size didn't quite cut it
  317. // Forced to allocate from heap and make call again.
  318. //
  319. pviValue = (KEY_VALUE_INFORMATION *) ExAllocatePoolWithTag(
  320. PagedPool,
  321. dwActualLength,
  322. ' sfD');
  323. if (!pviValue) {
  324. return(STATUS_NO_MEMORY);
  325. }
  326. Status = NtEnumerateValueKey(
  327. hKey,
  328. iValue,
  329. KeyValueFullInformation,
  330. pviValue,
  331. dwActualLength,
  332. &dwActualLength);
  333. }
  334. if (NT_SUCCESS(Status)) {
  335. if ( (*pcbMaxValueName < pviValue->vi.NameLength) ||
  336. (*pcbMaxDataSize < pviValue->vi.DataLength) ) {
  337. Status = STATUS_BUFFER_TOO_SMALL;
  338. goto Cleanup;
  339. }
  340. *pcbMaxValueName = pviValue->vi.NameLength;
  341. RtlMoveMemory(
  342. (BYTE *) wszValueName,
  343. (BYTE *) pviValue->vi.Name,
  344. pviValue->vi.NameLength
  345. );
  346. wszValueName[pviValue->vi.NameLength / sizeof(WCHAR)] = L'\0';
  347. RtlMoveMemory(
  348. pbData,
  349. ((BYTE *) &viValue) + pviValue->vi.DataOffset,
  350. pviValue->vi.DataLength
  351. );
  352. *pcbMaxDataSize = pviValue->vi.DataLength;
  353. }
  354. Cleanup:
  355. if (pviValue != &viValue) {
  356. DfsFree(pviValue);
  357. }
  358. return(Status);
  359. }
  360. //+----------------------------------------------------------------------------
  361. //
  362. // Function: KRegpEnumSubKeys
  363. //
  364. // Synopsis: Retrieve the i'th subkey name of a key.
  365. //
  366. // Arguments: [hKey] -- Parent key
  367. // [iSubKey] -- index of the subkey
  368. // [wszSubKeyName] Buffer to hold name of subkey
  369. // [pcbMaxNameSize] On entry, size in bytes of wszSubKeyName
  370. // On exit, size of name.
  371. //
  372. // Returns:
  373. //
  374. //-----------------------------------------------------------------------------
  375. NTSTATUS
  376. KRegpEnumSubKeys(
  377. HKEY hKey,
  378. ULONG iSubKey,
  379. PWSTR wszSubKeyName,
  380. PULONG pcbMaxNameSize
  381. )
  382. {
  383. KEY_SUBKEY_INFORMATION si, *psi;
  384. ULONG dwActualLength;
  385. NTSTATUS Status;
  386. psi = &si;
  387. Status = NtEnumerateKey(
  388. hKey,
  389. iSubKey,
  390. KeyNodeInformation,
  391. psi,
  392. KEY_SUBKEY_INFORMATION_LENGTH,
  393. &dwActualLength
  394. );
  395. if (Status == STATUS_BUFFER_OVERFLOW) {
  396. //
  397. // Our default buffer of MAX_INFO_LENGTH size didn't quite cut it
  398. // Forced to allocate from heap and make call again.
  399. //
  400. psi = (KEY_SUBKEY_INFORMATION *) ExAllocatePoolWithTag(
  401. PagedPool,
  402. dwActualLength,
  403. ' sfD');
  404. if (!psi) {
  405. return(STATUS_NO_MEMORY);
  406. }
  407. Status = NtEnumerateKey(
  408. hKey,
  409. iSubKey,
  410. KeyNodeInformation,
  411. psi,
  412. dwActualLength,
  413. &dwActualLength
  414. );
  415. }
  416. if (NT_SUCCESS(Status)) {
  417. if (*pcbMaxNameSize < si.ni.NameLength) {
  418. Status = STATUS_BUFFER_TOO_SMALL;
  419. goto Cleanup;
  420. }
  421. RtlMoveMemory(
  422. (BYTE *) wszSubKeyName,
  423. (BYTE *) psi->ni.Name,
  424. psi->ni.NameLength
  425. );
  426. wszSubKeyName[psi->ni.NameLength / sizeof(WCHAR)] = UNICODE_NULL;
  427. *pcbMaxNameSize = psi->ni.NameLength;
  428. }
  429. Cleanup:
  430. if (psi != &si) {
  431. DfsFree(psi);
  432. }
  433. return(Status);
  434. }