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

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: don't write success results 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
« no previous file with comments | « no previous file | chrome/installer/mini_installer/mini_installer_constants.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 21 matching lines...) Expand all
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
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
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
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
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
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
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"
OLDNEW
« no previous file with comments | « no previous file | chrome/installer/mini_installer/mini_installer_constants.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698