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