https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7d28dfd1848e83be05b3ec...
commit 7d28dfd1848e83be05b3ec06cb5151fb4b8e017f Author: Eric Kohl eric.kohl@reactos.org AuthorDate: Sat Mar 16 07:45:30 2019 +0100 Commit: Eric Kohl eric.kohl@reactos.org CommitDate: Sat Mar 16 07:45:30 2019 +0100
[USERENV] Use a reference counter when loading and unloading profiles. Unload the hive only when the reference counter reaches 0. This fixes the remaining bugs in "userenv_apitest LoadUserProfile". --- dll/win32/userenv/profile.c | 225 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 199 insertions(+), 26 deletions(-)
diff --git a/dll/win32/userenv/profile.c b/dll/win32/userenv/profile.c index 6b4635ba06..1c18a67ab6 100644 --- a/dll/win32/userenv/profile.c +++ b/dll/win32/userenv/profile.c @@ -197,6 +197,157 @@ CreateProfileMutex( }
+static +DWORD +IncrementRefCount( + PWSTR pszSidString, + PDWORD pdwRefCount) +{ + HKEY hProfilesKey = NULL, hProfileKey = NULL; + DWORD dwRefCount = 0, dwLength, dwType; + DWORD dwError; + + DPRINT1("IncrementRefCount(%S %p)\n", + pszSidString, pdwRefCount); + + dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList", + 0, + KEY_QUERY_VALUE, + &hProfilesKey); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("Error: %lu\n", dwError); + goto done; + } + + dwError = RegOpenKeyExW(hProfilesKey, + pszSidString, + 0, + KEY_QUERY_VALUE | KEY_SET_VALUE, + &hProfileKey); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("Error: %lu\n", dwError); + goto done; + } + + /* Get the reference counter */ + dwLength = sizeof(dwRefCount); + RegQueryValueExW(hProfileKey, + L"RefCount", + NULL, + &dwType, + (PBYTE)&dwRefCount, + &dwLength); + + dwRefCount++; + + dwLength = sizeof(dwRefCount); + dwError = RegSetValueExW(hProfileKey, + L"RefCount", + 0, + REG_DWORD, + (PBYTE)&dwRefCount, + dwLength); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("Error: %lu\n", dwError); + goto done; + } + + if (pdwRefCount != NULL) + *pdwRefCount = dwRefCount; + +done: + if (hProfileKey != NULL) + RegCloseKey(hProfileKey); + + if (hProfilesKey != NULL) + RegCloseKey(hProfilesKey); + + return dwError; +} + + +static +DWORD +DecrementRefCount( + PWSTR pszSidString, + PDWORD pdwRefCount) +{ + HKEY hProfilesKey = NULL, hProfileKey = NULL; + DWORD dwRefCount = 0, dwLength, dwType; + DWORD dwError; + + DPRINT1("DecrementRefCount(%S %p)\n", + pszSidString, pdwRefCount); + + dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList", + 0, + KEY_QUERY_VALUE, + &hProfilesKey); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("Error: %lu\n", dwError); + goto done; + } + + dwError = RegOpenKeyExW(hProfilesKey, + pszSidString, + 0, + KEY_QUERY_VALUE | KEY_SET_VALUE, + &hProfileKey); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("Error: %lu\n", dwError); + goto done; + } + + /* Get the reference counter */ + dwLength = sizeof(dwRefCount); + dwError = RegQueryValueExW(hProfileKey, + L"RefCount", + NULL, + &dwType, + (PBYTE)&dwRefCount, + &dwLength); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("Error: %lu\n", dwError); + goto done; + } + + dwRefCount--; + + dwLength = sizeof(dwRefCount); + dwError = RegSetValueExW(hProfileKey, + L"RefCount", + 0, + REG_DWORD, + (PBYTE)&dwRefCount, + dwLength); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("Error: %lu\n", dwError); + goto done; + } + + if (pdwRefCount != NULL) + *pdwRefCount = dwRefCount; + +done: + if (hProfileKey != NULL) + RegCloseKey(hProfileKey); + + if (hProfilesKey != NULL) + RegCloseKey(hProfilesKey); + + return dwError; +} + + /* PUBLIC FUNCTIONS ********************************************************/
BOOL @@ -1613,6 +1764,14 @@ LoadUserProfileW( goto cleanup; }
+ Error = IncrementRefCount(SidString.Buffer, NULL); + if (Error != ERROR_SUCCESS) + { + DPRINT1("IncrementRefCount() failed (Error %ld)\n", Error); + SetLastError((DWORD)Error); + goto cleanup; + } + ret = TRUE;
cleanup: @@ -1640,6 +1799,7 @@ UnloadUserProfile( { UNICODE_STRING SidString = {0, 0, NULL}; HANDLE hProfileMutex = NULL; + DWORD dwRefCount = 0; LONG Error; BOOL bRet = FALSE;
@@ -1675,44 +1835,57 @@ UnloadUserProfile( /* Close the profile handle */ RegCloseKey(hProfile);
- /* Acquire restore privilege */ - if (!AcquireRemoveRestorePrivilege(TRUE)) + Error = DecrementRefCount(SidString.Buffer, &dwRefCount); + if (Error != ERROR_SUCCESS) { - DPRINT1("AcquireRemoveRestorePrivilege() failed (Error %ld)\n", GetLastError()); + DPRINT1("DecrementRefCount() failed (Error %ld)\n", Error); + SetLastError((DWORD)Error); goto cleanup; }
- /* HACK */ + if (dwRefCount == 0) { - HKEY hUserKey; + DPRINT1("RefCount is 0: Unload the Hive!\n");
- Error = RegOpenKeyExW(HKEY_USERS, - SidString.Buffer, - 0, - KEY_WRITE, - &hUserKey); - if (Error == ERROR_SUCCESS) + /* Acquire restore privilege */ + if (!AcquireRemoveRestorePrivilege(TRUE)) { - RegDeleteKeyW(hUserKey, - L"Volatile Environment"); + DPRINT1("AcquireRemoveRestorePrivilege() failed (Error %ld)\n", GetLastError()); + goto cleanup; + } + + /* HACK */ + { + HKEY hUserKey; + + Error = RegOpenKeyExW(HKEY_USERS, + SidString.Buffer, + 0, + KEY_WRITE, + &hUserKey); + if (Error == ERROR_SUCCESS) + { + RegDeleteKeyW(hUserKey, + L"Volatile Environment");
- RegCloseKey(hUserKey); + RegCloseKey(hUserKey); + } } - } - /* End of HACK */ + /* End of HACK */
- /* Unload the hive */ - Error = RegUnLoadKeyW(HKEY_USERS, - SidString.Buffer); + /* Unload the hive */ + Error = RegUnLoadKeyW(HKEY_USERS, + SidString.Buffer);
- /* Remove restore privilege */ - AcquireRemoveRestorePrivilege(FALSE); + /* Remove restore privilege */ + AcquireRemoveRestorePrivilege(FALSE);
- if (Error != ERROR_SUCCESS) - { - DPRINT1("RegUnLoadKeyW() failed (Error %ld)\n", Error); - SetLastError((DWORD)Error); - goto cleanup; + if (Error != ERROR_SUCCESS) + { + DPRINT1("RegUnLoadKeyW() failed (Error %ld)\n", Error); + SetLastError((DWORD)Error); + goto cleanup; + } }
bRet = TRUE;