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 21 matching lines...) Expand all Loading... | |
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 | 35 |
36 namespace mini_installer { | 36 namespace mini_installer { |
37 | 37 |
38 typedef DWORD ProcessExitCode; | 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 DWORD LastWindowsError = 0; | |
grt (UTC plus 2)
2015/07/28 02:30:07
can you do away with this? i don't think it's nece
bcwhite
2015/07/28 13:14:01
Yes, though the global was the easiest. I could c
grt (UTC plus 2)
2015/07/28 14:00:03
Pair or a POD struct w/ value semantics both sound
| |
43 | |
42 // This structure passes data back and forth for the processing | 44 // This structure passes data back and forth for the processing |
43 // of resource callbacks. | 45 // of resource callbacks. |
44 struct Context { | 46 struct Context { |
45 // Input to the call back method. Specifies the dir to save resources. | 47 // Input to the call back method. Specifies the dir to save resources. |
46 const wchar_t* base_path; | 48 const wchar_t* base_path; |
47 // First output from call back method. Full path of Chrome archive. | 49 // First output from call back method. Full path of Chrome archive. |
48 PathString* chrome_resource_path; | 50 PathString* chrome_resource_path; |
49 // Second output from call back method. Full path of Setup archive/exe. | 51 // Second output from call back method. Full path of Setup archive/exe. |
50 PathString* setup_resource_path; | 52 PathString* setup_resource_path; |
51 }; | 53 }; |
52 | 54 |
53 // A helper class used to manipulate the Windows registry. Typically, members | 55 // A helper class used to manipulate the Windows registry. Typically, members |
54 // return Windows last-error codes a la the Win32 registry API. | 56 // return Windows last-error codes a la the Win32 registry API. |
55 class RegKey { | 57 class RegKey { |
56 public: | 58 public: |
57 RegKey() : key_(NULL) { } | 59 RegKey() : key_(NULL) { } |
58 ~RegKey() { Close(); } | 60 ~RegKey() { Close(); } |
59 | 61 |
60 // Opens the key named |sub_key| with given |access| rights. Returns | 62 // Opens the key named |sub_key| with given |access| rights. Returns |
61 // ERROR_SUCCESS or some other error. | 63 // ERROR_SUCCESS or some other error. |
62 LONG Open(HKEY key, const wchar_t* sub_key, REGSAM access); | 64 LONG Open(HKEY key, const wchar_t* sub_key, REGSAM access); |
63 | 65 |
64 // Returns true if a key is open. | 66 // Returns true if a key is open. |
65 bool is_valid() const { return key_ != NULL; } | 67 bool is_valid() const { return key_ != NULL; } |
66 | 68 |
67 // Read a REG_SZ value from the registry into the memory indicated by |value| | 69 // Read a value from the registry into the memory indicated by |value| |
68 // (of |value_size| wchar_t units). Returns ERROR_SUCCESS, | 70 // (of |value_size| wchar_t units). Returns ERROR_SUCCESS, |
69 // ERROR_FILE_NOT_FOUND, ERROR_MORE_DATA, or some other error. |value| is | 71 // ERROR_FILE_NOT_FOUND, ERROR_MORE_DATA, or some other error. |value| is |
70 // guaranteed to be null-terminated on success. | 72 // guaranteed to be null-terminated on success. |
71 LONG ReadValue(const wchar_t* value_name, | 73 LONG ReadSZValue(const wchar_t* value_name, |
72 wchar_t* value, | 74 wchar_t* value, |
73 size_t value_size) const; | 75 size_t value_size) const; |
76 LONG ReadDWValue(const wchar_t* value_name, DWORD* value) const; | |
74 | 77 |
75 // Write a REG_SZ value to the registry. |value| must be null-terminated. | 78 // Write a value to the registry. SZ |value| must be null-terminated. |
76 // Returns ERROR_SUCCESS or an error code. | 79 // Returns ERROR_SUCCESS or an error code. |
77 LONG WriteValue(const wchar_t* value_name, const wchar_t* value); | 80 LONG WriteSZValue(const wchar_t* value_name, const wchar_t* value); |
81 LONG WriteDWValue(const wchar_t* value_name, DWORD value); | |
78 | 82 |
79 // Closes the key if it was open. | 83 // Closes the key if it was open. |
80 void Close(); | 84 void Close(); |
81 | 85 |
82 private: | 86 private: |
83 RegKey(const RegKey&); | 87 RegKey(const RegKey&); |
84 RegKey& operator=(const RegKey&); | 88 RegKey& operator=(const RegKey&); |
85 | 89 |
86 HKEY key_; | 90 HKEY key_; |
87 }; // class RegKey | 91 }; // class RegKey |
88 | 92 |
89 LONG RegKey::Open(HKEY key, const wchar_t* sub_key, REGSAM access) { | 93 LONG RegKey::Open(HKEY key, const wchar_t* sub_key, REGSAM access) { |
90 Close(); | 94 Close(); |
91 return ::RegOpenKeyEx(key, sub_key, NULL, access, &key_); | 95 return ::RegOpenKeyEx(key, sub_key, NULL, access, &key_); |
92 } | 96 } |
93 | 97 |
94 LONG RegKey::ReadValue(const wchar_t* value_name, | 98 LONG RegKey::ReadSZValue(const wchar_t* value_name, |
95 wchar_t* value, | 99 wchar_t* value, |
96 size_t value_size) const { | 100 size_t value_size) const { |
97 DWORD type; | 101 DWORD type; |
98 DWORD byte_length = static_cast<DWORD>(value_size * sizeof(wchar_t)); | 102 DWORD byte_length = static_cast<DWORD>(value_size * sizeof(wchar_t)); |
99 LONG result = ::RegQueryValueEx(key_, value_name, NULL, &type, | 103 LONG result = ::RegQueryValueEx(key_, value_name, NULL, &type, |
100 reinterpret_cast<BYTE*>(value), | 104 reinterpret_cast<BYTE*>(value), |
101 &byte_length); | 105 &byte_length); |
102 if (result == ERROR_SUCCESS) { | 106 if (result == ERROR_SUCCESS) { |
103 if (type != REG_SZ) { | 107 if (type != REG_SZ) { |
104 result = ERROR_NOT_SUPPORTED; | 108 result = ERROR_NOT_SUPPORTED; |
105 } else if (byte_length == 0) { | 109 } else if (byte_length == 0) { |
106 *value = L'\0'; | 110 *value = L'\0'; |
107 } else if (value[byte_length/sizeof(wchar_t) - 1] != L'\0') { | 111 } else if (value[byte_length/sizeof(wchar_t) - 1] != L'\0') { |
108 if ((byte_length / sizeof(wchar_t)) < value_size) | 112 if ((byte_length / sizeof(wchar_t)) < value_size) |
109 value[byte_length / sizeof(wchar_t)] = L'\0'; | 113 value[byte_length / sizeof(wchar_t)] = L'\0'; |
110 else | 114 else |
111 result = ERROR_MORE_DATA; | 115 result = ERROR_MORE_DATA; |
112 } | 116 } |
113 } | 117 } |
114 return result; | 118 return result; |
115 } | 119 } |
116 | 120 |
117 LONG RegKey::WriteValue(const wchar_t* value_name, const wchar_t* value) { | 121 LONG RegKey::ReadDWValue(const wchar_t* value_name, DWORD* value) const { |
122 DWORD type; | |
123 DWORD byte_length = sizeof(*value); | |
124 LONG result = ::RegQueryValueEx(key_, value_name, NULL, &type, | |
125 reinterpret_cast<BYTE*>(value), | |
126 &byte_length); | |
127 if (result == ERROR_SUCCESS) { | |
128 if (type != REG_DWORD) { | |
129 result = ERROR_NOT_SUPPORTED; | |
130 } else if (byte_length != sizeof(*value)) { | |
131 result = ERROR_NO_DATA; | |
132 } | |
133 } | |
134 return result; | |
135 } | |
136 | |
137 LONG RegKey::WriteSZValue(const wchar_t* value_name, const wchar_t* value) { | |
118 return ::RegSetValueEx(key_, value_name, 0, REG_SZ, | 138 return ::RegSetValueEx(key_, value_name, 0, REG_SZ, |
119 reinterpret_cast<const BYTE*>(value), | 139 reinterpret_cast<const BYTE*>(value), |
120 (lstrlen(value) + 1) * sizeof(wchar_t)); | 140 (lstrlen(value) + 1) * sizeof(wchar_t)); |
121 } | 141 } |
122 | 142 |
143 LONG RegKey::WriteDWValue(const wchar_t* value_name, DWORD value) { | |
144 return ::RegSetValueEx(key_, value_name, 0, REG_DWORD, | |
145 reinterpret_cast<const BYTE*>(&value), | |
146 sizeof(value)); | |
147 } | |
148 | |
123 void RegKey::Close() { | 149 void RegKey::Close() { |
124 if (key_ != NULL) { | 150 if (key_ != NULL) { |
125 ::RegCloseKey(key_); | 151 ::RegCloseKey(key_); |
126 key_ = NULL; | 152 key_ = NULL; |
127 } | 153 } |
128 } | 154 } |
129 | 155 |
130 // Helper function to read a value from registry. Returns true if value | 156 // Helper function to read a value from registry. Returns true if value |
131 // is read successfully and stored in parameter value. Returns false otherwise. | 157 // is read successfully and stored in parameter value. Returns false otherwise. |
132 // |size| is measured in wchar_t units. | 158 // |size| is measured in wchar_t units. |
133 bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, | 159 bool ReadSZValueFromRegistry(HKEY root_key, const wchar_t *sub_key, |
134 const wchar_t *value_name, wchar_t *value, | 160 const wchar_t *value_name, wchar_t *value, |
135 size_t size) { | 161 size_t size) { |
136 RegKey key; | 162 RegKey key; |
137 | 163 |
138 if (key.Open(root_key, sub_key, KEY_QUERY_VALUE) == ERROR_SUCCESS && | 164 if (key.Open(root_key, sub_key, KEY_QUERY_VALUE) == ERROR_SUCCESS && |
139 key.ReadValue(value_name, value, size) == ERROR_SUCCESS) { | 165 key.ReadSZValue(value_name, value, size) == ERROR_SUCCESS) { |
140 return true; | 166 return true; |
141 } | 167 } |
142 return false; | 168 return false; |
143 } | 169 } |
144 | 170 |
145 // Opens the Google Update ClientState key for a product. This finds only | 171 // Opens the Google Update ClientState key for a product. This finds only |
146 // registry entries for Chrome; it does not support the Chromium registry | 172 // registry entries for Chrome; it does not support the Chromium registry |
147 // layout. | 173 // layout. |
148 bool OpenClientStateKey(HKEY root_key, const wchar_t* app_guid, REGSAM access, | 174 bool OpenClientStateKey(HKEY root_key, const wchar_t* app_guid, REGSAM access, |
149 RegKey* key) { | 175 RegKey* key) { |
150 PathString client_state_key; | 176 PathString client_state_key; |
151 return client_state_key.assign(kClientStateKeyBase) && | 177 return client_state_key.assign(kClientStateKeyBase) && |
152 client_state_key.append(app_guid) && | 178 client_state_key.append(app_guid) && |
153 (key->Open(root_key, | 179 (key->Open(root_key, |
154 client_state_key.get(), | 180 client_state_key.get(), |
155 access | KEY_WOW64_32KEY) == ERROR_SUCCESS); | 181 access | KEY_WOW64_32KEY) == ERROR_SUCCESS); |
156 } | 182 } |
157 | 183 |
158 // This function sets the flag in registry to indicate that Google Update | 184 // Opens the Google Update ClientState key for the current install |
159 // should try full installer next time. If the current installer works, this | 185 // configuration. This includes locating the correct key in the face of |
160 // flag is cleared by setup.exe at the end of install. The flag will by default | 186 // multi-install. The flag will by default be written to HKCU, but if |
161 // be written to HKCU, but if --system-level is included in the command line, | 187 // --system-level is included in the command line, it will be written to |
162 // it will be written to HKLM instead. | 188 // HKLM instead. |
163 // TODO(grt): Write a unit test for this that uses registry virtualization. | 189 // TODO(bcwhite): Write a unit test for this that uses registry virtualization. |
164 void SetInstallerFlags(const Configuration& configuration) { | 190 bool OpenInstallStateKey(const Configuration& configuration, RegKey* key) { |
grt (UTC plus 2)
2015/07/28 02:30:06
the logic in here that figures out which app_guid
bcwhite
2015/07/28 13:14:01
Okay. Any objection to RegKey becoming more sophi
| |
165 RegKey key; | |
166 const REGSAM key_access = KEY_QUERY_VALUE | KEY_SET_VALUE; | |
167 const HKEY root_key = | 191 const HKEY root_key = |
168 configuration.is_system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | 192 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 = | 193 const wchar_t* app_guid = |
171 configuration.has_chrome_frame() ? | 194 configuration.has_chrome_frame() ? |
172 google_update::kChromeFrameAppGuid : | 195 google_update::kChromeFrameAppGuid : |
173 configuration.chrome_app_guid(); | 196 configuration.chrome_app_guid(); |
174 StackString<128> value; | 197 const REGSAM key_access = KEY_QUERY_VALUE | KEY_SET_VALUE; |
175 LONG ret = ERROR_SUCCESS; | 198 LONG ret = ERROR_SUCCESS; |
176 | 199 |
177 // When multi_install is true, we are potentially: | 200 // When multi_install is true, we are potentially: |
178 // 1. Performing a multi-install of some product(s) on a clean machine. | 201 // 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 | 202 // Neither the product(s) nor the multi-installer will have a ClientState |
180 // key in the registry, so there is nothing to be done. | 203 // key in the registry, so there is no key to be modified. |
181 // 2. Upgrading an existing multi-install. The multi-installer will have a | 204 // 2. Upgrading an existing multi-install. The multi-installer will have a |
182 // ClientState key in the registry. Only it need be modified. | 205 // ClientState key in the registry. Only it need be modified. |
183 // 3. Migrating a single-install into a multi-install. The product will have | 206 // 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. | 207 // 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 | 208 // 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 | 209 // 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 | 210 // modify the product's ClientState. Otherwise, we check the |
188 // multi-installer's ClientState and modify it if it exists. | 211 // multi-installer's ClientState and modify it if it exists. |
189 if (configuration.is_multi_install()) { | 212 if (configuration.is_multi_install()) { |
190 if (OpenClientStateKey(root_key, app_guid, key_access, &key)) { | 213 if (OpenClientStateKey(root_key, app_guid, key_access, key)) { |
191 // The product has a client state key. See if it's a single-install. | 214 // The product has a client state key. See if it's a single-install. |
192 ret = key.ReadValue(kApRegistryValue, value.get(), value.capacity()); | 215 StackString<128> value; |
193 if (ret != ERROR_FILE_NOT_FOUND && | 216 ret = key->ReadSZValue(kApRegistryValue, value.get(), value.capacity()); |
194 (ret != ERROR_SUCCESS || | 217 if (ret == ERROR_FILE_NOT_FOUND || |
195 FindTagInStr(value.get(), kMultiInstallTag, NULL))) { | 218 (ret == ERROR_SUCCESS && |
196 // Error or case 2: modify the multi-installer's value. | 219 !FindTagInStr(value.get(), kMultiInstallTag, NULL))) { |
197 key.Close(); | 220 // yes -- case 3: modify this key. |
198 app_guid = google_update::kMultiInstallAppGuid; | 221 return true; |
199 } // else case 3: modify this value. | 222 } |
200 } else { | |
201 // case 1 or 2: modify the multi-installer's value. | |
202 key.Close(); | |
203 app_guid = google_update::kMultiInstallAppGuid; | |
204 } | 223 } |
224 // error, case 1, or case 2: modify the multi-installer's key. | |
225 key->Close(); | |
226 app_guid = google_update::kMultiInstallAppGuid; | |
205 } | 227 } |
206 | 228 |
207 if (!key.is_valid()) { | 229 return OpenClientStateKey(root_key, app_guid, key_access, key); |
208 if (!OpenClientStateKey(root_key, app_guid, key_access, &key)) | 230 } |
209 return; | |
210 | 231 |
211 value.clear(); | 232 // Writes install results into registry where it is read by Google Update. |
212 ret = key.ReadValue(kApRegistryValue, value.get(), value.capacity()); | 233 // Don't write anything if there is already a result present, likely |
234 // written by setup.exe. | |
235 void WriteInstallResults(const Configuration& configuration, | |
236 DWORD exit_code, DWORD last_error) { | |
237 #if defined(GOOGLE_CHROME_BUILD) | |
238 // Calls to setup.exe will write a "success" result if everything was good | |
239 // so we don't need to write anything from here. | |
240 if (exit_code == ERROR_SUCCESS) | |
241 return; | |
242 | |
243 RegKey key; | |
244 DWORD value; | |
245 if (OpenInstallStateKey(configuration, &key)) { | |
246 if (key.ReadDWValue(kInstallerResultRegistryValue, &value) | |
grt (UTC plus 2)
2015/07/28 02:30:06
this adds a dependency on an implementation detail
bcwhite
2015/07/28 13:14:01
I don't think so. We have to check if there is a
grt (UTC plus 2)
2015/07/28 14:00:04
Why? Does it not suffice to suppress writing when
bcwhite
2015/07/28 14:52:59
If we set a constraint that the MI isn't allowed t
| |
247 != ERROR_SUCCESS || value == 0) { | |
248 key.WriteDWValue(kInstallerResultRegistryValue, | |
249 exit_code ? 1 /* FAILED_CUSTOM_ERROR */ | |
250 : 0 /* SUCCESS */); | |
251 key.WriteDWValue(kInstallerErrorRegistryValue, exit_code); | |
252 key.WriteDWValue(kInstallerExtraCode1RegistryValue, last_error); | |
253 } | |
254 key.Close(); | |
213 } | 255 } |
256 #endif | |
257 } | |
258 | |
259 // This function sets the flag in registry to indicate that Google Update | |
260 // should try full installer next time. If the current installer works, this | |
261 // flag is cleared by setup.exe at the end of install. | |
262 void SetInstallerFlags(const Configuration& configuration) { | |
263 RegKey key; | |
264 StackString<128> value; | |
265 LONG ret = ERROR_SUCCESS; | |
266 | |
267 if (!OpenInstallStateKey(configuration, &key)) | |
268 return; | |
269 | |
270 ret = key.ReadSZValue(kApRegistryValue, value.get(), value.capacity()); | |
214 | 271 |
215 // The conditions below are handling two cases: | 272 // 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 | 273 // 1. When ap value is present, we want to add the required tag only if it is |
217 // not present. | 274 // not present. |
218 // 2. When ap value is missing, we are going to create it with the required | 275 // 2. When ap value is missing, we are going to create it with the required |
219 // tag. | 276 // tag. |
220 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { | 277 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { |
221 if (ret == ERROR_FILE_NOT_FOUND) | 278 if (ret == ERROR_FILE_NOT_FOUND) |
222 value.clear(); | 279 value.clear(); |
223 | 280 |
224 if (!StrEndsWith(value.get(), kFullInstallerSuffix) && | 281 if (!StrEndsWith(value.get(), kFullInstallerSuffix) && |
225 value.append(kFullInstallerSuffix)) { | 282 value.append(kFullInstallerSuffix)) { |
226 key.WriteValue(kApRegistryValue, value.get()); | 283 key.WriteSZValue(kApRegistryValue, value.get()); |
227 } | 284 } |
228 } | 285 } |
229 } | 286 } |
230 | 287 |
231 // Gets the setup.exe path from Registry by looking at the value of Uninstall | 288 // Gets the setup.exe path from Registry by looking at the value of Uninstall |
232 // string. |size| is measured in wchar_t units. | 289 // string. |size| is measured in wchar_t units. |
233 ProcessExitCode GetSetupExePathForAppGuid(bool system_level, | 290 ProcessExitCode GetSetupExePathForAppGuid(bool system_level, |
234 const wchar_t* app_guid, | 291 const wchar_t* app_guid, |
235 const wchar_t* previous_version, | 292 const wchar_t* previous_version, |
236 wchar_t* path, | 293 wchar_t* path, |
237 size_t size) { | 294 size_t size) { |
238 const HKEY root_key = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | 295 const HKEY root_key = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; |
239 RegKey key; | 296 RegKey key; |
240 if (!OpenClientStateKey(root_key, app_guid, KEY_QUERY_VALUE, &key) || | 297 if (!OpenClientStateKey(root_key, app_guid, KEY_QUERY_VALUE, &key) || |
241 (key.ReadValue(kUninstallRegistryValue, path, size) != ERROR_SUCCESS)) { | 298 (key.ReadSZValue(kUninstallRegistryValue, path, size) != ERROR_SUCCESS)) { |
242 return UNABLE_TO_FIND_REGISTRY_KEY; | 299 return UNABLE_TO_FIND_REGISTRY_KEY; |
243 } | 300 } |
244 | 301 |
245 // Check that the path to the existing installer includes the expected | 302 // Check that the path to the existing installer includes the expected |
246 // version number. It's not necessary for accuracy to verify before/after | 303 // version number. It's not necessary for accuracy to verify before/after |
247 // delimiters. | 304 // delimiters. |
248 if (!SearchStringI(path, previous_version)) | 305 if (!SearchStringI(path, previous_version)) |
249 return PATCH_NOT_FOR_INSTALLED_VERSION; | 306 return PATCH_NOT_FOR_INSTALLED_VERSION; |
250 | 307 |
251 return SUCCESS_EXIT_CODE; | 308 return SUCCESS_EXIT_CODE; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
287 } | 344 } |
288 | 345 |
289 // Calls CreateProcess with good default parameters and waits for the process to | 346 // 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 | 347 // terminate returning the process exit code. |exit_code|, if non-NULL, is |
291 // populated with the process exit code. | 348 // populated with the process exit code. |
292 ProcessExitCode RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline) { | 349 ProcessExitCode RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline) { |
293 STARTUPINFOW si = {sizeof(si)}; | 350 STARTUPINFOW si = {sizeof(si)}; |
294 PROCESS_INFORMATION pi = {0}; | 351 PROCESS_INFORMATION pi = {0}; |
295 if (!::CreateProcess(exe_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, | 352 if (!::CreateProcess(exe_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, |
296 NULL, NULL, &si, &pi)) { | 353 NULL, NULL, &si, &pi)) { |
354 LastWindowsError = ::GetLastError(); | |
297 return COULD_NOT_CREATE_PROCESS; | 355 return COULD_NOT_CREATE_PROCESS; |
298 } | 356 } |
299 | 357 |
300 ::CloseHandle(pi.hThread); | 358 ::CloseHandle(pi.hThread); |
301 | 359 |
302 ProcessExitCode exit_code = SUCCESS_EXIT_CODE; | 360 ProcessExitCode exit_code = SUCCESS_EXIT_CODE; |
303 DWORD wr = ::WaitForSingleObject(pi.hProcess, INFINITE); | 361 DWORD wr = ::WaitForSingleObject(pi.hProcess, INFINITE); |
304 if (WAIT_OBJECT_0 != wr || !::GetExitCodeProcess(pi.hProcess, &exit_code)) | 362 if (WAIT_OBJECT_0 != wr || !::GetExitCodeProcess(pi.hProcess, &exit_code)) { |
grt (UTC plus 2)
2015/07/28 02:30:07
please add a comment that this code assumes that w
bcwhite
2015/07/28 13:14:01
Done.
| |
363 LastWindowsError = ::GetLastError(); | |
305 exit_code = WAIT_FOR_PROCESS_FAILED; | 364 exit_code = WAIT_FOR_PROCESS_FAILED; |
365 } | |
306 | 366 |
307 ::CloseHandle(pi.hProcess); | 367 ::CloseHandle(pi.hProcess); |
308 | 368 |
309 return exit_code; | 369 return exit_code; |
310 } | 370 } |
311 | 371 |
312 // Appends any command line params passed to mini_installer to the given buffer | 372 // Appends any command line params passed to mini_installer to the given buffer |
313 // so that they can be passed on to setup.exe. | 373 // so that they can be passed on to setup.exe. |
314 // |buffer| is unchanged in case of error. | 374 // |buffer| is unchanged in case of error. |
315 void AppendCommandLineFlags(const Configuration& configuration, | 375 void AppendCommandLineFlags(const Configuration& configuration, |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
444 base_path, | 504 base_path, |
445 archive_path, | 505 archive_path, |
446 setup_path, | 506 setup_path, |
447 }; | 507 }; |
448 | 508 |
449 // Get the resources of type 'B7' (7zip archive). | 509 // Get the resources of type 'B7' (7zip archive). |
450 // We need a chrome archive to do the installation. So if there | 510 // We need a chrome archive to do the installation. So if there |
451 // is a problem in fetching B7 resource, just return an error. | 511 // is a problem in fetching B7 resource, just return an error. |
452 if (!::EnumResourceNames(module, kLZMAResourceType, OnResourceFound, | 512 if (!::EnumResourceNames(module, kLZMAResourceType, OnResourceFound, |
453 reinterpret_cast<LONG_PTR>(&context)) || | 513 reinterpret_cast<LONG_PTR>(&context)) || |
454 archive_path->length() == 0) | 514 archive_path->length() == 0) { |
515 LastWindowsError = ::GetLastError(); | |
grt (UTC plus 2)
2015/07/28 02:30:07
the last error code is generally not reset to ERRO
bcwhite
2015/07/28 13:14:01
Done.
| |
455 return UNABLE_TO_EXTRACT_CHROME_ARCHIVE; | 516 return UNABLE_TO_EXTRACT_CHROME_ARCHIVE; |
517 } | |
456 | 518 |
457 ProcessExitCode exit_code = SUCCESS_EXIT_CODE; | 519 ProcessExitCode exit_code = SUCCESS_EXIT_CODE; |
458 | 520 |
459 // If we found setup 'B7' resource (used for differential updates), handle | 521 // If we found setup 'B7' resource (used for differential updates), handle |
460 // it. Note that this is only for Chrome; Chromium installs are always | 522 // it. Note that this is only for Chrome; Chromium installs are always |
461 // "full" installs. | 523 // "full" installs. |
462 if (setup_path->length() > 0) { | 524 if (setup_path->length() > 0) { |
463 CommandString cmd_line; | 525 CommandString cmd_line; |
464 PathString exe_path; | 526 PathString exe_path; |
465 // Get the path to setup.exe first. | 527 // Get the path to setup.exe first. |
(...skipping 28 matching lines...) Expand all Loading... | |
494 else if (!setup_path->assign(setup_dest_path.get())) | 556 else if (!setup_path->assign(setup_dest_path.get())) |
495 exit_code = PATH_STRING_OVERFLOW; | 557 exit_code = PATH_STRING_OVERFLOW; |
496 | 558 |
497 return exit_code; | 559 return exit_code; |
498 } | 560 } |
499 | 561 |
500 // setup.exe wasn't sent as 'B7', lets see if it was sent as 'BL' | 562 // setup.exe wasn't sent as 'B7', lets see if it was sent as 'BL' |
501 // (compressed setup). | 563 // (compressed setup). |
502 if (!::EnumResourceNames(module, kLZCResourceType, OnResourceFound, | 564 if (!::EnumResourceNames(module, kLZCResourceType, OnResourceFound, |
503 reinterpret_cast<LONG_PTR>(&context)) && | 565 reinterpret_cast<LONG_PTR>(&context)) && |
504 ::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) | 566 ::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) { |
567 LastWindowsError = ::GetLastError(); | |
505 return UNABLE_TO_EXTRACT_SETUP_B7; | 568 return UNABLE_TO_EXTRACT_SETUP_B7; |
569 } | |
506 | 570 |
507 if (setup_path->length() > 0) { | 571 if (setup_path->length() > 0) { |
508 // Uncompress LZ compressed resource. Setup is packed with 'MSCF' | 572 // Uncompress LZ compressed resource. Setup is packed with 'MSCF' |
509 // as opposed to old DOS way of 'SZDD'. Hence we don't use LZCopy. | 573 // as opposed to old DOS way of 'SZDD'. Hence we don't use LZCopy. |
510 bool success = mini_installer::Expand(setup_path->get(), | 574 bool success = mini_installer::Expand(setup_path->get(), |
511 setup_dest_path.get()); | 575 setup_dest_path.get()); |
512 ::DeleteFile(setup_path->get()); | 576 ::DeleteFile(setup_path->get()); |
513 if (success) { | 577 if (success) { |
514 if (!setup_path->assign(setup_dest_path.get())) { | 578 if (!setup_path->assign(setup_dest_path.get())) { |
515 ::DeleteFile(setup_dest_path.get()); | 579 ::DeleteFile(setup_dest_path.get()); |
516 exit_code = PATH_STRING_OVERFLOW; | 580 exit_code = PATH_STRING_OVERFLOW; |
517 } | 581 } |
518 } else { | 582 } else { |
519 exit_code = UNABLE_TO_EXTRACT_SETUP_EXE; | 583 exit_code = UNABLE_TO_EXTRACT_SETUP_EXE; |
520 } | 584 } |
521 | 585 |
522 #if defined(COMPONENT_BUILD) | 586 #if defined(COMPONENT_BUILD) |
523 // Extract the (uncompressed) modules required by setup.exe. | 587 // Extract the (uncompressed) modules required by setup.exe. |
524 if (!::EnumResourceNames(module, kBinResourceType, WriteResourceToDirectory, | 588 if (!::EnumResourceNames(module, kBinResourceType, WriteResourceToDirectory, |
525 reinterpret_cast<LONG_PTR>(base_path))) | 589 reinterpret_cast<LONG_PTR>(base_path))) { |
590 LastWindowsError = ::GetLastError(); | |
526 return UNABLE_TO_EXTRACT_SETUP; | 591 return UNABLE_TO_EXTRACT_SETUP; |
592 } | |
527 #endif | 593 #endif |
528 | 594 |
529 return exit_code; | 595 return exit_code; |
530 } | 596 } |
531 | 597 |
532 // setup.exe still not found. So finally check if it was sent as 'BN' | 598 // setup.exe still not found. So finally check if it was sent as 'BN' |
533 // (uncompressed setup). | 599 // (uncompressed setup). |
534 // TODO(tommi): We don't need BN anymore so let's remove it (and remove | 600 // TODO(tommi): We don't need BN anymore so let's remove it (and remove |
535 // it from create_installer_archive.py). | 601 // it from create_installer_archive.py). |
536 if (!::EnumResourceNames(module, kBinResourceType, OnResourceFound, | 602 if (!::EnumResourceNames(module, kBinResourceType, OnResourceFound, |
537 reinterpret_cast<LONG_PTR>(&context)) && | 603 reinterpret_cast<LONG_PTR>(&context)) && |
538 ::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) | 604 ::GetLastError() != ERROR_RESOURCE_TYPE_NOT_FOUND) { |
605 LastWindowsError = ::GetLastError(); | |
539 return UNABLE_TO_EXTRACT_SETUP_BN; | 606 return UNABLE_TO_EXTRACT_SETUP_BN; |
607 } | |
540 | 608 |
541 if (setup_path->length() > 0) { | 609 if (setup_path->length() > 0) { |
542 if (setup_path->comparei(setup_dest_path.get()) != 0) { | 610 if (setup_path->comparei(setup_dest_path.get()) != 0) { |
543 if (!::MoveFileEx(setup_path->get(), setup_dest_path.get(), | 611 if (!::MoveFileEx(setup_path->get(), setup_dest_path.get(), |
544 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) { | 612 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) { |
545 ::DeleteFile(setup_path->get()); | 613 ::DeleteFile(setup_path->get()); |
546 setup_path->clear(); | 614 setup_path->clear(); |
547 } else if (!setup_path->assign(setup_dest_path.get())) { | 615 } else if (!setup_path->assign(setup_dest_path.get())) { |
548 ::DeleteFile(setup_dest_path.get()); | 616 ::DeleteFile(setup_dest_path.get()); |
549 } | 617 } |
(...skipping 18 matching lines...) Expand all Loading... | |
568 // Get the path to setup.exe first. | 636 // Get the path to setup.exe first. |
569 if (::lstrlen(setup_path) > 0) { | 637 if (::lstrlen(setup_path) > 0) { |
570 if (!cmd_line.assign(L"\"") || | 638 if (!cmd_line.assign(L"\"") || |
571 !cmd_line.append(setup_path) || | 639 !cmd_line.append(setup_path) || |
572 !cmd_line.append(L"\"")) | 640 !cmd_line.append(L"\"")) |
573 return COMMAND_STRING_OVERFLOW; | 641 return COMMAND_STRING_OVERFLOW; |
574 } else { | 642 } else { |
575 ProcessExitCode exit_code = GetPreviousSetupExePath( | 643 ProcessExitCode exit_code = GetPreviousSetupExePath( |
576 configuration, cmd_line.get(), cmd_line.capacity()); | 644 configuration, cmd_line.get(), cmd_line.capacity()); |
577 if (exit_code != SUCCESS_EXIT_CODE) | 645 if (exit_code != SUCCESS_EXIT_CODE) |
578 return exit_code; | 646 return exit_code; |
grt (UTC plus 2)
2015/07/28 02:30:07
if this is hit, the return value from the various
bcwhite
2015/07/28 13:14:01
Okay. This will be easier when the return-value i
| |
579 } | 647 } |
580 | 648 |
581 // Append the command line param for chrome archive file. | 649 // Append the command line param for chrome archive file. |
582 if (!cmd_line.append(L" --") || | 650 if (!cmd_line.append(L" --") || |
583 #if defined(COMPONENT_BUILD) | 651 #if defined(COMPONENT_BUILD) |
584 // For faster developer turnaround, the component build generates | 652 // For faster developer turnaround, the component build generates |
585 // uncompressed archives. | 653 // uncompressed archives. |
586 !cmd_line.append(kCmdUncompressedArchive) || | 654 !cmd_line.append(kCmdUncompressedArchive) || |
587 #else | 655 #else |
588 !cmd_line.append(kCmdInstallArchive) || | 656 !cmd_line.append(kCmdInstallArchive) || |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
820 | 888 |
821 // Returns true if we should delete the temp files we create (default). | 889 // Returns true if we should delete the temp files we create (default). |
822 // Returns false iff the user has manually created a ChromeInstallerCleanup | 890 // Returns false iff the user has manually created a ChromeInstallerCleanup |
823 // string value in the registry under HKCU\\Software\\[Google|Chromium] | 891 // string value in the registry under HKCU\\Software\\[Google|Chromium] |
824 // and set its value to "0". That explicitly forbids the mini installer from | 892 // and set its value to "0". That explicitly forbids the mini installer from |
825 // deleting these files. | 893 // deleting these files. |
826 // Support for this has been publicly mentioned in troubleshooting tips so | 894 // Support for this has been publicly mentioned in troubleshooting tips so |
827 // we continue to support it. | 895 // we continue to support it. |
828 bool ShouldDeleteExtractedFiles() { | 896 bool ShouldDeleteExtractedFiles() { |
829 wchar_t value[2] = {0}; | 897 wchar_t value[2] = {0}; |
830 if (ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, | 898 if (ReadSZValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, |
831 kCleanupRegistryValue, value, _countof(value)) && | 899 kCleanupRegistryValue, value, _countof(value)) && |
832 value[0] == L'0') { | 900 value[0] == L'0') { |
833 return false; | 901 return false; |
834 } | 902 } |
835 | 903 |
836 return true; | 904 return true; |
837 } | 905 } |
838 | 906 |
839 // Main function. First gets a working dir, unpacks the resources and finally | 907 // Main function. First gets a working dir, unpacks the resources and finally |
840 // executes setup.exe to do the install/upgrade. | 908 // executes setup.exe to do the install/upgrade. |
841 ProcessExitCode WMain(HMODULE module) { | 909 ProcessExitCode WMain(HMODULE module) { |
(...skipping 10 matching lines...) Expand all Loading... | |
852 if (!configuration.Initialize(module)) | 920 if (!configuration.Initialize(module)) |
853 return GENERIC_INITIALIZATION_FAILURE; | 921 return GENERIC_INITIALIZATION_FAILURE; |
854 | 922 |
855 // If the --cleanup switch was specified on the command line, then that means | 923 // If the --cleanup switch was specified on the command line, then that means |
856 // we should only do the cleanup and then exit. | 924 // we should only do the cleanup and then exit. |
857 if (ProcessNonInstallOperations(configuration, &exit_code)) | 925 if (ProcessNonInstallOperations(configuration, &exit_code)) |
858 return exit_code; | 926 return exit_code; |
859 | 927 |
860 // First get a path where we can extract payload | 928 // First get a path where we can extract payload |
861 PathString base_path; | 929 PathString base_path; |
862 if (!GetWorkDir(module, &base_path)) | 930 if (!GetWorkDir(module, &base_path)) |
grt (UTC plus 2)
2015/07/28 02:30:06
failures in here should be captured, too
| |
863 return UNABLE_TO_GET_WORK_DIRECTORY; | 931 return UNABLE_TO_GET_WORK_DIRECTORY; |
864 | 932 |
865 #if defined(GOOGLE_CHROME_BUILD) | 933 #if defined(GOOGLE_CHROME_BUILD) |
866 // Set the magic suffix in registry to try full installer next time. We ignore | 934 // 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 | 935 // 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 | 936 // --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. | 937 // level instead. This only applies to the Google Chrome distribution. |
870 SetInstallerFlags(configuration); | 938 SetInstallerFlags(configuration); |
871 #endif | 939 #endif |
872 | 940 |
873 PathString archive_path; | 941 PathString archive_path; |
874 PathString setup_path; | 942 PathString setup_path; |
875 exit_code = UnpackBinaryResources(configuration, module, base_path.get(), | 943 exit_code = UnpackBinaryResources(configuration, module, base_path.get(), |
876 &archive_path, &setup_path); | 944 &archive_path, &setup_path); |
877 | 945 |
878 // While unpacking the binaries, we paged in a whole bunch of memory that | 946 // 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 | 947 // we don't need anymore. Let's give it back to the pool before running |
880 // setup. | 948 // setup. |
881 ::SetProcessWorkingSetSize(::GetCurrentProcess(), -1, -1); | 949 ::SetProcessWorkingSetSize(::GetCurrentProcess(), -1, -1); |
882 | 950 |
883 if (exit_code == SUCCESS_EXIT_CODE) | 951 if (exit_code == SUCCESS_EXIT_CODE) |
884 exit_code = RunSetup(configuration, archive_path.get(), setup_path.get()); | 952 exit_code = RunSetup(configuration, archive_path.get(), setup_path.get()); |
885 | 953 |
886 if (ShouldDeleteExtractedFiles()) | 954 if (ShouldDeleteExtractedFiles()) |
887 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); | 955 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); |
888 | 956 |
957 WriteInstallResults(configuration, exit_code, LastWindowsError); | |
889 return exit_code; | 958 return exit_code; |
890 } | 959 } |
891 | 960 |
892 } // namespace mini_installer | 961 } // namespace mini_installer |
893 | 962 |
894 int MainEntryPoint() { | 963 int MainEntryPoint() { |
895 mini_installer::ProcessExitCode result = | 964 mini_installer::ProcessExitCode result = |
896 mini_installer::WMain(::GetModuleHandle(NULL)); | 965 mini_installer::WMain(::GetModuleHandle(NULL)); |
966 | |
897 ::ExitProcess(result); | 967 ::ExitProcess(result); |
898 } | 968 } |
899 | 969 |
900 // VC Express editions don't come with the memset CRT obj file and linking to | 970 // 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, | 971 // the obj files between versions becomes a bit problematic. Therefore, |
902 // simply implement memset. | 972 // simply implement memset. |
903 // | 973 // |
904 // This also avoids having to explicitly set the __sse2_available hack when | 974 // 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 | 975 // 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 | 976 // linking with the std C lib in certain instances (including Chromium) with |
907 // MSVC. __sse2_available determines whether to use SSE2 intructions with | 977 // 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. | 978 // std C lib routines, and is set by MSVC's std C lib implementation normally. |
909 extern "C" { | 979 extern "C" { |
910 #pragma function(memset) | 980 #pragma function(memset) |
911 void* memset(void* dest, int c, size_t count) { | 981 void* memset(void* dest, int c, size_t count) { |
912 void* start = dest; | 982 void* start = dest; |
913 while (count--) { | 983 while (count--) { |
914 *reinterpret_cast<char*>(dest) = static_cast<char>(c); | 984 *reinterpret_cast<char*>(dest) = static_cast<char>(c); |
915 dest = reinterpret_cast<char*>(dest) + 1; | 985 dest = reinterpret_cast<char*>(dest) + 1; |
916 } | 986 } |
917 return start; | 987 return start; |
918 } | 988 } |
919 } // extern "C" | 989 } // extern "C" |
OLD | NEW |