[LDR][APPHELP] Add a shim that disables manifest compatibility version parsing
[reactos.git] / 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 * PROGRAMMERS: Hervé Poussineau
25 * Hermès Bélusca-Maïto
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #define NDEBUG
31 #include "mkhive.h"
32
33 /* FUNCTIONS ****************************************************************/
34
35 PVOID
36 NTAPI
37 CmpAllocate(
38 IN SIZE_T Size,
39 IN BOOLEAN Paged,
40 IN ULONG Tag)
41 {
42 return (PVOID)malloc((size_t)Size);
43 }
44
45 VOID
46 NTAPI
47 CmpFree(
48 IN PVOID Ptr,
49 IN ULONG Quota)
50 {
51 free(Ptr);
52 }
53
54 static BOOLEAN
55 NTAPI
56 CmpFileRead(
57 IN PHHIVE RegistryHive,
58 IN ULONG FileType,
59 IN PULONG FileOffset,
60 OUT PVOID Buffer,
61 IN SIZE_T BufferLength)
62 {
63 PCMHIVE CmHive = (PCMHIVE)RegistryHive;
64 FILE *File = CmHive->FileHandles[HFILE_TYPE_PRIMARY];
65 if (fseek(File, *FileOffset, SEEK_SET) != 0)
66 return FALSE;
67
68 return (fread(Buffer, 1, BufferLength, File) == BufferLength);
69 }
70
71 static BOOLEAN
72 NTAPI
73 CmpFileWrite(
74 IN PHHIVE RegistryHive,
75 IN ULONG FileType,
76 IN PULONG FileOffset,
77 IN PVOID Buffer,
78 IN SIZE_T BufferLength)
79 {
80 PCMHIVE CmHive = (PCMHIVE)RegistryHive;
81 FILE *File = CmHive->FileHandles[HFILE_TYPE_PRIMARY];
82 if (fseek(File, *FileOffset, SEEK_SET) != 0)
83 return FALSE;
84
85 return (fwrite(Buffer, 1, BufferLength, File) == BufferLength);
86 }
87
88 static BOOLEAN
89 NTAPI
90 CmpFileSetSize(
91 IN PHHIVE RegistryHive,
92 IN ULONG FileType,
93 IN ULONG FileSize,
94 IN ULONG OldFileSize)
95 {
96 DPRINT1("CmpFileSetSize() unimplemented\n");
97 return FALSE;
98 }
99
100 static BOOLEAN
101 NTAPI
102 CmpFileFlush(
103 IN PHHIVE RegistryHive,
104 IN ULONG FileType,
105 PLARGE_INTEGER FileOffset,
106 ULONG Length)
107 {
108 PCMHIVE CmHive = (PCMHIVE)RegistryHive;
109 FILE *File = CmHive->FileHandles[HFILE_TYPE_PRIMARY];
110 return (fflush(File) == 0);
111 }
112
113 NTSTATUS
114 CmiInitializeHive(
115 IN OUT PCMHIVE Hive,
116 IN PCWSTR Name)
117 {
118 NTSTATUS Status;
119
120 RtlZeroMemory(Hive, sizeof(*Hive));
121
122 DPRINT("Hive 0x%p\n", Hive);
123
124 Status = HvInitialize(&Hive->Hive,
125 HINIT_CREATE,
126 HIVE_NOLAZYFLUSH,
127 HFILE_TYPE_PRIMARY,
128 0,
129 CmpAllocate,
130 CmpFree,
131 CmpFileSetSize,
132 CmpFileWrite,
133 CmpFileRead,
134 CmpFileFlush,
135 1,
136 NULL);
137 if (!NT_SUCCESS(Status))
138 {
139 return Status;
140 }
141
142 // HACK: See the HACK from r31253
143 if (!CmCreateRootNode(&Hive->Hive, Name))
144 {
145 HvFree(&Hive->Hive);
146 return STATUS_INSUFFICIENT_RESOURCES;
147 }
148
149 /* Add the new hive to the hive list */
150 InsertTailList(&CmiHiveListHead,
151 &Hive->HiveList);
152
153 return STATUS_SUCCESS;
154 }
155
156 NTSTATUS
157 CmiCreateSecurityKey(
158 IN PHHIVE Hive,
159 IN HCELL_INDEX Cell,
160 IN PUCHAR Descriptor,
161 IN ULONG DescriptorLength)
162 {
163 HCELL_INDEX SecurityCell;
164 PCM_KEY_NODE Node;
165 PCM_KEY_SECURITY Security;
166
167 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
168 SecurityCell = HvAllocateCell(Hive,
169 FIELD_OFFSET(CM_KEY_SECURITY, Descriptor) +
170 DescriptorLength,
171 Stable,
172 HCELL_NIL);
173 if (SecurityCell == HCELL_NIL)
174 {
175 HvReleaseCell(Hive, Cell);
176 return STATUS_INSUFFICIENT_RESOURCES;
177 }
178
179 Node->Security = SecurityCell;
180 Security = (PCM_KEY_SECURITY)HvGetCell(Hive, SecurityCell);
181 Security->Signature = CM_KEY_SECURITY_SIGNATURE;
182 Security->ReferenceCount = 1;
183 Security->DescriptorLength = DescriptorLength;
184
185 RtlMoveMemory(&Security->Descriptor,
186 Descriptor,
187 DescriptorLength);
188
189 Security->Flink = Security->Blink = SecurityCell;
190
191 HvReleaseCell(Hive, SecurityCell);
192 HvReleaseCell(Hive, Cell);
193
194 return STATUS_SUCCESS;
195 }
196
197 static NTSTATUS
198 CmiCreateSubKey(
199 IN PCMHIVE RegistryHive,
200 IN HCELL_INDEX ParentKeyCellOffset,
201 IN PCUNICODE_STRING SubKeyName,
202 IN BOOLEAN VolatileKey,
203 OUT HCELL_INDEX* pNKBOffset)
204 {
205 HCELL_INDEX NKBOffset;
206 PCM_KEY_NODE NewKeyCell;
207 UNICODE_STRING KeyName;
208 HSTORAGE_TYPE Storage;
209
210 /* Skip leading path separator if present */
211 if (SubKeyName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
212 {
213 KeyName.Buffer = &SubKeyName->Buffer[1];
214 KeyName.Length = KeyName.MaximumLength = SubKeyName->Length - sizeof(WCHAR);
215 }
216 else
217 {
218 KeyName = *SubKeyName;
219 }
220
221 Storage = (VolatileKey ? Volatile : Stable);
222
223 NKBOffset = HvAllocateCell(&RegistryHive->Hive,
224 FIELD_OFFSET(CM_KEY_NODE, Name) +
225 CmpNameSize(&RegistryHive->Hive, &KeyName),
226 Storage,
227 HCELL_NIL);
228 if (NKBOffset == HCELL_NIL)
229 {
230 return STATUS_INSUFFICIENT_RESOURCES;
231 }
232
233 NewKeyCell = (PCM_KEY_NODE)HvGetCell(&RegistryHive->Hive, NKBOffset);
234 if (NewKeyCell == NULL)
235 {
236 HvFreeCell(&RegistryHive->Hive, NKBOffset);
237 return STATUS_INSUFFICIENT_RESOURCES;
238 }
239
240 NewKeyCell->Signature = CM_KEY_NODE_SIGNATURE;
241 NewKeyCell->Flags = (VolatileKey ? KEY_IS_VOLATILE : 0);
242 KeQuerySystemTime(&NewKeyCell->LastWriteTime);
243 NewKeyCell->Parent = ParentKeyCellOffset;
244 NewKeyCell->SubKeyCounts[Stable] = 0;
245 NewKeyCell->SubKeyCounts[Volatile] = 0;
246 NewKeyCell->SubKeyLists[Stable] = HCELL_NIL;
247 NewKeyCell->SubKeyLists[Volatile] = HCELL_NIL;
248 NewKeyCell->ValueList.Count = 0;
249 NewKeyCell->ValueList.List = HCELL_NIL;
250 NewKeyCell->Security = HCELL_NIL;
251 NewKeyCell->Class = HCELL_NIL;
252 NewKeyCell->ClassLength = 0;
253 NewKeyCell->MaxNameLen = 0;
254 NewKeyCell->MaxClassLen = 0;
255 NewKeyCell->MaxValueNameLen = 0;
256 NewKeyCell->MaxValueDataLen = 0;
257 NewKeyCell->NameLength = CmpCopyName(&RegistryHive->Hive, NewKeyCell->Name, &KeyName);
258 if (NewKeyCell->NameLength < KeyName.Length) NewKeyCell->Flags |= KEY_COMP_NAME;
259
260 /* Inherit the security from the parent */
261 if (ParentKeyCellOffset == HCELL_NIL)
262 {
263 // We are in fact creating a root key.
264 // This is not handled there, but when we
265 // call CmCreateRootNode instead.
266 ASSERT(FALSE);
267 }
268 else
269 {
270 /* Get the parent node */
271 PCM_KEY_NODE ParentKeyCell;
272 ParentKeyCell = (PCM_KEY_NODE)HvGetCell(&RegistryHive->Hive, ParentKeyCellOffset);
273
274 if (ParentKeyCell)
275 {
276 /* Inherit the security block of the parent */
277 NewKeyCell->Security = ParentKeyCell->Security;
278 if (NewKeyCell->Security != HCELL_NIL)
279 {
280 PCM_KEY_SECURITY Security;
281 Security = (PCM_KEY_SECURITY)HvGetCell(&RegistryHive->Hive, NewKeyCell->Security);
282 ++Security->ReferenceCount;
283 HvReleaseCell(&RegistryHive->Hive, NewKeyCell->Security);
284 }
285
286 HvReleaseCell(&RegistryHive->Hive, ParentKeyCellOffset);
287 }
288 }
289
290 HvReleaseCell(&RegistryHive->Hive, NKBOffset);
291
292 *pNKBOffset = NKBOffset;
293 return STATUS_SUCCESS;
294 }
295
296 NTSTATUS
297 CmiAddSubKey(
298 IN PCMHIVE RegistryHive,
299 IN HCELL_INDEX ParentKeyCellOffset,
300 IN PCUNICODE_STRING SubKeyName,
301 IN BOOLEAN VolatileKey,
302 OUT HCELL_INDEX *pBlockOffset)
303 {
304 PCM_KEY_NODE ParentKeyCell;
305 HCELL_INDEX NKBOffset;
306 NTSTATUS Status;
307
308 /* Create the new key */
309 Status = CmiCreateSubKey(RegistryHive, ParentKeyCellOffset, SubKeyName, VolatileKey, &NKBOffset);
310 if (!NT_SUCCESS(Status))
311 return Status;
312
313 /* Mark the parent cell as dirty */
314 HvMarkCellDirty(&RegistryHive->Hive, ParentKeyCellOffset, FALSE);
315
316 if (!CmpAddSubKey(&RegistryHive->Hive, ParentKeyCellOffset, NKBOffset))
317 {
318 /* FIXME: delete newly created cell */
319 // CmpFreeKeyByCell(&RegistryHive->Hive, NewCell /*NKBOffset*/, FALSE);
320 ASSERT(FALSE);
321 return STATUS_UNSUCCESSFUL;
322 }
323
324 /* Get the parent node */
325 ParentKeyCell = (PCM_KEY_NODE)HvGetCell(&RegistryHive->Hive, ParentKeyCellOffset);
326 if (!ParentKeyCell)
327 {
328 /* FIXME: delete newly created cell */
329 return STATUS_UNSUCCESSFUL;
330 }
331 VERIFY_KEY_CELL(ParentKeyCell);
332
333 /* Update the timestamp */
334 KeQuerySystemTime(&ParentKeyCell->LastWriteTime);
335
336 /* Check if we need to update name maximum, update it if so */
337 if (ParentKeyCell->MaxNameLen < SubKeyName->Length)
338 ParentKeyCell->MaxNameLen = SubKeyName->Length;
339
340 /* Release the cell */
341 HvReleaseCell(&RegistryHive->Hive, ParentKeyCellOffset);
342
343 *pBlockOffset = NKBOffset;
344 return STATUS_SUCCESS;
345 }
346
347 NTSTATUS
348 CmiAddValueKey(
349 IN PCMHIVE RegistryHive,
350 IN PCM_KEY_NODE Parent,
351 IN ULONG ChildIndex,
352 IN PCUNICODE_STRING ValueName,
353 OUT PCM_KEY_VALUE *pValueCell,
354 OUT HCELL_INDEX *pValueCellOffset)
355 {
356 NTSTATUS Status;
357 HSTORAGE_TYPE Storage;
358 PCM_KEY_VALUE NewValueCell;
359 HCELL_INDEX NewValueCellOffset;
360
361 Storage = (Parent->Flags & KEY_IS_VOLATILE) ? Volatile : Stable;
362
363 NewValueCellOffset = HvAllocateCell(&RegistryHive->Hive,
364 FIELD_OFFSET(CM_KEY_VALUE, Name) +
365 CmpNameSize(&RegistryHive->Hive, (PUNICODE_STRING)ValueName),
366 Storage,
367 HCELL_NIL);
368 if (NewValueCellOffset == HCELL_NIL)
369 {
370 return STATUS_INSUFFICIENT_RESOURCES;
371 }
372
373 NewValueCell = (PCM_KEY_VALUE)HvGetCell(&RegistryHive->Hive, NewValueCellOffset);
374 if (NewValueCell == NULL)
375 {
376 HvFreeCell(&RegistryHive->Hive, NewValueCellOffset);
377 return STATUS_INSUFFICIENT_RESOURCES;
378 }
379
380 NewValueCell->Signature = CM_KEY_VALUE_SIGNATURE;
381 NewValueCell->NameLength = CmpCopyName(&RegistryHive->Hive,
382 NewValueCell->Name,
383 (PUNICODE_STRING)ValueName);
384
385 /* Check for compressed name */
386 if (NewValueCell->NameLength < ValueName->Length)
387 {
388 /* This is a compressed name */
389 NewValueCell->Flags = VALUE_COMP_NAME;
390 }
391 else
392 {
393 /* No flags to set */
394 NewValueCell->Flags = 0;
395 }
396
397 NewValueCell->Type = 0;
398 NewValueCell->DataLength = 0;
399 NewValueCell->Data = HCELL_NIL;
400
401 HvMarkCellDirty(&RegistryHive->Hive, NewValueCellOffset, FALSE);
402
403 /* Check if we already have a value list */
404 if (Parent->ValueList.Count)
405 {
406 /* Then make sure it's valid and dirty it */
407 ASSERT(Parent->ValueList.List != HCELL_NIL);
408 HvMarkCellDirty(&RegistryHive->Hive, Parent->ValueList.List, FALSE);
409 }
410
411 /* Add this value cell to the child list */
412 Status = CmpAddValueToList(&RegistryHive->Hive,
413 NewValueCellOffset,
414 ChildIndex,
415 Storage,
416 &Parent->ValueList);
417
418 /* If we failed, free the entire cell, including the data */
419 if (!NT_SUCCESS(Status))
420 {
421 /* Overwrite the status with a known one */
422 CmpFreeValue(&RegistryHive->Hive, NewValueCellOffset);
423 Status = STATUS_INSUFFICIENT_RESOURCES;
424 }
425 else
426 {
427 *pValueCell = NewValueCell;
428 *pValueCellOffset = NewValueCellOffset;
429 Status = STATUS_SUCCESS;
430 }
431
432 return Status;
433 }