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.

409 lines
12 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. cmtree.c
  5. Abstract:
  6. This module contains cm routines that understand the structure
  7. of the registry tree.
  8. Author:
  9. Bryan M. Willman (bryanwi) 12-Sep-1991
  10. Revision History:
  11. --*/
  12. #include "cmp.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE,CmpGetValueListFromCache)
  15. #pragma alloc_text(PAGE,CmpGetValueKeyFromCache)
  16. #pragma alloc_text(PAGE,CmpFindValueByNameFromCache)
  17. #endif
  18. #ifndef _CM_LDR_
  19. PCELL_DATA
  20. CmpGetValueListFromCache(
  21. IN PHHIVE Hive,
  22. IN PCACHED_CHILD_LIST ChildList,
  23. OUT BOOLEAN *IndexCached
  24. )
  25. /*++
  26. Routine Description:
  27. Get the Valve Index Array. Check if it is already cached, if not, cache it and return
  28. the cached entry.
  29. Arguments:
  30. Hive - pointer to hive control structure for hive of interest
  31. ChildList - pointer/index to the Value Index array
  32. IndexCached - Indicating whether Value Index list is cached or not.
  33. Return Value:
  34. Pointer to the Valve Index Array.
  35. NULL when we could not map view
  36. --*/
  37. {
  38. PCELL_DATA List;
  39. ULONG AllocSize;
  40. PCM_CACHED_VALUE_INDEX CachedValueIndex;
  41. ULONG i;
  42. HCELL_INDEX CellToRelease;
  43. #ifndef _WIN64
  44. *IndexCached = TRUE;
  45. if (CMP_IS_CELL_CACHED(ChildList->ValueList)) {
  46. //
  47. // The entry is already cached.
  48. //
  49. List = CMP_GET_CACHED_CELLDATA(ChildList->ValueList);
  50. } else {
  51. //
  52. // The entry is not cached. The element contains the hive index.
  53. //
  54. CellToRelease = CMP_GET_CACHED_CELL_INDEX(ChildList->ValueList);
  55. List = (PCELL_DATA) HvGetCell(Hive, CellToRelease);
  56. if( List == NULL ) {
  57. //
  58. // we couldn't map a view for this cell
  59. //
  60. return NULL;
  61. }
  62. //
  63. // Allocate a PagedPool to cache the value index cell.
  64. //
  65. AllocSize = ChildList->Count * sizeof(ULONG_PTR) + FIELD_OFFSET(CM_CACHED_VALUE_INDEX, Data);
  66. // Dragos: Changed to catch the memory violator
  67. // it didn't work
  68. //CachedValueIndex = (PCM_CACHED_VALUE_INDEX) ExAllocatePoolWithTagPriority(PagedPool, AllocSize, CM_CACHE_VALUE_INDEX_TAG,NormalPoolPrioritySpecialPoolUnderrun);
  69. CachedValueIndex = (PCM_CACHED_VALUE_INDEX) ExAllocatePoolWithTag(PagedPool, AllocSize, CM_CACHE_VALUE_INDEX_TAG);
  70. if (CachedValueIndex) {
  71. CachedValueIndex->CellIndex = CMP_GET_CACHED_CELL_INDEX(ChildList->ValueList);
  72. for (i=0; i<ChildList->Count; i++) {
  73. CachedValueIndex->Data.List[i] = (ULONG_PTR) List->u.KeyList[i];
  74. }
  75. ChildList->ValueList = CMP_MARK_CELL_CACHED(CachedValueIndex);
  76. // Trying to catch the BAD guy who writes over our pool.
  77. CmpMakeSpecialPoolReadOnly( CachedValueIndex );
  78. //
  79. // Now we have the stuff cached, use the cache data.
  80. //
  81. List = CMP_GET_CACHED_CELLDATA(ChildList->ValueList);
  82. } else {
  83. //
  84. // If the allocation fails, just do not cache it. continue.
  85. //
  86. *IndexCached = FALSE;
  87. }
  88. HvReleaseCell(Hive, CellToRelease);
  89. }
  90. #else
  91. CellToRelease = CMP_GET_CACHED_CELL_INDEX(ChildList->ValueList);
  92. List = (PCELL_DATA) HvGetCell(Hive, CMP_GET_CACHED_CELL_INDEX(ChildList->ValueList));
  93. *IndexCached = FALSE;
  94. if( List == NULL ) {
  95. //
  96. // we couldn't map a view for this cell
  97. // OBS: we can drop this as we return List anyway; just for clarity
  98. //
  99. return NULL;
  100. }
  101. HvReleaseCell(Hive, CellToRelease);
  102. #endif
  103. return (List);
  104. }
  105. PCM_KEY_VALUE
  106. CmpGetValueKeyFromCache(
  107. IN PHHIVE Hive,
  108. IN PCELL_DATA List,
  109. IN ULONG Index,
  110. OUT PPCM_CACHED_VALUE *ContainingList,
  111. IN BOOLEAN IndexCached,
  112. OUT BOOLEAN *ValueCached,
  113. OUT PHCELL_INDEX CellToRelease
  114. )
  115. /*++
  116. Routine Description:
  117. Get the Valve Node. Check if it is already cached, if not but the index is cached,
  118. cache and return the value node.
  119. Arguments:
  120. Hive - pointer to hive control structure for hive of interest.
  121. List - pointer to the Value Index Array (of ULONG_PTR if cached and ULONG if non-cached)
  122. Index - Index in the Value index array
  123. ContainlingList - The address of the entry that will receive the found cached value.
  124. IndexCached - Indicate if the index list is cached. If not, everything is from the
  125. original registry data.
  126. ValueCached - Indicating whether Value is cached or not.
  127. Return Value:
  128. Pointer to the Value Node.
  129. NULL when we couldn't map a view
  130. --*/
  131. {
  132. PCM_KEY_VALUE pchild;
  133. PULONG_PTR CachedList;
  134. ULONG AllocSize;
  135. ULONG CopySize;
  136. PCM_CACHED_VALUE CachedValue;
  137. *CellToRelease = HCELL_NIL;
  138. if (IndexCached) {
  139. //
  140. // The index array is cached, so List is pointing to an array of ULONG_PTR.
  141. // Use CachedList.
  142. //
  143. CachedList = (PULONG_PTR) List;
  144. *ValueCached = TRUE;
  145. if (CMP_IS_CELL_CACHED(CachedList[Index])) {
  146. pchild = CMP_GET_CACHED_KEYVALUE(CachedList[Index]);
  147. *ContainingList = &((PCM_CACHED_VALUE) CachedList[Index]);
  148. } else {
  149. pchild = (PCM_KEY_VALUE) HvGetCell(Hive, List->u.KeyList[Index]);
  150. if( pchild == NULL ) {
  151. //
  152. // we couldn't map a view for this cell
  153. // just return NULL; the caller must handle it gracefully
  154. //
  155. return NULL;
  156. }
  157. *CellToRelease = List->u.KeyList[Index];
  158. //
  159. // Allocate a PagedPool to cache the value node.
  160. //
  161. CopySize = (ULONG) HvGetCellSize(Hive, pchild);
  162. AllocSize = CopySize + FIELD_OFFSET(CM_CACHED_VALUE, KeyValue);
  163. // Dragos: Changed to catch the memory violator
  164. // it didn't work
  165. //CachedValue = (PCM_CACHED_VALUE) ExAllocatePoolWithTagPriority(PagedPool, AllocSize, CM_CACHE_VALUE_TAG,NormalPoolPrioritySpecialPoolUnderrun);
  166. CachedValue = (PCM_CACHED_VALUE) ExAllocatePoolWithTag(PagedPool, AllocSize, CM_CACHE_VALUE_TAG);
  167. if (CachedValue) {
  168. //
  169. // Set the information for later use if we need to cache data as well.
  170. //
  171. CachedValue->DataCacheType = CM_CACHE_DATA_NOT_CACHED;
  172. CachedValue->ValueKeySize = (USHORT) CopySize;
  173. RtlCopyMemory((PVOID)&(CachedValue->KeyValue), pchild, CopySize);
  174. // Trying to catch the BAD guy who writes over our pool.
  175. CmpMakeSpecialPoolReadWrite( CMP_GET_CACHED_ADDRESS(CachedList) );
  176. CachedList[Index] = CMP_MARK_CELL_CACHED(CachedValue);
  177. // Trying to catch the BAD guy who writes over our pool.
  178. CmpMakeSpecialPoolReadOnly( CMP_GET_CACHED_ADDRESS(CachedList) );
  179. // Trying to catch the BAD guy who writes over our pool.
  180. CmpMakeSpecialPoolReadOnly(CachedValue);
  181. *ContainingList = &((PCM_CACHED_VALUE) CachedList[Index]);
  182. //
  183. // Now we have the stuff cached, use the cache data.
  184. //
  185. pchild = CMP_GET_CACHED_KEYVALUE(CachedValue);
  186. } else {
  187. //
  188. // If the allocation fails, just do not cache it. continue.
  189. //
  190. *ValueCached = FALSE;
  191. }
  192. }
  193. } else {
  194. //
  195. // The Valve Index Array is from the registry hive, just get the cell and move on.
  196. //
  197. pchild = (PCM_KEY_VALUE) HvGetCell(Hive, List->u.KeyList[Index]);
  198. *ValueCached = FALSE;
  199. if( pchild == NULL ) {
  200. //
  201. // we couldn't map a view for this cell
  202. // just return NULL; the caller must handle it gracefully
  203. // OBS: we may remove this as we return pchild anyway; just for clarity
  204. //
  205. return NULL;
  206. }
  207. *CellToRelease = List->u.KeyList[Index];
  208. }
  209. return (pchild);
  210. }
  211. PCM_KEY_VALUE
  212. CmpFindValueByNameFromCache(
  213. IN PHHIVE Hive,
  214. IN PCACHED_CHILD_LIST ChildList,
  215. IN PUNICODE_STRING Name,
  216. OUT PPCM_CACHED_VALUE *ContainingList,
  217. OUT ULONG *Index,
  218. OUT BOOLEAN *ValueCached,
  219. OUT PHCELL_INDEX CellToRelease
  220. )
  221. /*++
  222. Routine Description:
  223. Find a value node given a value list array and a value name. It sequentially walk
  224. through each value node to look for a match. If the array and
  225. value nodes touched are not already cached, cache them.
  226. Arguments:
  227. Hive - pointer to hive control structure for hive of interest
  228. ChildList - pointer/index to the Value Index array
  229. Name - name of value to find
  230. ContainlingList - The address of the entry that will receive the found cached value.
  231. Index - pointer to variable to receive index for child
  232. ValueCached - Indicate if the value node is cached.
  233. Return Value:
  234. HCELL_INDEX for the found cell
  235. HCELL_NIL if not found
  236. Notes:
  237. New hives (Minor >= 4) have ValueList sorted; this implies ValueCache is sorted too;
  238. So, we can do a binary search here!
  239. --*/
  240. {
  241. NTSTATUS status;
  242. PCM_KEY_VALUE pchild;
  243. UNICODE_STRING Candidate;
  244. LONG Result;
  245. PCELL_DATA List;
  246. BOOLEAN IndexCached;
  247. ULONG Current;
  248. *CellToRelease = HCELL_NIL;
  249. if (ChildList->Count != 0) {
  250. List = CmpGetValueListFromCache(Hive, ChildList, &IndexCached);
  251. if( List == NULL ) {
  252. //
  253. // couldn't map view; bail out
  254. //
  255. return NULL;
  256. }
  257. //
  258. // old plain hive; simulate a for
  259. //
  260. Current = 0;
  261. while( TRUE ) {
  262. if( *CellToRelease != HCELL_NIL ) {
  263. HvReleaseCell(Hive,*CellToRelease);
  264. *CellToRelease = HCELL_NIL;
  265. }
  266. pchild = CmpGetValueKeyFromCache(Hive, List, Current, ContainingList, IndexCached, ValueCached, CellToRelease);
  267. if( pchild == NULL ) {
  268. //
  269. // couldn't map view; bail out
  270. //
  271. return NULL;
  272. }
  273. try {
  274. //
  275. // Name has user-mode buffer.
  276. //
  277. if (pchild->Flags & VALUE_COMP_NAME) {
  278. Result = CmpCompareCompressedName( Name,
  279. pchild->Name,
  280. pchild->NameLength,
  281. 0);
  282. } else {
  283. Candidate.Length = pchild->NameLength;
  284. Candidate.MaximumLength = Candidate.Length;
  285. Candidate.Buffer = pchild->Name;
  286. Result = RtlCompareUnicodeString( Name,
  287. &Candidate,
  288. TRUE);
  289. }
  290. } except (EXCEPTION_EXECUTE_HANDLER) {
  291. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_EXCEPTION,"CmpFindValueByNameFromCache: code:%08lx\n", GetExceptionCode()));
  292. //
  293. // the caller will bail out. Some ,alicious caller altered the Name buffer since we probed it.
  294. //
  295. return NULL;
  296. }
  297. if (Result == 0) {
  298. //
  299. // Success, fill the index, return data to caller and exit
  300. //
  301. *Index = Current;
  302. return(pchild);
  303. }
  304. //
  305. // compute the next index to try: old'n plain hive; go on
  306. //
  307. Current++;
  308. if( Current == ChildList->Count ) {
  309. //
  310. // we've reached the end of the list; nicely return
  311. //
  312. return NULL;
  313. }
  314. } // while(TRUE)
  315. }
  316. //
  317. // in the new design we shouldn't get here; we should exit the while loop with return
  318. //
  319. ASSERT( ChildList->Count == 0 );
  320. return NULL;
  321. }
  322. #endif