Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(260)

Side by Side Diff: chrome/installer/mini_installer/mini_installer.cc

Issue 1247993002: Return Windows error code when create-process fails. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixed configuration tests and added new ones Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // mini_installer.exe is the first exe that is run when chrome is being 5 // mini_installer.exe is the first exe that is run when chrome is being
6 // installed or upgraded. It is designed to be extremely small (~5KB with no 6 // installed or upgraded. It is designed to be extremely small (~5KB with no
7 // extra resources linked) and it has two main jobs: 7 // extra resources linked) and it has two main jobs:
8 // 1) unpack the resources (possibly decompressing some) 8 // 1) unpack the resources (possibly decompressing some)
9 // 2) run the real installer (setup.exe) with appropriate flags. 9 // 2) run the real installer (setup.exe) with appropriate flags.
10 // 10 //
(...skipping 14 matching lines...) Expand all
25 #include <shellapi.h> 25 #include <shellapi.h>
26 #include <stdlib.h> 26 #include <stdlib.h>
27 27
28 #include "chrome/installer/mini_installer/appid.h" 28 #include "chrome/installer/mini_installer/appid.h"
29 #include "chrome/installer/mini_installer/configuration.h" 29 #include "chrome/installer/mini_installer/configuration.h"
30 #include "chrome/installer/mini_installer/decompress.h" 30 #include "chrome/installer/mini_installer/decompress.h"
31 #include "chrome/installer/mini_installer/exit_code.h" 31 #include "chrome/installer/mini_installer/exit_code.h"
32 #include "chrome/installer/mini_installer/mini_installer_constants.h" 32 #include "chrome/installer/mini_installer/mini_installer_constants.h"
33 #include "chrome/installer/mini_installer/mini_string.h" 33 #include "chrome/installer/mini_installer/mini_string.h"
34 #include "chrome/installer/mini_installer/pe_resource.h" 34 #include "chrome/installer/mini_installer/pe_resource.h"
35 #include "chrome/installer/mini_installer/regkey.h"
35 36
36 namespace mini_installer { 37 namespace mini_installer {
37 38
38 typedef DWORD ProcessExitCode;
39 typedef StackString<MAX_PATH> PathString; 39 typedef StackString<MAX_PATH> PathString;
40 typedef StackString<MAX_PATH * 4> CommandString; 40 typedef StackString<MAX_PATH * 4> CommandString;
41 41
42 struct ProcessExitCode {
robertshield 2015/08/04 03:11:36 This isn't a just an exit code anymore, suggest ca
bcwhite 2015/08/04 19:34:30 Done.
43 DWORD exit_code;
44 DWORD windows_code;
robertshield 2015/08/04 03:11:36 It isn't clear to a Windows dev what "windows_code
bcwhite 2015/08/04 19:34:31 It's usually the result of ::GetLastError() but so
robertshield 2015/08/05 18:39:48 Ok.
45
46 explicit ProcessExitCode(DWORD exit) : exit_code(exit), windows_code(0) {}
47 ProcessExitCode(DWORD exit, DWORD win) : exit_code(exit), windows_code(win) {
48 }
49
50 bool IsSuccess() {
51 return exit_code == ERROR_SUCCESS;
robertshield 2015/08/04 03:11:36 Nit: ERROR_SUCCESS is a windows error code, not a
bcwhite 2015/08/04 19:34:30 Done.
52 }
53 };
54
42 // This structure passes data back and forth for the processing 55 // This structure passes data back and forth for the processing
43 // of resource callbacks. 56 // of resource callbacks.
44 struct Context { 57 struct Context {
45 // Input to the call back method. Specifies the dir to save resources. 58 // Input to the call back method. Specifies the dir to save resources.
46 const wchar_t* base_path; 59 const wchar_t* base_path;
47 // First output from call back method. Full path of Chrome archive. 60 // First output from call back method. Full path of Chrome archive.
48 PathString* chrome_resource_path; 61 PathString* chrome_resource_path;
49 // Second output from call back method. Full path of Setup archive/exe. 62 // Second output from call back method. Full path of Setup archive/exe.
50 PathString* setup_resource_path; 63 PathString* setup_resource_path;
51 }; 64 };
52 65
53 // A helper class used to manipulate the Windows registry. Typically, members
54 // return Windows last-error codes a la the Win32 registry API.
55 class RegKey {
56 public:
57 RegKey() : key_(NULL) { }
58 ~RegKey() { Close(); }
59 66
60 // Opens the key named |sub_key| with given |access| rights. Returns 67 // Opens the Google Update ClientState key for the current install
61 // ERROR_SUCCESS or some other error. 68 // configuration. This includes locating the correct key in the face of
62 LONG Open(HKEY key, const wchar_t* sub_key, REGSAM access); 69 // multi-install. The flag will by default be written to HKCU, but if
70 // --system-level is included in the command line, it will be written to
71 // HKLM instead.
72 bool OpenInstallStateKey(const Configuration& configuration, RegKey* key) {
73 const HKEY root_key =
74 configuration.is_system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
75 const wchar_t* app_guid = configuration.chrome_app_guid();
76 const REGSAM key_access = KEY_QUERY_VALUE | KEY_SET_VALUE;
77 LONG ret = ERROR_SUCCESS;
63 78
64 // Returns true if a key is open. 79 return RegKey::OpenClientStateKey(root_key, app_guid, key_access, key);
65 bool is_valid() const { return key_ != NULL; }
66
67 // Read a REG_SZ value from the registry into the memory indicated by |value|
68 // (of |value_size| wchar_t units). Returns ERROR_SUCCESS,
69 // ERROR_FILE_NOT_FOUND, ERROR_MORE_DATA, or some other error. |value| is
70 // guaranteed to be null-terminated on success.
71 LONG ReadValue(const wchar_t* value_name,
72 wchar_t* value,
73 size_t value_size) const;
74
75 // Write a REG_SZ value to the registry. |value| must be null-terminated.
76 // Returns ERROR_SUCCESS or an error code.
77 LONG WriteValue(const wchar_t* value_name, const wchar_t* value);
78
79 // Closes the key if it was open.
80 void Close();
81
82 private:
83 RegKey(const RegKey&);
84 RegKey& operator=(const RegKey&);
85
86 HKEY key_;
87 }; // class RegKey
88
89 LONG RegKey::Open(HKEY key, const wchar_t* sub_key, REGSAM access) {
90 Close();
91 return ::RegOpenKeyEx(key, sub_key, NULL, access, &key_);
92 } 80 }
93 81
94 LONG RegKey::ReadValue(const wchar_t* value_name, 82 // Writes install results into registry where it is read by Google Update.
95 wchar_t* value, 83 // Don't write anything if there is already a result present, likely
96 size_t value_size) const { 84 // written by setup.exe.
97 DWORD type; 85 void WriteInstallResults(const Configuration& configuration,
98 DWORD byte_length = static_cast<DWORD>(value_size * sizeof(wchar_t)); 86 ProcessExitCode result) {
99 LONG result = ::RegQueryValueEx(key_, value_name, NULL, &type, 87 #if defined(GOOGLE_CHROME_BUILD)
100 reinterpret_cast<BYTE*>(value), 88 // Calls to setup.exe will write a "success" result if everything was good
101 &byte_length); 89 // so we don't need to write anything from here.
102 if (result == ERROR_SUCCESS) { 90 if (result.IsSuccess())
103 if (type != REG_SZ) { 91 return;
104 result = ERROR_NOT_SUPPORTED; 92
105 } else if (byte_length == 0) { 93 RegKey key;
106 *value = L'\0'; 94 DWORD value;
107 } else if (value[byte_length/sizeof(wchar_t) - 1] != L'\0') { 95 if (OpenInstallStateKey(configuration, &key)) {
108 if ((byte_length / sizeof(wchar_t)) < value_size) 96 if (key.ReadDWValue(kInstallerResultRegistryValue, &value)
109 value[byte_length / sizeof(wchar_t)] = L'\0'; 97 != ERROR_SUCCESS || value == 0) {
110 else 98 key.WriteDWValue(kInstallerResultRegistryValue,
111 result = ERROR_MORE_DATA; 99 result.exit_code ? 1 /* FAILED_CUSTOM_ERROR */
100 : 0 /* SUCCESS */);
101 key.WriteDWValue(kInstallerErrorRegistryValue, result.exit_code);
102 key.WriteDWValue(kInstallerExtraCode1RegistryValue, result.windows_code);
112 } 103 }
104 key.Close();
113 } 105 }
114 return result; 106 #endif
115 }
116
117 LONG RegKey::WriteValue(const wchar_t* value_name, const wchar_t* value) {
118 return ::RegSetValueEx(key_, value_name, 0, REG_SZ,
119 reinterpret_cast<const BYTE*>(value),
120 (lstrlen(value) + 1) * sizeof(wchar_t));
121 }
122
123 void RegKey::Close() {
124 if (key_ != NULL) {
125 ::RegCloseKey(key_);
126 key_ = NULL;
127 }
128 }
129
130 // Helper function to read a value from registry. Returns true if value
131 // is read successfully and stored in parameter value. Returns false otherwise.
132 // |size| is measured in wchar_t units.
133 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key,
134 const wchar_t *value_name, wchar_t *value,
135 size_t size) {
136 RegKey key;
137
138 if (key.Open(root_key, sub_key, KEY_QUERY_VALUE) == ERROR_SUCCESS &&
139 key.ReadValue(value_name, value, size) == ERROR_SUCCESS) {
140 return true;
141 }
142 return false;
143 }
144
145 // Opens the Google Update ClientState key for a product. This finds only
146 // registry entries for Chrome; it does not support the Chromium registry
147 // layout.
148 bool OpenClientStateKey(HKEY root_key, const wchar_t* app_guid, REGSAM access,
149 RegKey* key) {
150 PathString client_state_key;
151 return client_state_key.assign(kClientStateKeyBase) &&
152 client_state_key.append(app_guid) &&
153 (key->Open(root_key,
154 client_state_key.get(),
155 access | KEY_WOW64_32KEY) == ERROR_SUCCESS);
156 } 107 }
157 108
158 // This function sets the flag in registry to indicate that Google Update 109 // This function sets the flag in registry to indicate that Google Update
159 // should try full installer next time. If the current installer works, this 110 // should try full installer next time. If the current installer works, this
160 // flag is cleared by setup.exe at the end of install. The flag will by default 111 // flag is cleared by setup.exe at the end of install.
161 // be written to HKCU, but if --system-level is included in the command line,
162 // it will be written to HKLM instead.
163 // TODO(grt): Write a unit test for this that uses registry virtualization.
164 void SetInstallerFlags(const Configuration& configuration) { 112 void SetInstallerFlags(const Configuration& configuration) {
165 RegKey key; 113 RegKey key;
166 const REGSAM key_access = KEY_QUERY_VALUE | KEY_SET_VALUE;
167 const HKEY root_key =
168 configuration.is_system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
169 // This is ignored if multi-install is true.
170 const wchar_t* app_guid =
171 configuration.has_chrome_frame() ?
172 google_update::kChromeFrameAppGuid :
173 configuration.chrome_app_guid();
174 StackString<128> value; 114 StackString<128> value;
175 LONG ret = ERROR_SUCCESS; 115 LONG ret = ERROR_SUCCESS;
176 116
177 // When multi_install is true, we are potentially: 117 if (!OpenInstallStateKey(configuration, &key))
178 // 1. Performing a multi-install of some product(s) on a clean machine. 118 return;
179 // Neither the product(s) nor the multi-installer will have a ClientState
180 // key in the registry, so there is nothing to be done.
181 // 2. Upgrading an existing multi-install. The multi-installer will have a
182 // ClientState key in the registry. Only it need be modified.
183 // 3. Migrating a single-install into a multi-install. The product will have
184 // a ClientState key in the registry. Only it need be modified.
185 // To handle all cases, we inspect the product's ClientState to see if it
186 // exists and its "ap" value does not contain "-multi". This is case 3, so we
187 // modify the product's ClientState. Otherwise, we check the
188 // multi-installer's ClientState and modify it if it exists.
189 if (configuration.is_multi_install()) {
190 if (OpenClientStateKey(root_key, app_guid, key_access, &key)) {
191 // The product has a client state key. See if it's a single-install.
192 ret = key.ReadValue(kApRegistryValue, value.get(), value.capacity());
193 if (ret != ERROR_FILE_NOT_FOUND &&
194 (ret != ERROR_SUCCESS ||
195 FindTagInStr(value.get(), kMultiInstallTag, NULL))) {
196 // Error or case 2: modify the multi-installer's value.
197 key.Close();
198 app_guid = google_update::kMultiInstallAppGuid;
199 } // else case 3: modify this value.
200 } else {
201 // case 1 or 2: modify the multi-installer's value.
202 key.Close();
203 app_guid = google_update::kMultiInstallAppGuid;
204 }
205 }
206 119
207 if (!key.is_valid()) { 120 ret = key.ReadSZValue(kApRegistryValue, value.get(), value.capacity());
208 if (!OpenClientStateKey(root_key, app_guid, key_access, &key))
209 return;
210
211 value.clear();
212 ret = key.ReadValue(kApRegistryValue, value.get(), value.capacity());
213 }
214 121
215 // The conditions below are handling two cases: 122 // The conditions below are handling two cases:
216 // 1. When ap value is present, we want to add the required tag only if it is 123 // 1. When ap value is present, we want to add the required tag only if it is
217 // not present. 124 // not present.
218 // 2. When ap value is missing, we are going to create it with the required 125 // 2. When ap value is missing, we are going to create it with the required
219 // tag. 126 // tag.
220 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { 127 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) {
221 if (ret == ERROR_FILE_NOT_FOUND) 128 if (ret == ERROR_FILE_NOT_FOUND)
222 value.clear(); 129 value.clear();
223 130
224 if (!StrEndsWith(value.get(), kFullInstallerSuffix) && 131 if (!StrEndsWith(value.get(), kFullInstallerSuffix) &&
225 value.append(kFullInstallerSuffix)) { 132 value.append(kFullInstallerSuffix)) {
226 key.WriteValue(kApRegistryValue, value.get()); 133 key.WriteSZValue(kApRegistryValue, value.get());
227 } 134 }
228 } 135 }
229 } 136 }
230 137
231 // Gets the setup.exe path from Registry by looking at the value of Uninstall 138 // Gets the setup.exe path from Registry by looking at the value of Uninstall
232 // string. |size| is measured in wchar_t units. 139 // string. |size| is measured in wchar_t units.
233 ProcessExitCode GetSetupExePathForAppGuid(bool system_level, 140 ProcessExitCode GetSetupExePathForAppGuid(bool system_level,
234 const wchar_t* app_guid, 141 const wchar_t* app_guid,
235 const wchar_t* previous_version, 142 const wchar_t* previous_version,
236 wchar_t* path, 143 wchar_t* path,
237 size_t size) { 144 size_t size) {
238 const HKEY root_key = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 145 const HKEY root_key = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
239 RegKey key; 146 RegKey key;
240 if (!OpenClientStateKey(root_key, app_guid, KEY_QUERY_VALUE, &key) || 147 if (!RegKey::OpenClientStateKey(root_key, app_guid, KEY_QUERY_VALUE, &key))
241 (key.ReadValue(kUninstallRegistryValue, path, size) != ERROR_SUCCESS)) { 148 return ProcessExitCode(UNABLE_TO_FIND_REGISTRY_KEY);
242 return UNABLE_TO_FIND_REGISTRY_KEY; 149 DWORD result = key.ReadSZValue(kUninstallRegistryValue, path, size);
243 } 150 if (result != ERROR_SUCCESS)
151 return ProcessExitCode(UNABLE_TO_FIND_REGISTRY_KEY, result);
244 152
245 // Check that the path to the existing installer includes the expected 153 // Check that the path to the existing installer includes the expected
246 // version number. It's not necessary for accuracy to verify before/after 154 // version number. It's not necessary for accuracy to verify before/after
247 // delimiters. 155 // delimiters.
248 if (!SearchStringI(path, previous_version)) 156 if (!SearchStringI(path, previous_version))
249 return PATCH_NOT_FOR_INSTALLED_VERSION; 157 return ProcessExitCode(PATCH_NOT_FOR_INSTALLED_VERSION);
250 158
251 return SUCCESS_EXIT_CODE; 159 return ProcessExitCode(SUCCESS_EXIT_CODE);
252 } 160 }
253 161
254 // Gets the path to setup.exe of the previous version. The overall path is found 162 // Gets the path to setup.exe of the previous version. The overall path is found
255 // in the Uninstall string in the registry. A previous version number specified 163 // in the Uninstall string in the registry. A previous version number specified
256 // in |configuration| is used if available. |size| is measured in wchar_t units. 164 // in |configuration| is used if available. |size| is measured in wchar_t units.
257 ProcessExitCode GetPreviousSetupExePath(const Configuration& configuration, 165 ProcessExitCode GetPreviousSetupExePath(const Configuration& configuration,
258 wchar_t* path, 166 wchar_t* path,
259 size_t size) { 167 size_t size) {
260 bool system_level = configuration.is_system_level(); 168 bool system_level = configuration.is_system_level();
261 const wchar_t* previous_version = configuration.previous_version(); 169 const wchar_t* previous_version = configuration.previous_version();
262 ProcessExitCode exit_code = GENERIC_ERROR; 170 ProcessExitCode exit_code = ProcessExitCode(GENERIC_ERROR);
263 171
264 // If this is a multi install, first try looking in the binaries for the path. 172 // If this is a multi install, first try looking in the binaries for the path.
265 if (configuration.is_multi_install()) { 173 if (configuration.is_multi_install()) {
266 exit_code = GetSetupExePathForAppGuid( 174 exit_code = GetSetupExePathForAppGuid(
267 system_level, google_update::kMultiInstallAppGuid, previous_version, 175 system_level, google_update::kMultiInstallAppGuid, previous_version,
268 path, size); 176 path, size);
269 } 177 }
270 178
271 // Failing that, look in Chrome Frame's client state key if --chrome-frame was 179 // Failing that, look in Chrome Frame's client state key if --chrome-frame was
272 // specified. 180 // specified.
273 if (exit_code != SUCCESS_EXIT_CODE && configuration.has_chrome_frame()) { 181 if (!exit_code.IsSuccess() && configuration.has_chrome_frame()) {
274 exit_code = GetSetupExePathForAppGuid( 182 exit_code = GetSetupExePathForAppGuid(
275 system_level, google_update::kChromeFrameAppGuid, previous_version, 183 system_level, google_update::kChromeFrameAppGuid, previous_version,
276 path, size); 184 path, size);
277 } 185 }
278 186
279 // Make a last-ditch effort to look in the Chrome client state key. 187 // Make a last-ditch effort to look in the Chrome client state key.
280 if (exit_code != SUCCESS_EXIT_CODE) { 188 if (!exit_code.IsSuccess()) {
281 exit_code = GetSetupExePathForAppGuid( 189 exit_code = GetSetupExePathForAppGuid(
282 system_level, configuration.chrome_app_guid(), previous_version, 190 system_level, configuration.chrome_app_guid(), previous_version,
283 path, size); 191 path, size);
284 } 192 }
285 193
286 return exit_code; 194 return exit_code;
287 } 195 }
288 196
289 // Calls CreateProcess with good default parameters and waits for the process to 197 // Calls CreateProcess with good default parameters and waits for the process to
290 // terminate returning the process exit code. |exit_code|, if non-NULL, is 198 // terminate returning the process exit code. |exit_code|, if non-NULL, is
291 // populated with the process exit code. 199 // populated with the process exit code.
292 ProcessExitCode RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline) { 200 ProcessExitCode RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline) {
293 STARTUPINFOW si = {sizeof(si)}; 201 STARTUPINFOW si = {sizeof(si)};
294 PROCESS_INFORMATION pi = {0}; 202 PROCESS_INFORMATION pi = {0};
295 if (!::CreateProcess(exe_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, 203 if (!::CreateProcess(exe_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW,
296 NULL, NULL, &si, &pi)) { 204 NULL, NULL, &si, &pi)) {
297 return COULD_NOT_CREATE_PROCESS; 205 return ProcessExitCode(COULD_NOT_CREATE_PROCESS, ::GetLastError());
298 } 206 }
299 207
300 ::CloseHandle(pi.hThread); 208 ::CloseHandle(pi.hThread);
301 209
302 ProcessExitCode exit_code = SUCCESS_EXIT_CODE; 210 DWORD exit_code = SUCCESS_EXIT_CODE;
303 DWORD wr = ::WaitForSingleObject(pi.hProcess, INFINITE); 211 DWORD wr = ::WaitForSingleObject(pi.hProcess, INFINITE);
304 if (WAIT_OBJECT_0 != wr || !::GetExitCodeProcess(pi.hProcess, &exit_code)) 212 if (WAIT_OBJECT_0 != wr || !::GetExitCodeProcess(pi.hProcess, &exit_code)) {
305 exit_code = WAIT_FOR_PROCESS_FAILED; 213 // Note: We've assumed that WAIT_OBJCT_0 != wr means a failure. The call
214 // could return a different object but since we never spawn more than one
215 // sub-process at a time that case should never happen.
216 return ProcessExitCode(WAIT_FOR_PROCESS_FAILED, ::GetLastError());
217 }
306 218
307 ::CloseHandle(pi.hProcess); 219 ::CloseHandle(pi.hProcess);
308 220
309 return exit_code; 221 return ProcessExitCode(exit_code);
310 } 222 }
311 223
312 // Appends any command line params passed to mini_installer to the given buffer 224 // Appends any command line params passed to mini_installer to the given buffer
313 // so that they can be passed on to setup.exe. 225 // so that they can be passed on to setup.exe.
314 // |buffer| is unchanged in case of error. 226 // |buffer| is unchanged in case of error.
315 void AppendCommandLineFlags(const Configuration& configuration, 227 void AppendCommandLineFlags(const Configuration& configuration,
316 CommandString* buffer) { 228 CommandString* buffer) {
317 PathString full_exe_path; 229 PathString full_exe_path;
318 size_t len = ::GetModuleFileName(NULL, full_exe_path.get(), 230 size_t len = ::GetModuleFileName(NULL, full_exe_path.get(),
319 full_exe_path.capacity()); 231 full_exe_path.capacity());
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
429 // uncompressed 'BN' resources are also extracted. This is generally the set of 341 // uncompressed 'BN' resources are also extracted. This is generally the set of
430 // DLLs/resources needed by setup.exe to run. 342 // DLLs/resources needed by setup.exe to run.
431 ProcessExitCode UnpackBinaryResources(const Configuration& configuration, 343 ProcessExitCode UnpackBinaryResources(const Configuration& configuration,
432 HMODULE module, const wchar_t* base_path, 344 HMODULE module, const wchar_t* base_path,
433 PathString* archive_path, 345 PathString* archive_path,
434 PathString* setup_path) { 346 PathString* setup_path) {
435 // Generate the setup.exe path where we patch/uncompress setup resource. 347 // Generate the setup.exe path where we patch/uncompress setup resource.
436 PathString setup_dest_path; 348 PathString setup_dest_path;
437 if (!setup_dest_path.assign(base_path) || 349 if (!setup_dest_path.assign(base_path) ||
438 !setup_dest_path.append(kSetupExe)) 350 !setup_dest_path.append(kSetupExe))
439 return PATH_STRING_OVERFLOW; 351 return ProcessExitCode(PATH_STRING_OVERFLOW);
440 352
441 // Prepare the input to OnResourceFound method that needs a location where 353 // Prepare the input to OnResourceFound method that needs a location where
442 // it will write all the resources. 354 // it will write all the resources.
443 Context context = { 355 Context context = {
444 base_path, 356 base_path,
445 archive_path, 357 archive_path,
446 setup_path, 358 setup_path,
447 }; 359 };
448 360
449 // Get the resources of type 'B7' (7zip archive). 361 // Get the resources of type 'B7' (7zip archive).
450 // We need a chrome archive to do the installation. So if there 362 // We need a chrome archive to do the installation. So if there
451 // is a problem in fetching B7 resource, just return an error. 363 // is a problem in fetching B7 resource, just return an error.
452 if (!::EnumResourceNames(module, kLZMAResourceType, OnResourceFound, 364 if (!::EnumResourceNames(module, kLZMAResourceType, OnResourceFound,
453 reinterpret_cast<LONG_PTR>(&context)) || 365 reinterpret_cast<LONG_PTR>(&context))) {
454 archive_path->length() == 0) 366 return ProcessExitCode(UNABLE_TO_EXTRACT_CHROME_ARCHIVE, ::GetLastError());
455 return UNABLE_TO_EXTRACT_CHROME_ARCHIVE; 367 }
368 if (archive_path->length() == 0) {
369 return ProcessExitCode(UNABLE_TO_EXTRACT_CHROME_ARCHIVE);
370 }
456 371
457 ProcessExitCode exit_code = SUCCESS_EXIT_CODE; 372 ProcessExitCode exit_code = ProcessExitCode(SUCCESS_EXIT_CODE);
458 373
459 // If we found setup 'B7' resource (used for differential updates), handle 374 // If we found setup 'B7' resource (used for differential updates), handle
460 // it. Note that this is only for Chrome; Chromium installs are always 375 // it. Note that this is only for Chrome; Chromium installs are always
461 // "full" installs. 376 // "full" installs.
462 if (setup_path->length() > 0) { 377 if (setup_path->length() > 0) {
463 CommandString cmd_line; 378 CommandString cmd_line;
464 PathString exe_path; 379 PathString exe_path;
465 // Get the path to setup.exe first. 380 // Get the path to setup.exe first.
466 exit_code = GetPreviousSetupExePath(configuration, exe_path.get(), 381 exit_code = GetPreviousSetupExePath(configuration, exe_path.get(),
467 exe_path.capacity()); 382 exe_path.capacity());
468 if (exit_code == SUCCESS_EXIT_CODE) { 383 if (exit_code.IsSuccess()) {
469 if (!cmd_line.append(exe_path.get()) || 384 if (!cmd_line.append(exe_path.get()) ||
470 !cmd_line.append(L" --") || 385 !cmd_line.append(L" --") ||
471 !cmd_line.append(kCmdUpdateSetupExe) || 386 !cmd_line.append(kCmdUpdateSetupExe) ||
472 !cmd_line.append(L"=\"") || 387 !cmd_line.append(L"=\"") ||
473 !cmd_line.append(setup_path->get()) || 388 !cmd_line.append(setup_path->get()) ||
474 !cmd_line.append(L"\" --") || 389 !cmd_line.append(L"\" --") ||
475 !cmd_line.append(kCmdNewSetupExe) || 390 !cmd_line.append(kCmdNewSetupExe) ||
476 !cmd_line.append(L"=\"") || 391 !cmd_line.append(L"=\"") ||
477 !cmd_line.append(setup_dest_path.get()) || 392 !cmd_line.append(setup_dest_path.get()) ||
478 !cmd_line.append(L"\"")) { 393 !cmd_line.append(L"\"")) {
479 exit_code = COMMAND_STRING_OVERFLOW; 394 exit_code = ProcessExitCode(COMMAND_STRING_OVERFLOW);
480 } 395 }
481 } 396 }
482 397
483 // Get any command line option specified for mini_installer and pass them 398 // Get any command line option specified for mini_installer and pass them
484 // on to setup.exe. This is important since switches such as 399 // on to setup.exe. This is important since switches such as
485 // --multi-install and --chrome-frame affect where setup.exe will write 400 // --multi-install and --chrome-frame affect where setup.exe will write
486 // installer results for consumption by Google Update. 401 // installer results for consumption by Google Update.
487 AppendCommandLineFlags(configuration, &cmd_line); 402 AppendCommandLineFlags(configuration, &cmd_line);
488 403
489 if (exit_code == SUCCESS_EXIT_CODE) 404 if (exit_code.IsSuccess())
490 exit_code = RunProcessAndWait(exe_path.get(), cmd_line.get()); 405 exit_code = RunProcessAndWait(exe_path.get(), cmd_line.get());
491 406
492 if (exit_code != SUCCESS_EXIT_CODE) 407 if (!exit_code.IsSuccess())
493 DeleteFile(setup_path->get()); 408 DeleteFile(setup_path->get());
494 else if (!setup_path->assign(setup_dest_path.get())) 409 else if (!setup_path->assign(setup_dest_path.get()))
495 exit_code = PATH_STRING_OVERFLOW; 410 exit_code = ProcessExitCode(PATH_STRING_OVERFLOW);
496 411
497 return exit_code; 412 return exit_code;
498 } 413 }
499 414
500 // setup.exe wasn't sent as 'B7', lets see if it was sent as 'BL' 415 // setup.exe wasn't sent as 'B7', lets see if it was sent as 'BL'
501 // (compressed setup). 416 // (compressed setup).
502 if (!::EnumResourceNames(module, kLZCResourceType, OnResourceFound, 417 if (!::EnumResourceNames(module, kLZCResourceType, OnResourceFound,
503 reinterpret_cast<LONG_PTR>(&context)) && 418 reinterpret_cast<LONG_PTR>(&context)) &&
504 ::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) 419 ::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) {
505 return UNABLE_TO_EXTRACT_SETUP_B7; 420 return ProcessExitCode(UNABLE_TO_EXTRACT_SETUP_B7, ::GetLastError());
421 }
506 422
507 if (setup_path->length() > 0) { 423 if (setup_path->length() > 0) {
508 // Uncompress LZ compressed resource. Setup is packed with 'MSCF' 424 // Uncompress LZ compressed resource. Setup is packed with 'MSCF'
509 // as opposed to old DOS way of 'SZDD'. Hence we don't use LZCopy. 425 // as opposed to old DOS way of 'SZDD'. Hence we don't use LZCopy.
510 bool success = mini_installer::Expand(setup_path->get(), 426 bool success = mini_installer::Expand(setup_path->get(),
511 setup_dest_path.get()); 427 setup_dest_path.get());
512 ::DeleteFile(setup_path->get()); 428 ::DeleteFile(setup_path->get());
513 if (success) { 429 if (success) {
514 if (!setup_path->assign(setup_dest_path.get())) { 430 if (!setup_path->assign(setup_dest_path.get())) {
515 ::DeleteFile(setup_dest_path.get()); 431 ::DeleteFile(setup_dest_path.get());
516 exit_code = PATH_STRING_OVERFLOW; 432 exit_code = ProcessExitCode(PATH_STRING_OVERFLOW);
517 } 433 }
518 } else { 434 } else {
519 exit_code = UNABLE_TO_EXTRACT_SETUP_EXE; 435 exit_code = ProcessExitCode(UNABLE_TO_EXTRACT_SETUP_EXE);
520 } 436 }
521 437
522 #if defined(COMPONENT_BUILD) 438 #if defined(COMPONENT_BUILD)
523 // Extract the (uncompressed) modules required by setup.exe. 439 // Extract the (uncompressed) modules required by setup.exe.
524 if (!::EnumResourceNames(module, kBinResourceType, WriteResourceToDirectory, 440 if (!::EnumResourceNames(module, kBinResourceType, WriteResourceToDirectory,
525 reinterpret_cast<LONG_PTR>(base_path))) 441 reinterpret_cast<LONG_PTR>(base_path))) {
526 return UNABLE_TO_EXTRACT_SETUP; 442 return ProcessExitCode(UNABLE_TO_EXTRACT_SETUP, ::GetLastError());
443 }
527 #endif 444 #endif
528 445
529 return exit_code; 446 return exit_code;
530 } 447 }
531 448
532 // setup.exe still not found. So finally check if it was sent as 'BN' 449 // setup.exe still not found. So finally check if it was sent as 'BN'
533 // (uncompressed setup). 450 // (uncompressed setup).
534 // TODO(tommi): We don't need BN anymore so let's remove it (and remove 451 // TODO(tommi): We don't need BN anymore so let's remove it (and remove
535 // it from create_installer_archive.py). 452 // it from create_installer_archive.py).
536 if (!::EnumResourceNames(module, kBinResourceType, OnResourceFound, 453 if (!::EnumResourceNames(module, kBinResourceType, OnResourceFound,
537 reinterpret_cast<LONG_PTR>(&context)) && 454 reinterpret_cast<LONG_PTR>(&context)) &&
538 ::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) 455 ::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) {
539 return UNABLE_TO_EXTRACT_SETUP_BN; 456 return ProcessExitCode(UNABLE_TO_EXTRACT_SETUP_BN, ::GetLastError());
457 }
540 458
541 if (setup_path->length() > 0) { 459 if (setup_path->length() > 0) {
542 if (setup_path->comparei(setup_dest_path.get()) != 0) { 460 if (setup_path->comparei(setup_dest_path.get()) != 0) {
543 if (!::MoveFileEx(setup_path->get(), setup_dest_path.get(), 461 if (!::MoveFileEx(setup_path->get(), setup_dest_path.get(),
544 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) { 462 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) {
545 ::DeleteFile(setup_path->get()); 463 ::DeleteFile(setup_path->get());
546 setup_path->clear(); 464 setup_path->clear();
547 } else if (!setup_path->assign(setup_dest_path.get())) { 465 } else if (!setup_path->assign(setup_dest_path.get())) {
548 ::DeleteFile(setup_dest_path.get()); 466 ::DeleteFile(setup_dest_path.get());
549 } 467 }
550 } 468 }
551 } 469 }
552 470
553 if (setup_path->length() == 0) 471 if (setup_path->length() == 0)
554 exit_code = UNABLE_TO_EXTRACT_SETUP; 472 exit_code = ProcessExitCode(UNABLE_TO_EXTRACT_SETUP);
555 473
556 return exit_code; 474 return exit_code;
557 } 475 }
558 476
559 // Executes setup.exe, waits for it to finish and returns the exit code. 477 // Executes setup.exe, waits for it to finish and returns the exit code.
560 ProcessExitCode RunSetup(const Configuration& configuration, 478 ProcessExitCode RunSetup(const Configuration& configuration,
561 const wchar_t* archive_path, 479 const wchar_t* archive_path,
562 const wchar_t* setup_path) { 480 const wchar_t* setup_path) {
563 // There could be three full paths in the command line for setup.exe (path 481 // There could be three full paths in the command line for setup.exe (path
564 // to exe itself, path to archive and path to log file), so we declare 482 // to exe itself, path to archive and path to log file), so we declare
565 // total size as three + one additional to hold command line options. 483 // total size as three + one additional to hold command line options.
566 CommandString cmd_line; 484 CommandString cmd_line;
567 485
568 // Get the path to setup.exe first. 486 // Get the path to setup.exe first.
569 if (::lstrlen(setup_path) > 0) { 487 if (::lstrlen(setup_path) > 0) {
570 if (!cmd_line.assign(L"\"") || 488 if (!cmd_line.assign(L"\"") ||
571 !cmd_line.append(setup_path) || 489 !cmd_line.append(setup_path) ||
572 !cmd_line.append(L"\"")) 490 !cmd_line.append(L"\""))
573 return COMMAND_STRING_OVERFLOW; 491 return ProcessExitCode(COMMAND_STRING_OVERFLOW);
574 } else { 492 } else {
575 ProcessExitCode exit_code = GetPreviousSetupExePath( 493 ProcessExitCode exit_code = GetPreviousSetupExePath(
576 configuration, cmd_line.get(), cmd_line.capacity()); 494 configuration, cmd_line.get(), cmd_line.capacity());
577 if (exit_code != SUCCESS_EXIT_CODE) 495 if (!exit_code.IsSuccess())
578 return exit_code; 496 return exit_code;
579 } 497 }
580 498
581 // Append the command line param for chrome archive file. 499 // Append the command line param for chrome archive file.
582 if (!cmd_line.append(L" --") || 500 if (!cmd_line.append(L" --") ||
583 #if defined(COMPONENT_BUILD) 501 #if defined(COMPONENT_BUILD)
584 // For faster developer turnaround, the component build generates 502 // For faster developer turnaround, the component build generates
585 // uncompressed archives. 503 // uncompressed archives.
586 !cmd_line.append(kCmdUncompressedArchive) || 504 !cmd_line.append(kCmdUncompressedArchive) ||
587 #else 505 #else
588 !cmd_line.append(kCmdInstallArchive) || 506 !cmd_line.append(kCmdInstallArchive) ||
589 #endif 507 #endif
590 !cmd_line.append(L"=\"") || 508 !cmd_line.append(L"=\"") ||
591 !cmd_line.append(archive_path) || 509 !cmd_line.append(archive_path) ||
592 !cmd_line.append(L"\"")) 510 !cmd_line.append(L"\""))
593 return COMMAND_STRING_OVERFLOW; 511 return ProcessExitCode(COMMAND_STRING_OVERFLOW);
594 512
595 // Append the command line param for chrome previous version. 513 // Append the command line param for chrome previous version.
596 if (configuration.previous_version() && 514 if (configuration.previous_version() &&
597 (!cmd_line.append(L" --") || 515 (!cmd_line.append(L" --") ||
598 !cmd_line.append(kCmdPreviousVersion) || 516 !cmd_line.append(kCmdPreviousVersion) ||
599 !cmd_line.append(L"=\"") || 517 !cmd_line.append(L"=\"") ||
600 !cmd_line.append(configuration.previous_version()) || 518 !cmd_line.append(configuration.previous_version()) ||
601 !cmd_line.append(L"\""))) { 519 !cmd_line.append(L"\""))) {
602 return COMMAND_STRING_OVERFLOW; 520 return ProcessExitCode(COMMAND_STRING_OVERFLOW);
603 } 521 }
604 522
605 // Get any command line option specified for mini_installer and pass them 523 // Get any command line option specified for mini_installer and pass them
606 // on to setup.exe 524 // on to setup.exe
607 AppendCommandLineFlags(configuration, &cmd_line); 525 AppendCommandLineFlags(configuration, &cmd_line);
608 526
609 return RunProcessAndWait(NULL, cmd_line.get()); 527 return RunProcessAndWait(NULL, cmd_line.get());
610 } 528 }
611 529
612 // Deletes given files and working dir. 530 // Deletes given files and working dir.
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
803 // Checks the command line for specific mini installer flags. 721 // Checks the command line for specific mini installer flags.
804 // If the function returns true, the command line has been processed and all 722 // If the function returns true, the command line has been processed and all
805 // required actions taken. The installer must exit and return the returned 723 // required actions taken. The installer must exit and return the returned
806 // |exit_code|. 724 // |exit_code|.
807 bool ProcessNonInstallOperations(const Configuration& configuration, 725 bool ProcessNonInstallOperations(const Configuration& configuration,
808 ProcessExitCode* exit_code) { 726 ProcessExitCode* exit_code) {
809 switch (configuration.operation()) { 727 switch (configuration.operation()) {
810 case Configuration::CLEANUP: 728 case Configuration::CLEANUP:
811 // Cleanup has already taken place in DeleteOldChromeTempDirectories at 729 // Cleanup has already taken place in DeleteOldChromeTempDirectories at
812 // this point, so just tell our caller to exit early. 730 // this point, so just tell our caller to exit early.
813 *exit_code = SUCCESS_EXIT_CODE; 731 *exit_code = ProcessExitCode(SUCCESS_EXIT_CODE);
814 return true; 732 return true;
815 733
816 default: 734 default:
817 return false; 735 return false;
818 } 736 }
819 } 737 }
820 738
821 // Returns true if we should delete the temp files we create (default). 739 // Returns true if we should delete the temp files we create (default).
822 // Returns false iff the user has manually created a ChromeInstallerCleanup 740 // Returns false iff the user has manually created a ChromeInstallerCleanup
823 // string value in the registry under HKCU\\Software\\[Google|Chromium] 741 // string value in the registry under HKCU\\Software\\[Google|Chromium]
824 // and set its value to "0". That explicitly forbids the mini installer from 742 // and set its value to "0". That explicitly forbids the mini installer from
825 // deleting these files. 743 // deleting these files.
826 // Support for this has been publicly mentioned in troubleshooting tips so 744 // Support for this has been publicly mentioned in troubleshooting tips so
827 // we continue to support it. 745 // we continue to support it.
828 bool ShouldDeleteExtractedFiles() { 746 bool ShouldDeleteExtractedFiles() {
829 wchar_t value[2] = {0}; 747 wchar_t value[2] = {0};
830 if (ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, 748 if (RegKey::ReadSZValue(HKEY_CURRENT_USER, kCleanupRegistryKey,
831 kCleanupRegistryValue, value, _countof(value)) && 749 kCleanupRegistryValue, value, _countof(value)) &&
832 value[0] == L'0') { 750 value[0] == L'0') {
833 return false; 751 return false;
834 } 752 }
835 753
836 return true; 754 return true;
837 } 755 }
838 756
839 // Main function. First gets a working dir, unpacks the resources and finally 757 // Main function. First gets a working dir, unpacks the resources and finally
840 // executes setup.exe to do the install/upgrade. 758 // executes setup.exe to do the install/upgrade.
841 ProcessExitCode WMain(HMODULE module) { 759 ProcessExitCode WMain(HMODULE module) {
842 // Always start with deleting potential leftovers from previous installations. 760 // Always start with deleting potential leftovers from previous installations.
843 // This can make the difference between success and failure. We've seen 761 // This can make the difference between success and failure. We've seen
844 // many installations out in the field fail due to out of disk space problems 762 // many installations out in the field fail due to out of disk space problems
845 // so this could buy us some space. 763 // so this could buy us some space.
846 DeleteOldChromeTempDirectories(); 764 DeleteOldChromeTempDirectories();
847 765
848 ProcessExitCode exit_code = SUCCESS_EXIT_CODE; 766 ProcessExitCode exit_code = ProcessExitCode(SUCCESS_EXIT_CODE);
849 767
850 // Parse configuration from the command line and resources. 768 // Parse configuration from the command line and resources.
851 Configuration configuration; 769 Configuration configuration;
852 if (!configuration.Initialize(module)) 770 if (!configuration.Initialize(module))
853 return GENERIC_INITIALIZATION_FAILURE; 771 return ProcessExitCode(GENERIC_INITIALIZATION_FAILURE);
854 772
855 // If the --cleanup switch was specified on the command line, then that means 773 // If the --cleanup switch was specified on the command line, then that means
856 // we should only do the cleanup and then exit. 774 // we should only do the cleanup and then exit.
857 if (ProcessNonInstallOperations(configuration, &exit_code)) 775 if (ProcessNonInstallOperations(configuration, &exit_code))
858 return exit_code; 776 return exit_code;
859 777
860 // First get a path where we can extract payload 778 // First get a path where we can extract payload
861 PathString base_path; 779 PathString base_path;
862 if (!GetWorkDir(module, &base_path)) 780 if (!GetWorkDir(module, &base_path))
863 return UNABLE_TO_GET_WORK_DIRECTORY; 781 return ProcessExitCode(UNABLE_TO_GET_WORK_DIRECTORY);
864 782
865 #if defined(GOOGLE_CHROME_BUILD) 783 #if defined(GOOGLE_CHROME_BUILD)
866 // Set the magic suffix in registry to try full installer next time. We ignore 784 // Set the magic suffix in registry to try full installer next time. We ignore
867 // any errors here and we try to set the suffix for user level unless 785 // any errors here and we try to set the suffix for user level unless
868 // --system-level is on the command line in which case we set it for system 786 // --system-level is on the command line in which case we set it for system
869 // level instead. This only applies to the Google Chrome distribution. 787 // level instead. This only applies to the Google Chrome distribution.
870 SetInstallerFlags(configuration); 788 SetInstallerFlags(configuration);
871 #endif 789 #endif
872 790
873 PathString archive_path; 791 PathString archive_path;
874 PathString setup_path; 792 PathString setup_path;
875 exit_code = UnpackBinaryResources(configuration, module, base_path.get(), 793 exit_code = UnpackBinaryResources(configuration, module, base_path.get(),
876 &archive_path, &setup_path); 794 &archive_path, &setup_path);
877 795
878 // While unpacking the binaries, we paged in a whole bunch of memory that 796 // While unpacking the binaries, we paged in a whole bunch of memory that
879 // we don't need anymore. Let's give it back to the pool before running 797 // we don't need anymore. Let's give it back to the pool before running
880 // setup. 798 // setup.
881 ::SetProcessWorkingSetSize(::GetCurrentProcess(), -1, -1); 799 ::SetProcessWorkingSetSize(::GetCurrentProcess(), -1, -1);
882 800
883 if (exit_code == SUCCESS_EXIT_CODE) 801 if (exit_code.IsSuccess())
884 exit_code = RunSetup(configuration, archive_path.get(), setup_path.get()); 802 exit_code = RunSetup(configuration, archive_path.get(), setup_path.get());
885 803
886 if (ShouldDeleteExtractedFiles()) 804 if (ShouldDeleteExtractedFiles())
887 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); 805 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get());
888 806
807 WriteInstallResults(configuration, exit_code);
889 return exit_code; 808 return exit_code;
890 } 809 }
891 810
892 } // namespace mini_installer 811 } // namespace mini_installer
893 812
894 int MainEntryPoint() { 813 int MainEntryPoint() {
895 mini_installer::ProcessExitCode result = 814 mini_installer::ProcessExitCode result =
896 mini_installer::WMain(::GetModuleHandle(NULL)); 815 mini_installer::WMain(::GetModuleHandle(NULL));
897 ::ExitProcess(result); 816
817 ::ExitProcess(result.exit_code);
898 } 818 }
899 819
900 // VC Express editions don't come with the memset CRT obj file and linking to 820 // VC Express editions don't come with the memset CRT obj file and linking to
901 // the obj files between versions becomes a bit problematic. Therefore, 821 // the obj files between versions becomes a bit problematic. Therefore,
902 // simply implement memset. 822 // simply implement memset.
903 // 823 //
904 // This also avoids having to explicitly set the __sse2_available hack when 824 // This also avoids having to explicitly set the __sse2_available hack when
905 // linking with both the x64 and x86 obj files which is required when not 825 // linking with both the x64 and x86 obj files which is required when not
906 // linking with the std C lib in certain instances (including Chromium) with 826 // linking with the std C lib in certain instances (including Chromium) with
907 // MSVC. __sse2_available determines whether to use SSE2 intructions with 827 // MSVC. __sse2_available determines whether to use SSE2 intructions with
908 // std C lib routines, and is set by MSVC's std C lib implementation normally. 828 // std C lib routines, and is set by MSVC's std C lib implementation normally.
909 extern "C" { 829 extern "C" {
910 #pragma function(memset) 830 #pragma function(memset)
911 void* memset(void* dest, int c, size_t count) { 831 void* memset(void* dest, int c, size_t count) {
912 void* start = dest; 832 void* start = dest;
913 while (count--) { 833 while (count--) {
914 *reinterpret_cast<char*>(dest) = static_cast<char>(c); 834 *reinterpret_cast<char*>(dest) = static_cast<char>(c);
915 dest = reinterpret_cast<char*>(dest) + 1; 835 dest = reinterpret_cast<char*>(dest) + 1;
916 } 836 }
917 return start; 837 return start;
918 } 838 }
919 } // extern "C" 839 } // extern "C"
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698