Sync with trunk revision 63128.
[reactos.git] / ntoskrnl / config / cmvalue.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmvalue.c
5 * PURPOSE: Configuration Manager - Cell Values
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "ntoskrnl.h"
12 #define NDEBUG
13 #include "debug.h"
14
15 /* FUNCTIONS *****************************************************************/
16
17 BOOLEAN
18 NTAPI
19 CmpMarkValueDataDirty(IN PHHIVE Hive,
20 IN PCM_KEY_VALUE Value)
21 {
22 ULONG KeySize;
23 PAGED_CODE();
24
25 /* Make sure there's actually any data */
26 if (Value->Data != HCELL_NIL)
27 {
28 /* If this is a small key, there's no need to have it dirty */
29 if (CmpIsKeyValueSmall(&KeySize, Value->DataLength)) return TRUE;
30
31 /* Check if this is a big key */
32 ASSERT_VALUE_BIG(Hive, KeySize);
33
34 /* Normal value, just mark it dirty */
35 HvMarkCellDirty(Hive, Value->Data, FALSE);
36 }
37
38 /* Operation complete */
39 return TRUE;
40 }
41
42 BOOLEAN
43 NTAPI
44 CmpFreeValueData(IN PHHIVE Hive,
45 IN HCELL_INDEX DataCell,
46 IN ULONG DataLength)
47 {
48 ULONG KeySize;
49 PAGED_CODE();
50
51 /* If this is a small key, the data is built-in */
52 if (!CmpIsKeyValueSmall(&KeySize, DataLength))
53 {
54 /* If there's no data cell, there's nothing to do */
55 if (DataCell == HCELL_NIL) return TRUE;
56
57 /* Make sure the data cell is allocated */
58 //ASSERT(HvIsCellAllocated(Hive, DataCell));
59
60 /* Unsupported value type */
61 ASSERT_VALUE_BIG(Hive, KeySize);
62
63 /* Normal value, just free the data cell */
64 HvFreeCell(Hive, DataCell);
65 }
66
67 /* Operation complete */
68 return TRUE;
69 }
70
71 BOOLEAN
72 NTAPI
73 CmpFreeValue(IN PHHIVE Hive,
74 IN HCELL_INDEX Cell)
75 {
76 PCM_KEY_VALUE Value;
77 PAGED_CODE();
78
79 /* Get the cell data */
80 Value = (PCM_KEY_VALUE)HvGetCell(Hive, Cell);
81 if (!Value) ASSERT(FALSE);
82
83 /* Free it */
84 if (!CmpFreeValueData(Hive, Value->Data, Value->DataLength))
85 {
86 /* We failed to free the data, return failure */
87 HvReleaseCell(Hive, Cell);
88 return FALSE;
89 }
90
91 /* Release the cell and free it */
92 HvReleaseCell(Hive, Cell);
93 HvFreeCell(Hive, Cell);
94 return TRUE;
95 }
96
97 HCELL_INDEX
98 NTAPI
99 CmpFindValueByName(IN PHHIVE Hive,
100 IN PCM_KEY_NODE KeyNode,
101 IN PUNICODE_STRING Name)
102 {
103 HCELL_INDEX CellIndex;
104
105 /* Call the main function */
106 if (!CmpFindNameInList(Hive,
107 &KeyNode->ValueList,
108 Name,
109 NULL,
110 &CellIndex))
111 {
112 /* Santy check */
113 ASSERT(CellIndex == HCELL_NIL);
114 }
115
116 /* Return the index */
117 return CellIndex;
118 }
119
120 BOOLEAN
121 NTAPI
122 CmpGetValueData(IN PHHIVE Hive,
123 IN PCM_KEY_VALUE Value,
124 IN PULONG Length,
125 OUT PVOID *Buffer,
126 OUT PBOOLEAN BufferAllocated,
127 OUT PHCELL_INDEX CellToRelease)
128 {
129 PAGED_CODE();
130
131 /* Sanity check */
132 ASSERT(Value->Signature == CM_KEY_VALUE_SIGNATURE);
133
134 /* Set failure defaults */
135 *BufferAllocated = FALSE;
136 *Buffer = NULL;
137 *CellToRelease = HCELL_NIL;
138
139 /* Check if this is a small key */
140 if (CmpIsKeyValueSmall(Length, Value->DataLength))
141 {
142 /* Return the data immediately */
143 *Buffer = &Value->Data;
144 return TRUE;
145 }
146
147 /* Unsupported */
148 ASSERT_VALUE_BIG(Hive, *Length);
149
150 /* Get the data from the cell */
151 *Buffer = HvGetCell(Hive, Value->Data);
152 if (!(*Buffer)) return FALSE;
153
154 /* Return success and the cell to be released */
155 *CellToRelease = Value->Data;
156 return TRUE;
157 }
158
159 PCELL_DATA
160 NTAPI
161 CmpValueToData(IN PHHIVE Hive,
162 IN PCM_KEY_VALUE Value,
163 OUT PULONG Length)
164 {
165 PCELL_DATA Buffer;
166 BOOLEAN BufferAllocated;
167 HCELL_INDEX CellToRelease;
168 PAGED_CODE();
169
170 /* Sanity check */
171 ASSERT(Hive->ReleaseCellRoutine == NULL);
172
173 /* Get the actual data */
174 if (!CmpGetValueData(Hive,
175 Value,
176 Length,
177 (PVOID)&Buffer,
178 &BufferAllocated,
179 &CellToRelease))
180 {
181 /* We failed */
182 ASSERT(BufferAllocated == FALSE);
183 ASSERT(Buffer == NULL);
184 return NULL;
185 }
186
187 /* This should never happen!*/
188 if (BufferAllocated)
189 {
190 /* Free the buffer and bugcheck */
191 CmpFree(Buffer, 0);
192 KeBugCheckEx(REGISTRY_ERROR, 8, 0, (ULONG_PTR)Hive, (ULONG_PTR)Value);
193 }
194
195 /* Otherwise, return the cell data */
196 return Buffer;
197 }
198
199 NTSTATUS
200 NTAPI
201 CmpAddValueToList(IN PHHIVE Hive,
202 IN HCELL_INDEX ValueCell,
203 IN ULONG Index,
204 IN ULONG Type,
205 IN OUT PCHILD_LIST ChildList)
206 {
207 HCELL_INDEX ListCell;
208 ULONG ChildCount, Length, i;
209 PCELL_DATA CellData;
210 PAGED_CODE();
211
212 /* Sanity check */
213 ASSERT((((LONG)Index) >= 0) && (Index <= ChildList->Count));
214
215 /* Get the number of entries in the child list */
216 ChildCount = ChildList->Count;
217 ChildCount++;
218 if (ChildCount > 1)
219 {
220 /* The cell should be dirty at this point */
221 ASSERT(HvIsCellDirty(Hive, ChildList->List));
222
223 /* Check if we have less then 100 children */
224 if (ChildCount < 100)
225 {
226 /* Allocate just enough as requested */
227 Length = ChildCount * sizeof(HCELL_INDEX);
228 }
229 else
230 {
231 /* Otherwise, we have quite a few, so allocate a batch */
232 Length = ROUND_UP(ChildCount, 100) * sizeof(HCELL_INDEX);
233 if (Length > HBLOCK_SIZE)
234 {
235 /* But make sure we don't allocate beyond our block size */
236 Length = ROUND_UP(Length, HBLOCK_SIZE);
237 }
238 }
239
240 /* Perform the allocation */
241 ListCell = HvReallocateCell(Hive, ChildList->List, Length);
242 }
243 else
244 {
245 /* This is our first child, so allocate a single cell */
246 ListCell = HvAllocateCell(Hive, sizeof(HCELL_INDEX), Type, HCELL_NIL);
247 }
248
249 /* Fail if we couldn't get a cell */
250 if (ListCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES;
251
252 /* Set this cell as the child list's list cell */
253 ChildList->List = ListCell;
254
255 /* Get the actual key list memory */
256 CellData = HvGetCell(Hive, ListCell);
257 ASSERT(CellData != NULL);
258
259 /* Loop all the children */
260 for (i = ChildCount - 1; i > Index; i--)
261 {
262 /* Move them all down */
263 CellData->u.KeyList[i] = CellData->u.KeyList[i - 1];
264 }
265
266 /* Insert us on top now */
267 CellData->u.KeyList[Index] = ValueCell;
268 ChildList->Count = ChildCount;
269
270 /* Release the list cell and make sure the value cell is dirty */
271 HvReleaseCell(Hive, ListCell);
272 ASSERT(HvIsCellDirty(Hive, ValueCell));
273
274 /* We're done here */
275 return STATUS_SUCCESS;
276 }
277
278 NTSTATUS
279 NTAPI
280 CmpSetValueDataNew(IN PHHIVE Hive,
281 IN PVOID Data,
282 IN ULONG DataSize,
283 IN ULONG StorageType,
284 IN HCELL_INDEX ValueCell,
285 OUT PHCELL_INDEX DataCell)
286 {
287 PCELL_DATA CellData;
288 PAGED_CODE();
289 ASSERT(DataSize > CM_KEY_VALUE_SMALL);
290
291 /* Check if this is a big key */
292 ASSERT_VALUE_BIG(Hive, DataSize);
293
294 /* Allocate a data cell */
295 *DataCell = HvAllocateCell(Hive, DataSize, StorageType, HCELL_NIL);
296 if (*DataCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES;
297
298 /* Get the actual data */
299 CellData = HvGetCell(Hive, *DataCell);
300 if (!CellData) ASSERT(FALSE);
301
302 /* Copy our buffer into it */
303 RtlCopyMemory(CellData, Data, DataSize);
304
305 /* All done */
306 return STATUS_SUCCESS;
307 }
308
309 NTSTATUS
310 NTAPI
311 CmpRemoveValueFromList(IN PHHIVE Hive,
312 IN ULONG Index,
313 IN OUT PCHILD_LIST ChildList)
314 {
315 ULONG Count;
316 PCELL_DATA CellData;
317 HCELL_INDEX NewCell;
318 PAGED_CODE();
319
320 /* Sanity check */
321 ASSERT((((LONG)Index) >= 0) && (Index <= ChildList->Count));
322
323 /* Get the new count after removal */
324 Count = ChildList->Count - 1;
325 if (Count > 0)
326 {
327 /* Get the actual list array */
328 CellData = HvGetCell(Hive, ChildList->List);
329 if (!CellData) return STATUS_INSUFFICIENT_RESOURCES;
330
331 /* Make sure cells data have been made dirty */
332 ASSERT(HvIsCellDirty(Hive, ChildList->List));
333 ASSERT(HvIsCellDirty(Hive, CellData->u.KeyList[Index]));
334
335 /* Loop the list */
336 while (Index < Count)
337 {
338 /* Move everything up */
339 CellData->u.KeyList[Index] = CellData->u.KeyList[Index + 1];
340 Index++;
341 }
342
343 /* Re-allocate the cell for the list by decreasing the count */
344 NewCell = HvReallocateCell(Hive,
345 ChildList->List,
346 Count * sizeof(HCELL_INDEX));
347 ASSERT(NewCell != HCELL_NIL);
348 HvReleaseCell(Hive,ChildList->List);
349
350 /* Update the list cell */
351 ChildList->List = NewCell;
352 }
353 else
354 {
355 /* Otherwise, we were the last entry, so free the list entirely */
356 HvFreeCell(Hive, ChildList->List);
357 ChildList->List = HCELL_NIL;
358 }
359
360 /* Update the child list with the new count */
361 ChildList->Count = Count;
362 return STATUS_SUCCESS;
363 }