3 * Copyright (C) 2006 ReactOS Team
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.
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.
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.
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
28 /* INCLUDES *****************************************************************/
33 /* FUNCTIONS ****************************************************************/
42 return (PVOID
)malloc((size_t)Size
);
57 IN PHHIVE RegistryHive
,
61 IN SIZE_T BufferLength
)
63 PCMHIVE CmHive
= (PCMHIVE
)RegistryHive
;
64 FILE *File
= CmHive
->FileHandles
[HFILE_TYPE_PRIMARY
];
65 if (fseek(File
, *FileOffset
, SEEK_SET
) != 0)
68 return (fread(Buffer
, 1, BufferLength
, File
) == BufferLength
);
74 IN PHHIVE RegistryHive
,
78 IN SIZE_T BufferLength
)
80 PCMHIVE CmHive
= (PCMHIVE
)RegistryHive
;
81 FILE *File
= CmHive
->FileHandles
[HFILE_TYPE_PRIMARY
];
82 if (fseek(File
, *FileOffset
, SEEK_SET
) != 0)
85 return (fwrite(Buffer
, 1, BufferLength
, File
) == BufferLength
);
91 IN PHHIVE RegistryHive
,
96 DPRINT1("CmpFileSetSize() unimplemented\n");
103 IN PHHIVE RegistryHive
,
105 PLARGE_INTEGER FileOffset
,
108 PCMHIVE CmHive
= (PCMHIVE
)RegistryHive
;
109 FILE *File
= CmHive
->FileHandles
[HFILE_TYPE_PRIMARY
];
110 return (fflush(File
) == 0);
120 RtlZeroMemory(Hive
, sizeof(*Hive
));
122 DPRINT("Hive 0x%p\n", Hive
);
124 Status
= HvInitialize(&Hive
->Hive
,
137 if (!NT_SUCCESS(Status
))
142 // HACK: See the HACK from r31253
143 if (!CmCreateRootNode(&Hive
->Hive
, Name
))
146 return STATUS_INSUFFICIENT_RESOURCES
;
149 /* Add the new hive to the hive list */
150 InsertTailList(&CmiHiveListHead
,
153 return STATUS_SUCCESS
;
157 CmiCreateSecurityKey(
160 IN PUCHAR Descriptor
,
161 IN ULONG DescriptorLength
)
163 HCELL_INDEX SecurityCell
;
165 PCM_KEY_SECURITY Security
;
167 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
168 SecurityCell
= HvAllocateCell(Hive
,
169 FIELD_OFFSET(CM_KEY_SECURITY
, Descriptor
) +
173 if (SecurityCell
== HCELL_NIL
)
175 HvReleaseCell(Hive
, Cell
);
176 return STATUS_INSUFFICIENT_RESOURCES
;
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
;
185 RtlMoveMemory(&Security
->Descriptor
,
189 Security
->Flink
= Security
->Blink
= SecurityCell
;
191 HvReleaseCell(Hive
, SecurityCell
);
192 HvReleaseCell(Hive
, Cell
);
194 return STATUS_SUCCESS
;
199 IN PCMHIVE RegistryHive
,
200 IN HCELL_INDEX ParentKeyCellOffset
,
201 IN PCUNICODE_STRING SubKeyName
,
202 IN BOOLEAN VolatileKey
,
203 OUT HCELL_INDEX
* pNKBOffset
)
205 HCELL_INDEX NKBOffset
;
206 PCM_KEY_NODE NewKeyCell
;
207 UNICODE_STRING KeyName
;
208 HSTORAGE_TYPE Storage
;
210 /* Skip leading path separator if present */
211 if (SubKeyName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
213 KeyName
.Buffer
= &SubKeyName
->Buffer
[1];
214 KeyName
.Length
= KeyName
.MaximumLength
= SubKeyName
->Length
- sizeof(WCHAR
);
218 KeyName
= *SubKeyName
;
221 Storage
= (VolatileKey
? Volatile
: Stable
);
223 NKBOffset
= HvAllocateCell(&RegistryHive
->Hive
,
224 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
225 CmpNameSize(&RegistryHive
->Hive
, &KeyName
),
228 if (NKBOffset
== HCELL_NIL
)
230 return STATUS_INSUFFICIENT_RESOURCES
;
233 NewKeyCell
= (PCM_KEY_NODE
)HvGetCell(&RegistryHive
->Hive
, NKBOffset
);
234 if (NewKeyCell
== NULL
)
236 HvFreeCell(&RegistryHive
->Hive
, NKBOffset
);
237 return STATUS_INSUFFICIENT_RESOURCES
;
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
;
260 /* Inherit the security from the parent */
261 if (ParentKeyCellOffset
== HCELL_NIL
)
263 // We are in fact creating a root key.
264 // This is not handled there, but when we
265 // call CmCreateRootNode instead.
270 /* Get the parent node */
271 PCM_KEY_NODE ParentKeyCell
;
272 ParentKeyCell
= (PCM_KEY_NODE
)HvGetCell(&RegistryHive
->Hive
, ParentKeyCellOffset
);
276 /* Inherit the security block of the parent */
277 NewKeyCell
->Security
= ParentKeyCell
->Security
;
278 if (NewKeyCell
->Security
!= HCELL_NIL
)
280 PCM_KEY_SECURITY Security
;
281 Security
= (PCM_KEY_SECURITY
)HvGetCell(&RegistryHive
->Hive
, NewKeyCell
->Security
);
282 ++Security
->ReferenceCount
;
283 HvReleaseCell(&RegistryHive
->Hive
, NewKeyCell
->Security
);
286 HvReleaseCell(&RegistryHive
->Hive
, ParentKeyCellOffset
);
290 HvReleaseCell(&RegistryHive
->Hive
, NKBOffset
);
292 *pNKBOffset
= NKBOffset
;
293 return STATUS_SUCCESS
;
298 IN PCMHIVE RegistryHive
,
299 IN HCELL_INDEX ParentKeyCellOffset
,
300 IN PCUNICODE_STRING SubKeyName
,
301 IN BOOLEAN VolatileKey
,
302 OUT HCELL_INDEX
*pBlockOffset
)
304 PCM_KEY_NODE ParentKeyCell
;
305 HCELL_INDEX NKBOffset
;
308 /* Create the new key */
309 Status
= CmiCreateSubKey(RegistryHive
, ParentKeyCellOffset
, SubKeyName
, VolatileKey
, &NKBOffset
);
310 if (!NT_SUCCESS(Status
))
313 /* Mark the parent cell as dirty */
314 HvMarkCellDirty(&RegistryHive
->Hive
, ParentKeyCellOffset
, FALSE
);
316 if (!CmpAddSubKey(&RegistryHive
->Hive
, ParentKeyCellOffset
, NKBOffset
))
318 /* FIXME: delete newly created cell */
319 // CmpFreeKeyByCell(&RegistryHive->Hive, NewCell /*NKBOffset*/, FALSE);
321 return STATUS_UNSUCCESSFUL
;
324 /* Get the parent node */
325 ParentKeyCell
= (PCM_KEY_NODE
)HvGetCell(&RegistryHive
->Hive
, ParentKeyCellOffset
);
328 /* FIXME: delete newly created cell */
329 return STATUS_UNSUCCESSFUL
;
331 VERIFY_KEY_CELL(ParentKeyCell
);
333 /* Update the timestamp */
334 KeQuerySystemTime(&ParentKeyCell
->LastWriteTime
);
336 /* Check if we need to update name maximum, update it if so */
337 if (ParentKeyCell
->MaxNameLen
< SubKeyName
->Length
)
338 ParentKeyCell
->MaxNameLen
= SubKeyName
->Length
;
340 /* Release the cell */
341 HvReleaseCell(&RegistryHive
->Hive
, ParentKeyCellOffset
);
343 *pBlockOffset
= NKBOffset
;
344 return STATUS_SUCCESS
;
349 IN PCMHIVE RegistryHive
,
350 IN PCM_KEY_NODE Parent
,
352 IN PCUNICODE_STRING ValueName
,
353 OUT PCM_KEY_VALUE
*pValueCell
,
354 OUT HCELL_INDEX
*pValueCellOffset
)
357 HSTORAGE_TYPE Storage
;
358 PCM_KEY_VALUE NewValueCell
;
359 HCELL_INDEX NewValueCellOffset
;
361 Storage
= (Parent
->Flags
& KEY_IS_VOLATILE
) ? Volatile
: Stable
;
363 NewValueCellOffset
= HvAllocateCell(&RegistryHive
->Hive
,
364 FIELD_OFFSET(CM_KEY_VALUE
, Name
) +
365 CmpNameSize(&RegistryHive
->Hive
, (PUNICODE_STRING
)ValueName
),
368 if (NewValueCellOffset
== HCELL_NIL
)
370 return STATUS_INSUFFICIENT_RESOURCES
;
373 NewValueCell
= (PCM_KEY_VALUE
)HvGetCell(&RegistryHive
->Hive
, NewValueCellOffset
);
374 if (NewValueCell
== NULL
)
376 HvFreeCell(&RegistryHive
->Hive
, NewValueCellOffset
);
377 return STATUS_INSUFFICIENT_RESOURCES
;
380 NewValueCell
->Signature
= CM_KEY_VALUE_SIGNATURE
;
381 NewValueCell
->NameLength
= CmpCopyName(&RegistryHive
->Hive
,
383 (PUNICODE_STRING
)ValueName
);
385 /* Check for compressed name */
386 if (NewValueCell
->NameLength
< ValueName
->Length
)
388 /* This is a compressed name */
389 NewValueCell
->Flags
= VALUE_COMP_NAME
;
393 /* No flags to set */
394 NewValueCell
->Flags
= 0;
397 NewValueCell
->Type
= 0;
398 NewValueCell
->DataLength
= 0;
399 NewValueCell
->Data
= HCELL_NIL
;
401 HvMarkCellDirty(&RegistryHive
->Hive
, NewValueCellOffset
, FALSE
);
403 /* Check if we already have a value list */
404 if (Parent
->ValueList
.Count
)
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
);
411 /* Add this value cell to the child list */
412 Status
= CmpAddValueToList(&RegistryHive
->Hive
,
418 /* If we failed, free the entire cell, including the data */
419 if (!NT_SUCCESS(Status
))
421 /* Overwrite the status with a known one */
422 CmpFreeValue(&RegistryHive
->Hive
, NewValueCellOffset
);
423 Status
= STATUS_INSUFFICIENT_RESOURCES
;
427 *pValueCell
= NewValueCell
;
428 *pValueCellOffset
= NewValueCellOffset
;
429 Status
= STATUS_SUCCESS
;