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.

1421 lines
43 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. cmsubs2.c
  5. Abstract:
  6. This module various support routines for the configuration manager.
  7. The routines in this module are independent enough to be linked into
  8. any other program. The routines in cmsubs.c are not.
  9. Author:
  10. Bryan M. Willman (bryanwi) 12-Sep-1991
  11. Revision History:
  12. --*/
  13. #include "cmp.h"
  14. BOOLEAN
  15. CmpGetValueDataFromCache(
  16. IN PHHIVE Hive,
  17. IN PPCM_CACHED_VALUE ContainingList,
  18. IN PCELL_DATA ValueKey,
  19. IN BOOLEAN ValueCached,
  20. OUT PUCHAR *DataPointer,
  21. OUT PBOOLEAN Allocated,
  22. OUT PHCELL_INDEX CellToRelease
  23. );
  24. #ifdef ALLOC_PRAGMA
  25. #pragma alloc_text(PAGE,CmpGetValueDataFromCache)
  26. #pragma alloc_text(PAGE,CmpQueryKeyData)
  27. #pragma alloc_text(PAGE,CmpQueryKeyDataFromCache)
  28. #pragma alloc_text(PAGE,CmpQueryKeyValueData)
  29. #endif
  30. //
  31. // Define alignment macro.
  32. //
  33. #define ALIGN_OFFSET(Offset) (ULONG) \
  34. ((((ULONG)(Offset) + sizeof(ULONG)-1)) & (~(sizeof(ULONG) - 1)))
  35. #define ALIGN_OFFSET64(Offset) (ULONG) \
  36. ((((ULONG)(Offset) + sizeof(ULONGLONG)-1)) & (~(sizeof(ULONGLONG) - 1)))
  37. //
  38. // Data transfer workers
  39. //
  40. #ifdef CMP_STATS
  41. extern struct {
  42. ULONG BasicInformation;
  43. UINT64 BasicInformationTimeCounter;
  44. UINT64 BasicInformationTimeElapsed;
  45. ULONG NodeInformation;
  46. UINT64 NodeInformationTimeCounter;
  47. UINT64 NodeInformationTimeElapsed;
  48. ULONG FullInformation;
  49. UINT64 FullInformationTimeCounter;
  50. UINT64 FullInformationTimeElapsed;
  51. ULONG EnumerateKeyBasicInformation;
  52. UINT64 EnumerateKeyBasicInformationTimeCounter;
  53. UINT64 EnumerateKeyBasicInformationTimeElapsed;
  54. ULONG EnumerateKeyNodeInformation;
  55. UINT64 EnumerateKeyNodeInformationTimeCounter;
  56. UINT64 EnumerateKeyNodeInformationTimeElapsed;
  57. ULONG EnumerateKeyFullInformation;
  58. UINT64 EnumerateKeyFullInformationTimeCounter;
  59. UINT64 EnumerateKeyFullInformationTimeElapsed;
  60. } CmpQueryKeyDataDebug;
  61. UINT64 CmpGetTimeStamp()
  62. {
  63. LARGE_INTEGER CurrentTime;
  64. LARGE_INTEGER PerfFrequency;
  65. UINT64 Freq;
  66. UINT64 Time;
  67. CurrentTime = KeQueryPerformanceCounter(&PerfFrequency);
  68. //
  69. // Convert the perffrequency into 100ns interval.
  70. //
  71. Freq = 0;
  72. Freq |= PerfFrequency.HighPart;
  73. Freq = Freq << 32;
  74. Freq |= PerfFrequency.LowPart;
  75. //
  76. // Convert from LARGE_INTEGER to UINT64
  77. //
  78. Time = 0;
  79. Time |= CurrentTime.HighPart;
  80. Time = Time << 32;
  81. Time |= CurrentTime.LowPart;
  82. // Normalize cycles with the frequency.
  83. Time *= 10000000;
  84. Time /= Freq;
  85. return Time;
  86. }
  87. #endif
  88. NTSTATUS
  89. CmpQueryKeyData(
  90. PHHIVE Hive,
  91. PCM_KEY_NODE Node,
  92. KEY_INFORMATION_CLASS KeyInformationClass,
  93. PVOID KeyInformation,
  94. ULONG Length,
  95. PULONG ResultLength
  96. #if defined(CMP_STATS) || defined(CMP_KCB_CACHE_VALIDATION)
  97. ,
  98. PCM_KEY_CONTROL_BLOCK Kcb
  99. #endif
  100. )
  101. /*++
  102. Routine Description:
  103. Do the actual copy of data for a key into caller's buffer.
  104. If KeyInformation is not long enough to hold all requested data,
  105. STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be
  106. set to the number of bytes actually required.
  107. Arguments:
  108. Hive - supplies a pointer to the hive control structure for the hive
  109. Node - Supplies pointer to node whose subkeys are to be found
  110. KeyInformationClass - Specifies the type of information returned in
  111. Buffer. One of the following types:
  112. KeyBasicInformation - return last write time, title index, and name.
  113. (see KEY_BASIC_INFORMATION structure)
  114. KeyNodeInformation - return last write time, title index, name, class.
  115. (see KEY_NODE_INFORMATION structure)
  116. KeyInformation -Supplies pointer to buffer to receive the data.
  117. Length - Length of KeyInformation in bytes.
  118. ResultLength - Number of bytes actually written into KeyInformation.
  119. Return Value:
  120. NTSTATUS - Result code from call, among the following:
  121. <TBS>
  122. --*/
  123. {
  124. NTSTATUS status;
  125. PCELL_DATA pclass;
  126. ULONG requiredlength;
  127. LONG leftlength;
  128. ULONG offset;
  129. ULONG minimumlength;
  130. PKEY_INFORMATION pbuffer;
  131. USHORT NameLength;
  132. #ifdef CMP_STATS
  133. //LARGE_INTEGER StartSystemTime;
  134. //LARGE_INTEGER EndSystemTime;
  135. UINT64 StartSystemTime;
  136. UINT64 EndSystemTime;
  137. PUINT64 TimeCounter = NULL;
  138. PUINT64 TimeElapsed = NULL;
  139. //KeQuerySystemTime(&StartSystemTime);
  140. //StartSystemTime = KeQueryPerformanceCounter(NULL);
  141. StartSystemTime = CmpGetTimeStamp();
  142. #endif //CMP_STATS
  143. #ifdef CMP_KCB_CACHE_VALIDATION
  144. //
  145. // We have cached a lot of info into the kcb; Here is some validation code
  146. //
  147. if( Kcb ) {
  148. BEGIN_KCB_LOCK_GUARD;
  149. CmpLockKCBTree();
  150. // number of values
  151. ASSERT( Node->ValueList.Count == Kcb->ValueCache.Count );
  152. // number of subkeys
  153. if( !(Kcb->ExtFlags & CM_KCB_INVALID_CACHED_INFO) ) {
  154. // there is some cached info
  155. ULONG SubKeyCount = Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile];
  156. if( Kcb->ExtFlags & CM_KCB_NO_SUBKEY ) {
  157. ASSERT( SubKeyCount == 0 );
  158. } else if( Kcb->ExtFlags & CM_KCB_SUBKEY_ONE ) {
  159. ASSERT( SubKeyCount == 1 );
  160. } else if( Kcb->ExtFlags & CM_KCB_SUBKEY_HINT ) {
  161. ASSERT( SubKeyCount == Kcb->IndexHint->Count );
  162. } else {
  163. ASSERT( SubKeyCount == Kcb->SubKeyCount );
  164. }
  165. }
  166. // LastWriteTime
  167. ASSERT( Node->LastWriteTime.QuadPart == Kcb->KcbLastWriteTime.QuadPart );
  168. // MaxNameLen
  169. ASSERT( Node->MaxNameLen == Kcb->KcbMaxNameLen );
  170. // MaxValueNameLen
  171. ASSERT( Node->MaxValueNameLen == Kcb->KcbMaxValueNameLen );
  172. // MaxValueDataLen
  173. ASSERT( Node->MaxValueDataLen == Kcb->KcbMaxValueDataLen );
  174. CmpUnlockKCBTree();
  175. END_KCB_LOCK_GUARD;
  176. }
  177. #endif //CMP_KCB_CACHE_VALIDATION
  178. pbuffer = (PKEY_INFORMATION)KeyInformation;
  179. NameLength = CmpHKeyNameLen(Node);
  180. switch (KeyInformationClass) {
  181. case KeyBasicInformation:
  182. #ifdef CMP_STATS
  183. if(Kcb) {
  184. CmpQueryKeyDataDebug.BasicInformation++;
  185. TimeCounter = &(CmpQueryKeyDataDebug.BasicInformationTimeCounter);
  186. TimeElapsed = &(CmpQueryKeyDataDebug.BasicInformationTimeElapsed);
  187. } else {
  188. CmpQueryKeyDataDebug.EnumerateKeyBasicInformation++;
  189. TimeCounter = &(CmpQueryKeyDataDebug.EnumerateKeyBasicInformationTimeCounter);
  190. TimeElapsed = &(CmpQueryKeyDataDebug.EnumerateKeyBasicInformationTimeElapsed);
  191. }
  192. #endif //CMP_STATS
  193. //
  194. // LastWriteTime, TitleIndex, NameLength, Name
  195. requiredlength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) +
  196. NameLength;
  197. minimumlength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name);
  198. *ResultLength = requiredlength;
  199. status = STATUS_SUCCESS;
  200. if (Length < minimumlength) {
  201. status = STATUS_BUFFER_TOO_SMALL;
  202. } else {
  203. pbuffer->KeyBasicInformation.LastWriteTime =
  204. Node->LastWriteTime;
  205. pbuffer->KeyBasicInformation.TitleIndex = 0;
  206. pbuffer->KeyBasicInformation.NameLength =
  207. NameLength;
  208. leftlength = Length - minimumlength;
  209. requiredlength = NameLength;
  210. if (leftlength < (LONG)requiredlength) {
  211. requiredlength = leftlength;
  212. status = STATUS_BUFFER_OVERFLOW;
  213. }
  214. if (Node->Flags & KEY_COMP_NAME) {
  215. CmpCopyCompressedName(pbuffer->KeyBasicInformation.Name,
  216. leftlength,
  217. Node->Name,
  218. Node->NameLength);
  219. } else {
  220. RtlCopyMemory(
  221. &(pbuffer->KeyBasicInformation.Name[0]),
  222. &(Node->Name[0]),
  223. requiredlength
  224. );
  225. }
  226. }
  227. break;
  228. case KeyNodeInformation:
  229. #ifdef CMP_STATS
  230. if(Kcb) {
  231. CmpQueryKeyDataDebug.NodeInformation++;
  232. TimeCounter = &(CmpQueryKeyDataDebug.NodeInformationTimeCounter);
  233. TimeElapsed = &(CmpQueryKeyDataDebug.NodeInformationTimeElapsed);
  234. } else {
  235. CmpQueryKeyDataDebug.EnumerateKeyNodeInformation++;
  236. TimeCounter = &(CmpQueryKeyDataDebug.EnumerateKeyNodeInformationTimeCounter);
  237. TimeElapsed = &(CmpQueryKeyDataDebug.EnumerateKeyNodeInformationTimeElapsed);
  238. }
  239. #endif //CMP_STATS
  240. //
  241. // LastWriteTime, TitleIndex, ClassOffset, ClassLength
  242. // NameLength, Name, Class
  243. //
  244. requiredlength = FIELD_OFFSET(KEY_NODE_INFORMATION, Name) +
  245. NameLength +
  246. Node->ClassLength;
  247. minimumlength = FIELD_OFFSET(KEY_NODE_INFORMATION, Name);
  248. *ResultLength = requiredlength;
  249. status = STATUS_SUCCESS;
  250. if (Length < minimumlength) {
  251. status = STATUS_BUFFER_TOO_SMALL;
  252. } else {
  253. pbuffer->KeyNodeInformation.LastWriteTime =
  254. Node->LastWriteTime;
  255. pbuffer->KeyNodeInformation.TitleIndex = 0;
  256. pbuffer->KeyNodeInformation.ClassLength =
  257. Node->ClassLength;
  258. pbuffer->KeyNodeInformation.NameLength =
  259. NameLength;
  260. leftlength = Length - minimumlength;
  261. requiredlength = NameLength;
  262. if (leftlength < (LONG)requiredlength) {
  263. requiredlength = leftlength;
  264. status = STATUS_BUFFER_OVERFLOW;
  265. }
  266. if (Node->Flags & KEY_COMP_NAME) {
  267. CmpCopyCompressedName(pbuffer->KeyNodeInformation.Name,
  268. leftlength,
  269. Node->Name,
  270. Node->NameLength);
  271. } else {
  272. RtlCopyMemory(
  273. &(pbuffer->KeyNodeInformation.Name[0]),
  274. &(Node->Name[0]),
  275. requiredlength
  276. );
  277. }
  278. if (Node->ClassLength > 0) {
  279. offset = FIELD_OFFSET(KEY_NODE_INFORMATION, Name) +
  280. NameLength;
  281. offset = ALIGN_OFFSET(offset);
  282. pbuffer->KeyNodeInformation.ClassOffset = offset;
  283. pclass = HvGetCell(Hive, Node->Class);
  284. if( pclass == NULL ) {
  285. //
  286. // we couldn't map this cell
  287. //
  288. status = STATUS_INSUFFICIENT_RESOURCES;
  289. break;
  290. }
  291. pbuffer = (PKEY_INFORMATION)((PUCHAR)pbuffer + offset);
  292. leftlength = (((LONG)Length - (LONG)offset) < 0) ?
  293. 0 :
  294. Length - offset;
  295. requiredlength = Node->ClassLength;
  296. if (leftlength < (LONG)requiredlength) {
  297. requiredlength = leftlength;
  298. status = STATUS_BUFFER_OVERFLOW;
  299. }
  300. RtlCopyMemory(
  301. pbuffer,
  302. pclass,
  303. requiredlength
  304. );
  305. HvReleaseCell(Hive,Node->Class);
  306. } else {
  307. pbuffer->KeyNodeInformation.ClassOffset = (ULONG)-1;
  308. }
  309. }
  310. break;
  311. case KeyFullInformation:
  312. #ifdef CMP_STATS
  313. if(Kcb) {
  314. CmpQueryKeyDataDebug.FullInformation++;
  315. TimeCounter = &(CmpQueryKeyDataDebug.FullInformationTimeCounter);
  316. TimeElapsed = &(CmpQueryKeyDataDebug.FullInformationTimeElapsed);
  317. } else {
  318. CmpQueryKeyDataDebug.EnumerateKeyFullInformation++;
  319. TimeCounter = &(CmpQueryKeyDataDebug.EnumerateKeyFullInformationTimeCounter);
  320. TimeElapsed = &(CmpQueryKeyDataDebug.EnumerateKeyFullInformationTimeElapsed);
  321. }
  322. #endif //CMP_STATS
  323. //
  324. // LastWriteTime, TitleIndex, ClassOffset, ClassLength,
  325. // SubKeys, MaxNameLen, MaxClassLen, Values, MaxValueNameLen,
  326. // MaxValueDataLen, Class
  327. //
  328. requiredlength = FIELD_OFFSET(KEY_FULL_INFORMATION, Class) +
  329. Node->ClassLength;
  330. minimumlength = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
  331. *ResultLength = requiredlength;
  332. status = STATUS_SUCCESS;
  333. if (Length < minimumlength) {
  334. status = STATUS_BUFFER_TOO_SMALL;
  335. } else {
  336. pbuffer->KeyFullInformation.LastWriteTime =
  337. Node->LastWriteTime;
  338. pbuffer->KeyFullInformation.TitleIndex = 0;
  339. pbuffer->KeyFullInformation.ClassLength =
  340. Node->ClassLength;
  341. if (Node->ClassLength > 0) {
  342. pbuffer->KeyFullInformation.ClassOffset =
  343. FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
  344. pclass = HvGetCell(Hive, Node->Class);
  345. if( pclass == NULL ) {
  346. //
  347. // we couldn't map this cell
  348. //
  349. status = STATUS_INSUFFICIENT_RESOURCES;
  350. break;
  351. }
  352. leftlength = Length - minimumlength;
  353. requiredlength = Node->ClassLength;
  354. if (leftlength < (LONG)requiredlength) {
  355. requiredlength = leftlength;
  356. status = STATUS_BUFFER_OVERFLOW;
  357. }
  358. RtlCopyMemory(
  359. &(pbuffer->KeyFullInformation.Class[0]),
  360. pclass,
  361. requiredlength
  362. );
  363. HvReleaseCell(Hive,Node->Class);
  364. } else {
  365. pbuffer->KeyFullInformation.ClassOffset = (ULONG)-1;
  366. }
  367. pbuffer->KeyFullInformation.SubKeys =
  368. Node->SubKeyCounts[Stable] +
  369. Node->SubKeyCounts[Volatile];
  370. pbuffer->KeyFullInformation.Values =
  371. Node->ValueList.Count;
  372. pbuffer->KeyFullInformation.MaxNameLen =
  373. Node->MaxNameLen;
  374. pbuffer->KeyFullInformation.MaxClassLen =
  375. Node->MaxClassLen;
  376. pbuffer->KeyFullInformation.MaxValueNameLen =
  377. Node->MaxValueNameLen;
  378. pbuffer->KeyFullInformation.MaxValueDataLen =
  379. Node->MaxValueDataLen;
  380. }
  381. break;
  382. default:
  383. status = STATUS_INVALID_PARAMETER;
  384. break;
  385. }
  386. #ifdef CMP_STATS
  387. if( TimeCounter && TimeElapsed ){
  388. //EndSystemTime = KeQueryPerformanceCounter(NULL);
  389. //KeQuerySystemTime(&EndSystemTime);
  390. EndSystemTime = CmpGetTimeStamp();
  391. if( (EndSystemTime - StartSystemTime) > 0 ) {
  392. (*TimeCounter)++;
  393. //(*TimeElapsed) += (ULONG)(EndSystemTime.QuadPart - StartSystemTime.QuadPart);
  394. (*TimeElapsed) += (EndSystemTime - StartSystemTime);
  395. }
  396. }
  397. #endif //CMP_STATS
  398. return status;
  399. }
  400. NTSTATUS
  401. CmpQueryKeyDataFromCache(
  402. PCM_KEY_CONTROL_BLOCK Kcb,
  403. KEY_INFORMATION_CLASS KeyInformationClass,
  404. PVOID KeyInformation,
  405. ULONG Length,
  406. PULONG ResultLength
  407. )
  408. /*++
  409. Routine Description:
  410. Do the actual copy of data for a key into caller's buffer.
  411. If KeyInformation is not long enough to hold all requested data,
  412. STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be
  413. set to the number of bytes actually required.
  414. Works only for the information cached into kcb. I.e. KeyBasicInformation
  415. and KeyCachedInfo
  416. Arguments:
  417. Kcb - Supplies pointer to the kcb to be queried
  418. KeyInformationClass - Specifies the type of information returned in
  419. Buffer. One of the following types:
  420. KeyBasicInformation - return last write time, title index, and name.
  421. (see KEY_BASIC_INFORMATION structure)
  422. KeyCachedInformation - return last write time, title index, name ....
  423. (see KEY_CACHED_INFORMATION structure)
  424. KeyInformation -Supplies pointer to buffer to receive the data.
  425. Length - Length of KeyInformation in bytes.
  426. ResultLength - Number of bytes actually written into KeyInformation.
  427. Return Value:
  428. NTSTATUS - Result code from call, among the following:
  429. <TBS>
  430. --*/
  431. {
  432. NTSTATUS status;
  433. PKEY_INFORMATION pbuffer;
  434. ULONG requiredlength;
  435. ULONG minimumlength;
  436. USHORT NameLength;
  437. LONG leftlength;
  438. PCM_KEY_NODE Node; // this is to be used only in case of cache incoherency
  439. PAGED_CODE();
  440. #ifdef CMP_KCB_CACHE_VALIDATION
  441. //
  442. // We have cached a lot of info into the kcb; Here is some validation code
  443. //
  444. if( Kcb ) {
  445. BEGIN_KCB_LOCK_GUARD;
  446. CmpLockKCBTree();
  447. Node = (PCM_KEY_NODE)HvGetCell(Kcb->KeyHive,Kcb->KeyCell);
  448. if( Node != NULL ) {
  449. // number of values
  450. ASSERT( Node->ValueList.Count == Kcb->ValueCache.Count );
  451. // number of subkeys
  452. if( !(Kcb->ExtFlags & CM_KCB_INVALID_CACHED_INFO) ) {
  453. // there is some cached info
  454. ULONG SubKeyCount = Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile];
  455. if( Kcb->ExtFlags & CM_KCB_NO_SUBKEY ) {
  456. ASSERT( SubKeyCount == 0 );
  457. } else if( Kcb->ExtFlags & CM_KCB_SUBKEY_ONE ) {
  458. ASSERT( SubKeyCount == 1 );
  459. } else if( Kcb->ExtFlags & CM_KCB_SUBKEY_HINT ) {
  460. ASSERT( SubKeyCount == Kcb->IndexHint->Count );
  461. } else {
  462. ASSERT( SubKeyCount == Kcb->SubKeyCount );
  463. }
  464. }
  465. // LastWriteTime
  466. ASSERT( Node->LastWriteTime.QuadPart == Kcb->KcbLastWriteTime.QuadPart );
  467. // MaxNameLen
  468. ASSERT( Node->MaxNameLen == Kcb->KcbMaxNameLen );
  469. // MaxValueNameLen
  470. ASSERT( Node->MaxValueNameLen == Kcb->KcbMaxValueNameLen );
  471. // MaxValueDataLen
  472. ASSERT( Node->MaxValueDataLen == Kcb->KcbMaxValueDataLen );
  473. HvReleaseCell(Kcb->KeyHive,Kcb->KeyCell);
  474. }
  475. CmpUnlockKCBTree();
  476. END_KCB_LOCK_GUARD;
  477. }
  478. #endif //CMP_KCB_CACHE_VALIDATION
  479. //
  480. // we cannot afford to return the kcb NameBlock as the key name
  481. // for KeyBasicInformation as there are lots of callers expecting
  482. // the name to be case-sensitive; KeyCachedInformation is new
  483. // and used only by the Win32 layer, which is not case sensitive
  484. // Note: future clients of KeyCachedInformation must be made aware
  485. // that name is NOT case-sensitive
  486. //
  487. ASSERT( KeyInformationClass == KeyCachedInformation );
  488. //
  489. // we are going to need the nameblock; if it is NULL, bail out
  490. //
  491. if( Kcb->NameBlock == NULL ) {
  492. return STATUS_INSUFFICIENT_RESOURCES;
  493. }
  494. pbuffer = (PKEY_INFORMATION)KeyInformation;
  495. if (Kcb->NameBlock->Compressed) {
  496. NameLength = CmpCompressedNameSize(Kcb->NameBlock->Name,Kcb->NameBlock->NameLength);
  497. } else {
  498. NameLength = Kcb->NameBlock->NameLength;
  499. }
  500. // Assume success
  501. status = STATUS_SUCCESS;
  502. switch (KeyInformationClass) {
  503. #if 0
  504. case KeyBasicInformation:
  505. //
  506. // LastWriteTime, TitleIndex, NameLength, Name
  507. requiredlength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) +
  508. NameLength;
  509. minimumlength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name);
  510. *ResultLength = requiredlength;
  511. if (Length < minimumlength) {
  512. status = STATUS_BUFFER_TOO_SMALL;
  513. } else {
  514. pbuffer->KeyBasicInformation.LastWriteTime = Kcb->KcbLastWriteTime;
  515. pbuffer->KeyBasicInformation.TitleIndex = 0;
  516. pbuffer->KeyBasicInformation.NameLength = NameLength;
  517. leftlength = Length - minimumlength;
  518. requiredlength = NameLength;
  519. if (leftlength < (LONG)requiredlength) {
  520. requiredlength = leftlength;
  521. status = STATUS_BUFFER_OVERFLOW;
  522. }
  523. if (Kcb->NameBlock->Compressed) {
  524. CmpCopyCompressedName(pbuffer->KeyBasicInformation.Name,
  525. leftlength,
  526. Kcb->NameBlock->Name,
  527. Kcb->NameBlock->NameLength);
  528. } else {
  529. RtlCopyMemory(
  530. &(pbuffer->KeyBasicInformation.Name[0]),
  531. &(Kcb->NameBlock->Name[0]),
  532. requiredlength
  533. );
  534. }
  535. }
  536. break;
  537. #endif
  538. case KeyCachedInformation:
  539. //
  540. // LastWriteTime, TitleIndex,
  541. // SubKeys, MaxNameLen, Values, MaxValueNameLen,
  542. // MaxValueDataLen, Name
  543. //
  544. requiredlength = sizeof(KEY_CACHED_INFORMATION);
  545. *ResultLength = requiredlength;
  546. if (Length < requiredlength) {
  547. status = STATUS_BUFFER_TOO_SMALL;
  548. } else {
  549. pbuffer->KeyCachedInformation.LastWriteTime = Kcb->KcbLastWriteTime;
  550. pbuffer->KeyCachedInformation.TitleIndex = 0;
  551. pbuffer->KeyCachedInformation.NameLength = NameLength;
  552. pbuffer->KeyCachedInformation.Values = Kcb->ValueCache.Count;
  553. pbuffer->KeyCachedInformation.MaxNameLen = Kcb->KcbMaxNameLen;
  554. pbuffer->KeyCachedInformation.MaxValueNameLen = Kcb->KcbMaxValueNameLen;
  555. pbuffer->KeyCachedInformation.MaxValueDataLen = Kcb->KcbMaxValueDataLen;
  556. if( !(Kcb->ExtFlags & CM_KCB_INVALID_CACHED_INFO) ) {
  557. // there is some cached info
  558. if( Kcb->ExtFlags & CM_KCB_NO_SUBKEY ) {
  559. pbuffer->KeyCachedInformation.SubKeys = 0;
  560. } else if( Kcb->ExtFlags & CM_KCB_SUBKEY_ONE ) {
  561. pbuffer->KeyCachedInformation.SubKeys = 1;
  562. } else if( Kcb->ExtFlags & CM_KCB_SUBKEY_HINT ) {
  563. pbuffer->KeyCachedInformation.SubKeys = Kcb->IndexHint->Count;
  564. } else {
  565. pbuffer->KeyCachedInformation.SubKeys = Kcb->SubKeyCount;
  566. }
  567. } else {
  568. //
  569. // kcb cache is not coherent; get the info from knode
  570. //
  571. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Kcb cache incoherency detected, kcb = %p\n",Kcb));
  572. Node = (PCM_KEY_NODE)HvGetCell(Kcb->KeyHive,Kcb->KeyCell);
  573. if( Node == NULL ) {
  574. //
  575. // couldn't map view for this cell
  576. //
  577. status = STATUS_INSUFFICIENT_RESOURCES;
  578. break;
  579. }
  580. pbuffer->KeyCachedInformation.SubKeys = Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile];
  581. HvReleaseCell(Kcb->KeyHive,Kcb->KeyCell);
  582. }
  583. }
  584. break;
  585. default:
  586. status = STATUS_INVALID_PARAMETER;
  587. break;
  588. }
  589. return status;
  590. }
  591. BOOLEAN
  592. CmpGetValueDataFromCache(
  593. IN PHHIVE Hive,
  594. IN PPCM_CACHED_VALUE ContainingList,
  595. IN PCELL_DATA ValueKey,
  596. IN BOOLEAN ValueCached,
  597. OUT PUCHAR *DataPointer,
  598. OUT PBOOLEAN Allocated,
  599. OUT PHCELL_INDEX CellToRelease
  600. )
  601. /*++
  602. Routine Description:
  603. Get the cached Value Data given a value node.
  604. Arguments:
  605. Hive - pointer to hive control structure for hive of interest
  606. ContainingList - Address that stores the allocation address of the value node.
  607. We need to update this when we do a re-allocate to cache
  608. both value key and value data.
  609. ValueKey - pointer to the Value Key
  610. ValueCached - Indicating whether Value key is cached or not.
  611. DataPointer - out param to receive a pointer to the data
  612. Allocated - out param telling if the caller should free the DataPointer
  613. Return Value:
  614. TRUE - data was retrieved
  615. FALSE - some error (STATUS_INSUFFICIENT_RESOURCES) occured
  616. Note:
  617. The caller is responsible for freeing the DataPointer when we signal it to him
  618. by setting Allocated on TRUE;
  619. Also we must be sure that MAXIMUM_CACHED_DATA is smaller than CM_KEY_VALUE_BIG
  620. --*/
  621. {
  622. //
  623. // Cache the data if needed.
  624. //
  625. PCM_CACHED_VALUE OldEntry;
  626. PCM_CACHED_VALUE NewEntry;
  627. PUCHAR Cacheddatapointer;
  628. ULONG AllocSize;
  629. ULONG CopySize;
  630. ULONG DataSize;
  631. ASSERT( MAXIMUM_CACHED_DATA < CM_KEY_VALUE_BIG );
  632. //
  633. // this routine should not be called for small data
  634. //
  635. ASSERT( (ValueKey->u.KeyValue.DataLength & CM_KEY_VALUE_SPECIAL_SIZE) == 0 );
  636. //
  637. // init out params
  638. //
  639. *DataPointer = NULL;
  640. *Allocated = FALSE;
  641. *CellToRelease = HCELL_NIL;
  642. if (ValueCached) {
  643. OldEntry = (PCM_CACHED_VALUE) CMP_GET_CACHED_ADDRESS(*ContainingList);
  644. if (OldEntry->DataCacheType == CM_CACHE_DATA_CACHED) {
  645. //
  646. // Data is already cached, use it.
  647. //
  648. *DataPointer = (PUCHAR) ((ULONG_PTR) ValueKey + OldEntry->ValueKeySize);
  649. } else {
  650. if ((OldEntry->DataCacheType == CM_CACHE_DATA_TOO_BIG) ||
  651. (ValueKey->u.KeyValue.DataLength > MAXIMUM_CACHED_DATA )
  652. ){
  653. //
  654. // Mark the type and do not cache it.
  655. //
  656. OldEntry->DataCacheType = CM_CACHE_DATA_TOO_BIG;
  657. //
  658. // Data is too big to warrent caching, get it from the registry;
  659. // - regardless of the size; we might be forced to allocate a buffer
  660. //
  661. if( CmpGetValueData(Hive,&(ValueKey->u.KeyValue),&DataSize,DataPointer,Allocated,CellToRelease) == FALSE ) {
  662. //
  663. // insufficient resources; return NULL
  664. //
  665. ASSERT( *Allocated == FALSE );
  666. ASSERT( *DataPointer == NULL );
  667. return FALSE;
  668. }
  669. } else {
  670. //
  671. // consistency check
  672. //
  673. ASSERT(OldEntry->DataCacheType == CM_CACHE_DATA_NOT_CACHED);
  674. //
  675. // Value data is not cached.
  676. // Check the size of value data, if it is smaller than MAXIMUM_CACHED_DATA, cache it.
  677. //
  678. // Anyway, the data is for sure not stored in a big data cell (see test above)
  679. //
  680. //
  681. *DataPointer = (PUCHAR)HvGetCell(Hive, ValueKey->u.KeyValue.Data);
  682. if( *DataPointer == NULL ) {
  683. //
  684. // we couldn't map this cell
  685. // the caller must handle this gracefully !
  686. //
  687. return FALSE;
  688. }
  689. //
  690. // inform the caller it has to release this cell
  691. //
  692. *CellToRelease = ValueKey->u.KeyValue.Data;
  693. //
  694. // copy only valid data; cell might be bigger
  695. //
  696. //DataSize = (ULONG) HvGetCellSize(Hive, datapointer);
  697. DataSize = (ULONG)ValueKey->u.KeyValue.DataLength;
  698. //
  699. // consistency check
  700. //
  701. ASSERT(DataSize <= MAXIMUM_CACHED_DATA);
  702. //
  703. // Data is not cached and now we are going to do it.
  704. // Reallocate a new cached entry for both value key and value data.
  705. //
  706. CopySize = DataSize + OldEntry->ValueKeySize;
  707. AllocSize = CopySize + FIELD_OFFSET(CM_CACHED_VALUE, KeyValue);
  708. // Dragos: Changed to catch the memory violator
  709. // it didn't work
  710. //NewEntry = (PCM_CACHED_VALUE) ExAllocatePoolWithTagPriority(PagedPool, AllocSize, CM_CACHE_VALUE_DATA_TAG,NormalPoolPrioritySpecialPoolUnderrun);
  711. NewEntry = (PCM_CACHED_VALUE) ExAllocatePoolWithTag(PagedPool, AllocSize, CM_CACHE_VALUE_DATA_TAG);
  712. if (NewEntry) {
  713. //
  714. // Now fill the data to the new cached entry
  715. //
  716. NewEntry->DataCacheType = CM_CACHE_DATA_CACHED;
  717. NewEntry->ValueKeySize = OldEntry->ValueKeySize;
  718. RtlCopyMemory((PVOID)&(NewEntry->KeyValue),
  719. (PVOID)&(OldEntry->KeyValue),
  720. NewEntry->ValueKeySize);
  721. Cacheddatapointer = (PUCHAR) ((ULONG_PTR) &(NewEntry->KeyValue) + OldEntry->ValueKeySize);
  722. RtlCopyMemory(Cacheddatapointer, *DataPointer, DataSize);
  723. // Trying to catch the BAD guy who writes over our pool.
  724. CmpMakeSpecialPoolReadWrite( OldEntry );
  725. *ContainingList = (PCM_CACHED_VALUE) CMP_MARK_CELL_CACHED(NewEntry);
  726. // Trying to catch the BAD guy who writes over our pool.
  727. CmpMakeSpecialPoolReadOnly( NewEntry );
  728. //
  729. // Free the old entry
  730. //
  731. ExFreePool(OldEntry);
  732. }
  733. }
  734. }
  735. } else {
  736. if( CmpGetValueData(Hive,&(ValueKey->u.KeyValue),&DataSize,DataPointer,Allocated,CellToRelease) == FALSE ) {
  737. //
  738. // insufficient resources; return NULL
  739. //
  740. ASSERT( *Allocated == FALSE );
  741. ASSERT( *DataPointer == NULL );
  742. return FALSE;
  743. }
  744. }
  745. return TRUE;
  746. }
  747. NTSTATUS
  748. CmpQueryKeyValueData(
  749. PHHIVE Hive,
  750. PPCM_CACHED_VALUE ContainingList,
  751. PCM_KEY_VALUE ValueKey,
  752. BOOLEAN ValueCached,
  753. KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
  754. PVOID KeyValueInformation,
  755. ULONG Length,
  756. PULONG ResultLength
  757. )
  758. /*++
  759. Routine Description:
  760. Do the actual copy of data for a key value into caller's buffer.
  761. If KeyValueInformation is not long enough to hold all requested data,
  762. STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be
  763. set to the number of bytes actually required.
  764. Arguments:
  765. Hive - supplies a pointer to the hive control structure for the hive
  766. Cell - supplies index of node to whose sub keys are to be found
  767. KeyValueInformationClass - Specifies the type of information returned in
  768. KeyValueInformation. One of the following types:
  769. KeyValueInformation -Supplies pointer to buffer to receive the data.
  770. Length - Length of KeyInformation in bytes.
  771. ResultLength - Number of bytes actually written into KeyInformation.
  772. Return Value:
  773. NTSTATUS - Result code from call, among the following:
  774. <TBS>
  775. --*/
  776. {
  777. NTSTATUS status;
  778. PKEY_VALUE_INFORMATION pbuffer;
  779. PCELL_DATA pcell;
  780. LONG leftlength;
  781. ULONG requiredlength;
  782. ULONG minimumlength;
  783. ULONG offset;
  784. ULONG base;
  785. ULONG realsize;
  786. PUCHAR datapointer;
  787. BOOLEAN small;
  788. USHORT NameLength;
  789. BOOLEAN BufferAllocated = FALSE;
  790. HCELL_INDEX CellToRelease = HCELL_NIL;
  791. pbuffer = (PKEY_VALUE_INFORMATION)KeyValueInformation;
  792. pcell = (PCELL_DATA) ValueKey;
  793. NameLength = CmpValueNameLen(&pcell->u.KeyValue);
  794. switch (KeyValueInformationClass) {
  795. case KeyValueBasicInformation:
  796. //
  797. // TitleIndex, Type, NameLength, Name
  798. //
  799. requiredlength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) +
  800. NameLength;
  801. minimumlength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name);
  802. *ResultLength = requiredlength;
  803. status = STATUS_SUCCESS;
  804. if (Length < minimumlength) {
  805. status = STATUS_BUFFER_TOO_SMALL;
  806. } else {
  807. pbuffer->KeyValueBasicInformation.TitleIndex = 0;
  808. pbuffer->KeyValueBasicInformation.Type =
  809. pcell->u.KeyValue.Type;
  810. pbuffer->KeyValueBasicInformation.NameLength =
  811. NameLength;
  812. leftlength = Length - minimumlength;
  813. requiredlength = NameLength;
  814. if (leftlength < (LONG)requiredlength) {
  815. requiredlength = leftlength;
  816. status = STATUS_BUFFER_OVERFLOW;
  817. }
  818. if (pcell->u.KeyValue.Flags & VALUE_COMP_NAME) {
  819. CmpCopyCompressedName(pbuffer->KeyValueBasicInformation.Name,
  820. requiredlength,
  821. pcell->u.KeyValue.Name,
  822. pcell->u.KeyValue.NameLength);
  823. } else {
  824. RtlCopyMemory(&(pbuffer->KeyValueBasicInformation.Name[0]),
  825. &(pcell->u.KeyValue.Name[0]),
  826. requiredlength);
  827. }
  828. }
  829. break;
  830. case KeyValueFullInformation:
  831. case KeyValueFullInformationAlign64:
  832. //
  833. // TitleIndex, Type, DataOffset, DataLength, NameLength,
  834. // Name, Data
  835. //
  836. small = CmpIsHKeyValueSmall(realsize, pcell->u.KeyValue.DataLength);
  837. requiredlength = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) +
  838. NameLength +
  839. realsize;
  840. minimumlength = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name);
  841. if (realsize > 0) {
  842. base = requiredlength - realsize;
  843. #if defined(_WIN64)
  844. offset = ALIGN_OFFSET64(base);
  845. #else
  846. if (KeyValueInformationClass == KeyValueFullInformationAlign64) {
  847. offset = ALIGN_OFFSET64(base);
  848. } else {
  849. offset = ALIGN_OFFSET(base);
  850. }
  851. #endif
  852. if (offset > base) {
  853. requiredlength += (offset - base);
  854. }
  855. #if DBG && defined(_WIN64)
  856. //
  857. // Some clients will have passed in a structure that they "know"
  858. // will be exactly the right size. The fact that alignment
  859. // has changed on NT64 may cause these clients to have problems.
  860. //
  861. // The solution is to fix the client, but print out some debug
  862. // spew here if it looks like this is the case. This problem
  863. // isn't particularly easy to spot from the client end.
  864. //
  865. if((KeyValueInformationClass == KeyValueFullInformation) &&
  866. (Length != minimumlength) &&
  867. (requiredlength > Length) &&
  868. ((requiredlength - Length) <=
  869. (ALIGN_OFFSET64(base) - ALIGN_OFFSET(base)))) {
  870. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"ntos/config-64 KeyValueFullInformation: "
  871. "Possible client buffer size problem.\n"));
  872. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL," Required size = %d\n", requiredlength));
  873. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL," Supplied size = %d\n", Length));
  874. }
  875. #endif
  876. }
  877. *ResultLength = requiredlength;
  878. status = STATUS_SUCCESS;
  879. if (Length < minimumlength) {
  880. status = STATUS_BUFFER_TOO_SMALL;
  881. } else {
  882. pbuffer->KeyValueFullInformation.TitleIndex = 0;
  883. pbuffer->KeyValueFullInformation.Type =
  884. pcell->u.KeyValue.Type;
  885. pbuffer->KeyValueFullInformation.DataLength =
  886. realsize;
  887. pbuffer->KeyValueFullInformation.NameLength =
  888. NameLength;
  889. leftlength = Length - minimumlength;
  890. requiredlength = NameLength;
  891. if (leftlength < (LONG)requiredlength) {
  892. requiredlength = leftlength;
  893. status = STATUS_BUFFER_OVERFLOW;
  894. }
  895. if (pcell->u.KeyValue.Flags & VALUE_COMP_NAME) {
  896. CmpCopyCompressedName(pbuffer->KeyValueFullInformation.Name,
  897. requiredlength,
  898. pcell->u.KeyValue.Name,
  899. pcell->u.KeyValue.NameLength);
  900. } else {
  901. RtlCopyMemory(
  902. &(pbuffer->KeyValueFullInformation.Name[0]),
  903. &(pcell->u.KeyValue.Name[0]),
  904. requiredlength
  905. );
  906. }
  907. if (realsize > 0) {
  908. if (small == TRUE) {
  909. datapointer = (PUCHAR)(&(pcell->u.KeyValue.Data));
  910. } else {
  911. if( CmpGetValueDataFromCache(Hive, ContainingList, pcell, ValueCached,&datapointer,&BufferAllocated,&CellToRelease) == FALSE ){
  912. //
  913. // we couldn't map view for cell; treat it as insufficient resources problem
  914. //
  915. ASSERT( datapointer == NULL );
  916. ASSERT( BufferAllocated == FALSE );
  917. status = STATUS_INSUFFICIENT_RESOURCES;
  918. }
  919. }
  920. pbuffer->KeyValueFullInformation.DataOffset = offset;
  921. leftlength = (((LONG)Length - (LONG)offset) < 0) ?
  922. 0 :
  923. Length - offset;
  924. requiredlength = realsize;
  925. if (leftlength < (LONG)requiredlength) {
  926. requiredlength = leftlength;
  927. status = STATUS_BUFFER_OVERFLOW;
  928. }
  929. ASSERT((small ? (requiredlength <= CM_KEY_VALUE_SMALL) : TRUE));
  930. if( datapointer != NULL ) {
  931. RtlCopyMemory(
  932. ((PUCHAR)pbuffer + offset),
  933. datapointer,
  934. requiredlength
  935. );
  936. if( BufferAllocated == TRUE ) {
  937. ExFreePool(datapointer);
  938. }
  939. if( CellToRelease != HCELL_NIL ) {
  940. HvReleaseCell(Hive,CellToRelease);
  941. }
  942. }
  943. } else {
  944. pbuffer->KeyValueFullInformation.DataOffset = (ULONG)-1;
  945. }
  946. }
  947. break;
  948. case KeyValuePartialInformation:
  949. //
  950. // TitleIndex, Type, DataLength, Data
  951. //
  952. small = CmpIsHKeyValueSmall(realsize, pcell->u.KeyValue.DataLength);
  953. requiredlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) +
  954. realsize;
  955. minimumlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
  956. *ResultLength = requiredlength;
  957. status = STATUS_SUCCESS;
  958. if (Length < minimumlength) {
  959. status = STATUS_BUFFER_TOO_SMALL;
  960. } else {
  961. pbuffer->KeyValuePartialInformation.TitleIndex = 0;
  962. pbuffer->KeyValuePartialInformation.Type =
  963. pcell->u.KeyValue.Type;
  964. pbuffer->KeyValuePartialInformation.DataLength =
  965. realsize;
  966. leftlength = Length - minimumlength;
  967. requiredlength = realsize;
  968. if (leftlength < (LONG)requiredlength) {
  969. requiredlength = leftlength;
  970. status = STATUS_BUFFER_OVERFLOW;
  971. }
  972. if (realsize > 0) {
  973. if (small == TRUE) {
  974. datapointer = (PUCHAR)(&(pcell->u.KeyValue.Data));
  975. } else {
  976. if( CmpGetValueDataFromCache(Hive, ContainingList, pcell, ValueCached,&datapointer,&BufferAllocated,&CellToRelease) == FALSE ){
  977. //
  978. // we couldn't map view for cell; treat it as insufficient resources problem
  979. //
  980. ASSERT( datapointer == NULL );
  981. ASSERT( BufferAllocated == FALSE );
  982. status = STATUS_INSUFFICIENT_RESOURCES;
  983. }
  984. }
  985. ASSERT((small ? (requiredlength <= CM_KEY_VALUE_SMALL) : TRUE));
  986. if( datapointer != NULL ) {
  987. RtlCopyMemory((PUCHAR)&(pbuffer->KeyValuePartialInformation.Data[0]),
  988. datapointer,
  989. requiredlength);
  990. if( BufferAllocated == TRUE ) {
  991. ExFreePool(datapointer);
  992. }
  993. if(CellToRelease != HCELL_NIL) {
  994. HvReleaseCell(Hive,CellToRelease);
  995. }
  996. }
  997. }
  998. }
  999. break;
  1000. case KeyValuePartialInformationAlign64:
  1001. //
  1002. // TitleIndex, Type, DataLength, Data
  1003. //
  1004. small = CmpIsHKeyValueSmall(realsize, pcell->u.KeyValue.DataLength);
  1005. requiredlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION_ALIGN64, Data) +
  1006. realsize;
  1007. minimumlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION_ALIGN64, Data);
  1008. *ResultLength = requiredlength;
  1009. status = STATUS_SUCCESS;
  1010. if (Length < minimumlength) {
  1011. status = STATUS_BUFFER_TOO_SMALL;
  1012. } else {
  1013. pbuffer->KeyValuePartialInformationAlign64.Type =
  1014. pcell->u.KeyValue.Type;
  1015. pbuffer->KeyValuePartialInformationAlign64.DataLength =
  1016. realsize;
  1017. leftlength = Length - minimumlength;
  1018. requiredlength = realsize;
  1019. if (leftlength < (LONG)requiredlength) {
  1020. requiredlength = leftlength;
  1021. status = STATUS_BUFFER_OVERFLOW;
  1022. }
  1023. if (realsize > 0) {
  1024. if (small == TRUE) {
  1025. datapointer = (PUCHAR)(&(pcell->u.KeyValue.Data));
  1026. } else {
  1027. if( CmpGetValueDataFromCache(Hive, ContainingList, pcell, ValueCached,&datapointer,&BufferAllocated,&CellToRelease) == FALSE ){
  1028. //
  1029. // we couldn't map view for cell; treat it as insufficient resources problem
  1030. //
  1031. ASSERT( datapointer == NULL );
  1032. ASSERT( BufferAllocated == FALSE );
  1033. status = STATUS_INSUFFICIENT_RESOURCES;
  1034. }
  1035. }
  1036. ASSERT((small ? (requiredlength <= CM_KEY_VALUE_SMALL) : TRUE));
  1037. if( datapointer != NULL ) {
  1038. RtlCopyMemory((PUCHAR)&(pbuffer->KeyValuePartialInformationAlign64.Data[0]),
  1039. datapointer,
  1040. requiredlength);
  1041. if( BufferAllocated == TRUE ) {
  1042. ExFreePool(datapointer);
  1043. }
  1044. if(CellToRelease != HCELL_NIL) {
  1045. HvReleaseCell(Hive,CellToRelease);
  1046. }
  1047. }
  1048. }
  1049. }
  1050. break;
  1051. default:
  1052. status = STATUS_INVALID_PARAMETER;
  1053. break;
  1054. }
  1055. return status;
  1056. }