#include "chrome/installer/util/helper.h"
#include <array>
#include <string>
#include <string_view>
#include "base/check.h"
#include "base/containers/fixed_flat_map.h"
#include "base/containers/span.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/version.h"
#include "base/win/windows_version.h"
#include "build/build_config.h"
#include "chrome/install_static/install_util.h"
#include "chrome/installer/util/initial_preferences.h"
#include "chrome/installer/util/initial_preferences_constants.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/installation_state.h"
#include "chrome/installer/util/util_constants.h"
namespace {
base::FilePath GetPathWithEnvironmentFallback(int key) {
if (base::FilePath path; base::PathService::Get(key, &path) &&
!path.empty() && base::DirectoryExists(path)) {
return path;
}
static constexpr auto kKeyToVariable =
base::MakeFixedFlatMap<int, std::wstring_view>(
{{base::DIR_PROGRAM_FILES, L"PROGRAMFILES"},
{base::DIR_PROGRAM_FILESX86, L"PROGRAMFILES(X86)"},
{base::DIR_PROGRAM_FILES6432, L"ProgramW6432"},
{base::DIR_LOCAL_APP_DATA, L"LOCALAPPDATA"}});
if (auto it = kKeyToVariable.find(key); it != kKeyToVariable.end()) {
std::array<wchar_t, MAX_PATH> value;
value[0] = L'\0';
if (DWORD ret = ::GetEnvironmentVariableW(it->second.data(), value.data(),
value.size());
ret && ret < value.size()) {
if (base::FilePath path(value.data()); path.IsAbsolute() &&
!path.ReferencesParent() &&
base::DirectoryExists(path)) {
return path;
}
}
}
return {};
}
base::FilePath GetInstallationDirFromPrefs(
const installer::InitialPreferences& prefs,
bool system_install) {
base::FilePath program_files_dir;
if (system_install) {
prefs.GetPath(installer::initial_preferences::kProgramFilesDir,
&program_files_dir);
}
if (program_files_dir.empty())
return program_files_dir;
base::FilePath expected_dir;
bool valid_program_files_path =
((!(expected_dir =
GetPathWithEnvironmentFallback(base::DIR_PROGRAM_FILES))
.empty() &&
base::FilePath::CompareEqualIgnoreCase(program_files_dir.value(),
expected_dir.value())) ||
(!(expected_dir =
GetPathWithEnvironmentFallback(base::DIR_PROGRAM_FILESX86))
.empty() &&
base::FilePath::CompareEqualIgnoreCase(program_files_dir.value(),
expected_dir.value())));
return valid_program_files_path
? expected_dir
.Append(install_static::GetChromeInstallSubDirectory())
.Append(installer::kInstallBinaryDir)
: base::FilePath();
}
base::FilePath GetDefaultChromeInstallPathChecked(bool system_install) {
base::FilePath install_path = GetPathWithEnvironmentFallback(
system_install ? base::DIR_PROGRAM_FILES : base::DIR_LOCAL_APP_DATA);
CHECK(!install_path.empty());
return install_path.Append(install_static::GetChromeInstallSubDirectory())
.Append(installer::kInstallBinaryDir);
}
base::FilePath GetCurrentInstallPathFromRegistry(bool system_install) {
installer::ProductState product_state;
if (!product_state.Initialize(system_install)) {
return {};
}
const base::FilePath setup_path =
product_state.uninstall_command().GetProgram();
if (setup_path.empty() || !setup_path.IsAbsolute() ||
setup_path.ReferencesParent()) {
return {};
}
const base::FilePath install_path = setup_path.DirName().DirName().DirName();
if (install_path == install_path.DirName() ||
!base::DirectoryExists(install_path)) {
return {};
}
return install_path;
}
base::span<const int> GetInstallationPathKeys(bool system_install) {
if (!system_install) {
static constexpr int kPerUserKeys[] = {base::DIR_LOCAL_APP_DATA};
return base::span(kPerUserKeys);
}
if (base::win::OSInfo::GetArchitecture() ==
base::win::OSInfo::X86_ARCHITECTURE) {
static constexpr int kPerMachineKeys[] = {base::DIR_PROGRAM_FILES};
return base::span(kPerMachineKeys);
}
static constexpr int kx64PerMachineKeys[] = {
base::DIR_PROGRAM_FILES,
#if defined(ARCH_CPU_64_BITS)
base::DIR_PROGRAM_FILESX86,
#else
base::DIR_PROGRAM_FILES6432,
#endif
};
return base::span(kx64PerMachineKeys);
}
}
namespace installer {
base::FilePath GetInstalledDirectory(bool system_install) {
return GetCurrentInstallPathFromRegistry(system_install);
}
base::FilePath GetDefaultChromeInstallPath(bool system_install) {
return GetDefaultChromeInstallPathChecked(system_install);
}
base::FilePath GetChromeInstallPathWithPrefs(bool system_install,
const InitialPreferences& prefs) {
base::FilePath install_path =
GetCurrentInstallPathFromRegistry(system_install);
if (!install_path.empty())
return install_path;
install_path = GetInstallationDirFromPrefs(prefs, system_install);
if (install_path.empty())
install_path = GetDefaultChromeInstallPathChecked(system_install);
return install_path;
}
base::FilePath FindInstallPath(bool system_install,
const base::Version& version) {
CHECK(version.IsValid());
for (int path_key : GetInstallationPathKeys(system_install)) {
if (auto path = GetPathWithEnvironmentFallback(path_key); !path.empty()) {
path = path.Append(install_static::GetChromeInstallSubDirectory())
.Append(kInstallBinaryDir)
.AppendASCII(version.GetString());
if (base::DirectoryExists(path)) {
return path;
}
}
}
return {};
}
bool IsCurrentProcessInstalled() {
const base::FilePath install_dir = GetInstalledDirectory(
!InstallUtil::IsPerUserInstall());
if (install_dir.empty()) {
return false;
}
const base::FilePath this_exe = base::PathService::CheckedGet(base::FILE_EXE);
return install_dir.IsParent(this_exe);
}
}