[STORAHCI] Merge Storport Miniport driver by Aman Priyadarshi in GSoC.
[reactos.git] / reactos / sdk / tools / mkhive / cmi.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2006 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS hive maker
22 * FILE: tools/mkhive/cmi.c
23 * PURPOSE: Registry file manipulation routines
24 * PROGRAMMER: Hervé Poussineau
25 */
26
27 #define NDEBUG
28 #include "mkhive.h"
29
30 PVOID
31 NTAPI
32 CmpAllocate(
33 IN SIZE_T Size,
34 IN BOOLEAN Paged,
35 IN ULONG Tag)
36 {
37 return (PVOID)malloc((size_t)Size);
38 }
39
40 VOID
41 NTAPI
42 CmpFree(
43 IN PVOID Ptr,
44 IN ULONG Quota)
45 {
46 free(Ptr);
47 }
48
49 static BOOLEAN
50 NTAPI
51 CmpFileRead(
52 IN PHHIVE RegistryHive,
53 IN ULONG FileType,
54 IN PULONG FileOffset,
55 OUT PVOID Buffer,
56 IN SIZE_T BufferLength)
57 {
58 DPRINT1("CmpFileRead() unimplemented\n");
59 return FALSE;
60 }
61
62 static BOOLEAN
63 NTAPI
64 CmpFileWrite(
65 IN PHHIVE RegistryHive,
66 IN ULONG FileType,
67 IN PULONG FileOffset,
68 IN PVOID Buffer,
69 IN SIZE_T BufferLength)
70 {
71 PCMHIVE CmHive = (PCMHIVE)RegistryHive;
72 FILE *File = CmHive->FileHandles[HFILE_TYPE_PRIMARY];
73 if (fseek(File, *FileOffset, SEEK_SET) != 0)
74 return FALSE;
75
76 return (fwrite(Buffer, 1, BufferLength, File) == BufferLength);
77 }
78
79 static BOOLEAN
80 NTAPI
81 CmpFileSetSize(
82 IN PHHIVE RegistryHive,
83 IN ULONG FileType,
84 IN ULONG FileSize,
85 IN ULONG OldFileSize)
86 {
87 DPRINT1("CmpFileSetSize() unimplemented\n");
88 return FALSE;
89 }
90
91 static BOOLEAN
92 NTAPI
93 CmpFileFlush(
94 IN PHHIVE RegistryHive,
95 IN ULONG FileType,
96 PLARGE_INTEGER FileOffset,
97 ULONG Length)
98 {
99 PCMHIVE CmHive = (PCMHIVE)RegistryHive;
100 FILE *File = CmHive->FileHandles[HFILE_TYPE_PRIMARY];
101 return (fflush(File) == 0);
102 }
103
104 NTSTATUS
105 CmiInitializeHive(
106 IN OUT PCMHIVE Hive,
107 IN PCWSTR Name)
108 {
109 NTSTATUS Status;
110
111 RtlZeroMemory(Hive, sizeof(*Hive));
112
113 DPRINT("Hive 0x%p\n", Hive);
114
115 Status = HvInitialize(&Hive->Hive,
116 HINIT_CREATE,
117 HIVE_NOLAZYFLUSH,
118 HFILE_TYPE_PRIMARY,
119 0,
120 CmpAllocate,
121 CmpFree,
122 CmpFileSetSize,
123 CmpFileWrite,
124 CmpFileRead,
125 CmpFileFlush,
126 1,
127 NULL);
128 if (!NT_SUCCESS(Status))
129 {
130 return Status;
131 }
132
133 // HACK: See the HACK from r31253
134 if (!CmCreateRootNode(&Hive->Hive, Name))
135 {
136 HvFree(&Hive->Hive);
137 return STATUS_INSUFFICIENT_RESOURCES;
138 }
139
140 /* Add the new hive to the hive list */
141 InsertTailList(&CmiHiveListHead,
142 &Hive->HiveList);
143
144 return STATUS_SUCCESS;
145 }
146
147 NTSTATUS
148 CmiCreateSecurityKey(
149 IN PHHIVE Hive,
150 IN HCELL_INDEX Cell,
151 IN PUCHAR Descriptor,
152 IN ULONG DescriptorLength)
153 {
154 HCELL_INDEX SecurityCell;
155 PCM_KEY_NODE Node;
156 PCM_KEY_SECURITY Security;
157
158 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
159 SecurityCell = HvAllocateCell(Hive,
160 FIELD_OFFSET(CM_KEY_SECURITY, Descriptor) +
161 DescriptorLength,
162 Stable,
163 HCELL_NIL);
164 if (SecurityCell == HCELL_NIL)
165 {
166 HvReleaseCell(Hive, Cell);
167 return STATUS_INSUFFICIENT_RESOURCES;
168 }
169
170 Node->Security = SecurityCell;
171 Security = (PCM_KEY_SECURITY)HvGetCell(Hive, SecurityCell);
172 Security->Signature = CM_KEY_SECURITY_SIGNATURE;
173 Security->ReferenceCount = 1;
174 Security->DescriptorLength = DescriptorLength;
175
176 RtlMoveMemory(&Security->Descriptor,
177 Descriptor,
178 DescriptorLength);
179
180 Security->Flink = Security->Blink = SecurityCell;
181
182 HvReleaseCell(Hive, SecurityCell);
183 HvReleaseCell(Hive, Cell);
184
185 return STATUS_SUCCESS;
186 }
187
188 static NTSTATUS
189 CmiCreateSubKey(
190 IN PCMHIVE RegistryHive,
191 IN HCELL_INDEX ParentKeyCellOffset,
192 IN PCUNICODE_STRING SubKeyName,
193 IN BOOLEAN VolatileKey,
194 OUT HCELL_INDEX* pNKBOffset)
195 {
196 HCELL_INDEX NKBOffset;
197 PCM_KEY_NODE NewKeyCell;
198 UNICODE_STRING KeyName;
199 HSTORAGE_TYPE Storage;
200
201 /* Skip leading path separator if present */
202 if (SubKeyName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
203 {
204 KeyName.Buffer = &SubKeyName->Buffer[1];
205 KeyName.Length = KeyName.MaximumLength = SubKeyName->Length - sizeof(WCHAR);
206 }
207 else
208 {
209 KeyName = *SubKeyName;
210 }
211
212 Storage = (VolatileKey ? Volatile : Stable);
213
214 NKBOffset = HvAllocateCell(&RegistryHive->Hive,
215 FIELD_OFFSET(CM_KEY_NODE, Name) +
216 CmpNameSize(&RegistryHive->Hive, &KeyName),
217 Storage,
218 HCELL_NIL);
219 if (NKBOffset == HCELL_NIL)
220 {
221 return STATUS_INSUFFICIENT_RESOURCES;
222 }
223
224 NewKeyCell = (PCM_KEY_NODE)HvGetCell(&RegistryHive->Hive, NKBOffset);
225 if (NewKeyCell == NULL)
226 {
227 HvFreeCell(&RegistryHive->Hive, NKBOffset);
228 return STATUS_INSUFFICIENT_RESOURCES;
229 }
230
231 NewKeyCell->Signature = CM_KEY_NODE_SIGNATURE;
232 NewKeyCell->Flags = (VolatileKey ? KEY_IS_VOLATILE : 0);
233 KeQuerySystemTime(&NewKeyCell->LastWriteTime);
234 NewKeyCell->Parent = ParentKeyCellOffset;
235 NewKeyCell->SubKeyCounts[Stable] = 0;
236 NewKeyCell->SubKeyCounts[Volatile] = 0;
237 NewKeyCell->SubKeyLists[Stable] = HCELL_NIL;
238 NewKeyCell->SubKeyLists[Volatile] = HCELL_NIL;
239 NewKeyCell->ValueList.Count = 0;
240 NewKeyCell->ValueList.List = HCELL_NIL;
241 NewKeyCell->Security = HCELL_NIL;
242 NewKeyCell->Class = HCELL_NIL;
243 NewKeyCell->ClassLength = 0;
244 NewKeyCell->MaxNameLen = 0;
245 NewKeyCell->MaxClassLen = 0;
246 NewKeyCell->MaxValueNameLen = 0;
247 NewKeyCell->MaxValueDataLen = 0;
248 NewKeyCell->NameLength = CmpCopyName(&RegistryHive->Hive, NewKeyCell->Name, &KeyName);
249 if (NewKeyCell->NameLength < KeyName.Length) NewKeyCell->Flags |= KEY_COMP_NAME;
250
251 /* Inherit the security from the parent */
252 if (ParentKeyCellOffset == HCELL_NIL)
253 {
254 // We are in fact creating a root key.
255 // This is not handled there, but when we
256 // call CmCreateRootNode instead.
257 ASSERT(FALSE);
258 }
259 else
260 {
261 /* Get the parent node */
262 PCM_KEY_NODE ParentKeyCell;
263 ParentKeyCell = (PCM_KEY_NODE)HvGetCell(&RegistryHive->Hive, ParentKeyCellOffset);
264
265 if (ParentKeyCell)
266 {
267 /* Inherit the security block of the parent */
268 NewKeyCell->Security = ParentKeyCell->Security;
269 if (NewKeyCell->Security != HCELL_NIL)
270 {
271 PCM_KEY_SECURITY Security;
272 Security = (PCM_KEY_SECURITY)HvGetCell(&RegistryHive->Hive, NewKeyCell->Security);
273 ++Security->ReferenceCount;
274 HvReleaseCell(&RegistryHive->Hive, NewKeyCell->Security);
275 }
276
277 HvReleaseCell(&RegistryHive->Hive, ParentKeyCellOffset);
278 }
279 }
280
281 HvReleaseCell(&RegistryHive->Hive, NKBOffset);
282
283 *pNKBOffset = NKBOffset;
284 return STATUS_SUCCESS;
285 }
286
287 NTSTATUS
288 CmiAddSubKey(
289 IN PCMHIVE RegistryHive,
290 IN HCELL_INDEX ParentKeyCellOffset,
291 IN PCUNICODE_STRING SubKeyName,
292 IN BOOLEAN VolatileKey,
293 OUT HCELL_INDEX *pBlockOffset)
294 {
295 PCM_KEY_NODE ParentKeyCell;
296 HCELL_INDEX NKBOffset;
297 NTSTATUS Status;
298
299 /* Create the new key */
300 Status = CmiCreateSubKey(RegistryHive, ParentKeyCellOffset, SubKeyName, VolatileKey, &NKBOffset);
301 if (!NT_SUCCESS(Status))
302 return Status;
303
304 /* Mark the parent cell as dirty */
305 HvMarkCellDirty(&RegistryHive->Hive, ParentKeyCellOffset, FALSE);
306
307 if (!CmpAddSubKey(&RegistryHive->Hive, ParentKeyCellOffset, NKBOffset))
308 {
309 /* FIXME: delete newly created cell */
310 // CmpFreeKeyByCell(&RegistryHive->Hive, NewCell /*NKBOffset*/, FALSE);
311 ASSERT(FALSE);
312 return STATUS_UNSUCCESSFUL;
313 }
314
315 /* Get the parent node */
316 ParentKeyCell = (PCM_KEY_NODE)HvGetCell(&RegistryHive->Hive, ParentKeyCellOffset);
317 if (!ParentKeyCell)
318 {
319 /* FIXME: delete newly created cell */
320 return STATUS_UNSUCCESSFUL;
321 }
322 VERIFY_KEY_CELL(ParentKeyCell);
323
324 /* Update the timestamp */
325 KeQuerySystemTime(&ParentKeyCell->LastWriteTime);
326
327 /* Check if we need to update name maximum, update it if so */
328 if (ParentKeyCell->MaxNameLen < SubKeyName->Length)
329 ParentKeyCell->MaxNameLen = SubKeyName->Length;
330
331 /* Release the cell */
332 HvReleaseCell(&RegistryHive->Hive, ParentKeyCellOffset);
333
334 *pBlockOffset = NKBOffset;
335 return STATUS_SUCCESS;
336 }
337
338 NTSTATUS
339 CmiAddValueKey(
340 IN PCMHIVE RegistryHive,
341 IN PCM_KEY_NODE Parent,
342 IN PCUNICODE_STRING ValueName,
343 OUT PCM_KEY_VALUE *pValueCell,
344 OUT HCELL_INDEX *pValueCellOffset)
345 {
346 PCELL_DATA ValueListCell;
347 PCM_KEY_VALUE NewValueCell;
348 HCELL_INDEX ValueListCellOffset;
349 HCELL_INDEX NewValueCellOffset;
350 ULONG CellSize;
351 HSTORAGE_TYPE Storage;
352
353 #ifndef FIELD_SIZE
354 #define FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
355 #endif
356
357 Storage = (Parent->Flags & KEY_IS_VOLATILE) ? Volatile : Stable;
358 if (Parent->ValueList.List == HCELL_NIL)
359 {
360 /* Allocate some room for the value list */
361 CellSize = FIELD_SIZE(CELL_DATA, u.KeyList) + (3 * sizeof(HCELL_INDEX));
362 ValueListCellOffset = HvAllocateCell(&RegistryHive->Hive, CellSize, Storage, HCELL_NIL);
363 if (ValueListCellOffset == HCELL_NIL)
364 return STATUS_INSUFFICIENT_RESOURCES;
365
366 ValueListCell = (PCELL_DATA)HvGetCell(&RegistryHive->Hive, ValueListCellOffset);
367 if (!ValueListCell)
368 {
369 HvFreeCell(&RegistryHive->Hive, ValueListCellOffset);
370 return STATUS_UNSUCCESSFUL;
371 }
372
373 Parent->ValueList.List = ValueListCellOffset;
374 }
375 else
376 {
377 ValueListCell = (PCELL_DATA)HvGetCell(&RegistryHive->Hive, Parent->ValueList.List);
378 if (!ValueListCell)
379 return STATUS_UNSUCCESSFUL;
380
381 CellSize = ABS_VALUE(HvGetCellSize(&RegistryHive->Hive, ValueListCell));
382
383 if (Parent->ValueList.Count >= CellSize / sizeof(HCELL_INDEX))
384 {
385 CellSize *= 2;
386 ValueListCellOffset = HvReallocateCell(&RegistryHive->Hive, Parent->ValueList.List, CellSize);
387 if (ValueListCellOffset == HCELL_NIL)
388 return STATUS_INSUFFICIENT_RESOURCES;
389
390 ValueListCell = (PCELL_DATA)HvGetCell(&RegistryHive->Hive, ValueListCellOffset);
391 if (!ValueListCell)
392 return STATUS_UNSUCCESSFUL;
393
394 Parent->ValueList.List = ValueListCellOffset;
395 }
396 }
397
398
399 NewValueCellOffset = HvAllocateCell(&RegistryHive->Hive,
400 FIELD_OFFSET(CM_KEY_VALUE, Name) +
401 CmpNameSize(&RegistryHive->Hive, (PUNICODE_STRING)ValueName),
402 Storage,
403 HCELL_NIL);
404 if (NewValueCellOffset == HCELL_NIL)
405 {
406 return STATUS_INSUFFICIENT_RESOURCES;
407 }
408
409 NewValueCell = (PCM_KEY_VALUE)HvGetCell(&RegistryHive->Hive, NewValueCellOffset);
410 if (NewValueCell == NULL)
411 {
412 HvFreeCell(&RegistryHive->Hive, NewValueCellOffset);
413 return STATUS_INSUFFICIENT_RESOURCES;
414 }
415
416 NewValueCell->Signature = CM_KEY_VALUE_SIGNATURE;
417 NewValueCell->NameLength = CmpCopyName(&RegistryHive->Hive,
418 NewValueCell->Name,
419 (PUNICODE_STRING)ValueName);
420
421 /* Check for compressed name */
422 if (NewValueCell->NameLength < ValueName->Length)
423 {
424 /* This is a compressed name */
425 NewValueCell->Flags = VALUE_COMP_NAME;
426 }
427 else
428 {
429 /* No flags to set */
430 NewValueCell->Flags = 0;
431 }
432
433 NewValueCell->Type = 0;
434 NewValueCell->DataLength = 0;
435 NewValueCell->Data = HCELL_NIL;
436
437
438 ValueListCell->u.KeyList[Parent->ValueList.Count] = NewValueCellOffset;
439 Parent->ValueList.Count++;
440
441 HvMarkCellDirty(&RegistryHive->Hive, Parent->ValueList.List, FALSE);
442 HvMarkCellDirty(&RegistryHive->Hive, NewValueCellOffset, FALSE);
443
444 *pValueCell = NewValueCell;
445 *pValueCellOffset = NewValueCellOffset;
446
447 return STATUS_SUCCESS;
448 }