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 * PROGRAMMER: Hervé Poussineau
37 return (PVOID
)malloc((size_t)Size
);
52 IN PHHIVE RegistryHive
,
56 IN SIZE_T BufferLength
)
58 DPRINT1("CmpFileRead() unimplemented\n");
65 IN PHHIVE RegistryHive
,
69 IN SIZE_T BufferLength
)
71 PCMHIVE CmHive
= (PCMHIVE
)RegistryHive
;
72 FILE *File
= CmHive
->FileHandles
[HFILE_TYPE_PRIMARY
];
73 if (fseek(File
, *FileOffset
, SEEK_SET
) != 0)
76 return (fwrite(Buffer
, 1, BufferLength
, File
) == BufferLength
);
82 IN PHHIVE RegistryHive
,
87 DPRINT1("CmpFileSetSize() unimplemented\n");
94 IN PHHIVE RegistryHive
,
96 PLARGE_INTEGER FileOffset
,
99 PCMHIVE CmHive
= (PCMHIVE
)RegistryHive
;
100 FILE *File
= CmHive
->FileHandles
[HFILE_TYPE_PRIMARY
];
101 return (fflush(File
) == 0);
111 RtlZeroMemory(Hive
, sizeof(*Hive
));
113 DPRINT("Hive 0x%p\n", Hive
);
115 Status
= HvInitialize(&Hive
->Hive
,
128 if (!NT_SUCCESS(Status
))
133 // HACK: See the HACK from r31253
134 if (!CmCreateRootNode(&Hive
->Hive
, Name
))
137 return STATUS_INSUFFICIENT_RESOURCES
;
140 /* Add the new hive to the hive list */
141 InsertTailList(&CmiHiveListHead
,
144 return STATUS_SUCCESS
;
148 CmiCreateSecurityKey(
151 IN PUCHAR Descriptor
,
152 IN ULONG DescriptorLength
)
154 HCELL_INDEX SecurityCell
;
156 PCM_KEY_SECURITY Security
;
158 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
159 SecurityCell
= HvAllocateCell(Hive
,
160 FIELD_OFFSET(CM_KEY_SECURITY
, Descriptor
) +
164 if (SecurityCell
== HCELL_NIL
)
166 HvReleaseCell(Hive
, Cell
);
167 return STATUS_INSUFFICIENT_RESOURCES
;
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
;
176 RtlMoveMemory(&Security
->Descriptor
,
180 Security
->Flink
= Security
->Blink
= SecurityCell
;
182 HvReleaseCell(Hive
, SecurityCell
);
183 HvReleaseCell(Hive
, Cell
);
185 return STATUS_SUCCESS
;
190 IN PCMHIVE RegistryHive
,
191 IN HCELL_INDEX ParentKeyCellOffset
,
192 IN PCUNICODE_STRING SubKeyName
,
193 IN BOOLEAN VolatileKey
,
194 OUT HCELL_INDEX
* pNKBOffset
)
196 HCELL_INDEX NKBOffset
;
197 PCM_KEY_NODE NewKeyCell
;
198 UNICODE_STRING KeyName
;
199 HSTORAGE_TYPE Storage
;
201 /* Skip leading path separator if present */
202 if (SubKeyName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
204 KeyName
.Buffer
= &SubKeyName
->Buffer
[1];
205 KeyName
.Length
= KeyName
.MaximumLength
= SubKeyName
->Length
- sizeof(WCHAR
);
209 KeyName
= *SubKeyName
;
212 Storage
= (VolatileKey
? Volatile
: Stable
);
214 NKBOffset
= HvAllocateCell(&RegistryHive
->Hive
,
215 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
216 CmpNameSize(&RegistryHive
->Hive
, &KeyName
),
219 if (NKBOffset
== HCELL_NIL
)
221 return STATUS_INSUFFICIENT_RESOURCES
;
224 NewKeyCell
= (PCM_KEY_NODE
)HvGetCell(&RegistryHive
->Hive
, NKBOffset
);
225 if (NewKeyCell
== NULL
)
227 HvFreeCell(&RegistryHive
->Hive
, NKBOffset
);
228 return STATUS_INSUFFICIENT_RESOURCES
;
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
;
251 /* Inherit the security from the parent */
252 if (ParentKeyCellOffset
== HCELL_NIL
)
254 // We are in fact creating a root key.
255 // This is not handled there, but when we
256 // call CmCreateRootNode instead.
261 /* Get the parent node */
262 PCM_KEY_NODE ParentKeyCell
;
263 ParentKeyCell
= (PCM_KEY_NODE
)HvGetCell(&RegistryHive
->Hive
, ParentKeyCellOffset
);
267 /* Inherit the security block of the parent */
268 NewKeyCell
->Security
= ParentKeyCell
->Security
;
269 if (NewKeyCell
->Security
!= HCELL_NIL
)
271 PCM_KEY_SECURITY Security
;
272 Security
= (PCM_KEY_SECURITY
)HvGetCell(&RegistryHive
->Hive
, NewKeyCell
->Security
);
273 ++Security
->ReferenceCount
;
274 HvReleaseCell(&RegistryHive
->Hive
, NewKeyCell
->Security
);
277 HvReleaseCell(&RegistryHive
->Hive
, ParentKeyCellOffset
);
281 HvReleaseCell(&RegistryHive
->Hive
, NKBOffset
);
283 *pNKBOffset
= NKBOffset
;
284 return STATUS_SUCCESS
;
289 IN PCMHIVE RegistryHive
,
290 IN HCELL_INDEX ParentKeyCellOffset
,
291 IN PCUNICODE_STRING SubKeyName
,
292 IN BOOLEAN VolatileKey
,
293 OUT HCELL_INDEX
*pBlockOffset
)
295 PCM_KEY_NODE ParentKeyCell
;
296 HCELL_INDEX NKBOffset
;
299 /* Create the new key */
300 Status
= CmiCreateSubKey(RegistryHive
, ParentKeyCellOffset
, SubKeyName
, VolatileKey
, &NKBOffset
);
301 if (!NT_SUCCESS(Status
))
304 /* Mark the parent cell as dirty */
305 HvMarkCellDirty(&RegistryHive
->Hive
, ParentKeyCellOffset
, FALSE
);
307 if (!CmpAddSubKey(&RegistryHive
->Hive
, ParentKeyCellOffset
, NKBOffset
))
309 /* FIXME: delete newly created cell */
310 // CmpFreeKeyByCell(&RegistryHive->Hive, NewCell /*NKBOffset*/, FALSE);
312 return STATUS_UNSUCCESSFUL
;
315 /* Get the parent node */
316 ParentKeyCell
= (PCM_KEY_NODE
)HvGetCell(&RegistryHive
->Hive
, ParentKeyCellOffset
);
319 /* FIXME: delete newly created cell */
320 return STATUS_UNSUCCESSFUL
;
322 VERIFY_KEY_CELL(ParentKeyCell
);
324 /* Update the timestamp */
325 KeQuerySystemTime(&ParentKeyCell
->LastWriteTime
);
327 /* Check if we need to update name maximum, update it if so */
328 if (ParentKeyCell
->MaxNameLen
< SubKeyName
->Length
)
329 ParentKeyCell
->MaxNameLen
= SubKeyName
->Length
;
331 /* Release the cell */
332 HvReleaseCell(&RegistryHive
->Hive
, ParentKeyCellOffset
);
334 *pBlockOffset
= NKBOffset
;
335 return STATUS_SUCCESS
;
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
)
346 PCELL_DATA ValueListCell
;
347 PCM_KEY_VALUE NewValueCell
;
348 HCELL_INDEX ValueListCellOffset
;
349 HCELL_INDEX NewValueCellOffset
;
351 HSTORAGE_TYPE Storage
;
354 #define FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
357 Storage
= (Parent
->Flags
& KEY_IS_VOLATILE
) ? Volatile
: Stable
;
358 if (Parent
->ValueList
.List
== HCELL_NIL
)
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
;
366 ValueListCell
= (PCELL_DATA
)HvGetCell(&RegistryHive
->Hive
, ValueListCellOffset
);
369 HvFreeCell(&RegistryHive
->Hive
, ValueListCellOffset
);
370 return STATUS_UNSUCCESSFUL
;
373 Parent
->ValueList
.List
= ValueListCellOffset
;
377 ValueListCell
= (PCELL_DATA
)HvGetCell(&RegistryHive
->Hive
, Parent
->ValueList
.List
);
379 return STATUS_UNSUCCESSFUL
;
381 CellSize
= ABS_VALUE(HvGetCellSize(&RegistryHive
->Hive
, ValueListCell
));
383 if (Parent
->ValueList
.Count
>= CellSize
/ sizeof(HCELL_INDEX
))
386 ValueListCellOffset
= HvReallocateCell(&RegistryHive
->Hive
, Parent
->ValueList
.List
, CellSize
);
387 if (ValueListCellOffset
== HCELL_NIL
)
388 return STATUS_INSUFFICIENT_RESOURCES
;
390 ValueListCell
= (PCELL_DATA
)HvGetCell(&RegistryHive
->Hive
, ValueListCellOffset
);
392 return STATUS_UNSUCCESSFUL
;
394 Parent
->ValueList
.List
= ValueListCellOffset
;
399 NewValueCellOffset
= HvAllocateCell(&RegistryHive
->Hive
,
400 FIELD_OFFSET(CM_KEY_VALUE
, Name
) +
401 CmpNameSize(&RegistryHive
->Hive
, (PUNICODE_STRING
)ValueName
),
404 if (NewValueCellOffset
== HCELL_NIL
)
406 return STATUS_INSUFFICIENT_RESOURCES
;
409 NewValueCell
= (PCM_KEY_VALUE
)HvGetCell(&RegistryHive
->Hive
, NewValueCellOffset
);
410 if (NewValueCell
== NULL
)
412 HvFreeCell(&RegistryHive
->Hive
, NewValueCellOffset
);
413 return STATUS_INSUFFICIENT_RESOURCES
;
416 NewValueCell
->Signature
= CM_KEY_VALUE_SIGNATURE
;
417 NewValueCell
->NameLength
= CmpCopyName(&RegistryHive
->Hive
,
419 (PUNICODE_STRING
)ValueName
);
421 /* Check for compressed name */
422 if (NewValueCell
->NameLength
< ValueName
->Length
)
424 /* This is a compressed name */
425 NewValueCell
->Flags
= VALUE_COMP_NAME
;
429 /* No flags to set */
430 NewValueCell
->Flags
= 0;
433 NewValueCell
->Type
= 0;
434 NewValueCell
->DataLength
= 0;
435 NewValueCell
->Data
= HCELL_NIL
;
438 ValueListCell
->u
.KeyList
[Parent
->ValueList
.Count
] = NewValueCellOffset
;
439 Parent
->ValueList
.Count
++;
441 HvMarkCellDirty(&RegistryHive
->Hive
, Parent
->ValueList
.List
, FALSE
);
442 HvMarkCellDirty(&RegistryHive
->Hive
, NewValueCellOffset
, FALSE
);
444 *pValueCell
= NewValueCell
;
445 *pValueCellOffset
= NewValueCellOffset
;
447 return STATUS_SUCCESS
;