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.

1420 lines
45 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. USHORT NameLength;
  436. PCM_KEY_NODE Node; // this is to be used only in case of cache incoherency
  437. PAGED_CODE();
  438. #ifdef CMP_KCB_CACHE_VALIDATION
  439. //
  440. // We have cached a lot of info into the kcb; Here is some validation code
  441. //
  442. if( Kcb ) {
  443. BEGIN_KCB_LOCK_GUARD;
  444. CmpLockKCBTree();
  445. Node = (PCM_KEY_NODE)HvGetCell(Kcb->KeyHive,Kcb->KeyCell);
  446. if( Node != NULL ) {
  447. // number of values
  448. ASSERT( Node->ValueList.Count == Kcb->ValueCache.Count );
  449. // number of subkeys
  450. if( !(Kcb->ExtFlags & CM_KCB_INVALID_CACHED_INFO) ) {
  451. // there is some cached info
  452. ULONG SubKeyCount = Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile];
  453. if( Kcb->ExtFlags & CM_KCB_NO_SUBKEY ) {
  454. ASSERT( SubKeyCount == 0 );
  455. } else if( Kcb->ExtFlags & CM_KCB_SUBKEY_ONE ) {
  456. ASSERT( SubKeyCount == 1 );
  457. } else if( Kcb->ExtFlags & CM_KCB_SUBKEY_HINT ) {
  458. ASSERT( SubKeyCount == Kcb->IndexHint->Count );
  459. } else {
  460. ASSERT( SubKeyCount == Kcb->SubKeyCount );
  461. }
  462. }
  463. // LastWriteTime
  464. ASSERT( Node->LastWriteTime.QuadPart == Kcb->KcbLastWriteTime.QuadPart );
  465. // MaxNameLen
  466. ASSERT( Node->MaxNameLen == Kcb->KcbMaxNameLen );
  467. // MaxValueNameLen
  468. ASSERT( Node->MaxValueNameLen == Kcb->KcbMaxValueNameLen );
  469. // MaxValueDataLen
  470. ASSERT( Node->MaxValueDataLen == Kcb->KcbMaxValueDataLen );
  471. HvReleaseCell(Kcb->KeyHive,Kcb->KeyCell);
  472. }
  473. CmpUnlockKCBTree();
  474. END_KCB_LOCK_GUARD;
  475. }
  476. #endif //CMP_KCB_CACHE_VALIDATION
  477. //
  478. // we cannot afford to return the kcb NameBlock as the key name
  479. // for KeyBasicInformation as there are lots of callers expecting
  480. // the name to be case-sensitive; KeyCachedInformation is new
  481. // and used only by the Win32 layer, which is not case sensitive
  482. // Note: future clients of KeyCachedInformation must be made aware
  483. // that name is NOT case-sensitive
  484. //
  485. ASSERT( KeyInformationClass == KeyCachedInformation );
  486. //
  487. // we are going to need the nameblock; if it is NULL, bail out
  488. //
  489. if( Kcb->NameBlock == NULL ) {
  490. return STATUS_INSUFFICIENT_RESOURCES;
  491. }
  492. pbuffer = (PKEY_INFORMATION)KeyInformation;
  493. if (Kcb->NameBlock->Compressed) {
  494. NameLength = CmpCompressedNameSize(Kcb->NameBlock->Name,Kcb->NameBlock->NameLength);
  495. } else {
  496. NameLength = Kcb->NameBlock->NameLength;
  497. }
  498. // Assume success
  499. status = STATUS_SUCCESS;
  500. switch (KeyInformationClass) {
  501. #if 0
  502. case KeyBasicInformation:
  503. //
  504. // LastWriteTime, TitleIndex, NameLength, Name
  505. requiredlength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) +
  506. NameLength;
  507. minimumlength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name);
  508. *ResultLength = requiredlength;
  509. if (Length < minimumlength) {
  510. status = STATUS_BUFFER_TOO_SMALL;
  511. } else {
  512. pbuffer->KeyBasicInformation.LastWriteTime = Kcb->KcbLastWriteTime;
  513. pbuffer->KeyBasicInformation.TitleIndex = 0;
  514. pbuffer->KeyBasicInformation.NameLength = NameLength;
  515. leftlength = Length - minimumlength;
  516. requiredlength = NameLength;
  517. if (leftlength < (LONG)requiredlength) {
  518. requiredlength = leftlength;
  519. status = STATUS_BUFFER_OVERFLOW;
  520. }
  521. if (Kcb->NameBlock->Compressed) {
  522. CmpCopyCompressedName(pbuffer->KeyBasicInformation.Name,
  523. leftlength,
  524. Kcb->NameBlock->Name,
  525. Kcb->NameBlock->NameLength);
  526. } else {
  527. RtlCopyMemory(
  528. &(pbuffer->KeyBasicInformation.Name[0]),
  529. &(Kcb->NameBlock->Name[0]),
  530. requiredlength
  531. );
  532. }
  533. }
  534. break;
  535. #endif
  536. case KeyCachedInformation:
  537. //
  538. // LastWriteTime, TitleIndex,
  539. // SubKeys, MaxNameLen, Values, MaxValueNameLen,
  540. // MaxValueDataLen, Name
  541. //
  542. requiredlength = sizeof(KEY_CACHED_INFORMATION);
  543. *ResultLength = requiredlength;
  544. if (Length < requiredlength) {
  545. status = STATUS_BUFFER_TOO_SMALL;
  546. } else {
  547. pbuffer->KeyCachedInformation.LastWriteTime = Kcb->KcbLastWriteTime;
  548. pbuffer->KeyCachedInformation.TitleIndex = 0;
  549. pbuffer->KeyCachedInformation.NameLength = NameLength;
  550. pbuffer->KeyCachedInformation.Values = Kcb->ValueCache.Count;
  551. pbuffer->KeyCachedInformation.MaxNameLen = Kcb->KcbMaxNameLen;
  552. pbuffer->KeyCachedInformation.MaxValueNameLen = Kcb->KcbMaxValueNameLen;
  553. pbuffer->KeyCachedInformation.MaxValueDataLen = Kcb->KcbMaxValueDataLen;
  554. if( !(Kcb->ExtFlags & CM_KCB_INVALID_CACHED_INFO) ) {
  555. // there is some cached info
  556. if( Kcb->ExtFlags & CM_KCB_NO_SUBKEY ) {
  557. pbuffer->KeyCachedInformation.SubKeys = 0;
  558. } else if( Kcb->ExtFlags & CM_KCB_SUBKEY_ONE ) {
  559. pbuffer->KeyCachedInformation.SubKeys = 1;
  560. } else if( Kcb->ExtFlags & CM_KCB_SUBKEY_HINT ) {
  561. pbuffer->KeyCachedInformation.SubKeys = Kcb->IndexHint->Count;
  562. } else {
  563. pbuffer->KeyCachedInformation.SubKeys = Kcb->SubKeyCount;
  564. }
  565. } else {
  566. //
  567. // kcb cache is not coherent; get the info from knode
  568. //
  569. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Kcb cache incoherency detected, kcb = %p\n",Kcb));
  570. Node = (PCM_KEY_NODE)HvGetCell(Kcb->KeyHive,Kcb->KeyCell);
  571. if( Node == NULL ) {
  572. //
  573. // couldn't map view for this cell
  574. //
  575. status = STATUS_INSUFFICIENT_RESOURCES;
  576. break;
  577. }
  578. pbuffer->KeyCachedInformation.SubKeys = Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile];
  579. HvReleaseCell(Kcb->KeyHive,Kcb->KeyCell);
  580. }
  581. }
  582. break;
  583. default:
  584. status = STATUS_INVALID_PARAMETER;
  585. break;
  586. }
  587. return status;
  588. }
  589. BOOLEAN
  590. CmpGetValueDataFromCache(
  591. IN PHHIVE Hive,
  592. IN PPCM_CACHED_VALUE ContainingList,
  593. IN PCELL_DATA ValueKey,
  594. IN BOOLEAN ValueCached,
  595. OUT PUCHAR *DataPointer,
  596. OUT PBOOLEAN Allocated,
  597. OUT PHCELL_INDEX CellToRelease
  598. )
  599. /*++
  600. Routine Description:
  601. Get the cached Value Data given a value node.
  602. Arguments:
  603. Hive - pointer to hive control structure for hive of interest
  604. ContainingList - Address that stores the allocation address of the value node.
  605. We need to update this when we do a re-allocate to cache
  606. both value key and value data.
  607. ValueKey - pointer to the Value Key
  608. ValueCached - Indicating whether Value key is cached or not.
  609. DataPointer - out param to receive a pointer to the data
  610. Allocated - out param telling if the caller should free the DataPointer
  611. Return Value:
  612. TRUE - data was retrieved
  613. FALSE - some error (STATUS_INSUFFICIENT_RESOURCES) occured
  614. Note:
  615. The caller is responsible for freeing the DataPointer when we signal it to him
  616. by setting Allocated on TRUE;
  617. Also we must be sure that MAXIMUM_CACHED_DATA is smaller than CM_KEY_VALUE_BIG
  618. --*/
  619. {
  620. //
  621. // Cache the data if needed.
  622. //
  623. PCM_CACHED_VALUE OldEntry;
  624. PCM_CACHED_VALUE NewEntry;
  625. PUCHAR Cacheddatapointer;
  626. ULONG AllocSize;
  627. ULONG CopySize;
  628. ULONG DataSize;
  629. ASSERT( MAXIMUM_CACHED_DATA < CM_KEY_VALUE_BIG );
  630. //
  631. // this routine should not be called for small data
  632. //
  633. ASSERT( (ValueKey->u.KeyValue.DataLength & CM_KEY_VALUE_SPECIAL_SIZE) == 0 );
  634. //
  635. // init out params
  636. //
  637. *DataPointer = NULL;
  638. *Allocated = FALSE;
  639. *CellToRelease = HCELL_NIL;
  640. if (ValueCached) {
  641. OldEntry = (PCM_CACHED_VALUE) CMP_GET_CACHED_ADDRESS(*ContainingList);
  642. if (OldEntry->DataCacheType == CM_CACHE_DATA_CACHED) {
  643. //
  644. // Data is already cached, use it.
  645. //
  646. *DataPointer = (PUCHAR) ((ULONG_PTR) ValueKey + OldEntry->ValueKeySize);
  647. } else {
  648. if ((OldEntry->DataCacheType == CM_CACHE_DATA_TOO_BIG) ||
  649. (ValueKey->u.KeyValue.DataLength > MAXIMUM_CACHED_DATA )
  650. ){
  651. //
  652. // Mark the type and do not cache it.
  653. //
  654. OldEntry->DataCacheType = CM_CACHE_DATA_TOO_BIG;
  655. //
  656. // Data is too big to warrent caching, get it from the registry;
  657. // - regardless of the size; we might be forced to allocate a buffer
  658. //
  659. if( CmpGetValueData(Hive,&(ValueKey->u.KeyValue),&DataSize,DataPointer,Allocated,CellToRelease) == FALSE ) {
  660. //
  661. // insufficient resources; return NULL
  662. //
  663. ASSERT( *Allocated == FALSE );
  664. ASSERT( *DataPointer == NULL );
  665. return FALSE;
  666. }
  667. } else {
  668. //
  669. // consistency check
  670. //
  671. ASSERT(OldEntry->DataCacheType == CM_CACHE_DATA_NOT_CACHED);
  672. //
  673. // Value data is not cached.
  674. // Check the size of value data, if it is smaller than MAXIMUM_CACHED_DATA, cache it.
  675. //
  676. // Anyway, the data is for sure not stored in a big data cell (see test above)
  677. //
  678. //
  679. *DataPointer = (PUCHAR)HvGetCell(Hive, ValueKey->u.KeyValue.Data);
  680. if( *DataPointer == NULL ) {
  681. //
  682. // we couldn't map this cell
  683. // the caller must handle this gracefully !
  684. //
  685. return FALSE;
  686. }
  687. //
  688. // inform the caller it has to release this cell
  689. //
  690. *CellToRelease = ValueKey->u.KeyValue.Data;
  691. //
  692. // copy only valid data; cell might be bigger
  693. //
  694. //DataSize = (ULONG) HvGetCellSize(Hive, datapointer);
  695. DataSize = (ULONG)ValueKey->u.KeyValue.DataLength;
  696. //
  697. // consistency check
  698. //
  699. ASSERT(DataSize <= MAXIMUM_CACHED_DATA);
  700. //
  701. // Data is not cached and now we are going to do it.
  702. // Reallocate a new cached entry for both value key and value data.
  703. //
  704. CopySize = DataSize + OldEntry->ValueKeySize;
  705. AllocSize = CopySize + FIELD_OFFSET(CM_CACHED_VALUE, KeyValue);
  706. // Dragos: Changed to catch the memory violator
  707. // it didn't work
  708. //NewEntry = (PCM_CACHED_VALUE) ExAllocatePoolWithTagPriority(PagedPool, AllocSize, CM_CACHE_VALUE_DATA_TAG,NormalPoolPrioritySpecialPoolUnderrun);
  709. NewEntry = (PCM_CACHED_VALUE) ExAllocatePoolWithTag(PagedPool, AllocSize, CM_CACHE_VALUE_DATA_TAG);
  710. if (NewEntry) {
  711. //
  712. // Now fill the data to the new cached entry
  713. //
  714. NewEntry->DataCacheType = CM_CACHE_DATA_CACHED;
  715. NewEntry->ValueKeySize = OldEntry->ValueKeySize;
  716. RtlCopyMemory((PVOID)&(NewEntry->KeyValue),
  717. (PVOID)&(OldEntry->KeyValue),
  718. NewEntry->ValueKeySize);
  719. Cacheddatapointer = (PUCHAR) ((ULONG_PTR) &(NewEntry->KeyValue) + OldEntry->ValueKeySize);
  720. RtlCopyMemory(Cacheddatapointer, *DataPointer, DataSize);
  721. // Trying to catch the BAD guy who writes over our pool.
  722. CmpMakeSpecialPoolReadWrite( OldEntry );
  723. *ContainingList = (PCM_CACHED_VALUE) CMP_MARK_CELL_CACHED(NewEntry);
  724. // Trying to catch the BAD guy who writes over our pool.
  725. CmpMakeSpecialPoolReadOnly( NewEntry );
  726. //
  727. // Free the old entry
  728. //
  729. ExFreePool(OldEntry);
  730. }
  731. }
  732. }
  733. } else {
  734. if( CmpGetValueData(Hive,&(ValueKey->u.KeyValue),&DataSize,DataPointer,Allocated,CellToRelease) == FALSE ) {
  735. //
  736. // insufficient resources; return NULL
  737. //
  738. ASSERT( *Allocated == FALSE );
  739. ASSERT( *DataPointer == NULL );
  740. return FALSE;
  741. }
  742. }
  743. return TRUE;
  744. }
  745. NTSTATUS
  746. CmpQueryKeyValueData(
  747. PHHIVE Hive,
  748. PPCM_CACHED_VALUE ContainingList,
  749. PCM_KEY_VALUE ValueKey,
  750. BOOLEAN ValueCached,
  751. KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
  752. PVOID KeyValueInformation,
  753. ULONG Length,
  754. PULONG ResultLength
  755. )
  756. /*++
  757. Routine Description:
  758. Do the actual copy of data for a key value into caller's buffer.
  759. If KeyValueInformation is not long enough to hold all requested data,
  760. STATUS_BUFFER_OVERFLOW will be returned, and ResultLength will be
  761. set to the number of bytes actually required.
  762. Arguments:
  763. Hive - supplies a pointer to the hive control structure for the hive
  764. Cell - supplies index of node to whose sub keys are to be found
  765. KeyValueInformationClass - Specifies the type of information returned in
  766. KeyValueInformation. One of the following types:
  767. KeyValueInformation -Supplies pointer to buffer to receive the data.
  768. Length - Length of KeyInformation in bytes.
  769. ResultLength - Number of bytes actually written into KeyInformation.
  770. Return Value:
  771. NTSTATUS - Result code from call, among the following:
  772. <TBS>
  773. --*/
  774. {
  775. NTSTATUS status;
  776. PKEY_VALUE_INFORMATION pbuffer;
  777. PCELL_DATA pcell;
  778. LONG leftlength;
  779. ULONG requiredlength;
  780. ULONG minimumlength;
  781. ULONG offset;
  782. ULONG base;
  783. ULONG realsize;
  784. PUCHAR datapointer;
  785. BOOLEAN small;
  786. USHORT NameLength;
  787. BOOLEAN BufferAllocated = FALSE;
  788. HCELL_INDEX CellToRelease = HCELL_NIL;
  789. pbuffer = (PKEY_VALUE_INFORMATION)KeyValueInformation;
  790. pcell = (PCELL_DATA) ValueKey;
  791. NameLength = CmpValueNameLen(&pcell->u.KeyValue);
  792. switch (KeyValueInformationClass) {
  793. case KeyValueBasicInformation:
  794. //
  795. // TitleIndex, Type, NameLength, Name
  796. //
  797. requiredlength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) +
  798. NameLength;
  799. minimumlength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name);
  800. *ResultLength = requiredlength;
  801. status = STATUS_SUCCESS;
  802. if (Length < minimumlength) {
  803. status = STATUS_BUFFER_TOO_SMALL;
  804. } else {
  805. pbuffer->KeyValueBasicInformation.TitleIndex = 0;
  806. pbuffer->KeyValueBasicInformation.Type =
  807. pcell->u.KeyValue.Type;
  808. pbuffer->KeyValueBasicInformation.NameLength =
  809. NameLength;
  810. leftlength = Length - minimumlength;
  811. requiredlength = NameLength;
  812. if (leftlength < (LONG)requiredlength) {
  813. requiredlength = leftlength;
  814. status = STATUS_BUFFER_OVERFLOW;
  815. }
  816. if (pcell->u.KeyValue.Flags & VALUE_COMP_NAME) {
  817. CmpCopyCompressedName(pbuffer->KeyValueBasicInformation.Name,
  818. requiredlength,
  819. pcell->u.KeyValue.Name,
  820. pcell->u.KeyValue.NameLength);
  821. } else {
  822. RtlCopyMemory(&(pbuffer->KeyValueBasicInformation.Name[0]),
  823. &(pcell->u.KeyValue.Name[0]),
  824. requiredlength);
  825. }
  826. }
  827. break;
  828. case KeyValueFullInformation:
  829. case KeyValueFullInformationAlign64:
  830. //
  831. // TitleIndex, Type, DataOffset, DataLength, NameLength,
  832. // Name, Data
  833. //
  834. small = CmpIsHKeyValueSmall(realsize, pcell->u.KeyValue.DataLength);
  835. requiredlength = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) +
  836. NameLength +
  837. realsize;
  838. minimumlength = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name);
  839. offset = 0;
  840. if (realsize > 0) {
  841. base = requiredlength - realsize;
  842. #if defined(_WIN64)
  843. offset = ALIGN_OFFSET64(base);
  844. #else
  845. if (KeyValueInformationClass == KeyValueFullInformationAlign64) {
  846. offset = ALIGN_OFFSET64(base);
  847. } else {
  848. offset = ALIGN_OFFSET(base);
  849. }
  850. #endif
  851. if (offset > base) {
  852. requiredlength += (offset - base);
  853. }
  854. #if DBG && defined(_WIN64)
  855. //
  856. // Some clients will have passed in a structure that they "know"
  857. // will be exactly the right size. The fact that alignment
  858. // has changed on NT64 may cause these clients to have problems.
  859. //
  860. // The solution is to fix the client, but print out some debug
  861. // spew here if it looks like this is the case. This problem
  862. // isn't particularly easy to spot from the client end.
  863. //
  864. if((KeyValueInformationClass == KeyValueFullInformation) &&
  865. (Length != minimumlength) &&
  866. (requiredlength > Length) &&
  867. ((requiredlength - Length) <=
  868. (ALIGN_OFFSET64(base) - ALIGN_OFFSET(base)))) {
  869. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"ntos/config-64 KeyValueFullInformation: "
  870. "Possible client buffer size problem.\n"));
  871. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL," Required size = %d\n", requiredlength));
  872. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL," Supplied size = %d\n", Length));
  873. }
  874. #endif
  875. }
  876. *ResultLength = requiredlength;
  877. status = STATUS_SUCCESS;
  878. if (Length < minimumlength) {
  879. status = STATUS_BUFFER_TOO_SMALL;
  880. } else {
  881. pbuffer->KeyValueFullInformation.TitleIndex = 0;
  882. pbuffer->KeyValueFullInformation.Type =
  883. pcell->u.KeyValue.Type;
  884. pbuffer->KeyValueFullInformation.DataLength =
  885. realsize;
  886. pbuffer->KeyValueFullInformation.NameLength =
  887. NameLength;
  888. leftlength = Length - minimumlength;
  889. requiredlength = NameLength;
  890. if (leftlength < (LONG)requiredlength) {
  891. requiredlength = leftlength;
  892. status = STATUS_BUFFER_OVERFLOW;
  893. }
  894. if (pcell->u.KeyValue.Flags & VALUE_COMP_NAME) {
  895. CmpCopyCompressedName(pbuffer->KeyValueFullInformation.Name,
  896. requiredlength,
  897. pcell->u.KeyValue.Name,
  898. pcell->u.KeyValue.NameLength);
  899. } else {
  900. RtlCopyMemory(
  901. &(pbuffer->KeyValueFullInformation.Name[0]),
  902. &(pcell->u.KeyValue.Name[0]),
  903. requiredlength
  904. );
  905. }
  906. if (realsize > 0) {
  907. if (small == TRUE) {
  908. datapointer = (PUCHAR)(&(pcell->u.KeyValue.Data));
  909. } else {
  910. if( CmpGetValueDataFromCache(Hive, ContainingList, pcell, ValueCached,&datapointer,&BufferAllocated,&CellToRelease) == FALSE ){
  911. //
  912. // we couldn't map view for cell; treat it as insufficient resources problem
  913. //
  914. ASSERT( datapointer == NULL );
  915. ASSERT( BufferAllocated == FALSE );
  916. status = STATUS_INSUFFICIENT_RESOURCES;
  917. }
  918. }
  919. pbuffer->KeyValueFullInformation.DataOffset = offset;
  920. leftlength = (((LONG)Length - (LONG)offset) < 0) ?
  921. 0 :
  922. Length - offset;
  923. requiredlength = realsize;
  924. if (leftlength < (LONG)requiredlength) {
  925. requiredlength = leftlength;
  926. status = STATUS_BUFFER_OVERFLOW;
  927. }
  928. ASSERT((small ? (requiredlength <= CM_KEY_VALUE_SMALL) : TRUE));
  929. if( datapointer != NULL ) {
  930. RtlCopyMemory(
  931. ((PUCHAR)pbuffer + offset),
  932. datapointer,
  933. requiredlength
  934. );
  935. if( BufferAllocated == TRUE ) {
  936. ExFreePool(datapointer);
  937. }
  938. if( CellToRelease != HCELL_NIL ) {
  939. HvReleaseCell(Hive,CellToRelease);
  940. }
  941. }
  942. } else {
  943. pbuffer->KeyValueFullInformation.DataOffset = (ULONG)-1;
  944. }
  945. }
  946. break;
  947. case KeyValuePartialInformation:
  948. //
  949. // TitleIndex, Type, DataLength, Data
  950. //
  951. small = CmpIsHKeyValueSmall(realsize, pcell->u.KeyValue.DataLength);
  952. requiredlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) +
  953. realsize;
  954. minimumlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
  955. *ResultLength = requiredlength;
  956. status = STATUS_SUCCESS;
  957. if (Length < minimumlength) {
  958. status = STATUS_BUFFER_TOO_SMALL;
  959. } else {
  960. pbuffer->KeyValuePartialInformation.TitleIndex = 0;
  961. pbuffer->KeyValuePartialInformation.Type =
  962. pcell->u.KeyValue.Type;
  963. pbuffer->KeyValuePartialInformation.DataLength =
  964. realsize;
  965. leftlength = Length - minimumlength;
  966. requiredlength = realsize;
  967. if (leftlength < (LONG)requiredlength) {
  968. requiredlength = leftlength;
  969. status = STATUS_BUFFER_OVERFLOW;
  970. }
  971. if (realsize > 0) {
  972. if (small == TRUE) {
  973. datapointer = (PUCHAR)(&(pcell->u.KeyValue.Data));
  974. } else {
  975. if( CmpGetValueDataFromCache(Hive, ContainingList, pcell, ValueCached,&datapointer,&BufferAllocated,&CellToRelease) == FALSE ){
  976. //
  977. // we couldn't map view for cell; treat it as insufficient resources problem
  978. //
  979. ASSERT( datapointer == NULL );
  980. ASSERT( BufferAllocated == FALSE );
  981. status = STATUS_INSUFFICIENT_RESOURCES;
  982. }
  983. }
  984. ASSERT((small ? (requiredlength <= CM_KEY_VALUE_SMALL) : TRUE));
  985. if( datapointer != NULL ) {
  986. RtlCopyMemory((PUCHAR)&(pbuffer->KeyValuePartialInformation.Data[0]),
  987. datapointer,
  988. requiredlength);
  989. if( BufferAllocated == TRUE ) {
  990. ExFreePool(datapointer);
  991. }
  992. if(CellToRelease != HCELL_NIL) {
  993. HvReleaseCell(Hive,CellToRelease);
  994. }
  995. }
  996. }
  997. }
  998. break;
  999. case KeyValuePartialInformationAlign64:
  1000. //
  1001. // TitleIndex, Type, DataLength, Data
  1002. //
  1003. small = CmpIsHKeyValueSmall(realsize, pcell->u.KeyValue.DataLength);
  1004. requiredlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION_ALIGN64, Data) +
  1005. realsize;
  1006. minimumlength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION_ALIGN64, Data);
  1007. *ResultLength = requiredlength;
  1008. status = STATUS_SUCCESS;
  1009. if (Length < minimumlength) {
  1010. status = STATUS_BUFFER_TOO_SMALL;
  1011. } else {
  1012. pbuffer->KeyValuePartialInformationAlign64.Type =
  1013. pcell->u.KeyValue.Type;
  1014. pbuffer->KeyValuePartialInformationAlign64.DataLength =
  1015. realsize;
  1016. leftlength = Length - minimumlength;
  1017. requiredlength = realsize;
  1018. if (leftlength < (LONG)requiredlength) {
  1019. requiredlength = leftlength;
  1020. status = STATUS_BUFFER_OVERFLOW;
  1021. }
  1022. if (realsize > 0) {
  1023. if (small == TRUE) {
  1024. datapointer = (PUCHAR)(&(pcell->u.KeyValue.Data));
  1025. } else {
  1026. if( CmpGetValueDataFromCache(Hive, ContainingList, pcell, ValueCached,&datapointer,&BufferAllocated,&CellToRelease) == FALSE ){
  1027. //
  1028. // we couldn't map view for cell; treat it as insufficient resources problem
  1029. //
  1030. ASSERT( datapointer == NULL );
  1031. ASSERT( BufferAllocated == FALSE );
  1032. status = STATUS_INSUFFICIENT_RESOURCES;
  1033. }
  1034. }
  1035. ASSERT((small ? (requiredlength <= CM_KEY_VALUE_SMALL) : TRUE));
  1036. if( datapointer != NULL ) {
  1037. RtlCopyMemory((PUCHAR)&(pbuffer->KeyValuePartialInformationAlign64.Data[0]),
  1038. datapointer,
  1039. requiredlength);
  1040. if( BufferAllocated == TRUE ) {
  1041. ExFreePool(datapointer);
  1042. }
  1043. if(CellToRelease != HCELL_NIL) {
  1044. HvReleaseCell(Hive,CellToRelease);
  1045. }
  1046. }
  1047. }
  1048. }
  1049. break;
  1050. default:
  1051. status = STATUS_INVALID_PARAMETER;
  1052. break;
  1053. }
  1054. return status;
  1055. }