diff options
author | Torne (Richard Coles) <torne@google.com> | 2013-09-26 13:24:57 +0100 |
---|---|---|
committer | Torne (Richard Coles) <torne@google.com> | 2013-09-26 13:24:57 +0100 |
commit | 68043e1e95eeb07d5cae7aca370b26518b0867d6 (patch) | |
tree | cc6a216bce6aa9319a216327b73a07f49200dab5 /chrome/installer | |
parent | cede44592cfb9ec370925d10c2df733349a94a82 (diff) | |
download | chromium_org-68043e1e95eeb07d5cae7aca370b26518b0867d6.tar.gz |
Merge from Chromium at DEPS revision 225410
This commit was generated by merge_to_master.py.
Change-Id: Ifa1539ca216abb163295ee7a77f81bb67f52e178
Diffstat (limited to 'chrome/installer')
-rw-r--r-- | chrome/installer/gcapi_mac/gcapi.mm | 7 | ||||
-rwxr-xr-x | chrome/installer/linux/debian/build.sh | 10 | ||||
-rw-r--r-- | chrome/installer/setup/cf_migration.cc | 131 | ||||
-rw-r--r-- | chrome/installer/setup/cf_migration.h | 45 | ||||
-rw-r--r-- | chrome/installer/setup/install.cc | 10 | ||||
-rw-r--r-- | chrome/installer/setup/setup_main.cc | 189 | ||||
-rw-r--r-- | chrome/installer/setup/setup_main.h | 23 | ||||
-rw-r--r-- | chrome/installer/setup/uninstall.cc | 12 | ||||
-rw-r--r-- | chrome/installer/util/channel_info.cc | 13 | ||||
-rw-r--r-- | chrome/installer/util/channel_info.h | 7 | ||||
-rw-r--r-- | chrome/installer/util/channel_info_unittest.cc | 34 | ||||
-rw-r--r-- | chrome/installer/util/delete_after_reboot_helper.cc | 91 | ||||
-rw-r--r-- | chrome/installer/util/delete_after_reboot_helper.h | 22 | ||||
-rw-r--r-- | chrome/installer/util/delete_after_reboot_helper_unittest.cc | 41 | ||||
-rw-r--r-- | chrome/installer/util/self_cleaning_temp_dir.cc | 4 | ||||
-rw-r--r-- | chrome/installer/util/shell_util.cc | 7 |
16 files changed, 439 insertions, 207 deletions
diff --git a/chrome/installer/gcapi_mac/gcapi.mm b/chrome/installer/gcapi_mac/gcapi.mm index 57f0d02d58..1ca5839300 100644 --- a/chrome/installer/gcapi_mac/gcapi.mm +++ b/chrome/installer/gcapi_mac/gcapi.mm @@ -34,9 +34,6 @@ NSString* const kUserMasterPrefsPath = @"~~/Library/Application Support/Google/Chrome/" "Google Chrome Master Preferences"; -NSString* const kChannelKey = @"KSChannelID"; -NSString* const kVersionKey = @"KSVersion"; - // Condensed from chromium's base/mac/mac_util.mm. bool IsOSXVersionSupported() { // On 10.6, Gestalt() was observed to be able to spawn threads (see @@ -60,8 +57,8 @@ bool IsOSXVersionSupported() { // 10.2. int mac_os_x_minor_version = darwin_major_version - 4; - // Chrome is known to work on 10.6 - 10.8. - return mac_os_x_minor_version >= 6 && mac_os_x_minor_version <= 8; + // Chrome is known to work on 10.6 - 10.9. + return mac_os_x_minor_version >= 6 && mac_os_x_minor_version <= 9; } // Returns the pid/gid of the logged-in user, even if getuid() claims that the diff --git a/chrome/installer/linux/debian/build.sh b/chrome/installer/linux/debian/build.sh index 290aaef053..dad1f03ab8 100755 --- a/chrome/installer/linux/debian/build.sh +++ b/chrome/installer/linux/debian/build.sh @@ -94,9 +94,13 @@ do_package() { echo "Packaging ${ARCHITECTURE}..." PREDEPENDS="$COMMON_PREDEPS" DEPENDS="${COMMON_DEPS}" - REPLACES="" - CONFLICTS="" - PROVIDES="www-browser" + # Trunk is a special package, mostly for development testing, so don't make + # it replace any installed release packages. + if [ "$CHANNEL" != "trunk" ] && [ "$CHANNEL" != "asan" ]; then + REPLACES="${PACKAGE}" + CONFLICTS="${PACKAGE}" + PROVIDES="${PACKAGE}, www-browser" + fi gen_changelog process_template "${SCRIPTDIR}/control.template" "${DEB_CONTROL}" export DEB_HOST_ARCH="${ARCHITECTURE}" diff --git a/chrome/installer/setup/cf_migration.cc b/chrome/installer/setup/cf_migration.cc new file mode 100644 index 0000000000..313f2ce317 --- /dev/null +++ b/chrome/installer/setup/cf_migration.cc @@ -0,0 +1,131 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/installer/setup/cf_migration.h" + +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/logging.h" +#include "base/process/launch.h" +#include "base/win/registry.h" +#include "chrome/installer/setup/setup_constants.h" +#include "chrome/installer/setup/setup_main.h" +#include "chrome/installer/setup/setup_util.h" +#include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/install_util.h" +#include "chrome/installer/util/installation_state.h" +#include "chrome/installer/util/installer_state.h" +#include "chrome/installer/util/master_preferences.h" +#include "chrome/installer/util/util_constants.h" + +namespace installer { + +bool LaunchChromeFrameMigrationProcess( + const ProductState& chrome_frame_product, + const CommandLine& command_line, + const base::FilePath& installer_directory, + bool system_level) { + // Before running the migration, mutate the CF ap value to include a + // "-migrate" beacon. This beacon value will be cleaned up by the "ap" + // cleanup in MigrateGoogleUpdateStateMultiToSingle that calls + // ChannelInfo::RemoveAllModifiersAndSuffixes(). + if (chrome_frame_product.is_multi_install()) { + const HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + base::win::RegKey state_key; + installer::ChannelInfo channel_info; + BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_FRAME); + + LONG result = state_key.Open(root, dist->GetStateKey().c_str(), + KEY_QUERY_VALUE | KEY_SET_VALUE); + if (result != ERROR_SUCCESS || !channel_info.Initialize(state_key)) { + LOG(ERROR) << "Failed to read CF channel to store beacon."; + } else if (!channel_info.SetMigratingSuffix(true)) { + LOG(WARNING) << "CF already has migration beacon in channel."; + } else { + VLOG(1) << "Writing CF migration beacon to channel: " + << channel_info.value(); + channel_info.Write(&state_key); + } + } + + // Call the installed setup.exe using the current installer command line and + // adding the migration flags. This seems like it could be unsafe, here's why + // it's safe today: + // 1) MigrateChromeFrameInChildProcess is called only during a multi update. + // 2) Multi update processing occurs after HandleNonInstallCmdLineOptions is + // called. + // 3) Setup exits if there were any non-install command line options handled. + // 4) Thus, the command line being copied will have no non-install command + // line options at time of copying. + // 5) kMigrateChromeFrame is a non-install command line option. + // 6) Thus, it will be handled (and the child setup process will exit) before + // the child setup process acts on any other flags on the command line. + // 7) Furthermore, --uncompressed-archive takes precedence over + // --install-archive, so it is safe to add the former to the command line + // without removing the latter. + CommandLine setup_cmd(command_line); + setup_cmd.SetProgram(installer_directory.Append(installer::kSetupExe)); + setup_cmd.AppendSwitchPath( + switches::kUncompressedArchive, + installer_directory.Append(installer::kChromeArchive)); + setup_cmd.AppendSwitch(switches::kMigrateChromeFrame); + + VLOG(1) << "Running Chrome Frame migration process with command line: " + << setup_cmd.GetCommandLineString(); + + base::LaunchOptions options; + options.force_breakaway_from_job_ = true; + if (!base::LaunchProcess(setup_cmd, options, NULL)) { + PLOG(ERROR) << "Launching Chrome Frame migration process failed. " + << "(Command line: " << setup_cmd.GetCommandLineString() << ")"; + return false; + } + + return true; +} + +InstallStatus MigrateChromeFrame(const InstallationState& original_state, + InstallerState* installer_state) { + const bool system_level = installer_state->system_install(); + + // Nothing to do if multi-install Chrome Frame is not installed. + const ProductState* multi_chrome_frame = original_state.GetProductState( + system_level, BrowserDistribution::CHROME_FRAME); + if (!multi_chrome_frame || !multi_chrome_frame->is_multi_install()) + return INVALID_STATE_FOR_OPTION; + + // Install SxS Chrome Frame. + InstallerState install_gcf(installer_state->level()); + { + scoped_ptr<Product> chrome_frame( + new Product(BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_FRAME))); + install_gcf.AddProduct(&chrome_frame); + } + DCHECK(!install_gcf.is_multi_install()); + + ArchiveType archive_type = UNKNOWN_ARCHIVE_TYPE; + bool delegated_to_existing = false; + InstallStatus install_status = InstallProductsHelper( + original_state, *CommandLine::ForCurrentProcess(), + MasterPreferences::ForCurrentProcess(), install_gcf, + NULL, &archive_type, &delegated_to_existing); + + if (!InstallUtil::GetInstallReturnCode(install_status)) { + // Migration was successful. There's no turning back now. The multi-install + // npchrome_frame.dll and/or chrome.exe may still be in use at this point, + // although the user-level helper will not be. It is not safe to delete the + // multi-install binaries until npchrome_frame.dll and chrome.exe are no + // longer in use. The remaining tasks here are best-effort. Failure does not + // do any harm. + MigrateGoogleUpdateStateMultiToSingle(system_level, + BrowserDistribution::CHROME_FRAME, + original_state); + } + + return install_status; +} + +} // namespace installer diff --git a/chrome/installer/setup/cf_migration.h b/chrome/installer/setup/cf_migration.h new file mode 100644 index 0000000000..976e54464a --- /dev/null +++ b/chrome/installer/setup/cf_migration.h @@ -0,0 +1,45 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_INSTALLER_SETUP_CF_MIGRATION_H_ +#define CHROME_INSTALLER_SETUP_CF_MIGRATION_H_ + +#include "chrome/installer/util/util_constants.h" + +class CommandLine; + +namespace base { +class FilePath; +} + +namespace installer { + +class InstallationState; +class InstallerState; +class ProductState; + +// Invokes a child helper instance of the setup.exe in |installer_directory| to +// run MigrateChromeFrame (see comments below) using the archive in +// |installer_directory| for the given installation level. Returns true if the +// process is launched. +bool LaunchChromeFrameMigrationProcess( + const ProductState& chrome_frame_product, + const CommandLine& command_line, + const base::FilePath& installer_directory, + bool system_level); + +// Migrates multi-install Chrome Frame to single-install at the current +// level. Does not remove the multi-install binaries if no other products are +// using them. --uncompressed-archive=chrome.7z is expected to be given on the +// command line to point this setup.exe at the (possibly patched) archive from +// the calling instance. +// Note about process model: this is called in a child setup.exe that is +// invoked from the setup.exe instance run as part of an update to a +// multi-install Chrome Frame. +InstallStatus MigrateChromeFrame(const InstallationState& original_state, + InstallerState* installer_state); + +} // namespace installer + +#endif // CHROME_INSTALLER_SETUP_CF_MIGRATION_H_ diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc index 688df1c786..5049fdca81 100644 --- a/chrome/installer/setup/install.cc +++ b/chrome/installer/setup/install.cc @@ -17,6 +17,7 @@ #include "base/memory/scoped_ptr.h" #include "base/path_service.h" #include "base/process/launch.h" +#include "base/safe_numerics.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" @@ -340,9 +341,10 @@ bool CreateVisualElementsManifest(const base::FilePath& src_path, // Write the manifest to |src_path|. const std::string manifest(UTF16ToUTF8(manifest16)); + int size = base::checked_numeric_cast<int>(manifest.size()); if (file_util::WriteFile( - src_path.Append(installer::kVisualElementsManifest), - manifest.c_str(), manifest.size())) { + src_path.Append(installer::kVisualElementsManifest), + manifest.c_str(), size) == size) { VLOG(1) << "Successfully wrote " << installer::kVisualElementsManifest << " to " << src_path.value(); return true; @@ -504,10 +506,8 @@ InstallStatus InstallOrUpdateProduct( DCHECK(products.size()); if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { // Make sure that we don't end up deleting installed files on next reboot. - if (!RemoveFromMovesPendingReboot( - installer_state.target_path().value().c_str())) { + if (!RemoveFromMovesPendingReboot(installer_state.target_path())) LOG(ERROR) << "Error accessing pending moves value."; - } } // Create VisualElementManifest.xml in |src_path| (if required) so that it diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index 171ac7c7c4..9f38cfff19 100644 --- a/chrome/installer/setup/setup_main.cc +++ b/chrome/installer/setup/setup_main.cc @@ -36,6 +36,7 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_switches.h" #include "chrome/installer/setup/archive_patch_helper.h" +#include "chrome/installer/setup/cf_migration.h" #include "chrome/installer/setup/chrome_frame_quick_enable.h" #include "chrome/installer/setup/chrome_frame_ready_mode.h" #include "chrome/installer/setup/install.h" @@ -71,10 +72,10 @@ using installer::InstallerState; using installer::InstallationState; using installer::InstallationValidator; +using installer::MasterPreferences; using installer::Product; using installer::ProductState; using installer::Products; -using installer::MasterPreferences; const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices"; const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; @@ -691,7 +692,8 @@ installer::InstallStatus InstallProducts( const InstallationState& original_state, const CommandLine& cmd_line, const MasterPreferences& prefs, - InstallerState* installer_state) { + InstallerState* installer_state, + base::FilePath* installer_directory) { DCHECK(installer_state); const bool system_install = installer_state->system_install(); installer::InstallStatus install_status = installer::UNKNOWN_STATUS; @@ -706,8 +708,8 @@ installer::InstallStatus InstallProducts( &install_status)) { VLOG(1) << "Installing to " << installer_state->target_path().value(); install_status = InstallProductsHelper( - original_state, cmd_line, prefs, *installer_state, &archive_type, - &delegated_to_existing); + original_state, cmd_line, prefs, *installer_state, + installer_directory, &archive_type, &delegated_to_existing); } else { // CheckPreInstallConditions must set the status on failure. DCHECK_NE(install_status, installer::UNKNOWN_STATUS); @@ -723,7 +725,7 @@ installer::InstallStatus InstallProducts( LOG(ERROR) << "Failed deleting master preferences file " << prefs_path.value() << ", scheduling for deletion after reboot."; - ScheduleFileSystemEntityForDeletion(prefs_path.value().c_str()); + ScheduleFileSystemEntityForDeletion(prefs_path); } } @@ -981,55 +983,6 @@ installer::InstallStatus RegisterDevChrome( return status; } -// Migrates multi-install Chrome Frame to single-install at the current -// level. Does not remove the multi-install binaries if no other products are -// using them. --uncompressed-archive=chrome.7z is expected to be given on the -// command line to point this setup.exe at the (possibly patched) archive from -// the calling instance. -installer::InstallStatus MigrateChromeFrame( - const InstallationState& original_state, - InstallerState* installer_state) { - const bool system_level = installer_state->system_install(); - - // Nothing to do if multi-install Chrome Frame is not installed. - const ProductState* multi_chrome_frame = original_state.GetProductState( - system_level, BrowserDistribution::CHROME_FRAME); - if (!multi_chrome_frame || !multi_chrome_frame->is_multi_install()) - return installer::INVALID_STATE_FOR_OPTION; - - // Install SxS Chrome Frame. - InstallerState install_gcf(installer_state->level()); - { - scoped_ptr<Product> chrome_frame( - new Product(BrowserDistribution::GetSpecificDistribution( - BrowserDistribution::CHROME_FRAME))); - install_gcf.AddProduct(&chrome_frame); - } - DCHECK(!install_gcf.is_multi_install()); - - installer::ArchiveType archive_type = installer::UNKNOWN_ARCHIVE_TYPE; - bool delegated_to_existing = false; - installer::InstallStatus install_status = InstallProductsHelper( - original_state, *CommandLine::ForCurrentProcess(), - MasterPreferences::ForCurrentProcess(), install_gcf, - &archive_type, &delegated_to_existing); - - if (!InstallUtil::GetInstallReturnCode(install_status)) { - // Migration was successful. There's no turning back now. The multi-install - // npchrome_frame.dll and/or chrome.exe may still be in use at this point, - // although the user-level helper will not be. It is not safe to delete the - // multi-install binaries until npchrome_frame.dll and chrome.exe are no - // longer in use. The remaining tasks here are best-effort. Failure does not - // do any harm. - installer::MigrateGoogleUpdateStateMultiToSingle( - system_level, - BrowserDistribution::CHROME_FRAME, - original_state); - } - - return install_status; -} - // This method processes any command line options that make setup.exe do // various tasks other than installation (renaming chrome.exe, showing eula // among others). This function returns true if any such command line option @@ -1070,7 +1023,7 @@ bool HandleNonInstallCmdLineOptions(const InstallationState& original_state, // the Windows last-error code. LOG(WARNING) << "Scheduling temporary path " << temp_path.path().value() << " for deletion at reboot."; - ScheduleDirectoryForDeletion(temp_path.path().value().c_str()); + ScheduleDirectoryForDeletion(temp_path.path()); } } @@ -1401,42 +1354,43 @@ google_breakpad::ExceptionHandler* InitializeCrashReporting( namespace installer { -installer::InstallStatus InstallProductsHelper( +InstallStatus InstallProductsHelper( const InstallationState& original_state, const CommandLine& cmd_line, const MasterPreferences& prefs, const InstallerState& installer_state, - installer::ArchiveType* archive_type, + base::FilePath* installer_directory, + ArchiveType* archive_type, bool* delegated_to_existing) { DCHECK(archive_type); DCHECK(delegated_to_existing); const bool system_install = installer_state.system_install(); - installer::InstallStatus install_status = installer::UNKNOWN_STATUS; + InstallStatus install_status = UNKNOWN_STATUS; // Drop to background processing mode if the process was started below the // normal process priority class. - bool entered_background_mode = installer::AdjustProcessPriority(); + bool entered_background_mode = AdjustProcessPriority(); VLOG_IF(1, entered_background_mode) << "Entered background processing mode."; // Create a temp folder where we will unpack Chrome archive. If it fails, // then we are doomed, so return immediately and no cleanup is required. - installer::SelfCleaningTempDir temp_path; + SelfCleaningTempDir temp_path; base::FilePath unpack_path; if (!CreateTemporaryAndUnpackDirectories(installer_state, &temp_path, &unpack_path)) { - installer_state.WriteInstallerResult(installer::TEMP_DIR_FAILED, + installer_state.WriteInstallerResult(TEMP_DIR_FAILED, IDS_INSTALL_TEMP_DIR_FAILED_BASE, NULL); - return installer::TEMP_DIR_FAILED; + return TEMP_DIR_FAILED; } // Uncompress and optionally patch the archive if an uncompressed archive was // not specified on the command line and a compressed archive is found. - *archive_type = installer::UNKNOWN_ARCHIVE_TYPE; + *archive_type = UNKNOWN_ARCHIVE_TYPE; base::FilePath uncompressed_archive(cmd_line.GetSwitchValuePath( - installer::switches::kUncompressedArchive)); + switches::kUncompressedArchive)); if (uncompressed_archive.empty()) { - scoped_ptr<installer::ArchivePatchHelper> archive_helper( + scoped_ptr<ArchivePatchHelper> archive_helper( CreateChromeArchiveHelper(cmd_line, installer_state, unpack_path)); if (archive_helper) { VLOG(1) << "Installing Chrome from compressed archive " @@ -1446,7 +1400,7 @@ installer::InstallStatus InstallProductsHelper( archive_helper.get(), archive_type, &install_status)) { - DCHECK_NE(install_status, installer::UNKNOWN_STATUS); + DCHECK_NE(install_status, UNKNOWN_STATUS); return install_status; } uncompressed_archive = archive_helper->target(); @@ -1458,19 +1412,19 @@ installer::InstallStatus InstallProductsHelper( // was not given or generated. if (uncompressed_archive.empty()) { uncompressed_archive = - cmd_line.GetProgram().DirName().Append(installer::kChromeArchive); + cmd_line.GetProgram().DirName().Append(kChromeArchive); } - if (*archive_type == installer::UNKNOWN_ARCHIVE_TYPE) { + if (*archive_type == UNKNOWN_ARCHIVE_TYPE) { // An archive was not uncompressed or patched above. if (uncompressed_archive.empty() || !base::PathExists(uncompressed_archive)) { LOG(ERROR) << "Cannot install Chrome without an uncompressed archive."; installer_state.WriteInstallerResult( - installer::INVALID_ARCHIVE, IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL); - return installer::INVALID_ARCHIVE; + INVALID_ARCHIVE, IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL); + return INVALID_ARCHIVE; } - *archive_type = installer::FULL_ARCHIVE_TYPE; + *archive_type = FULL_ARCHIVE_TYPE; } // Unpack the uncompressed archive. @@ -1478,20 +1432,20 @@ installer::InstallStatus InstallProductsHelper( unpack_path.value(), NULL)) { installer_state.WriteInstallerResult( - installer::UNCOMPRESSION_FAILED, + UNCOMPRESSION_FAILED, IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, NULL); - return installer::UNCOMPRESSION_FAILED; + return UNCOMPRESSION_FAILED; } VLOG(1) << "unpacked to " << unpack_path.value(); base::FilePath src_path( - unpack_path.Append(installer::kInstallSourceChromeDir)); + unpack_path.Append(kInstallSourceChromeDir)); scoped_ptr<Version> - installer_version(installer::GetMaxVersionFromArchiveDir(src_path)); + installer_version(GetMaxVersionFromArchiveDir(src_path)); if (!installer_version.get()) { LOG(ERROR) << "Did not find any valid version in installer."; - install_status = installer::INVALID_ARCHIVE; + install_status = INVALID_ARCHIVE; installer_state.WriteInstallerResult(install_status, IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL); } else { @@ -1508,7 +1462,7 @@ installer::InstallStatus InstallProductsHelper( if (GetExistingHigherInstaller(original_state, system_install, *installer_version, &setup_exe)) { VLOG(1) << "Deferring to existing installer."; - installer_state.UpdateStage(installer::DEFERRING_TO_HIGHER_VERSION); + installer_state.UpdateStage(DEFERRING_TO_HIGHER_VERSION); if (DeferToExistingInstall(setup_exe, cmd_line, installer_state, temp_path.path(), &install_status)) { *delegated_to_existing = true; @@ -1546,7 +1500,7 @@ installer::InstallStatus InstallProductsHelper( int message_id = 0; proceed_with_installation = false; - install_status = installer::HIGHER_VERSION_EXISTS; + install_status = HIGHER_VERSION_EXISTS; switch (higher_products) { case kBrowserBit: message_id = IDS_INSTALL_HIGHER_VERSION_BASE; @@ -1579,16 +1533,17 @@ installer::InstallStatus InstallProductsHelper( if (!google_update::EnsureUserLevelGoogleUpdatePresent()) { LOG(ERROR) << "Failed to install Google Update"; proceed_with_installation = false; - install_status = installer::INSTALL_OF_GOOGLE_UPDATE_FAILED; + install_status = INSTALL_OF_GOOGLE_UPDATE_FAILED; installer_state.WriteInstallerResult(install_status, 0, NULL); } } + } if (proceed_with_installation) { base::FilePath prefs_source_path(cmd_line.GetSwitchValueNative( - installer::switches::kInstallerData)); - install_status = installer::InstallOrUpdateProduct( + switches::kInstallerData)); + install_status = InstallOrUpdateProduct( original_state, installer_state, cmd_line.GetProgram(), uncompressed_archive, temp_path.path(), src_path, prefs_source_path, prefs, *installer_version); @@ -1596,27 +1551,26 @@ installer::InstallStatus InstallProductsHelper( int install_msg_base = IDS_INSTALL_FAILED_BASE; string16 chrome_exe; string16 quoted_chrome_exe; - if (install_status == installer::SAME_VERSION_REPAIR_FAILED) { + if (install_status == SAME_VERSION_REPAIR_FAILED) { if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { install_msg_base = IDS_SAME_VERSION_REPAIR_FAILED_CF_BASE; } else { install_msg_base = IDS_SAME_VERSION_REPAIR_FAILED_BASE; } - } else if (install_status != installer::INSTALL_FAILED) { + } else if (install_status != INSTALL_FAILED) { if (installer_state.target_path().empty()) { // If we failed to construct install path, it means the OS call to // get %ProgramFiles% or %AppData% failed. Report this as failure. install_msg_base = IDS_INSTALL_OS_ERROR_BASE; - install_status = installer::OS_ERROR; + install_status = OS_ERROR; } else { - chrome_exe = installer_state.target_path() - .Append(installer::kChromeExe).value(); + chrome_exe = installer_state.target_path().Append(kChromeExe).value(); quoted_chrome_exe = L"\"" + chrome_exe + L"\""; install_msg_base = 0; } } - installer_state.UpdateStage(installer::FINISHING); + installer_state.UpdateStage(FINISHING); // Only do Chrome-specific stuff (like launching the browser) if // Chrome was specifically requested (rather than being upgraded as @@ -1627,48 +1581,45 @@ installer::InstallStatus InstallProductsHelper( bool do_not_register_for_update_launch = false; if (chrome_install) { - prefs.GetBool( - installer::master_preferences::kDoNotRegisterForUpdateLaunch, - &do_not_register_for_update_launch); + prefs.GetBool(master_preferences::kDoNotRegisterForUpdateLaunch, + &do_not_register_for_update_launch); } else { do_not_register_for_update_launch = true; // Never register. } bool write_chrome_launch_string = (!do_not_register_for_update_launch && - install_status != installer::IN_USE_UPDATED); + install_status != IN_USE_UPDATED); installer_state.WriteInstallerResult(install_status, install_msg_base, write_chrome_launch_string ? "ed_chrome_exe : NULL); - if (install_status == installer::FIRST_INSTALL_SUCCESS) { + if (install_status == FIRST_INSTALL_SUCCESS) { VLOG(1) << "First install successful."; if (chrome_install) { // We never want to launch Chrome in system level install mode. bool do_not_launch_chrome = false; - prefs.GetBool( - installer::master_preferences::kDoNotLaunchChrome, - &do_not_launch_chrome); + prefs.GetBool(master_preferences::kDoNotLaunchChrome, + &do_not_launch_chrome); if (!system_install && !do_not_launch_chrome) chrome_install->LaunchChrome(installer_state.target_path()); } - } else if ((install_status == installer::NEW_VERSION_UPDATED) || - (install_status == installer::IN_USE_UPDATED)) { + } else if ((install_status == NEW_VERSION_UPDATED) || + (install_status == IN_USE_UPDATED)) { const Product* chrome = installer_state.FindProduct( BrowserDistribution::CHROME_BROWSER); if (chrome != NULL) { DCHECK_NE(chrome_exe, string16()); - installer::RemoveChromeLegacyRegistryKeys(chrome->distribution(), - chrome_exe); + RemoveChromeLegacyRegistryKeys(chrome->distribution(), chrome_exe); } } if (prefs.install_chrome_app_launcher() && InstallUtil::GetInstallReturnCode(install_status) == 0) { std::string webstore_item(google_update::GetUntrustedDataValue( - installer::kInstallFromWebstore)); + kInstallFromWebstore)); if (!webstore_item.empty()) { - bool success = installer::InstallFromWebstore(webstore_item); + bool success = InstallFromWebstore(webstore_item); VLOG_IF(1, !success) << "Failed to launch app installation."; } } @@ -1699,6 +1650,15 @@ installer::InstallStatus InstallProductsHelper( } } + // If installation completed successfully, return the path to the directory + // containing the newly installed setup.exe and uncompressed archive if the + // caller requested it. + if (installer_directory && + InstallUtil::GetInstallReturnCode(install_status) == 0) { + *installer_directory = + installer_state.GetInstallerDirectory(*installer_version); + } + // temp_path's dtor will take care of deleting or scheduling itself for // deletion at reboot when this scope closes. VLOG(1) << "Deleting temporary directory " << temp_path.path().value(); @@ -1798,6 +1758,7 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, } } + base::FilePath installer_directory; installer::InstallStatus install_status = installer::UNKNOWN_STATUS; // If --uninstall option is given, uninstall the identified product(s) if (is_uninstall) { @@ -1806,7 +1767,8 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, } else { // If --uninstall option is not specified, we assume it is install case. install_status = - InstallProducts(original_state, cmd_line, prefs, &installer_state); + InstallProducts(original_state, cmd_line, prefs, &installer_state, + &installer_directory); } // Validate that the machine is now in a good state following the operation. @@ -1820,7 +1782,6 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, const Product* cf_install = installer_state.FindProduct(BrowserDistribution::CHROME_FRAME); - if (cf_install && !cmd_line.HasSwitch(installer::switches::kForceUninstall)) { if (install_status == installer::UNINSTALL_REQUIRES_REBOOT) { @@ -1849,11 +1810,31 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, // MSI demands that custom actions always return 0 (ERROR_SUCCESS) or it will // rollback the action. If we're uninstalling we want to avoid this, so always // report success, squashing any more informative return codes. - if (!(installer_state.is_msi() && is_uninstall)) + if (!(installer_state.is_msi() && is_uninstall)) { // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT // to pass through, since this is only returned on uninstall which is // never invoked directly by Google Update. return_code = InstallUtil::GetInstallReturnCode(install_status); + } + + // Reinitialize original_state to make sure it reflects the now-current + // state of the system. + original_state.Initialize(); + + // If multi Chrome Frame was just updated, migrate the installation to a SxS + // install. Do this right before quitting. + const ProductState* chrome_frame_state = + original_state.GetProductState(system_install, + BrowserDistribution::CHROME_FRAME); + if ((install_status == installer::NEW_VERSION_UPDATED || + install_status == installer::IN_USE_UPDATED) && + chrome_frame_state && + installer_state.operation() == InstallerState::MULTI_UPDATE) { + // Call the newly updated setup.exe with kUncompressedArchive and + // kMigrateChromeFrame to perform the migration. + LaunchChromeFrameMigrationProcess(*chrome_frame_state, cmd_line, + installer_directory, system_install); + } VLOG(1) << "Installation complete, returning: " << return_code; diff --git a/chrome/installer/setup/setup_main.h b/chrome/installer/setup/setup_main.h index f39e742de0..f87509cf68 100644 --- a/chrome/installer/setup/setup_main.h +++ b/chrome/installer/setup/setup_main.h @@ -12,20 +12,27 @@ class CommandLine; -namespace installer { +namespace base { +class FilePath; +} // namespace base +namespace installer { class InstallationState; class InstallerState; class MasterPreferences; // Helper function that performs the installation of a set of products. -installer::InstallStatus InstallProductsHelper( - const installer::InstallationState& original_state, - const CommandLine& cmd_line, - const installer::MasterPreferences& prefs, - const installer::InstallerState& installer_state, - installer::ArchiveType* archive_type, - bool* delegated_to_existing); +// |installer_directory|, if non-NULL, is populated with the path to the +// directory containing the newly installed setup.exe. |archive_type| is +// populated with the type of archive found. |delegated_to_existing| is set to +// |true| if installation was delegated to a pre-existing higher version. +InstallStatus InstallProductsHelper(const InstallationState& original_state, + const CommandLine& cmd_line, + const MasterPreferences& prefs, + const InstallerState& installer_state, + base::FilePath* installer_directory, + ArchiveType* archive_type, + bool* delegated_to_existing); } // namespace installer diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc index 2387ab319b..ad0b0d25e3 100644 --- a/chrome/installer/setup/uninstall.cc +++ b/chrome/installer/setup/uninstall.cc @@ -428,13 +428,13 @@ void DeleteShortcuts(const InstallerState& installer_state, bool ScheduleParentAndGrandparentForDeletion(const base::FilePath& path) { base::FilePath parent_dir = path.DirName(); - bool ret = ScheduleFileSystemEntityForDeletion(parent_dir.value().c_str()); + bool ret = ScheduleFileSystemEntityForDeletion(parent_dir); if (!ret) { LOG(ERROR) << "Failed to schedule parent dir for deletion: " << parent_dir.value(); } else { base::FilePath grandparent_dir(parent_dir.DirName()); - ret = ScheduleFileSystemEntityForDeletion(grandparent_dir.value().c_str()); + ret = ScheduleFileSystemEntityForDeletion(grandparent_dir); if (!ret) { LOG(ERROR) << "Failed to schedule grandparent dir for deletion: " << grandparent_dir.value(); @@ -508,7 +508,7 @@ DeleteResult DeleteLocalState( LOG(ERROR) << "Failed to delete user profile dir: " << user_local_state.value(); if (schedule_on_failure) { - ScheduleDirectoryForDeletion(user_local_state.value().c_str()); + ScheduleDirectoryForDeletion(user_local_state); result = DELETE_REQUIRES_REBOOT; } else { result = DELETE_FAILED; @@ -652,9 +652,9 @@ DeleteResult DeleteChromeFilesAndFolders(const InstallerState& installer_state, // return a value that will trigger a reboot prompt. base::FileEnumerator::FileInfo find_info = file_enumerator.GetInfo(); if (find_info.IsDirectory()) - ScheduleDirectoryForDeletion(to_delete.value().c_str()); + ScheduleDirectoryForDeletion(to_delete); else - ScheduleFileSystemEntityForDeletion(to_delete.value().c_str()); + ScheduleFileSystemEntityForDeletion(to_delete); result = DELETE_REQUIRES_REBOOT; } else { // Try closing any running Chrome processes and deleting files once @@ -1496,7 +1496,7 @@ void CleanUpInstallationDirectoryAfterUninstall( if (*uninstall_status == installer::UNINSTALL_REQUIRES_REBOOT) { // Delete the Application directory at reboot if empty. - ScheduleFileSystemEntityForDeletion(target_path.value().c_str()); + ScheduleFileSystemEntityForDeletion(target_path); // If we need a reboot to continue, schedule the parent directories for // deletion unconditionally. If they are not empty, the session manager diff --git a/chrome/installer/util/channel_info.cc b/chrome/installer/util/channel_info.cc index e52ae77afe..48a4e32127 100644 --- a/chrome/installer/util/channel_info.cc +++ b/chrome/installer/util/channel_info.cc @@ -22,6 +22,7 @@ const wchar_t kModMultiInstall[] = L"-multi"; const wchar_t kModReadyMode[] = L"-readymode"; const wchar_t kModStage[] = L"-stage:"; const wchar_t kSfxFull[] = L"-full"; +const wchar_t kSfxMigrating[] = L"-migrating"; const wchar_t kSfxMultiFail[] = L"-multifail"; const wchar_t* const kChannels[] = { @@ -38,7 +39,8 @@ const wchar_t* const kModifiers[] = { kModAppLauncher, kModReadyMode, kSfxMultiFail, - kSfxFull + kSfxMigrating, + kSfxFull, }; enum ModifierIndex { @@ -50,6 +52,7 @@ enum ModifierIndex { MOD_APP_LAUNCHER, MOD_READY_MODE, SFX_MULTI_FAIL, + SFX_MIGRATING, SFX_FULL, NUM_MODIFIERS }; @@ -281,6 +284,14 @@ bool ChannelInfo::SetMultiFailSuffix(bool value) { return SetModifier(SFX_MULTI_FAIL, value, &value_); } +bool ChannelInfo::SetMigratingSuffix(bool value) { + return SetModifier(SFX_MIGRATING, value, &value_); +} + +bool ChannelInfo::HasMigratingSuffix() const { + return HasModifier(SFX_MIGRATING, value_); +} + bool ChannelInfo::RemoveAllModifiersAndSuffixes() { bool modified = false; diff --git a/chrome/installer/util/channel_info.h b/chrome/installer/util/channel_info.h index 438966f247..f14811390a 100644 --- a/chrome/installer/util/channel_info.h +++ b/chrome/installer/util/channel_info.h @@ -101,6 +101,13 @@ class ChannelInfo { // modified. bool SetMultiFailSuffix(bool value); + // Adds or removes the -migrating suffix, returning true if the value is + // modified. + bool SetMigratingSuffix(bool value); + + // Returns true if the -migrating suffix is present in the value. + bool HasMigratingSuffix() const; + // Removes all modifiers and suffixes. For example, 2.0-dev-multi-chrome-full // becomes 2.0-dev. Returns true if the value is modified. bool RemoveAllModifiersAndSuffixes(); diff --git a/chrome/installer/util/channel_info_unittest.cc b/chrome/installer/util/channel_info_unittest.cc index 1aacb24730..d08f2c3104 100644 --- a/chrome/installer/util/channel_info_unittest.cc +++ b/chrome/installer/util/channel_info_unittest.cc @@ -118,6 +118,38 @@ TEST(ChannelInfoTest, MultiInstall) { EXPECT_EQ(L"2.0-beta", ci.value()); } +TEST(ChannelInfoTest, Migration) { + ChannelInfo ci; + + ci.set_value(L""); + EXPECT_TRUE(ci.SetMigratingSuffix(true)); + EXPECT_TRUE(ci.HasMigratingSuffix()); + EXPECT_EQ(L"-migrating", ci.value()); + EXPECT_FALSE(ci.SetMigratingSuffix(true)); + EXPECT_TRUE(ci.HasMigratingSuffix()); + EXPECT_EQ(L"-migrating", ci.value()); + EXPECT_TRUE(ci.SetMigratingSuffix(false)); + EXPECT_FALSE(ci.HasMigratingSuffix()); + EXPECT_EQ(L"", ci.value()); + EXPECT_FALSE(ci.SetMigratingSuffix(false)); + EXPECT_FALSE(ci.HasMigratingSuffix()); + EXPECT_EQ(L"", ci.value()); + + ci.set_value(L"2.0-beta"); + EXPECT_TRUE(ci.SetMigratingSuffix(true)); + EXPECT_TRUE(ci.HasMigratingSuffix()); + EXPECT_EQ(L"2.0-beta-migrating", ci.value()); + EXPECT_FALSE(ci.SetMigratingSuffix(true)); + EXPECT_TRUE(ci.HasMigratingSuffix()); + EXPECT_EQ(L"2.0-beta-migrating", ci.value()); + EXPECT_TRUE(ci.SetMigratingSuffix(false)); + EXPECT_FALSE(ci.HasMigratingSuffix()); + EXPECT_EQ(L"2.0-beta", ci.value()); + EXPECT_FALSE(ci.SetMigratingSuffix(false)); + EXPECT_FALSE(ci.HasMigratingSuffix()); + EXPECT_EQ(L"2.0-beta", ci.value()); +} + TEST(ChannelInfoTest, Combinations) { ChannelInfo ci; @@ -212,7 +244,7 @@ TEST(ChannelInfoTest, RemoveAllModifiersAndSuffixes) { EXPECT_FALSE(ci.RemoveAllModifiersAndSuffixes()); EXPECT_EQ(L"", ci.value()); - ci.set_value(L"2.0-dev-multi-chrome-chromeframe"); + ci.set_value(L"2.0-dev-multi-chrome-chromeframe-migrating"); EXPECT_TRUE(ci.RemoveAllModifiersAndSuffixes()); EXPECT_EQ(L"2.0-dev", ci.value()); } diff --git a/chrome/installer/util/delete_after_reboot_helper.cc b/chrome/installer/util/delete_after_reboot_helper.cc index 5131b1d58b..fb7956ed26 100644 --- a/chrome/installer/util/delete_after_reboot_helper.cc +++ b/chrome/installer/util/delete_after_reboot_helper.cc @@ -30,20 +30,19 @@ namespace { // Returns true if this directory name is 'safe' for deletion (doesn't contain // "..", doesn't specify a drive root) -bool IsSafeDirectoryNameForDeletion(const wchar_t* dir_name) { - DCHECK(dir_name); - +bool IsSafeDirectoryNameForDeletion(const base::FilePath& dir_name) { // empty name isn't allowed - if (!(dir_name && *dir_name)) + if (dir_name.empty()) return false; // require a character other than \/:. after the last : // disallow anything with ".." bool ok = false; - for (const wchar_t* s = dir_name; *s; ++s) { + const wchar_t* dir_name_str = dir_name.value().c_str(); + for (const wchar_t* s = dir_name_str; *s; ++s) { if (*s != L'\\' && *s != L'/' && *s != L':' && *s != L'.') ok = true; - if (*s == L'.' && s > dir_name && *(s - 1) == L'.') + if (*s == L'.' && s > dir_name_str && *(s - 1) == L'.') return false; if (*s == L':') ok = false; @@ -54,22 +53,23 @@ bool IsSafeDirectoryNameForDeletion(const wchar_t* dir_name) { } // end namespace // Must only be called for regular files or directories that will be empty. -bool ScheduleFileSystemEntityForDeletion(const wchar_t* path) { +bool ScheduleFileSystemEntityForDeletion(const base::FilePath& path) { // Check if the file exists, return false if not. WIN32_FILE_ATTRIBUTE_DATA attrs = {0}; - if (!::GetFileAttributesEx(path, ::GetFileExInfoStandard, &attrs)) { - PLOG(WARNING) << path << " does not exist."; + if (!::GetFileAttributesEx(path.value().c_str(), + ::GetFileExInfoStandard, &attrs)) { + PLOG(WARNING) << path.value() << " does not exist."; return false; } DWORD flags = MOVEFILE_DELAY_UNTIL_REBOOT; - if (!base::DirectoryExists(base::FilePath::FromWStringHack(path))) { + if (!base::DirectoryExists(path)) { // This flag valid only for files flags |= MOVEFILE_REPLACE_EXISTING; } - if (!::MoveFileEx(path, NULL, flags)) { - PLOG(ERROR) << "Could not schedule " << path << " for deletion."; + if (!::MoveFileEx(path.value().c_str(), NULL, flags)) { + PLOG(ERROR) << "Could not schedule " << path.value() << " for deletion."; return false; } @@ -77,51 +77,53 @@ bool ScheduleFileSystemEntityForDeletion(const wchar_t* path) { // Useful debugging code to track down what files are in use. if (flags & MOVEFILE_REPLACE_EXISTING) { // Attempt to open the file exclusively. - HANDLE file = ::CreateFileW(path, GENERIC_READ | GENERIC_WRITE, 0, NULL, - OPEN_EXISTING, 0, NULL); + HANDLE file = ::CreateFileW(path.value().c_str(), + GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, 0, NULL); if (file != INVALID_HANDLE_VALUE) { - LOG(INFO) << " file not in use: " << path; + LOG(INFO) << " file not in use: " << path.value(); ::CloseHandle(file); } else { - PLOG(INFO) << " file in use (or not found?): " << path; + PLOG(INFO) << " file in use (or not found?): " << path.value(); } } #endif - VLOG(1) << "Scheduled for deletion: " << path; + VLOG(1) << "Scheduled for deletion: " << path.value(); return true; } -bool ScheduleDirectoryForDeletion(const wchar_t* dir_name) { +bool ScheduleDirectoryForDeletion(const base::FilePath& dir_name) { if (!IsSafeDirectoryNameForDeletion(dir_name)) { - LOG(ERROR) << "Unsafe directory name for deletion: " << dir_name; + LOG(ERROR) << "Unsafe directory name for deletion: " << dir_name.value(); return false; } // Make sure the directory exists (it is ok if it doesn't) - DWORD dir_attributes = ::GetFileAttributes(dir_name); + DWORD dir_attributes = ::GetFileAttributes(dir_name.value().c_str()); if (dir_attributes == INVALID_FILE_ATTRIBUTES) { if (::GetLastError() == ERROR_FILE_NOT_FOUND) { return true; // Ok if directory is missing } else { - PLOG(ERROR) << "Could not GetFileAttributes for " << dir_name; + PLOG(ERROR) << "Could not GetFileAttributes for " << dir_name.value(); return false; } } // Confirm it is a directory if (!(dir_attributes & FILE_ATTRIBUTE_DIRECTORY)) { - LOG(ERROR) << "Scheduled directory is not a directory: " << dir_name; + LOG(ERROR) << "Scheduled directory is not a directory: " + << dir_name.value(); return false; } // First schedule all the normal files for deletion. { bool success = true; - base::FileEnumerator file_enum(base::FilePath(dir_name), false, + base::FileEnumerator file_enum(dir_name, false, base::FileEnumerator::FILES); for (base::FilePath file = file_enum.Next(); !file.empty(); file = file_enum.Next()) { - success = ScheduleFileSystemEntityForDeletion(file.value().c_str()); + success = ScheduleFileSystemEntityForDeletion(file); if (!success) { LOG(ERROR) << "Failed to schedule file for deletion: " << file.value(); return false; @@ -132,11 +134,11 @@ bool ScheduleDirectoryForDeletion(const wchar_t* dir_name) { // Then recurse to all the subdirectories. { bool success = true; - base::FileEnumerator dir_enum(base::FilePath(dir_name), false, + base::FileEnumerator dir_enum(dir_name, false, base::FileEnumerator::DIRECTORIES); for (base::FilePath sub_dir = dir_enum.Next(); !sub_dir.empty(); sub_dir = dir_enum.Next()) { - success = ScheduleDirectoryForDeletion(sub_dir.value().c_str()); + success = ScheduleDirectoryForDeletion(sub_dir); if (!success) { LOG(ERROR) << "Failed to schedule subdirectory for deletion: " << sub_dir.value(); @@ -146,8 +148,10 @@ bool ScheduleDirectoryForDeletion(const wchar_t* dir_name) { } // Now schedule the empty directory itself - if (!ScheduleFileSystemEntityForDeletion(dir_name)) - LOG(ERROR) << "Failed to schedule directory for deletion: " << dir_name; + if (!ScheduleFileSystemEntityForDeletion(dir_name)) { + LOG(ERROR) << "Failed to schedule directory for deletion: " + << dir_name.value(); + } return true; } @@ -240,9 +244,10 @@ void StringArrayToMultiSZBytes(const std::vector<PendingMove>& strings, DCHECK(++write_pointer == end_pointer); } -std::wstring GetShortPathName(const wchar_t* path) { +base::FilePath GetShortPathName(const base::FilePath& path) { std::wstring short_path; - DWORD length = GetShortPathName(path, WriteInto(&short_path, MAX_PATH), + DWORD length = GetShortPathName(path.value().c_str(), + WriteInto(&short_path, MAX_PATH), MAX_PATH); DWORD last_error = ::GetLastError(); DLOG_IF(WARNING, length == 0 && last_error != ERROR_PATH_NOT_FOUND) @@ -255,11 +260,10 @@ std::wstring GetShortPathName(const wchar_t* path) { } short_path.resize(length); - return short_path; + return base::FilePath(short_path); } -HRESULT GetPendingMovesValue( - std::vector<PendingMove>* pending_moves) { +HRESULT GetPendingMovesValue(std::vector<PendingMove>* pending_moves) { DCHECK(pending_moves); pending_moves->clear(); @@ -319,9 +323,10 @@ HRESULT GetPendingMovesValue( return hr; } -bool MatchPendingDeletePath(const std::wstring& short_form_needle, - const std::wstring& reg_path) { - std::wstring match_path(reg_path); // Stores the path stored in each entry. +bool MatchPendingDeletePath(const base::FilePath& short_form_needle, + const base::FilePath& reg_path) { + // Stores the path stored in each entry. + std::wstring match_path(reg_path.value()); // First chomp the prefix since that will mess up GetShortPathName. std::wstring prefix(L"\\??\\"); @@ -329,17 +334,16 @@ bool MatchPendingDeletePath(const std::wstring& short_form_needle, match_path = match_path.substr(4); // Get the short path name of the entry. - std::wstring short_match_path(GetShortPathName(match_path.c_str())); + base::FilePath short_match_path(GetShortPathName(base::FilePath(match_path))); // Now compare the paths. If it isn't one we're looking for, add it // to the list to keep. - return StartsWith(short_match_path, short_form_needle, false); + return StartsWith(short_match_path.value(), short_form_needle.value(), false); } // Removes all pending moves for the given |directory| and any contained // files or subdirectories. Returns true on success -bool RemoveFromMovesPendingReboot(const wchar_t* directory) { - DCHECK(directory); +bool RemoveFromMovesPendingReboot(const base::FilePath& directory) { std::vector<PendingMove> pending_moves; HRESULT hr = GetPendingMovesValue(&pending_moves); if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) { @@ -352,12 +356,13 @@ bool RemoveFromMovesPendingReboot(const wchar_t* directory) { } // Get the short form of |directory| and use that to match. - std::wstring short_directory(GetShortPathName(directory)); + base::FilePath short_directory(GetShortPathName(directory)); std::vector<PendingMove> strings_to_keep; for (std::vector<PendingMove>::const_iterator iter(pending_moves.begin()); - iter != pending_moves.end(); iter++) { - if (!MatchPendingDeletePath(short_directory, iter->first)) { + iter != pending_moves.end(); ++iter) { + base::FilePath move_path(iter->first); + if (!MatchPendingDeletePath(short_directory, move_path)) { // This doesn't match the deletions we are looking for. Preserve // this string pair, making sure that it is in fact a pair. strings_to_keep.push_back(*iter); diff --git a/chrome/installer/util/delete_after_reboot_helper.h b/chrome/installer/util/delete_after_reboot_helper.h index 6d59b26fb6..55cc52205a 100644 --- a/chrome/installer/util/delete_after_reboot_helper.h +++ b/chrome/installer/util/delete_after_reboot_helper.h @@ -13,6 +13,10 @@ #include <windows.h> +namespace base { +class FilePath; +} + // Used by the unit tests. extern const wchar_t kSessionManagerKey[]; extern const wchar_t kPendingFileRenameOps[]; @@ -20,14 +24,14 @@ extern const wchar_t kPendingFileRenameOps[]; typedef std::pair<std::wstring, std::wstring> PendingMove; // Attempts to schedule only the item at path for deletion. -bool ScheduleFileSystemEntityForDeletion(const wchar_t* path); +bool ScheduleFileSystemEntityForDeletion(const base::FilePath& path); // Attempts to recursively schedule the directory for deletion. -bool ScheduleDirectoryForDeletion(const wchar_t* dir_name); +bool ScheduleDirectoryForDeletion(const base::FilePath& dir_name); // Removes all pending moves that are registered for |directory| and all // elements contained in |directory|. -bool RemoveFromMovesPendingReboot(const wchar_t* directory); +bool RemoveFromMovesPendingReboot(const base::FilePath& directory); // Retrieves the list of pending renames from the registry and returns a vector // containing pairs of strings that represent the operations. If the list @@ -39,8 +43,8 @@ HRESULT GetPendingMovesValue(std::vector<PendingMove>* pending_moves); // |short_form_needle| is a file system path that has been shortened by // GetShortPathName and |reg_path| is a path stored in the // PendingFileRenameOperations key. -bool MatchPendingDeletePath(const std::wstring& short_form_needle, - const std::wstring& reg_path); +bool MatchPendingDeletePath(const base::FilePath& short_form_needle, + const base::FilePath& reg_path); // Converts the strings found in |buffer| to a list of PendingMoves that is // returned in |value|. @@ -63,9 +67,9 @@ void StringArrayToMultiSZBytes(const std::vector<PendingMove>& strings, std::vector<char>* buffer); // A helper function for the win32 GetShortPathName that more conveniently -// returns a correctly sized wstring. Note that if |path| is not present on the -// file system then GetShortPathName will return |path| unchanged, unlike the -// win32 GetShortPathName which will return an error. -std::wstring GetShortPathName(const wchar_t* path); +// returns a FilePath. Note that if |path| is not present on the file system +// then GetShortPathName will return |path| unchanged, unlike the win32 +// GetShortPathName which will return an error. +base::FilePath GetShortPathName(const base::FilePath& path); #endif // CHROME_INSTALLER_UTIL_DELETE_AFTER_REBOOT_HELPER_H_ diff --git a/chrome/installer/util/delete_after_reboot_helper_unittest.cc b/chrome/installer/util/delete_after_reboot_helper_unittest.cc index 7fb7360c2d..c97cecdfa4 100644 --- a/chrome/installer/util/delete_after_reboot_helper_unittest.cc +++ b/chrome/installer/util/delete_after_reboot_helper_unittest.cc @@ -96,7 +96,8 @@ class DeleteAfterRebootHelperTest : public testing::Test { base::FilePath temp_subdir_; base::FilePath temp_subdir_file_; }; -} + +} // namespace TEST_F(DeleteAfterRebootHelperTest, TestStringListToMultiSZConversions) { struct StringTest { @@ -143,22 +144,23 @@ TEST_F(DeleteAfterRebootHelperTest, TestFileDeleteScheduleAndUnschedule) { return; } - EXPECT_TRUE(ScheduleDirectoryForDeletion(temp_dir_.value().c_str())); + EXPECT_TRUE(ScheduleDirectoryForDeletion(temp_dir_)); std::vector<PendingMove> pending_moves; EXPECT_TRUE(SUCCEEDED(GetPendingMovesValue(&pending_moves))); // We should see, somewhere in this key, deletion writs for // temp_file_, temp_subdir_file_, temp_subdir_ and temp_dir_ in that order. - EXPECT_TRUE(pending_moves.size() > 3); + EXPECT_GT(pending_moves.size(), 3U); // Get the short form of temp_file_ and use that to match. - std::wstring short_temp_file(GetShortPathName(temp_file_.value().c_str())); + base::FilePath short_temp_file(GetShortPathName(temp_file_)); // Scan for the first expected delete. std::vector<PendingMove>::const_iterator iter(pending_moves.begin()); for (; iter != pending_moves.end(); iter++) { - if (MatchPendingDeletePath(short_temp_file, iter->first)) + base::FilePath move_path(iter->first); + if (MatchPendingDeletePath(short_temp_file, move_path)) break; } @@ -168,21 +170,22 @@ TEST_F(DeleteAfterRebootHelperTest, TestFileDeleteScheduleAndUnschedule) { for (int i = 0; i < arraysize(expected_paths); ++i) { EXPECT_FALSE(iter == pending_moves.end()); if (iter != pending_moves.end()) { - std::wstring short_path_name( - GetShortPathName(expected_paths[i].value().c_str())); - EXPECT_TRUE(MatchPendingDeletePath(short_path_name, iter->first)); + base::FilePath short_path_name(GetShortPathName(expected_paths[i])); + base::FilePath move_path(iter->first); + EXPECT_TRUE(MatchPendingDeletePath(short_path_name, move_path)); ++iter; } } // Test that we can remove the pending deletes. - EXPECT_TRUE(RemoveFromMovesPendingReboot(temp_dir_.value().c_str())); + EXPECT_TRUE(RemoveFromMovesPendingReboot(temp_dir_)); HRESULT hr = GetPendingMovesValue(&pending_moves); EXPECT_TRUE(hr == S_OK || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); std::vector<PendingMove>::const_iterator check_iter(pending_moves.begin()); for (; check_iter != pending_moves.end(); ++check_iter) { - EXPECT_FALSE(MatchPendingDeletePath(short_temp_file, check_iter->first)); + base::FilePath move_path(check_iter->first); + EXPECT_FALSE(MatchPendingDeletePath(short_temp_file, move_path)); } } @@ -195,7 +198,7 @@ TEST_F(DeleteAfterRebootHelperTest, TestFileDeleteSchedulingWithActualDeletes) { GetPendingMovesValue(&initial_pending_moves); size_t initial_pending_moves_size = initial_pending_moves.size(); - EXPECT_TRUE(ScheduleDirectoryForDeletion(temp_dir_.value().c_str())); + EXPECT_TRUE(ScheduleDirectoryForDeletion(temp_dir_)); std::vector<PendingMove> pending_moves; EXPECT_TRUE(SUCCEEDED(GetPendingMovesValue(&pending_moves))); @@ -205,12 +208,13 @@ TEST_F(DeleteAfterRebootHelperTest, TestFileDeleteSchedulingWithActualDeletes) { EXPECT_TRUE(pending_moves.size() > 3); // Get the short form of temp_file_ and use that to match. - std::wstring short_temp_file(GetShortPathName(temp_file_.value().c_str())); + base::FilePath short_temp_file(GetShortPathName(temp_file_)); // Scan for the first expected delete. std::vector<PendingMove>::const_iterator iter(pending_moves.begin()); for (; iter != pending_moves.end(); iter++) { - if (MatchPendingDeletePath(short_temp_file, iter->first)) + base::FilePath move_path(iter->first); + if (MatchPendingDeletePath(short_temp_file, move_path)) break; } @@ -220,9 +224,9 @@ TEST_F(DeleteAfterRebootHelperTest, TestFileDeleteSchedulingWithActualDeletes) { for (int i = 0; i < arraysize(expected_paths); ++i) { EXPECT_FALSE(iter == pending_moves.end()); if (iter != pending_moves.end()) { - std::wstring short_path_name( - GetShortPathName(expected_paths[i].value().c_str())); - EXPECT_TRUE(MatchPendingDeletePath(short_path_name, iter->first)); + base::FilePath short_path_name(GetShortPathName(expected_paths[i])); + base::FilePath move_path(iter->first); + EXPECT_TRUE(MatchPendingDeletePath(short_path_name, move_path)); ++iter; } } @@ -231,7 +235,7 @@ TEST_F(DeleteAfterRebootHelperTest, TestFileDeleteSchedulingWithActualDeletes) { base::DeleteFile(temp_dir_, true); // Test that we can remove the pending deletes. - EXPECT_TRUE(RemoveFromMovesPendingReboot(temp_dir_.value().c_str())); + EXPECT_TRUE(RemoveFromMovesPendingReboot(temp_dir_)); HRESULT hr = GetPendingMovesValue(&pending_moves); EXPECT_TRUE(hr == S_OK || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); @@ -239,7 +243,8 @@ TEST_F(DeleteAfterRebootHelperTest, TestFileDeleteSchedulingWithActualDeletes) { std::vector<PendingMove>::const_iterator check_iter(pending_moves.begin()); for (; check_iter != pending_moves.end(); ++check_iter) { - EXPECT_FALSE(MatchPendingDeletePath(short_temp_file, check_iter->first)); + base::FilePath move_path(check_iter->first); + EXPECT_FALSE(MatchPendingDeletePath(short_temp_file, move_path)); } } diff --git a/chrome/installer/util/self_cleaning_temp_dir.cc b/chrome/installer/util/self_cleaning_temp_dir.cc index 6426dd9f98..23d3091802 100644 --- a/chrome/installer/util/self_cleaning_temp_dir.cc +++ b/chrome/installer/util/self_cleaning_temp_dir.cc @@ -84,7 +84,7 @@ bool SelfCleaningTempDir::Delete() { LOG(WARNING) << "Failed to delete temporary directory " << path().value() << ". Scheduling for deletion at reboot."; schedule_deletes = true; - if (!ScheduleDirectoryForDeletion(path().value().c_str())) + if (!ScheduleDirectoryForDeletion(path())) return false; // Entirely unexpected failure (Schedule logs the reason). } @@ -101,7 +101,7 @@ bool SelfCleaningTempDir::Delete() { if (schedule_deletes) { // Ignore the return code. If we fail to schedule, go ahead and add the // other parent directories anyway. - ScheduleFileSystemEntityForDeletion(next_dir.value().c_str()); + ScheduleFileSystemEntityForDeletion(next_dir); } if (next_dir == base_dir_) break; // We just processed the topmost directory we created. diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc index c74754770c..19a5feb5a9 100644 --- a/chrome/installer/util/shell_util.cc +++ b/chrome/installer/util/shell_util.cc @@ -697,8 +697,7 @@ bool ElevateAndRegisterChrome(BrowserDistribution* dist, DCHECK(InstallUtil::IsPerUserInstall(chrome_exe.c_str())); DCHECK_LT(base::win::GetVersion(), base::win::VERSION_WIN8); base::FilePath exe_path = - base::FilePath::FromWStringHack(chrome_exe).DirName() - .Append(installer::kSetupExe); + base::FilePath(chrome_exe).DirName().Append(installer::kSetupExe); if (!base::PathExists(exe_path)) { HKEY reg_root = InstallUtil::IsPerUserInstall(chrome_exe.c_str()) ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; @@ -1696,6 +1695,8 @@ string16 ShellUtil::BuildAppModelId( } ShellUtil::DefaultState ShellUtil::GetChromeDefaultState() { + if (!BrowserDistribution::GetDistribution()->CanSetAsDefault()) + return NOT_DEFAULT; // When we check for default browser we don't necessarily want to count file // type handlers and icons as having changed the default browser status, // since the user may have changed their shell settings to cause HTML files @@ -1711,6 +1712,8 @@ ShellUtil::DefaultState ShellUtil::GetChromeDefaultState() { ShellUtil::DefaultState ShellUtil::GetChromeDefaultProtocolClientState( const string16& protocol) { + if (!BrowserDistribution::GetDistribution()->CanSetAsDefault()) + return NOT_DEFAULT; if (protocol.empty()) return UNKNOWN_DEFAULT; |