Reactos

[SERVICES] Improvements to registry control sets

- Add a function that creates a new control set and deletes unused control sets in case of a successful boot.
- Add a stub function that will soon switch to the last known good control set in case of an unsuccessful boot.

+252 -4
+240
base/system/services/controlset.c
··· 17 17 18 18 /* GLOBALS *******************************************************************/ 19 19 20 + static BOOL bBootAccepted = FALSE; 21 + 20 22 21 23 /* FUNCTIONS *****************************************************************/ 22 24 ··· 240 242 241 243 return ERROR_SUCCESS; 242 244 } 245 + 246 + 247 + DWORD 248 + ScmDeleteTree( 249 + HKEY hKey, 250 + PCWSTR pszSubKey) 251 + { 252 + DWORD dwMaxSubkeyLength, dwMaxValueLength; 253 + DWORD dwMaxLength, dwSize; 254 + PWSTR pszName = NULL; 255 + HKEY hSubKey = NULL; 256 + DWORD dwError; 257 + 258 + if (pszSubKey != NULL) 259 + { 260 + dwError = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_READ, &hSubKey); 261 + if (dwError != ERROR_SUCCESS) 262 + return dwError; 263 + } 264 + else 265 + { 266 + hSubKey = hKey; 267 + } 268 + 269 + /* Get highest length for keys, values */ 270 + dwError = RegQueryInfoKeyW(hSubKey, 271 + NULL, 272 + NULL, 273 + NULL, 274 + NULL, 275 + &dwMaxSubkeyLength, 276 + NULL, 277 + NULL, 278 + &dwMaxValueLength, 279 + NULL, 280 + NULL, 281 + NULL); 282 + if (dwError != ERROR_SUCCESS) 283 + goto done; 284 + 285 + dwMaxSubkeyLength++; 286 + dwMaxValueLength++; 287 + dwMaxLength = max(dwMaxSubkeyLength, dwMaxValueLength); 288 + 289 + /* Allocate a buffer for key and value names */ 290 + pszName = HeapAlloc(GetProcessHeap(), 291 + 0, 292 + dwMaxLength * sizeof(WCHAR)); 293 + if (pszName == NULL) 294 + { 295 + dwError = ERROR_NOT_ENOUGH_MEMORY; 296 + goto done; 297 + } 298 + 299 + /* Recursively delete all the subkeys */ 300 + while (TRUE) 301 + { 302 + dwSize = dwMaxLength; 303 + if (RegEnumKeyExW(hSubKey, 304 + 0, 305 + pszName, 306 + &dwSize, 307 + NULL, 308 + NULL, 309 + NULL, 310 + NULL)) 311 + break; 312 + 313 + dwError = ScmDeleteTree(hSubKey, pszName); 314 + if (dwError != ERROR_SUCCESS) 315 + goto done; 316 + } 317 + 318 + if (pszSubKey != NULL) 319 + { 320 + dwError = RegDeleteKeyW(hKey, pszSubKey); 321 + } 322 + else 323 + { 324 + while (TRUE) 325 + { 326 + dwSize = dwMaxLength; 327 + if (RegEnumValueW(hKey, 328 + 0, 329 + pszName, 330 + &dwSize, 331 + NULL, 332 + NULL, 333 + NULL, 334 + NULL)) 335 + break; 336 + 337 + dwError = RegDeleteValueW(hKey, pszName); 338 + if (dwError != ERROR_SUCCESS) 339 + goto done; 340 + } 341 + } 342 + 343 + done: 344 + if (pszName != NULL) 345 + HeapFree(GetProcessHeap(), 0, pszName); 346 + 347 + if (pszSubKey != NULL) 348 + RegCloseKey(hSubKey); 349 + 350 + return dwError; 351 + } 243 352 #endif 244 353 245 354 ··· 460 569 } 461 570 462 571 572 + static 573 + DWORD 574 + ScmDeleteControlSet( 575 + DWORD dwControlSet) 576 + { 577 + WCHAR szControlSetName[32]; 578 + HKEY hControlSetKey = NULL; 579 + DWORD dwError; 580 + 581 + DPRINT("ScmDeleteControSet(%lu)\n", dwControlSet); 582 + 583 + /* Create the control set name */ 584 + swprintf(szControlSetName, L"SYSTEM\\ControlSet%03lu", dwControlSet); 585 + DPRINT("Control set: %S\n", szControlSetName); 586 + 587 + /* Open the system key */ 588 + dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 589 + szControlSetName, 590 + 0, 591 + DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_SET_VALUE, 592 + &hControlSetKey); 593 + if (dwError != ERROR_SUCCESS) 594 + return dwError; 595 + 596 + /* Delete the control set */ 597 + #if (_WIN32_WINNT >= 0x0600) 598 + dwError = RegDeleteTreeW(hControlSetKey, 599 + NULL); 600 + #else 601 + dwError = ScmDeleteTree(hControlSetKey, 602 + NULL); 603 + #endif 604 + 605 + /* Open the system key */ 606 + RegCloseKey(hControlSetKey); 607 + 608 + return dwError; 609 + } 610 + 611 + 463 612 DWORD 464 613 ScmCreateLastKnownGoodControlSet(VOID) 465 614 { ··· 507 656 508 657 /* Set the new 'LastKnownGood' control set */ 509 658 dwError = ScmSetLastKnownGoodControlSet(dwNewControlSet); 659 + if (dwError == ERROR_SUCCESS) 660 + { 661 + /* 662 + * Accept the boot here in order to prevent the creation of 663 + * another control set when a user is going to get logged on 664 + */ 665 + bBootAccepted = TRUE; 666 + } 510 667 } 511 668 512 669 return dwError; 670 + } 671 + 672 + 673 + DWORD 674 + ScmAcceptBoot(VOID) 675 + { 676 + DWORD dwCurrentControlSet, dwDefaultControlSet; 677 + DWORD dwFailedControlSet, dwLastKnownGoodControlSet; 678 + DWORD dwNewControlSet; 679 + DWORD dwError; 680 + 681 + DPRINT("ScmAcceptBoot()\n"); 682 + 683 + if (bBootAccepted) 684 + { 685 + DPRINT1("Boot has alread been accepted!\n"); 686 + return ERROR_BOOT_ALREADY_ACCEPTED; 687 + } 688 + 689 + /* Get the control set values */ 690 + dwError = ScmGetControlSetValues(&dwCurrentControlSet, 691 + &dwDefaultControlSet, 692 + &dwFailedControlSet, 693 + &dwLastKnownGoodControlSet); 694 + if (dwError != ERROR_SUCCESS) 695 + return dwError; 696 + 697 + /* Search for a new control set number */ 698 + for (dwNewControlSet = 1; dwNewControlSet < 1000; dwNewControlSet++) 699 + { 700 + if ((dwNewControlSet != dwCurrentControlSet) && 701 + (dwNewControlSet != dwDefaultControlSet) && 702 + (dwNewControlSet != dwFailedControlSet) && 703 + (dwNewControlSet != dwLastKnownGoodControlSet)) 704 + break; 705 + } 706 + 707 + /* Fail if we did not find an unused control set!*/ 708 + if (dwNewControlSet >= 1000) 709 + { 710 + DPRINT1("Too many control sets!\n"); 711 + return ERROR_NO_MORE_ITEMS; 712 + } 713 + 714 + /* Copy the current control set */ 715 + dwError = ScmCopyControlSet(dwCurrentControlSet, 716 + dwNewControlSet); 717 + if (dwError != ERROR_SUCCESS) 718 + return dwError; 719 + 720 + /* Delete the current last known good contol set, if it is not used anywhere else */ 721 + if ((dwLastKnownGoodControlSet != dwCurrentControlSet) && 722 + (dwLastKnownGoodControlSet != dwDefaultControlSet) && 723 + (dwLastKnownGoodControlSet != dwFailedControlSet)) 724 + { 725 + ScmDeleteControlSet(dwLastKnownGoodControlSet); 726 + } 727 + 728 + /* Set the new 'LastKnownGood' control set */ 729 + dwError = ScmSetLastKnownGoodControlSet(dwNewControlSet); 730 + if (dwError != ERROR_SUCCESS) 731 + return dwError; 732 + 733 + bBootAccepted = TRUE; 734 + 735 + return ERROR_SUCCESS; 736 + } 737 + 738 + 739 + DWORD 740 + ScmRunLastKnownGood(VOID) 741 + { 742 + DPRINT("ScmRunLastKnownGood()\n"); 743 + 744 + if (bBootAccepted) 745 + { 746 + DPRINT1("Boot has alread been accepted!\n"); 747 + return ERROR_BOOT_ALREADY_ACCEPTED; 748 + } 749 + 750 + /* FIXME */ 751 + 752 + return ERROR_SUCCESS; 513 753 } 514 754 515 755 /* EOF */
+6 -4
base/system/services/rpcserver.c
··· 1848 1848 SVCCTL_HANDLEW lpMachineName, 1849 1849 DWORD BootAcceptable) 1850 1850 { 1851 - DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable); 1852 - return ERROR_SUCCESS; 1851 + DPRINT("RNotifyBootConfigStatus(%p %lu)\n", 1852 + lpMachineName, BootAcceptable); 1853 1853 1854 - // UNIMPLEMENTED; 1855 - // return ERROR_CALL_NOT_IMPLEMENTED; 1854 + if (BootAcceptable) 1855 + return ScmAcceptBoot(); 1856 + 1857 + return ScmRunLastKnownGood(); 1856 1858 } 1857 1859 1858 1860
+6
base/system/services/services.h
··· 164 164 DWORD 165 165 ScmCreateLastKnownGoodControlSet(VOID); 166 166 167 + DWORD 168 + ScmAcceptBoot(VOID); 169 + 170 + DWORD 171 + ScmRunLastKnownGood(VOID); 172 + 167 173 168 174 /* database.c */ 169 175