1 /* 2 * ReactOS kernel 3 * Copyright (C) 2003, 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/reginf.c 23 * PURPOSE: Inf file import code 24 * PROGRAMMERS: Eric Kohl 25 * Herv� Poussineau 26 */ 27 28 /* INCLUDES *****************************************************************/ 29 30 #include <string.h> 31 #include <stdlib.h> 32 #include <stdio.h> 33 34 #define NDEBUG 35 #include "mkhive.h" 36 37 #define FLG_ADDREG_BINVALUETYPE 0x00000001 38 #define FLG_ADDREG_NOCLOBBER 0x00000002 39 #define FLG_ADDREG_DELVAL 0x00000004 40 #define FLG_ADDREG_APPEND 0x00000008 41 #define FLG_ADDREG_KEYONLY 0x00000010 42 #define FLG_ADDREG_OVERWRITEONLY 0x00000020 43 #define FLG_ADDREG_KEYONLY_COMMON 0x00002000 44 #define FLG_DELREG_KEYONLY_COMMON FLG_ADDREG_KEYONLY_COMMON 45 #define FLG_ADDREG_DELREG_BIT 0x00008000 46 47 #define FLG_ADDREG_TYPE_SZ 0x00000000 48 #define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000 49 #define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000 50 #define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE) 51 #define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE) 52 #define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE) 53 #define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE) 54 55 56 static const WCHAR HKCR[] = {'H','K','C','R',0}; 57 static const WCHAR HKCU[] = {'H','K','C','U',0}; 58 static const WCHAR HKLM[] = {'H','K','L','M',0}; 59 static const WCHAR HKU[] = {'H','K','U',0}; 60 static const WCHAR HKR[] = {'H','K','R',0}; 61 static const WCHAR BCD[] = {'B','C','D',0}; 62 63 static const WCHAR HKCRPath[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\','S','O','F','T','W','A','R','E','\\','C','l','a','s','s','e','s','\\',0}; 64 static const WCHAR HKCUPath[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\','.','D','E','F','A','U','L','T','\\',0}; 65 static const WCHAR HKLMPath[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',0}; 66 static const WCHAR HKUPath[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\',0}; 67 static const WCHAR BCDPath[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',0}; 68 69 static const WCHAR AddReg[] = {'A','d','d','R','e','g',0}; 70 static const WCHAR DelReg[] = {'D','e','l','R','e','g',0}; 71 72 /* FUNCTIONS ****************************************************************/ 73 74 static BOOL 75 get_root_key(PWCHAR Name) 76 { 77 if (!strcmpiW(Name, HKCR)) 78 { 79 strcpyW(Name, HKCRPath); 80 return TRUE; 81 } 82 83 if (!strcmpiW(Name, HKCU)) 84 { 85 strcpyW(Name, HKCUPath); 86 return TRUE; 87 } 88 89 if (!strcmpiW(Name, HKLM)) 90 { 91 strcpyW(Name, HKLMPath); 92 return TRUE; 93 } 94 95 if (!strcmpiW(Name, HKU)) 96 { 97 strcpyW(Name, HKUPath); 98 return TRUE; 99 } 100 101 if (!strcmpiW(Name, BCD)) 102 { 103 strcpyW(Name, BCDPath); 104 return TRUE; 105 } 106 107 #if 0 108 if (!strcmpiW(Name, HKR)) 109 return FALSE; 110 #endif 111 112 return FALSE; 113 } 114 115 116 /*********************************************************************** 117 * append_multi_sz_value 118 * 119 * Append a multisz string to a multisz registry value. 120 */ 121 // NOTE: Synced with setupapi/install.c ; see also usetup/registry.c 122 static VOID 123 append_multi_sz_value( 124 IN HKEY KeyHandle, 125 IN PCWSTR ValueName, 126 IN PCWSTR Strings, 127 IN ULONG StringSize) // In characters 128 { 129 ULONG Size, Total; // In bytes 130 ULONG Type; 131 PWCHAR Buffer; 132 PWCHAR p; 133 size_t len; 134 LONG Error; 135 136 Error = RegQueryValueExW(KeyHandle, 137 ValueName, 138 NULL, 139 &Type, 140 NULL, 141 &Size); 142 if ((Error != ERROR_SUCCESS) || (Type != REG_MULTI_SZ)) 143 return; 144 145 Buffer = malloc(Size + StringSize * sizeof(WCHAR)); 146 if (Buffer == NULL) 147 return; 148 149 Error = RegQueryValueExW(KeyHandle, 150 ValueName, 151 NULL, 152 NULL, 153 (PUCHAR)Buffer, 154 &Size); 155 if (Error != ERROR_SUCCESS) 156 goto done; 157 158 /* compare each string against all the existing ones */ 159 Total = Size; 160 while (*Strings != 0) 161 { 162 len = strlenW(Strings) + 1; 163 164 for (p = Buffer; *p != 0; p += strlenW(p) + 1) 165 if (!strcmpiW(p, Strings)) 166 break; 167 168 if (*p == 0) /* not found, need to append it */ 169 { 170 memcpy(p, Strings, len * sizeof(WCHAR)); 171 p[len] = 0; 172 Total += len * sizeof(WCHAR); 173 } 174 Strings += len; 175 } 176 177 if (Total != Size) 178 { 179 DPRINT("setting value '%S' to '%S'\n", ValueName, Buffer); 180 RegSetValueExW(KeyHandle, 181 ValueName, 182 0, 183 REG_MULTI_SZ, 184 (PUCHAR)Buffer, 185 Total + sizeof(WCHAR)); 186 } 187 188 done: 189 free(Buffer); 190 } 191 192 193 /*********************************************************************** 194 * do_reg_operation 195 * 196 * Perform an add/delete registry operation depending on the flags. 197 */ 198 static BOOL 199 do_reg_operation( 200 IN HKEY KeyHandle, 201 IN PCWSTR ValueName, 202 IN PINFCONTEXT Context, 203 IN ULONG Flags) 204 { 205 WCHAR EmptyStr = 0; 206 ULONG Type; 207 ULONG Size; 208 LONG Error; 209 210 if (Flags & (FLG_ADDREG_DELREG_BIT | FLG_ADDREG_DELVAL)) /* deletion */ 211 { 212 if (ValueName && *ValueName && !(Flags & FLG_DELREG_KEYONLY_COMMON)) 213 { 214 // NOTE: We don't currently handle deleting sub-values inside multi-strings. 215 RegDeleteValueW(KeyHandle, ValueName); 216 } 217 else 218 { 219 RegDeleteKeyW(KeyHandle, NULL); 220 } 221 return TRUE; 222 } 223 224 if (Flags & (FLG_ADDREG_KEYONLY | FLG_ADDREG_KEYONLY_COMMON)) 225 return TRUE; 226 227 if (Flags & (FLG_ADDREG_NOCLOBBER | FLG_ADDREG_OVERWRITEONLY)) 228 { 229 Error = RegQueryValueExW(KeyHandle, 230 ValueName, 231 NULL, 232 NULL, 233 NULL, 234 NULL); 235 236 if ((Error == ERROR_SUCCESS) && (Flags & FLG_ADDREG_NOCLOBBER)) 237 return TRUE; 238 239 if ((Error != ERROR_SUCCESS) && (Flags & FLG_ADDREG_OVERWRITEONLY)) 240 return TRUE; 241 } 242 243 switch (Flags & FLG_ADDREG_TYPE_MASK) 244 { 245 case FLG_ADDREG_TYPE_SZ: 246 Type = REG_SZ; 247 break; 248 249 case FLG_ADDREG_TYPE_MULTI_SZ: 250 Type = REG_MULTI_SZ; 251 break; 252 253 case FLG_ADDREG_TYPE_EXPAND_SZ: 254 Type = REG_EXPAND_SZ; 255 break; 256 257 case FLG_ADDREG_TYPE_BINARY: 258 Type = REG_BINARY; 259 break; 260 261 case FLG_ADDREG_TYPE_DWORD: 262 Type = REG_DWORD; 263 break; 264 265 case FLG_ADDREG_TYPE_NONE: 266 Type = REG_NONE; 267 break; 268 269 default: 270 Type = Flags >> 16; 271 break; 272 } 273 274 if (!(Flags & FLG_ADDREG_BINVALUETYPE) || 275 (Type == REG_DWORD && InfHostGetFieldCount(Context) == 5)) 276 { 277 PWCHAR Str = NULL; 278 279 if (Type == REG_MULTI_SZ) 280 { 281 if (InfHostGetMultiSzField(Context, 5, NULL, 0, &Size) != 0) 282 Size = 0; 283 284 if (Size) 285 { 286 Str = malloc(Size * sizeof(WCHAR)); 287 if (Str == NULL) 288 return FALSE; 289 290 InfHostGetMultiSzField(Context, 5, Str, Size, NULL); 291 } 292 293 if (Flags & FLG_ADDREG_APPEND) 294 { 295 if (Str == NULL) 296 return TRUE; 297 298 DPRINT("append_multi_sz_value(ValueName = '%S')\n", ValueName); 299 append_multi_sz_value(KeyHandle, 300 ValueName, 301 Str, 302 Size); 303 304 free(Str); 305 return TRUE; 306 } 307 /* else fall through to normal string handling */ 308 } 309 else 310 { 311 if (InfHostGetStringField(Context, 5, NULL, 0, &Size) != 0) 312 Size = 0; 313 314 if (Size) 315 { 316 Str = malloc(Size * sizeof(WCHAR)); 317 if (Str == NULL) 318 return FALSE; 319 320 InfHostGetStringField(Context, 5, Str, Size, NULL); 321 } 322 } 323 324 if (Type == REG_DWORD) 325 { 326 ULONG dw = Str ? strtoulW(Str, NULL, 0) : 0; 327 328 DPRINT("setting dword '%S' to %x\n", ValueName, dw); 329 330 RegSetValueExW(KeyHandle, 331 ValueName, 332 0, 333 Type, 334 (const PUCHAR)&dw, 335 sizeof(ULONG)); 336 } 337 else 338 { 339 DPRINT("setting value '%S' to '%S'\n", ValueName, Str); 340 341 if (Str) 342 { 343 RegSetValueExW(KeyHandle, 344 ValueName, 345 0, 346 Type, 347 (PVOID)Str, 348 (ULONG)(Size * sizeof(WCHAR))); 349 } 350 else 351 { 352 RegSetValueExW(KeyHandle, 353 ValueName, 354 0, 355 Type, 356 (PVOID)&EmptyStr, 357 sizeof(WCHAR)); 358 } 359 } 360 free(Str); 361 } 362 else /* get the binary data */ 363 { 364 PUCHAR Data = NULL; 365 366 if (InfHostGetBinaryField(Context, 5, NULL, 0, &Size) != 0) 367 Size = 0; 368 369 if (Size) 370 { 371 Data = malloc(Size); 372 if (Data == NULL) 373 return FALSE; 374 375 DPRINT("setting binary data '%S' len %d\n", ValueName, (ULONG)Size); 376 InfHostGetBinaryField(Context, 5, Data, Size, NULL); 377 } 378 379 RegSetValueExW(KeyHandle, 380 ValueName, 381 0, 382 Type, 383 (PVOID)Data, 384 (ULONG)Size); 385 386 free(Data); 387 } 388 389 return TRUE; 390 } 391 392 /*********************************************************************** 393 * registry_callback 394 * 395 * Called once for each AddReg and DelReg entry in a given section. 396 */ 397 static BOOL 398 registry_callback(HINF hInf, PCWSTR Section, BOOL Delete) 399 { 400 WCHAR Buffer[MAX_INF_STRING_LENGTH]; 401 PWCHAR ValuePtr; 402 ULONG Flags; 403 size_t Length; 404 405 PINFCONTEXT Context = NULL; 406 HKEY KeyHandle; 407 BOOL Ok; 408 409 Ok = InfHostFindFirstLine(hInf, Section, NULL, &Context) == 0; 410 if (!Ok) 411 return TRUE; /* Don't fail if the section isn't present */ 412 413 for (Ok = TRUE; Ok; Ok = (InfHostFindNextLine(Context, Context) == 0)) 414 { 415 /* Get root */ 416 if (InfHostGetStringField(Context, 1, Buffer, sizeof(Buffer)/sizeof(WCHAR), NULL) != 0) 417 continue; 418 if (!get_root_key(Buffer)) 419 continue; 420 421 /* Get key */ 422 Length = strlenW(Buffer); 423 if (InfHostGetStringField(Context, 2, Buffer + Length, sizeof(Buffer)/sizeof(WCHAR) - (ULONG)Length, NULL) != 0) 424 *Buffer = 0; 425 426 DPRINT("KeyName: <%S>\n", Buffer); 427 428 /* Get flags */ 429 if (InfHostGetIntField(Context, 4, (INT*)&Flags) != 0) 430 Flags = 0; 431 432 if (Delete) 433 { 434 if (!Flags) 435 Flags = FLG_ADDREG_DELREG_BIT; 436 else if (!(Flags & FLG_ADDREG_DELREG_BIT)) 437 continue; /* ignore this entry */ 438 } 439 else 440 { 441 if (Flags & FLG_ADDREG_DELREG_BIT) 442 continue; /* ignore this entry */ 443 } 444 445 DPRINT("Flags: 0x%x\n", Flags); 446 447 if (Delete || (Flags & FLG_ADDREG_OVERWRITEONLY)) 448 { 449 if (RegOpenKeyW(NULL, Buffer, &KeyHandle) != ERROR_SUCCESS) 450 { 451 DPRINT("RegOpenKey(%S) failed\n", Buffer); 452 continue; /* ignore if it doesn't exist */ 453 } 454 } 455 else 456 { 457 if (RegCreateKeyW(NULL, Buffer, &KeyHandle) != ERROR_SUCCESS) 458 { 459 DPRINT("RegCreateKey(%S) failed\n", Buffer); 460 continue; 461 } 462 } 463 464 /* Get value name */ 465 if (InfHostGetStringField(Context, 3, Buffer, sizeof(Buffer)/sizeof(WCHAR), NULL) == 0) 466 { 467 ValuePtr = Buffer; 468 } 469 else 470 { 471 ValuePtr = NULL; 472 } 473 474 /* And now do it */ 475 if (!do_reg_operation(KeyHandle, ValuePtr, Context, Flags)) 476 { 477 RegCloseKey(KeyHandle); 478 return FALSE; 479 } 480 481 RegCloseKey(KeyHandle); 482 } 483 484 InfHostFreeContext(Context); 485 486 return TRUE; 487 } 488 489 490 BOOL 491 ImportRegistryFile(PCHAR FileName) 492 { 493 HINF hInf; 494 ULONG ErrorLine; 495 496 /* Load inf file from install media. */ 497 if (InfHostOpenFile(&hInf, FileName, 0, &ErrorLine) != 0) 498 { 499 DPRINT1("InfHostOpenFile(%s) failed\n", FileName); 500 return FALSE; 501 } 502 503 if (!registry_callback(hInf, (PWCHAR)DelReg, TRUE)) 504 { 505 DPRINT1("registry_callback() for DelReg failed\n"); 506 InfHostCloseFile(hInf); 507 return FALSE; 508 } 509 510 if (!registry_callback(hInf, (PWCHAR)AddReg, FALSE)) 511 { 512 DPRINT1("registry_callback() for AddReg failed\n"); 513 InfHostCloseFile(hInf); 514 return FALSE; 515 } 516 517 InfHostCloseFile(hInf); 518 return TRUE; 519 } 520 521 /* EOF */ 522