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 } 434