diff --git a/Userland/Libraries/LibCore/Environment.cpp b/Userland/Libraries/LibCore/Environment.cpp index 13420928fa6..b377bf7f5fd 100644 --- a/Userland/Libraries/LibCore/Environment.cpp +++ b/Userland/Libraries/LibCore/Environment.cpp @@ -3,6 +3,7 @@ * Copyright (c) 2021-2022, Kenneth Myhra * Copyright (c) 2021-2024, Sam Atkins * Copyright (c) 2022, Matthias Zimmerman + * Copyright (c) 2024, stasoid * * SPDX-License-Identifier: BSD-2-Clause */ @@ -12,7 +13,7 @@ #if defined(AK_OS_MACOS) || defined(AK_OS_IOS) # include -#else +#elif !defined(AK_OS_WINDOWS) extern "C" char** environ; #endif @@ -93,8 +94,8 @@ Optional get(StringView name, [[maybe_unused]] SecureOnly secure) builder.append('\0'); // Note the explicit null terminators above. - // FreeBSD < 14, Android, and generic BSDs do not support secure_getenv. -#if (defined(__FreeBSD__) && __FreeBSD__ >= 14) || (!defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_ANDROID)) + // FreeBSD < 14, Android, generic BSDs, and Windows do not support secure_getenv. +#if (defined(__FreeBSD__) && __FreeBSD__ >= 14) || (!defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_ANDROID) && !defined(AK_OS_WINDOWS)) char* result; if (secure == SecureOnly::Yes) { result = ::secure_getenv(builder.string_view().characters_without_null_termination()); @@ -119,7 +120,13 @@ ErrorOr set(StringView name, StringView value, Overwrite overwrite) // Note the explicit null terminators above. auto c_name = builder.string_view().characters_without_null_termination(); auto c_value = c_name + name.length() + 1; +#ifndef AK_OS_WINDOWS auto rc = ::setenv(c_name, c_value, overwrite == Overwrite::Yes ? 1 : 0); +#else + if (overwrite == Overwrite::No && getenv(c_name)) + return {}; + auto rc = _putenv_s(c_name, c_value); +#endif if (rc < 0) return Error::from_errno(errno); return {}; @@ -130,9 +137,14 @@ ErrorOr unset(StringView name) auto builder = TRY(StringBuilder::create()); TRY(builder.try_append(name)); TRY(builder.try_append('\0')); - // Note the explicit null terminator above. - auto rc = ::unsetenv(builder.string_view().characters_without_null_termination()); + auto c_name = builder.string_view().characters_without_null_termination(); + +#ifndef AK_OS_WINDOWS + auto rc = ::unsetenv(c_name); +#else + auto rc = _putenv_s(c_name, ""); +#endif if (rc < 0) return Error::from_errno(errno); return {}; @@ -142,6 +154,9 @@ ErrorOr put(StringView env) { #if defined(AK_OS_SERENITY) auto rc = ::serenity_putenv(env.characters_without_null_termination(), env.length()); +#elif defined(AK_OS_WINDOWS) + ByteString str = env; + auto rc = ::putenv(str.characters()); #else // Leak somewhat unavoidable here due to the putenv API. auto leaked_new_env = strndup(env.characters_without_null_termination(), env.length()); @@ -161,6 +176,16 @@ ErrorOr clear() for (size_t environ_size = 0; environment[environ_size]; ++environ_size) { environment[environ_size] = NULL; } +#elif defined(AK_OS_WINDOWS) + // environ = 0 doesn't work on Windows + while (auto str = environ[0]) { + auto eq = strchr(str, '='); + VERIFY(eq); + size_t name_len = eq - str; + auto result = unset({ str, name_len }); + if (result.is_error()) + return result; + } #else auto rc = ::clearenv(); if (rc < 0)