[PATCH 2/2] dlls/ntdll: adding support for pseudo environment variables
Eric Pouech
eric.pouech at gmail.com
Tue Mar 1 08:48:22 CST 2022
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52544
Signed-off-by: Eric Pouech <eric.pouech at 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
More information about the wine-devel
mailing list