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.

400 lines
12 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. Regekey.c
  5. Abstract:
  6. This module contains the server side implementation for the Win32
  7. Registry API to enumerate keys. That is:
  8. - BaseRegEnumKey
  9. Author:
  10. David J. Gilman (davegi) 23-Dec-1991
  11. Notes:
  12. See the Notes in Regkey.c.
  13. --*/
  14. #include <rpc.h>
  15. #include "regrpc.h"
  16. #include "localreg.h"
  17. #include "regclass.h"
  18. #include "regecls.h"
  19. #include <malloc.h>
  20. #define DEFAULT_KEY_NAME_SIZE 128
  21. #define DEFAULT_CLASS_SIZE 128
  22. error_status_t
  23. BaseRegEnumKey (
  24. IN HKEY hKey,
  25. IN DWORD dwIndex,
  26. OUT PUNICODE_STRING lpName,
  27. OUT PUNICODE_STRING lpClass OPTIONAL,
  28. OUT PFILETIME lpftLastWriteTime OPTIONAL
  29. )
  30. /*++
  31. Routine Description:
  32. Used to enumerate subkeys of an open key. This function copies the
  33. dwIndex-th subkey of hKey.
  34. Arguments:
  35. hKey - A handle to the open key. The keys returned are relative to
  36. the key pointed to by this key handle. Any of the predefined reserved
  37. handles or a previously opened key handle may be used for hKey.
  38. dwIndex - The index of the subkey to return. Note that this is for
  39. convenience, subkeys are not ordered (a new subkey has an arbitrary
  40. index). Indexes start at 0.
  41. lpName - Provides a pointer to a buffer to receive the name of the
  42. key.
  43. lpClass - If present, provides a pointer to a buffer to receive the
  44. class of the key.
  45. lpftLastWriteTime - The time when the value was last written (set or
  46. created).
  47. Return Value:
  48. Returns ERROR_SUCCESS (0) for success; error-code for failure.
  49. Notes:
  50. This function is guaranteed to operate correctly only if dwIndex
  51. starts at 0 and is incremented on successive calls without intervening
  52. calls to other registration APIs that will change the key.
  53. KEY_ENUMERATE_SUB_KEYS access is required.
  54. --*/
  55. {
  56. NTSTATUS Status;
  57. ULONG BufferLength;
  58. KEY_INFORMATION_CLASS KeyInformationClass;
  59. PVOID KeyInformation;
  60. ULONG ResultLength;
  61. BOOL fClassKey;
  62. BYTE PrivateKeyInformation[ sizeof( KEY_NODE_INFORMATION ) +
  63. DEFAULT_KEY_NAME_SIZE +
  64. DEFAULT_CLASS_SIZE ];
  65. ASSERT( lpName != NULL );
  66. //
  67. // Protect ourselves against malicious callers passing NULL
  68. // pointers.
  69. //
  70. if (lpClass == NULL) {
  71. return(ERROR_INVALID_PARAMETER);
  72. }
  73. //
  74. // Call out to Perflib if the HKEY is HKEY_PERFOMANCE_DATA or
  75. // HKEY_PERFORMANCE_TEXT or HKEY_PERFORMANCE_NLSTEXT
  76. if (hKey == HKEY_PERFORMANCE_DATA ||
  77. hKey == HKEY_PERFORMANCE_TEXT ||
  78. hKey == HKEY_PERFORMANCE_NLSTEXT ) {
  79. // if( hKey == HKEY_PERFORMANCE_DATA ) {
  80. return (error_status_t)PerfRegEnumKey (
  81. hKey,
  82. dwIndex,
  83. lpName,
  84. NULL,
  85. lpClass,
  86. lpftLastWriteTime
  87. );
  88. }
  89. //
  90. // First we assume that the information we want will fit on
  91. // PrivateKeyValueInformattion
  92. //
  93. KeyInformationClass = (ARGUMENT_PRESENT( lpClass->Buffer ))?
  94. KeyNodeInformation :
  95. KeyBasicInformation;
  96. KeyInformation = PrivateKeyInformation;
  97. BufferLength = sizeof( PrivateKeyInformation );
  98. fClassKey = FALSE;
  99. Status = STATUS_SUCCESS;
  100. //
  101. // Query for the necessary information about the supplied key.
  102. //
  103. #ifdef LOCAL
  104. //
  105. // For hkcr, we need to do special enumeration
  106. //
  107. if (REG_CLASS_IS_SPECIAL_KEY(hKey)) {
  108. Status = EnumTableGetNextEnum( &gClassesEnumTable,
  109. hKey,
  110. dwIndex,
  111. KeyInformationClass,
  112. KeyInformation,
  113. BufferLength,
  114. &ResultLength);
  115. if (!NT_SUCCESS(Status) || (NT_SUCCESS(Status) && ResultLength)) {
  116. fClassKey = TRUE;
  117. }
  118. }
  119. #endif // LOCAL
  120. if (!fClassKey) {
  121. Status = NtEnumerateKey( hKey,
  122. dwIndex,
  123. KeyInformationClass,
  124. KeyInformation,
  125. BufferLength,
  126. &ResultLength
  127. );
  128. }
  129. //
  130. // A return value of STATUS_BUFFER_TOO_SMALL would mean that there
  131. // was not enough room for even the fixed portions of the structure.
  132. //
  133. ASSERT( Status != STATUS_BUFFER_TOO_SMALL );
  134. if( Status == STATUS_BUFFER_OVERFLOW ) {
  135. //
  136. // The buffer defined in the stack wasn't big enough to hold
  137. // the Key information.
  138. // If the caller's buffer are big enough to hold the key name
  139. // and key class, then allocate a new buffer, and call the
  140. // NT API again.
  141. //
  142. if( ( ( KeyInformationClass == KeyBasicInformation ) &&
  143. ( (ULONG)( lpName->MaximumLength ) >=
  144. (( PKEY_BASIC_INFORMATION )
  145. KeyInformation )->NameLength + sizeof(UNICODE_NULL)
  146. )
  147. ) ||
  148. ( ( KeyInformationClass == KeyNodeInformation ) &&
  149. ( (ULONG)(lpName->MaximumLength) >=
  150. (( PKEY_NODE_INFORMATION )
  151. KeyInformation )->NameLength + sizeof(UNICODE_NULL)
  152. ) &&
  153. (
  154. ARGUMENT_PRESENT( lpClass->Buffer )
  155. ) &&
  156. (
  157. (ULONG)(lpClass->MaximumLength) >= (( PKEY_NODE_INFORMATION )
  158. KeyInformation )->ClassLength + sizeof(UNICODE_NULL)
  159. )
  160. )
  161. ) {
  162. BufferLength = ResultLength;
  163. KeyInformation = RtlAllocateHeap( RtlProcessHeap( ), 0,
  164. BufferLength
  165. );
  166. //
  167. // If the memory allocation fails, return a Registry error.
  168. //
  169. if( ! KeyInformation ) {
  170. return ERROR_OUTOFMEMORY;
  171. }
  172. //
  173. // Query for the necessary information about the supplied key.
  174. // This may or may not include the class depending on lpClass->Buffer
  175. // as determined above.
  176. //
  177. #ifdef LOCAL
  178. if (fClassKey) {
  179. //
  180. // For hkcr, we need to do special enumeration
  181. //
  182. Status = EnumTableGetNextEnum( &gClassesEnumTable,
  183. hKey,
  184. dwIndex,
  185. KeyInformationClass,
  186. KeyInformation,
  187. BufferLength,
  188. &ResultLength);
  189. } else
  190. #endif // LOCAL
  191. {
  192. Status = NtEnumerateKey( hKey,
  193. dwIndex,
  194. KeyInformationClass,
  195. KeyInformation,
  196. BufferLength,
  197. &ResultLength
  198. );
  199. }
  200. }
  201. }
  202. if( NT_SUCCESS( Status ) ) {
  203. //
  204. // Copy key name
  205. //
  206. if( KeyInformationClass == KeyBasicInformation ) {
  207. //
  208. // Return the name length and the name of the key.
  209. // Note that the NUL byte is included so that RPC copies the
  210. // correct number of bytes. It is decremented on the client
  211. // side.
  212. //
  213. if( (ULONG)(lpName->MaximumLength) >=
  214. (( PKEY_BASIC_INFORMATION )
  215. KeyInformation )->NameLength + sizeof( UNICODE_NULL ) ) {
  216. lpName->Length = ( USHORT )
  217. (( PKEY_BASIC_INFORMATION )
  218. KeyInformation )->NameLength;
  219. RtlMoveMemory( lpName->Buffer,
  220. (( PKEY_BASIC_INFORMATION )
  221. KeyInformation )->Name,
  222. lpName->Length
  223. );
  224. //
  225. // NUL terminate the value name.
  226. //
  227. lpName->Buffer[ lpName->Length >> 1 ] = UNICODE_NULL;
  228. lpName->Length += sizeof( UNICODE_NULL );
  229. } else {
  230. Status = STATUS_BUFFER_OVERFLOW;
  231. }
  232. //
  233. // If requested, return the last write time.
  234. //
  235. if( ARGUMENT_PRESENT( lpftLastWriteTime )) {
  236. *lpftLastWriteTime
  237. = *( PFILETIME )
  238. &(( PKEY_BASIC_INFORMATION ) KeyInformation )
  239. ->LastWriteTime;
  240. }
  241. } else {
  242. //
  243. // Return the name length and the name of the key.
  244. // Note that the NUL byte is included so that RPC copies the
  245. // correct number of bytes. It is decremented on the client
  246. // side.
  247. //
  248. if( ( (ULONG)(lpName->MaximumLength) >=
  249. (( PKEY_NODE_INFORMATION )
  250. KeyInformation )->NameLength + sizeof( UNICODE_NULL ) ) &&
  251. ( (ULONG)(lpClass->MaximumLength) >=
  252. (( PKEY_NODE_INFORMATION )
  253. KeyInformation )->ClassLength + sizeof( UNICODE_NULL) )
  254. ) {
  255. //
  256. // Copy the key name
  257. //
  258. lpName->Length = ( USHORT )
  259. (( PKEY_NODE_INFORMATION )
  260. KeyInformation )->NameLength;
  261. RtlMoveMemory( lpName->Buffer,
  262. (( PKEY_NODE_INFORMATION )
  263. KeyInformation )->Name,
  264. lpName->Length
  265. );
  266. //
  267. // NUL terminate the key name.
  268. //
  269. lpName->Buffer[ lpName->Length >> 1 ] = UNICODE_NULL;
  270. lpName->Length += sizeof( UNICODE_NULL );
  271. //
  272. // Copy the key class
  273. //
  274. lpClass->Length = (USHORT)
  275. ((( PKEY_NODE_INFORMATION ) KeyInformation )->ClassLength );
  276. RtlMoveMemory(
  277. lpClass->Buffer,
  278. ( PBYTE ) KeyInformation
  279. + (( PKEY_NODE_INFORMATION ) KeyInformation )->ClassOffset,
  280. (( PKEY_NODE_INFORMATION ) KeyInformation )->ClassLength
  281. );
  282. //
  283. // NUL terminate the class.
  284. //
  285. lpClass->Buffer[ lpClass->Length >> 1 ] = UNICODE_NULL;
  286. lpClass->Length += sizeof( UNICODE_NULL );
  287. } else {
  288. Status = STATUS_BUFFER_OVERFLOW;
  289. }
  290. //
  291. // If requested, return the last write time.
  292. //
  293. if( ARGUMENT_PRESENT( lpftLastWriteTime )) {
  294. *lpftLastWriteTime
  295. = *( PFILETIME )
  296. &(( PKEY_NODE_INFORMATION ) KeyInformation )
  297. ->LastWriteTime;
  298. }
  299. }
  300. }
  301. if( KeyInformation != PrivateKeyInformation ) {
  302. //
  303. // Free the buffer allocated.
  304. //
  305. RtlFreeHeap( RtlProcessHeap( ), 0, KeyInformation );
  306. }
  307. return (error_status_t)RtlNtStatusToDosError( Status );
  308. }