#include "chrome/install_static/user_data_dir.h"
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include <optional>
#include "chrome/chrome_elf/nt_registry/nt_registry.h"
#include "chrome/install_static/install_details.h"
#include "chrome/install_static/install_util.h"
#include "chrome/install_static/policy_path_parser.h"
namespace install_static {
namespace {
std::wstring* g_user_data_dir;
std::wstring* g_invalid_user_data_dir;
bool g_temp_user_data_dir_created_for_headless = false;
void GetUserDataDirFromRegistryPolicyIfSet(const InstallConstants& mode,
std::wstring* user_data_dir) {
assert(user_data_dir);
std::wstring policies_path = L"SOFTWARE\\Policies\\";
AppendChromeInstallSubDirectory(mode, false ,
&policies_path);
std::wstring value;
constexpr wchar_t kUserDataDirRegistryKeyName[] = L"UserDataDir";
if (nt::QueryRegValueSZ(nt::HKLM, nt::NONE, policies_path.c_str(),
kUserDataDirRegistryKeyName, &value)) {
*user_data_dir = ExpandPathVariables(value);
return;
}
if (nt::QueryRegValueSZ(nt::HKCU, nt::NONE, policies_path.c_str(),
kUserDataDirRegistryKeyName, &value)) {
*user_data_dir = ExpandPathVariables(value);
return;
}
}
std::wstring MakeAbsoluteFilePath(const std::wstring& input) {
wchar_t file_path[MAX_PATH];
if (!_wfullpath(file_path, input.c_str(), _countof(file_path)))
return std::wstring();
return file_path;
}
bool GetUserDataDirectoryUsingProcessCommandLine(
const InstallConstants& mode,
std::wstring* result,
std::wstring* invalid_supplied_directory) {
return GetUserDataDirectoryImpl(::GetCommandLine(), mode, result,
invalid_supplied_directory);
}
bool GetDefaultUserDataDirectory(const InstallConstants& mode,
std::wstring* result) {
std::wstring user_data_dir = GetEnvironmentString(L"LOCALAPPDATA");
if (user_data_dir.empty()) {
DWORD size = ::GetTempPath(0, nullptr);
if (!size)
return false;
user_data_dir.resize(size + 1);
size = ::GetTempPath(size + 1, &user_data_dir[0]);
if (!size || size >= user_data_dir.size())
return false;
user_data_dir.resize(size);
}
result->swap(user_data_dir);
if ((*result)[result->length() - 1] != L'\\')
result->push_back(L'\\');
AppendChromeInstallSubDirectory(mode, true , result);
result->push_back(L'\\');
result->append(L"User Data");
return true;
}
bool IsHeadlessMode(const std::wstring& command_line) {
std::optional<std::wstring> opt =
GetCommandLineSwitch(command_line, L"headless");
return opt ? opt.value() != L"old" : false;
}
}
bool GetUserDataDirectoryImpl(const std::wstring& command_line,
const InstallConstants& mode,
std::wstring* result,
std::wstring* invalid_supplied_directory) {
std::wstring user_data_dir =
GetCommandLineSwitchValue(command_line, kUserDataDirSwitch);
GetUserDataDirFromRegistryPolicyIfSet(mode, &user_data_dir);
g_temp_user_data_dir_created_for_headless = false;
if (user_data_dir.empty() && IsHeadlessMode(command_line)) {
assert(GetCommandLineSwitchValue(command_line, kProcessType).empty());
user_data_dir = CreateUniqueTempDirectory(L"Headless");
if (!user_data_dir.empty()) {
g_temp_user_data_dir_created_for_headless = true;
}
}
while (!user_data_dir.empty() &&
(user_data_dir.back() == '\\' || user_data_dir.back() == '/')) {
user_data_dir.pop_back();
}
bool got_valid_directory =
!user_data_dir.empty() && RecursiveDirectoryCreate(user_data_dir);
if (!got_valid_directory) {
*invalid_supplied_directory = user_data_dir;
got_valid_directory = GetDefaultUserDataDirectory(mode, &user_data_dir);
}
assert(got_valid_directory);
if (!got_valid_directory)
return false;
*result = MakeAbsoluteFilePath(user_data_dir);
return true;
}
bool GetUserDataDirectory(std::wstring* user_data_dir,
std::wstring* invalid_user_data_dir) {
if (!g_user_data_dir) {
g_user_data_dir = new std::wstring();
g_invalid_user_data_dir = new std::wstring();
if (!GetUserDataDirectoryUsingProcessCommandLine(
InstallDetails::Get().mode(), g_user_data_dir,
g_invalid_user_data_dir)) {
return false;
}
assert(!g_user_data_dir->empty());
}
*user_data_dir = *g_user_data_dir;
if (invalid_user_data_dir)
*invalid_user_data_dir = *g_invalid_user_data_dir;
return true;
}
bool IsTemporaryUserDataDirectoryCreatedForHeadless() {
return g_temp_user_data_dir_created_for_headless;
}
}