Files
AnyPS5/core/libs/prx/libc/src/Environment.cpp
T
Hussein Kadhim 6b03cf445f fix(libc): serialise guest TZ changes with time conversions
Copy the guest TZ under the guest environment lock so a concurrent setenv
cannot free it while it is read, and hold one lock across the zone switch
and the conversion so the fields of two zones are never mixed. Document the
host rejection, Windows zone name and stale tm_zone limits.
2026-10-19 13:03:54 +02:00

99 lines
3.6 KiB
C++

#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <algorithm>
#include <memory>
#include <mutex>
#include <string>
#include <string_view>
#include <vector>
#include "prx/libc/include/General.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
namespace {
struct EnvironmentEntry {
std::unique_ptr<std::string> owned;
char* borrowed = nullptr;
char* Data() { return borrowed ? borrowed : owned->data(); }
bool Matches(std::string_view name) {
const char* data = Data();
const char* separator = std::strchr(data, '=');
return separator && std::string_view(data, separator - data) == name;
}
};
std::mutex environmentMutex;
std::vector<EnvironmentEntry>& Environment() {
static std::vector<EnvironmentEntry> entries;
return entries;
}
bool ValidEnvironmentName(const char* name) {
return name && *name && !std::strchr(name, '=');
}
int EnvironmentError(int error) { errno = error; return -1; }
}
extern "C" {
bool CopyGuestEnvironment_nid_no_patch(const char* name, std::string& value) {
if (!ValidEnvironmentName(name)) return false;
std::lock_guard lock(environmentMutex);
for (auto& entry : Environment())
if (entry.Matches(name)) {
value = entry.Data() + std::strlen(name) + 1;
return true;
}
return false;
}
char* APS5_VABI getenv_nid_postfix(const char* name) {
if (!ValidEnvironmentName(name)) { errno = 22; return nullptr; }
try {
std::lock_guard lock(environmentMutex);
for (auto& entry : Environment())
if (entry.Matches(name)) return entry.Data() + std::strlen(name) + 1;
return nullptr;
} catch (const std::bad_alloc&) { errno = 12; return nullptr; }
}
int APS5_VABI setenv_nid_postfix(const char* name, const char* value, int overwrite) {
if (!ValidEnvironmentName(name) || !value) return EnvironmentError(22);
try {
std::lock_guard lock(environmentMutex);
auto& entries = Environment();
auto found = std::find_if(entries.begin(), entries.end(),
[name](auto& entry) { return entry.Matches(name); });
if (found != entries.end() && !overwrite) return 0;
EnvironmentEntry replacement{std::make_unique<std::string>(std::string(name) + '=' + value), nullptr};
if (found != entries.end()) *found = std::move(replacement);
else entries.push_back(std::move(replacement));
return 0;
} catch (const std::bad_alloc&) { return EnvironmentError(12); }
}
int APS5_VABI unsetenv_nid_postfix(const char* name) {
if (!ValidEnvironmentName(name)) return EnvironmentError(22);
try {
std::lock_guard lock(environmentMutex);
auto& entries = Environment();
const std::string key(name);
std::erase_if(entries, [&key](auto& entry) { return entry.Matches(key); });
return 0;
} catch (const std::bad_alloc&) { return EnvironmentError(12); }
}
int APS5_VABI putenv_nid_postfix(char* text) {
const char* separator = text ? std::strchr(text, '=') : nullptr;
if (!separator || separator == text) return EnvironmentError(22);
try {
std::lock_guard lock(environmentMutex);
auto& entries = Environment();
const std::string_view name(text, separator - text);
auto found = std::find_if(entries.begin(), entries.end(),
[name](auto& entry) { return entry.Matches(name); });
EnvironmentEntry replacement{nullptr, text};
if (found != entries.end()) *found = std::move(replacement);
else entries.push_back(std::move(replacement));
return 0;
} catch (const std::bad_alloc&) { return EnvironmentError(12); }
}
}