Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/ntdll/tests/env.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+)
diff --git a/dlls/ntdll/tests/env.c b/dlls/ntdll/tests/env.c index 9cfbf9eb435..51fee774b8b 100644 --- a/dlls/ntdll/tests/env.c +++ b/dlls/ntdll/tests/env.c @@ -654,6 +654,143 @@ static void test_RtlSetEnvironmentVariable(void) ok(!status, "got %#x\n", status); }
+/* if 'value' is non NULL, returns TRUE iff env var 'name' is present and of value 'value' + * if 'value' is NULL, returns TRUE iff env var 'name' is not present present + */ +static BOOL check_pseudo_in_peb(const WCHAR* name, const WCHAR* value) +{ + WCHAR* envstrings; + WCHAR* ptr; + size_t len = wcslen(name); + BOOL ret = FALSE; + + RtlAcquirePebLock(); + envstrings = NtCurrentTeb()->Peb->ProcessParameters->Environment; + if (envstrings) + { + for (ptr = envstrings; *ptr; ptr += wcslen(ptr) + 1) + { + if (!wcsncmp(ptr, name, len) && ptr[len] == L'=') + { + ret = value && !wcscmp(&ptr[len + 1], value); + break; + } + } + if (value == NULL && !*ptr) ret = TRUE; + } + RtlReleasePebLock(); + return ret; +} + +static DWORD test_one_pseudo_variable(const WCHAR* pseudo, WCHAR* value, UINT value_len) +{ + const WCHAR* dummystr = L"let's land onto the moon"; + WCHAR value2_buffer[1024]; + UNICODE_STRING var_string, value_string, value2_string; + NTSTATUS status; + BOOL ret; + + RtlInitUnicodeString(&var_string, pseudo); + value_string.Buffer = value; + value_string.MaximumLength = value_len * sizeof(WCHAR); + + status = RtlQueryEnvironmentVariable_U(small_env, &var_string, &value_string); + todo_wine + ok(!status, "Should have found %ls env var in small_env (%x)\n", pseudo, status); + + status = RtlQueryEnvironmentVariable_U(NULL, &var_string, &value_string); + todo_wine + ok(!status && value_string.Length >= sizeof(WCHAR), "Couldn't find %ls env var\n", pseudo); + ok(value_string.Length == wcslen(value_string.Buffer) * sizeof(WCHAR), + "Expecting length of %u but got %u\n", + wcslen(value_string.Buffer) * sizeof(WCHAR), value_string.Length); + + if (pRtlQueryEnvironmentVariable) + { + SIZE_T zzlen; + status = pRtlQueryEnvironmentVariable(NULL, (WCHAR*)pseudo, wcslen(pseudo), + value, value_len / sizeof(WCHAR), &zzlen); + todo_wine + ok(!status && zzlen >= sizeof(WCHAR), "Couldn't find %ls env var\n", pseudo); + } + ret = check_pseudo_in_peb(pseudo, NULL); + ok(ret, "Pseudo env var %ls shouldn't be present in env strings\n", pseudo); + + status = set_env_var(NULL, pseudo, dummystr); + ok(!status, "Should be able to write value for set %ls\n", pseudo); + + value2_string.Buffer = value2_buffer; + value2_string.MaximumLength = sizeof(value2_buffer); + + status = RtlQueryEnvironmentVariable_U(NULL, &var_string, &value2_string); + ok(!status && value2_string.Length >= sizeof(WCHAR), "Couldn't find %ls env var\n", pseudo); + todo_wine + ok(!wcscmp(value2_string.Buffer, value_string.Buffer), + "Expecting %ls but got %ls for env variable %ls\n", + value_string.Buffer, value2_string.Buffer, pseudo); + + ret = check_pseudo_in_peb(pseudo, dummystr); + ok(ret, "Pseudo env var %ls should be present in env strings with value %ls\n", pseudo, dummystr); + + status = set_env_var(NULL, pseudo, NULL); + ok(!status, "Should be able to remove value for set %ls\n", pseudo); + + status = RtlQueryEnvironmentVariable_U(NULL, &var_string, &value2_string); + todo_wine + ok(!status && value2_string.Length >= sizeof(WCHAR), "Couldn't find %ls env var\n", pseudo); + todo_wine + ok(!wcscmp(value, value2_string.Buffer), "Should get back pseudo value for %ls\n", pseudo); + + ret = check_pseudo_in_peb(pseudo, NULL); + ok(ret, "Pseudo env var %ls shouldn't be present in env strings\n", pseudo); + + value2_string.Buffer = value2_buffer; + value2_string.MaximumLength = wcslen(value) * sizeof(WCHAR); /* missing one wchar */ + memset(value2_buffer, 0xa5, sizeof(value2_buffer)); + + status = RtlQueryEnvironmentVariable_U(NULL, &var_string, &value2_string); + todo_wine + ok(status == STATUS_BUFFER_TOO_SMALL && value2_string.Length >= sizeof(WCHAR), + "Couldn't find %ls env var\n", pseudo); + todo_wine + ok(!value2_string.Buffer[0], "Expecting empty buffer for env variable %ls\n", pseudo); + ok(value2_string.Length == value_string.Length, "Expecting length of %u but got %u\n", + value_string.Length, value2_string.Length); + + return value_string.Length / sizeof(WCHAR); +} + +static void test_pseudo_env_variables(void) +{ + WCHAR value[1024]; + WCHAR value2[1024]; + DWORD size, size2; + + size = test_one_pseudo_variable(L"__APPDIR__", value, ARRAY_SIZE(value)); + size2 = GetModuleFileNameW(NULL, value2, ARRAY_SIZE(value2)); + ok(size2 && size2 + 1 < ARRAY_SIZE(value2), "couldn't get app module filename\n"); + ok(size + 1 < size2, "Mismatch in sizes (%u / %u)\n", size, size2); + todo_wine + ok(size && !memcmp(value, value2, size * sizeof(WCHAR)) && value[size - 1] == L'\', + "__APPDIR__: got %ls while expecting %ls\\n", value, value2); + todo_wine + ok(!wcschr(&value2[size], L'/') && !wcschr(&value2[size], L'\'), + "expecting %ls not to include directories\n", &value2[size]); + + size = test_one_pseudo_variable(L"__CD__", value, ARRAY_SIZE(value)); + size2 = GetCurrentDirectoryW(ARRAY_SIZE(value2), value2); + ok(size2 && size2 + 1 < ARRAY_SIZE(value2), "couldn't get current directory\n"); + todo_wine + ok(size2 + 1 == size, "Mismatch in sizes (%u / %u)\n", size, size2); + todo_wine + ok(!memcmp(value, value2, size2 * sizeof(WCHAR)) && value[size2] == L'\', + "__CD__: got %ls while expecting %ls\\n", value, value2); + /* FIXME could check changing directories + * - that __CD__ changes automatically + * - even if an old value still present in env strings + */ +} + START_TEST(env) { HMODULE mod = GetModuleHandleA("ntdll.dll"); @@ -672,4 +809,5 @@ START_TEST(env) test_process_params(); test_RtlSetCurrentEnvironment(); test_RtlSetEnvironmentVariable(); + test_pseudo_env_variables(); }
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52544 Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/ntdll/env.c | 109 +++++++++++++++++++++++++++++++++++++++--------- dlls/ntdll/tests/env.c | 12 ----- 2 files changed, 89 insertions(+), 32 deletions(-)
diff --git a/dlls/ntdll/env.c b/dlls/ntdll/env.c index bb8931a556b..de794a03f78 100644 --- a/dlls/ntdll/env.c +++ b/dlls/ntdll/env.c @@ -154,6 +154,58 @@ static LPCWSTR ENV_FindVariable(PCWSTR var, PCWSTR name, unsigned namelen) return NULL; }
+static BOOL ENV_get_pseudo_variable(const WCHAR* name, SIZE_T len, WCHAR* value, SIZE_T value_len, SIZE_T* ret_len) +{ + static WCHAR appdir[] = {'_','_','A','P','P','D','I','R','_','_'}; + static WCHAR cd[] = {'_','_','C','D','_','_'}; + + if (!RtlCompareUnicodeStrings( name, len, appdir, ARRAY_SIZE(appdir), FALSE )) + { + ULONG_PTR magic; + LDR_DATA_TABLE_ENTRY *pldr; + NTSTATUS status; + + LdrLockLoaderLock( 0, NULL, &magic ); + status = LdrFindEntryForAddress( NtCurrentTeb()->Peb->ImageBaseAddress, &pldr ); + if (!status) + { + WCHAR* ptr = wcsrchr(pldr->FullDllName.Buffer, L'\'); + if (ptr) + { + SIZE_T len = ++ptr - pldr->FullDllName.Buffer; + *ret_len = len * sizeof(WCHAR); + if ((len + 1) * sizeof(WCHAR) <= value_len) + { + memcpy( value, pldr->FullDllName.Buffer, *ret_len ); + value[len] = L'\0'; + } + else if (value_len >= sizeof(WCHAR)) + value[0] = L'\0'; + } + else status = STATUS_INVALID_PARAMETER; + } + LdrUnlockLoaderLock( 0, magic ); + return !status; + } + else if (!RtlCompareUnicodeStrings( name, len, cd, ARRAY_SIZE(cd), FALSE )) + { + unsigned actual = RtlGetCurrentDirectory_U( value_len >= sizeof(WCHAR) ? value_len - sizeof(WCHAR) : 0, value ); + if (actual + sizeof(WCHAR) <= value_len) + { + value[actual / sizeof(WCHAR)] = L'\'; + value[actual / sizeof(WCHAR) + 1] = L'\0'; + *ret_len = actual + sizeof(WCHAR); + } + else + { + *ret_len = actual; + if (value_len >= sizeof(WCHAR)) value[0] = L'\0'; + } + return TRUE; + } + return FALSE; +} + /****************************************************************** * RtlQueryEnvironmentVariable_U [NTDLL.@] * @@ -169,6 +221,7 @@ NTSTATUS WINAPI RtlQueryEnvironmentVariable_U(PWSTR env, NTSTATUS nts = STATUS_VARIABLE_NOT_FOUND; PCWSTR var; unsigned namelen; + SIZE_T ret_len;
TRACE("%p %s %p\n", env, debugstr_us(name), value);
@@ -183,17 +236,25 @@ NTSTATUS WINAPI RtlQueryEnvironmentVariable_U(PWSTR env, } else var = env;
- var = ENV_FindVariable(var, name->Buffer, namelen); - if (var != NULL) + if (ENV_get_pseudo_variable(name->Buffer, namelen, value->Buffer, value->MaximumLength, &ret_len)) { - value->Length = wcslen(var) * sizeof(WCHAR); - - if (value->Length <= value->MaximumLength) + value->Length = ret_len; + nts = (value->Length >= value->MaximumLength) ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS; + } + else + { + var = ENV_FindVariable(var, name->Buffer, namelen); + if (var != NULL) { - memmove(value->Buffer, var, min(value->Length + sizeof(WCHAR), value->MaximumLength)); - nts = STATUS_SUCCESS; + value->Length = wcslen(var) * sizeof(WCHAR); + + if (value->Length <= value->MaximumLength) + { + memmove(value->Buffer, var, min(value->Length + sizeof(WCHAR), value->MaximumLength)); + nts = STATUS_SUCCESS; + } + else nts = STATUS_BUFFER_TOO_SMALL; } - else nts = STATUS_BUFFER_TOO_SMALL; }
if (!env) RtlReleasePebLock(); @@ -221,22 +282,30 @@ NTSTATUS WINAPI RtlQueryEnvironmentVariable( WCHAR *env, const WCHAR *name, SIZE } else var = env;
- var = ENV_FindVariable(var, name, namelen); - if (var != NULL) + if (ENV_get_pseudo_variable(name, namelen, value, value_length * sizeof(WCHAR), return_length)) { - len = wcslen(var); - if (len <= value_length) - { - memcpy(value, var, min(len + 1, value_length) * sizeof(WCHAR)); - nts = STATUS_SUCCESS; - } - else + *return_length /= sizeof(WCHAR); + nts = (*return_length > value_length) ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS; + } + else + { + var = ENV_FindVariable(var, name, namelen); + if (var != NULL) { - len++; - nts = STATUS_BUFFER_TOO_SMALL; + len = wcslen(var); + if (len <= value_length) + { + memcpy(value, var, min(len + 1, value_length) * sizeof(WCHAR)); + nts = STATUS_SUCCESS; + } + else + { + len++; + nts = STATUS_BUFFER_TOO_SMALL; + } } + *return_length = len; } - *return_length = len;
if (!env) RtlReleasePebLock();
diff --git a/dlls/ntdll/tests/env.c b/dlls/ntdll/tests/env.c index 51fee774b8b..b5cf42f86d1 100644 --- a/dlls/ntdll/tests/env.c +++ b/dlls/ntdll/tests/env.c @@ -695,11 +695,9 @@ static DWORD test_one_pseudo_variable(const WCHAR* pseudo, WCHAR* value, UINT va value_string.MaximumLength = value_len * sizeof(WCHAR);
status = RtlQueryEnvironmentVariable_U(small_env, &var_string, &value_string); - todo_wine ok(!status, "Should have found %ls env var in small_env (%x)\n", pseudo, status);
status = RtlQueryEnvironmentVariable_U(NULL, &var_string, &value_string); - todo_wine ok(!status && value_string.Length >= sizeof(WCHAR), "Couldn't find %ls env var\n", pseudo); ok(value_string.Length == wcslen(value_string.Buffer) * sizeof(WCHAR), "Expecting length of %u but got %u\n", @@ -710,7 +708,6 @@ static DWORD test_one_pseudo_variable(const WCHAR* pseudo, WCHAR* value, UINT va SIZE_T zzlen; status = pRtlQueryEnvironmentVariable(NULL, (WCHAR*)pseudo, wcslen(pseudo), value, value_len / sizeof(WCHAR), &zzlen); - todo_wine ok(!status && zzlen >= sizeof(WCHAR), "Couldn't find %ls env var\n", pseudo); } ret = check_pseudo_in_peb(pseudo, NULL); @@ -724,7 +721,6 @@ static DWORD test_one_pseudo_variable(const WCHAR* pseudo, WCHAR* value, UINT va
status = RtlQueryEnvironmentVariable_U(NULL, &var_string, &value2_string); ok(!status && value2_string.Length >= sizeof(WCHAR), "Couldn't find %ls env var\n", pseudo); - todo_wine ok(!wcscmp(value2_string.Buffer, value_string.Buffer), "Expecting %ls but got %ls for env variable %ls\n", value_string.Buffer, value2_string.Buffer, pseudo); @@ -736,9 +732,7 @@ static DWORD test_one_pseudo_variable(const WCHAR* pseudo, WCHAR* value, UINT va ok(!status, "Should be able to remove value for set %ls\n", pseudo);
status = RtlQueryEnvironmentVariable_U(NULL, &var_string, &value2_string); - todo_wine ok(!status && value2_string.Length >= sizeof(WCHAR), "Couldn't find %ls env var\n", pseudo); - todo_wine ok(!wcscmp(value, value2_string.Buffer), "Should get back pseudo value for %ls\n", pseudo);
ret = check_pseudo_in_peb(pseudo, NULL); @@ -749,10 +743,8 @@ static DWORD test_one_pseudo_variable(const WCHAR* pseudo, WCHAR* value, UINT va memset(value2_buffer, 0xa5, sizeof(value2_buffer));
status = RtlQueryEnvironmentVariable_U(NULL, &var_string, &value2_string); - todo_wine ok(status == STATUS_BUFFER_TOO_SMALL && value2_string.Length >= sizeof(WCHAR), "Couldn't find %ls env var\n", pseudo); - todo_wine ok(!value2_string.Buffer[0], "Expecting empty buffer for env variable %ls\n", pseudo); ok(value2_string.Length == value_string.Length, "Expecting length of %u but got %u\n", value_string.Length, value2_string.Length); @@ -770,19 +762,15 @@ static void test_pseudo_env_variables(void) size2 = GetModuleFileNameW(NULL, value2, ARRAY_SIZE(value2)); ok(size2 && size2 + 1 < ARRAY_SIZE(value2), "couldn't get app module filename\n"); ok(size + 1 < size2, "Mismatch in sizes (%u / %u)\n", size, size2); - todo_wine ok(size && !memcmp(value, value2, size * sizeof(WCHAR)) && value[size - 1] == L'\', "__APPDIR__: got %ls while expecting %ls\\n", value, value2); - todo_wine ok(!wcschr(&value2[size], L'/') && !wcschr(&value2[size], L'\'), "expecting %ls not to include directories\n", &value2[size]);
size = test_one_pseudo_variable(L"__CD__", value, ARRAY_SIZE(value)); size2 = GetCurrentDirectoryW(ARRAY_SIZE(value2), value2); ok(size2 && size2 + 1 < ARRAY_SIZE(value2), "couldn't get current directory\n"); - todo_wine ok(size2 + 1 == size, "Mismatch in sizes (%u / %u)\n", size, size2); - todo_wine ok(!memcmp(value, value2, size2 * sizeof(WCHAR)) && value[size2] == L'\', "__CD__: got %ls while expecting %ls\\n", value, value2); /* FIXME could check changing directories