15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See the corresponding header file for description of the functions in this
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// file.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/install_util.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shellapi.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shlobj.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shlwapi.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
21a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/launch.h"
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sys_info.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/version.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/metro.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/registry.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/common/chrome_constants.h"
31effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/common/chrome_paths.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/browser_distribution.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/google_update_constants.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/helper.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/installation_state.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/l10n_string_util.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/util_constants.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/work_item_list.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::win::RegKey;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using installer::ProductState;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageBinaryPatching[] = L"binary_patching";
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageBuilding[] = L"building";
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageConfiguringAutoLaunch[] = L"configuring_auto_launch";
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageCopyingPreferencesFile[] = L"copying_prefs";
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageCreatingShortcuts[] = L"creating_shortcuts";
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageEnsemblePatching[] = L"ensemble_patching";
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageExecuting[] = L"executing";
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageFinishing[] = L"finishing";
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStagePreconditions[] = L"preconditions";
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageRefreshingPolicy[] = L"refreshing_policy";
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageRegisteringChrome[] = L"registering_chrome";
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageRemovingOldVersions[] = L"removing_old_ver";
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageRollingback[] = L"rollingback";
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageUncompressing[] = L"uncompressing";
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageUnpacking[] = L"unpacking";
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageUpdatingChannels[] = L"updating_channels";
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageCreatingVisualManifest[] = L"creating_visual_manifest";
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kStageDeferringToHigherVersion[] = L"deferring_to_higher_version";
63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const wchar_t kStageUninstallingBinaries[] = L"uninstalling_binaries";
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const wchar_t kStageUninstallingChromeFrame[] = L"uninstalling_chrome_frame";
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t* const kStages[] = {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NULL,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStagePreconditions,
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageUncompressing,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageEnsemblePatching,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageBinaryPatching,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageUnpacking,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageBuilding,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageExecuting,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageRollingback,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageRefreshingPolicy,
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageUpdatingChannels,
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageCopyingPreferencesFile,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageCreatingShortcuts,
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageRegisteringChrome,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageRemovingOldVersions,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageFinishing,
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageConfiguringAutoLaunch,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageCreatingVisualManifest,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kStageDeferringToHigherVersion,
86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  kStageUninstallingBinaries,
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  kStageUninstallingChromeFrame,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMPILE_ASSERT(installer::NUM_STAGES == arraysize(kStages),
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               kStages_disagrees_with_Stage_comma_they_must_match_bang);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Creates a zero-sized non-decorated foreground window that doesn't appear
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the taskbar. This is used as a parent window for calls to ShellExecuteEx
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in order for the UAC dialog to appear in the foreground and for focus
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to be returned to this process once the UAC task is dismissed. Returns
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NULL on failure, a handle to the UAC window on success.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HWND CreateUACForegroundWindow() {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HWND foreground_window = ::CreateWindowEx(WS_EX_TOOLWINDOW,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            L"STATIC",
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            NULL,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            WS_POPUP | WS_VISIBLE,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            0, 0, 0, 0,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            NULL, NULL,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            ::GetModuleHandle(NULL),
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            NULL);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (foreground_window) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HMONITOR monitor = ::MonitorFromWindow(foreground_window,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           MONITOR_DEFAULTTONEAREST);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (monitor) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MONITORINFO mi = {0};
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mi.cbSize = sizeof(mi);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ::GetMonitorInfo(monitor, &mi);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RECT screen_rect = mi.rcWork;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int x_offset = (screen_rect.right - screen_rect.left) / 2;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int y_offset = (screen_rect.bottom - screen_rect.top) / 2;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ::MoveWindow(foreground_window,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   screen_rect.left + x_offset,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   screen_rect.top + y_offset,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   0, 0, FALSE);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Unable to get default monitor";
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::SetForegroundWindow(foreground_window);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return foreground_window;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 InstallUtil::GetActiveSetupPath(BrowserDistribution* dist) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const wchar_t kInstalledComponentsPath[] =
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      L"Software\\Microsoft\\Active Setup\\Installed Components\\";
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return kInstalledComponentsPath + dist->GetActiveSetupGuid();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InstallUtil::TriggerActiveSetupCommand() {
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 active_setup_reg(
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetActiveSetupPath(BrowserDistribution::GetDistribution()));
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::RegKey active_setup_key(
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HKEY_LOCAL_MACHINE, active_setup_reg.c_str(), KEY_QUERY_VALUE);
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 cmd_str;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LONG read_status = active_setup_key.ReadValue(L"StubPath", &cmd_str);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (read_status != ERROR_SUCCESS) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << active_setup_reg << ", " << read_status;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This should never fail if Chrome is registered at system-level, but if it
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // does there is not much else to be done.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine cmd(CommandLine::FromString(cmd_str));
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force creation of shortcuts as the First Run beacon might land between now
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and the time setup.exe checks for it.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AppendSwitch(installer::switches::kForceConfigureUserSettings);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::LaunchOptions launch_options;
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::win::IsMetroProcess())
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    launch_options.force_breakaway_from_job_ = true;
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!base::LaunchProcess(cmd.GetCommandLineString(), launch_options, NULL))
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PLOG(ERROR) << cmd.GetCommandLineString();
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InstallUtil::ExecuteExeAsAdmin(const CommandLine& cmd, DWORD* exit_code) {
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType program(cmd.GetProgram().value());
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!program.empty());
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(program[0], L'\"');
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine::StringType params(cmd.GetCommandLineString());
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params[0] == '"') {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ('"', params[program.length() + 1]);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(program, params.substr(1, program.length()));
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    params = params.substr(program.length() + 2);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(program, params.substr(0, program.length()));
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    params = params.substr(program.length());
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::TrimWhitespace(params, base::TRIM_ALL, &params);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HWND uac_foreground_window = CreateUACForegroundWindow();
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SHELLEXECUTEINFO info = {0};
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.cbSize = sizeof(SHELLEXECUTEINFO);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.fMask = SEE_MASK_NOCLOSEPROCESS;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.hwnd = uac_foreground_window;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.lpVerb = L"runas";
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.lpFile = program.c_str();
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.lpParameters = params.c_str();
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.nShow = SW_SHOW;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = false;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (::ShellExecuteEx(&info) == TRUE) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::WaitForSingleObject(info.hProcess, INFINITE);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD ret_val = 0;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (::GetExitCodeProcess(info.hProcess, &ret_val)) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      success = true;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (exit_code)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *exit_code = ret_val;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (uac_foreground_window) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DestroyWindow(uac_foreground_window);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return success;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CommandLine InstallUtil::GetChromeUninstallCmd(
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool system_install, BrowserDistribution::Type distribution_type) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProductState state;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state.Initialize(system_install, distribution_type)) {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return state.uninstall_command();
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CommandLine(CommandLine::NO_PROGRAM);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InstallUtil::GetChromeVersion(BrowserDistribution* dist,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   bool system_install,
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   Version* version) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(dist);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegKey key;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  LONG result = key.Open(reg_root,
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         dist->GetVersionKey().c_str(),
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         KEY_QUERY_VALUE | KEY_WOW64_32KEY);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 version_str;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == ERROR_SUCCESS)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = key.ReadValue(google_update::kRegVersionField, &version_str);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *version = Version();
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == ERROR_SUCCESS && !version_str.empty()) {
2343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    VLOG(1) << "Existing " << dist->GetDisplayName() << " version found "
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << version_str;
236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    *version = Version(base::UTF16ToASCII(version_str));
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(ERROR_FILE_NOT_FOUND, result);
2393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    VLOG(1) << "No existing " << dist->GetDisplayName()
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << " install found.";
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InstallUtil::GetCriticalUpdateVersion(BrowserDistribution* dist,
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           bool system_install,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           Version* version) {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(dist);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegKey key;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  LONG result = key.Open(reg_root,
251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         dist->GetVersionKey().c_str(),
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         KEY_QUERY_VALUE | KEY_WOW64_32KEY);
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 version_str;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == ERROR_SUCCESS)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = key.ReadValue(google_update::kRegCriticalVersionField,
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &version_str);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *version = Version();
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == ERROR_SUCCESS && !version_str.empty()) {
2613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    VLOG(1) << "Critical Update version for " << dist->GetDisplayName()
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << " found " << version_str;
263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    *version = Version(base::UTF16ToASCII(version_str));
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(ERROR_FILE_NOT_FOUND, result);
2663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    VLOG(1) << "No existing " << dist->GetDisplayName()
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << " install found.";
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InstallUtil::IsOSSupported() {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We do not support Win2K or older, or XP without service pack 2.
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << base::SysInfo::OperatingSystemName() << ' '
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << base::SysInfo::OperatingSystemVersion();
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::Version version = base::win::GetVersion();
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (version > base::win::VERSION_XP) ||
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ((version == base::win::VERSION_XP) &&
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       (base::win::OSInfo::GetInstance()->service_pack().major >= 2));
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InstallUtil::AddInstallerResultItems(
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool system_install,
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& state_key,
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    installer::InstallStatus status,
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int string_resource_id,
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16* const launch_cmd,
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    WorkItemList* install_list) {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(install_list);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD installer_result = (GetInstallReturnCode(status) == 0) ? 0 : 1;
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  install_list->AddCreateRegKeyWorkItem(root, state_key, KEY_WOW64_32KEY);
292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  install_list->AddSetRegValueWorkItem(root,
293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       state_key,
294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       KEY_WOW64_32KEY,
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       installer::kInstallerResult,
296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       installer_result,
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       true);
298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  install_list->AddSetRegValueWorkItem(root,
299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       state_key,
300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       KEY_WOW64_32KEY,
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       installer::kInstallerError,
302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       static_cast<DWORD>(status),
303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       true);
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (string_resource_id != 0) {
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 msg = installer::GetLocalizedString(string_resource_id);
306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    install_list->AddSetRegValueWorkItem(root,
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                         state_key,
308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                         KEY_WOW64_32KEY,
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                         installer::kInstallerResultUIString,
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                         msg,
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                         true);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (launch_cmd != NULL && !launch_cmd->empty()) {
314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    install_list->AddSetRegValueWorkItem(
315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        root,
316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        state_key,
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        KEY_WOW64_32KEY,
318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        installer::kInstallerSuccessLaunchCmdLine,
319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        *launch_cmd,
320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        true);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InstallUtil::UpdateInstallerStage(bool system_install,
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       const base::string16& state_key_path,
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       installer::InstallerStage stage) {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(static_cast<installer::InstallerStage>(0), stage);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(installer::NUM_STAGES, stage);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegKey state_key;
331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  LONG result =
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      state_key.Open(root,
333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     state_key_path.c_str(),
334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_WOW64_32KEY);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == ERROR_SUCCESS) {
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (stage == installer::NO_STAGE) {
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result = state_key.DeleteValue(installer::kInstallerExtraCode1);
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG_IF(ERROR, result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << "Failed deleting installer stage from " << state_key_path
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << "; result: " << result;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const DWORD extra_code_1 = static_cast<DWORD>(stage);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result = state_key.WriteValue(installer::kInstallerExtraCode1,
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    extra_code_1);
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG_IF(ERROR, result != ERROR_SUCCESS)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << "Failed writing installer stage to " << state_key_path
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << "; result: " << result;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(grt): Remove code below here once we're convinced that our use of
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Google Update's new InstallerExtraCode1 value is good.
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    installer::ChannelInfo channel_info;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This will return false if the "ap" value isn't present, which is fine.
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    channel_info.Initialize(state_key);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (channel_info.SetStage(kStages[stage]) &&
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !channel_info.Write(&state_key)) {
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Failed writing installer stage to " << state_key_path;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed opening " << state_key_path
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " to update installer stage; result: " << result;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InstallUtil::IsPerUserInstall(const wchar_t* const exe_path) {
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t program_files_path[MAX_PATH] = {0};
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL,
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                SHGFP_TYPE_CURRENT, program_files_path))) {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return !StartsWith(exe_path, program_files_path, false);
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InstallUtil::IsMultiInstall(BrowserDistribution* dist,
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 bool system_install) {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(dist);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProductState state;
379a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return state.Initialize(system_install, dist) && state.is_multi_install();
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CheckIsChromeSxSProcess() {
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine* command_line = CommandLine::ForCurrentProcess();
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(command_line);
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (command_line->HasSwitch(installer::switches::kChromeSxS))
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Also return true if we are running from Chrome SxS installed path.
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath exe_dir;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PathService::Get(base::DIR_EXE, &exe_dir);
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 chrome_sxs_dir(installer::kGoogleChromeInstallSubDir2);
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chrome_sxs_dir.append(installer::kSxSSuffix);
394d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
395d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // This is SxS if current EXE is in or under (possibly multiple levels under)
396d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // |chrome_sxs_dir|\|installer::kInstallBinaryDir|
397d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::vector<base::FilePath::StringType> components;
398d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  exe_dir.GetComponents(&components);
399d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // We need at least 1 element in the array for the behavior of the following
400d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // loop to be defined.  This should always be true, since we're splitting the
401d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // path to our executable and one of the components will be the drive letter.
402d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK(!components.empty());
403d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  typedef std::vector<base::FilePath::StringType>::const_reverse_iterator
404d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      ComponentsIterator;
405d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (ComponentsIterator current = components.rbegin(), parent = current + 1;
406d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)       parent != components.rend(); current = parent++) {
407d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (base::FilePath::CompareEqualIgnoreCase(
408d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            *current, installer::kInstallBinaryDir) &&
409d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        base::FilePath::CompareEqualIgnoreCase(*parent, chrome_sxs_dir)) {
410d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      return true;
411d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
412d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
413d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
414d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return false;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InstallUtil::IsChromeSxSProcess() {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool sxs = CheckIsChromeSxSProcess();
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return sxs;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
422effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// static
423effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool InstallUtil::IsFirstRunSentinelPresent() {
424effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // TODO(msw): Consolidate with first_run::internal::IsFirstRunSentinelPresent.
425effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  base::FilePath user_data_dir;
426effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return !PathService::Get(chrome::DIR_USER_DATA, &user_data_dir) ||
427effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         base::PathExists(user_data_dir.Append(chrome::kFirstRunSentinel));
428effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
429effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
430effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// static
4310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool InstallUtil::GetEULASentinelFilePath(base::FilePath* path) {
4320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::FilePath user_data_dir;
4330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir))
434a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
4350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  *path = user_data_dir.Append(installer::kEULASentinelFile);
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This method tries to delete a registry key and logs an error message
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in case of failure. It returns true if deletion is successful (or the key did
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// not exist), otherwise false.
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InstallUtil::DeleteRegistryKey(HKEY root_key,
443cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                    const base::string16& key_path,
444cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                    REGSAM wow64_access) {
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "Deleting registry key " << key_path;
446cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  RegKey target_key;
447cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  LONG result = target_key.Open(root_key, key_path.c_str(),
448cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                KEY_READ | KEY_WRITE | wow64_access);
449cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
450cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (result == ERROR_FILE_NOT_FOUND)
451cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return true;
452cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
453cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (result == ERROR_SUCCESS)
454cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    result = target_key.DeleteKey(L"");
455cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
456cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (result != ERROR_SUCCESS) {
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to delete registry key: " << key_path
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " error: " << result;
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This method tries to delete a registry value and logs an error message
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in case of failure. It returns true if deletion is successful (or the key did
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// not exist), otherwise false.
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InstallUtil::DeleteRegistryValue(HKEY reg_root,
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const base::string16& key_path,
469cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                      REGSAM wow64_access,
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const base::string16& value_name) {
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegKey key;
472cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  LONG result = key.Open(reg_root, key_path.c_str(),
473cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         KEY_SET_VALUE | wow64_access);
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == ERROR_SUCCESS)
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = key.DeleteValue(value_name.c_str());
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) {
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to delete registry value: " << value_name
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " error: " << result;
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InstallUtil::ConditionalDeleteResult InstallUtil::DeleteRegistryKeyIf(
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HKEY root_key,
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& key_to_delete_path,
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& key_to_test_path,
489cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const REGSAM wow64_access,
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t* value_name,
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const RegistryValuePredicate& predicate) {
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(root_key);
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConditionalDeleteResult delete_result = NOT_FOUND;
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegKey key;
4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 actual_value;
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (key.Open(root_key, key_to_test_path.c_str(),
497cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)               KEY_QUERY_VALUE | wow64_access) == ERROR_SUCCESS &&
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key.ReadValue(value_name, &actual_value) == ERROR_SUCCESS &&
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      predicate.Evaluate(actual_value)) {
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    key.Close();
501cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    delete_result = DeleteRegistryKey(root_key,
502cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                      key_to_delete_path,
503cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                      wow64_access)
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ? DELETED : DELETE_FAILED;
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return delete_result;
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InstallUtil::ConditionalDeleteResult InstallUtil::DeleteRegistryValueIf(
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HKEY root_key,
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t* key_path,
513cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    REGSAM wow64_access,
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t* value_name,
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const RegistryValuePredicate& predicate) {
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(root_key);
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(key_path);
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConditionalDeleteResult delete_result = NOT_FOUND;
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegKey key;
5205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 actual_value;
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (key.Open(root_key, key_path,
522cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)               KEY_QUERY_VALUE | KEY_SET_VALUE | wow64_access)
523cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          == ERROR_SUCCESS &&
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key.ReadValue(value_name, &actual_value) == ERROR_SUCCESS &&
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      predicate.Evaluate(actual_value)) {
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LONG result = key.DeleteValue(value_name);
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result != ERROR_SUCCESS) {
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Failed to delete registry value: "
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << (value_name ? value_name : L"(Default)")
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << " error: " << result;
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete_result = DELETE_FAILED;
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete_result = DELETED;
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return delete_result;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool InstallUtil::ValueEquals::Evaluate(const base::string16& value) const {
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return value == value_to_match_;
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int InstallUtil::GetInstallReturnCode(installer::InstallStatus status) {
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (status) {
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case installer::FIRST_INSTALL_SUCCESS:
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case installer::INSTALL_REPAIRED:
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case installer::NEW_VERSION_UPDATED:
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case installer::IN_USE_UPDATED:
5494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case installer::UNUSED_BINARIES_UNINSTALLED:
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return status;
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InstallUtil::MakeUninstallCommand(const base::string16& program,
5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       const base::string16& arguments,
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       CommandLine* command_line) {
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *command_line = CommandLine::FromString(L"\"" + program + L"\" " + arguments);
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 InstallUtil::GetCurrentDate() {
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const wchar_t kDateFormat[] = L"yyyyMMdd";
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t date_str[arraysize(kDateFormat)] = {0};
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int len = GetDateFormatW(LOCALE_INVARIANT, 0, NULL, kDateFormat,
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           date_str, arraysize(date_str));
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (len) {
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    --len;  // Subtract terminating \0.
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PLOG(DFATAL) << "GetDateFormat";
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return base::string16(date_str, len);
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Open |path| with minimal access to obtain information about it, returning
579a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// true and populating |file| on success.
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool InstallUtil::ProgramCompare::OpenForInfo(const base::FilePath& path,
582a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                              base::File* file) {
583a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(file);
584a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  file->Initialize(path, base::File::FLAG_OPEN);
585a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return file->IsValid();
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
588a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Populate |info| for |file|, returning true on success.
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
590a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool InstallUtil::ProgramCompare::GetInfo(const base::File& file,
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          BY_HANDLE_FILE_INFORMATION* info) {
592a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(file.IsValid());
593a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return GetFileInformationByHandle(file.GetPlatformFile(), info) != 0;
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InstallUtil::ProgramCompare::ProgramCompare(const base::FilePath& path_to_match)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : path_to_match_(path_to_match),
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_info_() {
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!path_to_match_.empty());
600a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!OpenForInfo(path_to_match_, &file_)) {
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PLOG(WARNING) << "Failed opening " << path_to_match_.value()
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << "; falling back to path string comparisons.";
603a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else if (!GetInfo(file_, &file_info_)) {
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PLOG(WARNING) << "Failed getting information for "
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << path_to_match_.value()
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << "; falling back to path string comparisons.";
607a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    file_.Close();
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InstallUtil::ProgramCompare::~ProgramCompare() {
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool InstallUtil::ProgramCompare::Evaluate(const base::string16& value) const {
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Suss out the exe portion of the value, which is expected to be a command
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // line kinda (or exactly) like:
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "c:\foo\bar\chrome.exe" -- "%1"
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath program(CommandLine::FromString(value).GetProgram());
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (program.empty()) {
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Failed to parse an executable name from command line: \""
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << value << "\"";
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return EvaluatePath(program);
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool InstallUtil::ProgramCompare::EvaluatePath(
6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& path) const {
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try the simple thing first: do the paths happen to match?
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::FilePath::CompareEqualIgnoreCase(path_to_match_.value(),
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             path.value()))
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the paths don't match and we couldn't open the expected file, we've done
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // our best.
637a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!file_.IsValid())
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Open the program and see if it references the expected file.
641a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::File file;
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BY_HANDLE_FILE_INFORMATION info = {};
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
644a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return (OpenForInfo(path, &file) &&
645a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          GetInfo(file, &info) &&
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          info.dwVolumeSerialNumber == file_info_.dwVolumeSerialNumber &&
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          info.nFileIndexHigh == file_info_.nFileIndexHigh &&
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          info.nFileIndexLow == file_info_.nFileIndexLow);
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
650