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

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

Issue 1285473002: Revert of Return Windows error code when create-process fails. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // mini_installer.exe is the first exe that is run when chrome is being 5 // mini_installer.exe is the first exe that is run when chrome is being
6 // installed or upgraded. It is designed to be extremely small (~5KB with no 6 // installed or upgraded. It is designed to be extremely small (~5KB with no
7 // extra resources linked) and it has two main jobs: 7 // extra resources linked) and it has two main jobs:
8 // 1) unpack the resources (possibly decompressing some) 8 // 1) unpack the resources (possibly decompressing some)
9 // 2) run the real installer (setup.exe) with appropriate flags. 9 // 2) run the real installer (setup.exe) with appropriate flags.
10 // 10 //
(...skipping 14 matching lines...) Expand all
25 #include <shellapi.h> 25 #include <shellapi.h>
26 #include <stdlib.h> 26 #include <stdlib.h>
27 27
28 #include "chrome/installer/mini_installer/appid.h" 28 #include "chrome/installer/mini_installer/appid.h"
29 #include "chrome/installer/mini_installer/configuration.h" 29 #include "chrome/installer/mini_installer/configuration.h"
30 #include "chrome/installer/mini_installer/decompress.h" 30 #include "chrome/installer/mini_installer/decompress.h"
31 #include "chrome/installer/mini_installer/exit_code.h" 31 #include "chrome/installer/mini_installer/exit_code.h"
32 #include "chrome/installer/mini_installer/mini_installer_constants.h" 32 #include "chrome/installer/mini_installer/mini_installer_constants.h"
33 #include "chrome/installer/mini_installer/mini_string.h" 33 #include "chrome/installer/mini_installer/mini_string.h"
34 #include "chrome/installer/mini_installer/pe_resource.h" 34 #include "chrome/installer/mini_installer/pe_resource.h"
35 #include "chrome/installer/mini_installer/regkey.h"
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
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
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"
OLDNEW
« no previous file with comments | « chrome/installer/mini_installer/configuration_test.cc ('k') | chrome/installer/mini_installer/mini_installer_constants.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698