forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathhelper.cc
225 lines (195 loc) · 8.29 KB
/
helper.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#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 {
// Returns the path denoted by `key`. If `base::PathService` fails to return the
// path to a directory that exists, the value of the environment variable
// corresponding to `key`, if any, is used if it names an absolute directory
// that exists. Returns an empty path if all attempts fail.
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 {};
}
// Returns a valid file path with the proper casing from the system if `prefs`
// has a `distribution.program_files_dir` value that is a valid target for the
// browser's installation and `system_install` is true. Returns an empty file
// path otherwise.
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();
}
// Returns the default install path given an install level.
base::FilePath GetDefaultChromeInstallPathChecked(bool system_install) {
base::FilePath install_path = GetPathWithEnvironmentFallback(
system_install ? base::DIR_PROGRAM_FILES : base::DIR_LOCAL_APP_DATA);
// Later steps assume a valid install path was found.
CHECK(!install_path.empty());
return install_path.Append(install_static::GetChromeInstallSubDirectory())
.Append(installer::kInstallBinaryDir);
}
// Returns the path to the installation at `system_install` provided that the
// browser is installed and its `UninstallString` points into a valid install
// directory.
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 {};
}
// The path to setup.exe has the format
// [InstallPath]/[version]/Installer/setup.exe. In order to get the
// [InstallPath], the full path must be pruned of the last 3 components.
const base::FilePath install_path = setup_path.DirName().DirName().DirName();
// The install path must not be at the root of the volume and must exist.
if (install_path == install_path.DirName() ||
!base::DirectoryExists(install_path)) {
return {};
}
return install_path;
}
// Returns path keys for the standard installation locations for either
// per-user or per-machine installs. In cases where more than one location is
// possible, the default is always first.
base::span<const int> GetInstallationPathKeys(bool system_install) {
if (!system_install) {
// %LOCALAPPDATA% is the only location for per-user installs.
static constexpr int kPerUserKeys[] = {base::DIR_LOCAL_APP_DATA};
return base::span(kPerUserKeys);
}
if (base::win::OSInfo::GetArchitecture() ==
base::win::OSInfo::X86_ARCHITECTURE) {
// %PROGRAMFILES% is the only location for 32-bit Windows.
static constexpr int kPerMachineKeys[] = {base::DIR_PROGRAM_FILES};
return base::span(kPerMachineKeys);
}
// %PROGRAMFILES%, which matches the current binary's bitness, is the default
// for 64-bit Windows (x64 and arm64). The "opposite" location is the
// secondary.
static constexpr int kx64PerMachineKeys[] = {
base::DIR_PROGRAM_FILES, // Native folder for this bitness.
#if defined(ARCH_CPU_64_BITS)
base::DIR_PROGRAM_FILESX86, // Folder for 32-bit apps.
#else
base::DIR_PROGRAM_FILES6432, // Folder for 64-bit apps.
#endif
};
return base::span(kx64PerMachineKeys);
}
} // namespace
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());
// Is there an installation in one of the standard locations with a matching
// version directory?
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() {
// Get the directory in which the product is installed as per its registration
// with the updater.
const base::FilePath install_dir = GetInstalledDirectory(
/*system_install=*/!InstallUtil::IsPerUserInstall());
if (install_dir.empty()) {
return false; // No product installed at this level and mode.
}
// Return true if the current process resides within that directory.
const base::FilePath this_exe = base::PathService::CheckedGet(base::FILE_EXE);
return install_dir.IsParent(this_exe);
}
} // namespace installer.