Chromium Code Reviews| Index: chrome/installer/setup/uninstall.cc |
| diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc |
| index 5f7578b0608f00f4b84a3810fe879259f849538d..1c18b97c468f79c3c6d260342de94393d36ebd93 100644 |
| --- a/chrome/installer/setup/uninstall.cc |
| +++ b/chrome/installer/setup/uninstall.cc |
| @@ -49,6 +49,23 @@ using installer::MasterPreferences; |
| namespace { |
| +// Avoid leaving behind a Temp dir. If one exists, ask SelfCleaningTempDir to |
| +// clean it up for us. This may involve scheduling it for deletion after |
| +// reboot. Don't report that a reboot is required in this case, however. |
| +// TODO(erikwright): Shouldn't this still lead to |
| +// ScheduleParentAndGrandparentForDeletion? |
|
tommi (sloooow) - chröme
2012/07/12 08:11:31
if so, file a bug for tracking?
erikwright (departed)
2012/07/16 20:13:11
I don't know the answer. I'll ask Greg OOB.
|
| +void DeleteInstallTempDir(const FilePath& target_path) { |
| + FilePath temp_path(target_path.DirName().Append(installer::kInstallTempDir)); |
| + if (file_util::DirectoryExists(temp_path)) { |
| + installer::SelfCleaningTempDir temp_dir; |
| + if (!temp_dir.Initialize(target_path.DirName(), |
| + installer::kInstallTempDir) || |
| + !temp_dir.Delete()) { |
| + LOG(ERROR) << "Failed to delete temp dir " << temp_path.value(); |
| + } |
| + } |
| +} |
| + |
| // Makes appropriate changes to the Google Update "ap" value in the registry. |
| // Specifically, removes the flags associated with this product ("-chrome" or |
| // "-chromeframe[-readymode]") from the "ap" values for all other |
| @@ -72,16 +89,17 @@ void ProcessGoogleUpdateItems( |
| // Apply the new channel value to all other products and to the multi package. |
| if (modified) { |
| - BrowserDistribution::Type other_dist_types[] = { |
| - (distribution->GetType() == BrowserDistribution::CHROME_BROWSER) ? |
| - BrowserDistribution::CHROME_FRAME : |
| - BrowserDistribution::CHROME_BROWSER, |
| - BrowserDistribution::CHROME_BINARIES |
| - }; |
| + std::vector<BrowserDistribution::Type> other_dist_types; |
| + for (size_t i = 0; i < BrowserDistribution::kNumProductTypes; ++i) { |
| + if (distribution->GetType() != BrowserDistribution::kProductTypes[i]) |
| + other_dist_types.push_back(BrowserDistribution::kProductTypes[i]); |
| + } |
| + |
| scoped_ptr<WorkItemList> |
| update_list(WorkItem::CreateNoRollbackWorkItemList()); |
| - for (int i = 0; i < arraysize(other_dist_types); ++i) { |
| + for (size_t i = 0; i < other_dist_types.size(); ++i) { |
| + // TODO(erikwright): Who updates the ap value for the binaries? |
| BrowserDistribution::Type other_dist_type = other_dist_types[i]; |
| product_state = |
| original_state.GetProductState(system_level, other_dist_type); |
| @@ -396,44 +414,80 @@ bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state, |
| return ret; |
| } |
| -DeleteResult DeleteFilesAndFolders(const InstallerState& installer_state, |
| - const Version& installed_version) { |
| +DeleteResult DeleteAppHostFilesAndFolders(const InstallerState& installer_state, |
| + const Version& installed_version) { |
| const FilePath& target_path = installer_state.target_path(); |
| if (target_path.empty()) { |
| - LOG(ERROR) << "DeleteFilesAndFolders: no installation destination path."; |
| + LOG(ERROR) << "DeleteAppHostFilesAndFolders: no installation destination " |
| + << "path."; |
| return DELETE_FAILED; // Nothing else we can do to uninstall, so we return. |
| } |
| + DeleteInstallTempDir(target_path); |
| + |
| DeleteResult result = DELETE_SUCCEEDED; |
| - // Avoid leaving behind a Temp dir. If one exists, ask SelfCleaningTempDir to |
| - // clean it up for us. This may involve scheduling it for deletion after |
| - // reboot. Don't report that a reboot is required in this case, however. |
| - FilePath temp_path(target_path.DirName().Append(kInstallTempDir)); |
| - if (file_util::DirectoryExists(temp_path)) { |
| - installer::SelfCleaningTempDir temp_dir; |
| - if (!temp_dir.Initialize(target_path.DirName(), kInstallTempDir) || |
| - !temp_dir.Delete()) { |
| - LOG(ERROR) << "Failed to delete temp dir " << temp_path.value(); |
| - } |
| + FilePath app_host_exe(target_path.Append(installer::kChromeAppHostExe)); |
| + if (!file_util::Delete(app_host_exe, false)) { |
| + result = DELETE_FAILED; |
| + LOG(ERROR) << "Failed to delete path: " << app_host_exe.value(); |
| + } else { |
| + DeleteEmptyParentDir(target_path); |
| } |
| - VLOG(1) << "Deleting install path " << target_path.value(); |
| - if (!file_util::Delete(target_path, true)) { |
| - LOG(ERROR) << "Failed to delete folder (1st try): " << target_path.value(); |
| - if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { |
| - // We don't try killing Chrome processes for Chrome Frame builds since |
| - // that is unlikely to help. Instead, schedule files for deletion and |
| - // return a value that will trigger a reboot prompt. |
| - ScheduleDirectoryForDeletion(target_path.value().c_str()); |
| - result = DELETE_REQUIRES_REBOOT; |
| - } else { |
| - // Try closing any running chrome processes and deleting files once again. |
| - CloseAllChromeProcesses(); |
| - if (!file_util::Delete(target_path, true)) { |
| - LOG(ERROR) << "Failed to delete folder (2nd try): " |
| - << target_path.value(); |
| - result = DELETE_FAILED; |
| + return result; |
| +} |
| + |
| +DeleteResult DeleteChromeFilesAndFolders(const InstallerState& installer_state, |
| + const Version& installed_version) { |
| + const FilePath& target_path = installer_state.target_path(); |
| + if (target_path.empty()) { |
| + LOG(ERROR) << "DeleteChromeFilesAndFolders: no installation destination " |
| + << "path."; |
| + return DELETE_FAILED; // Nothing else we can do to uninstall, so we return. |
| + } |
| + |
| + DeleteInstallTempDir(target_path); |
| + |
| + DeleteResult result = DELETE_SUCCEEDED; |
| + |
| + using file_util::FileEnumerator; |
| + FileEnumerator file_enumerator( |
| + target_path, |
| + false, |
| + static_cast<FileEnumerator::FileType>(FileEnumerator::FILES | |
| + FileEnumerator::DIRECTORIES)); |
| + while (true) { |
| + FilePath to_delete(file_enumerator.Next()); |
| + if (to_delete.empty()) |
| + break; |
| + if (to_delete.BaseName().value() == installer::kChromeAppHostExe) |
| + continue; |
| + |
| + VLOG(1) << "Deleting install path " << target_path.value(); |
| + if (!file_util::Delete(to_delete, true)) { |
| + LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value(); |
| + if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { |
| + // We don't try killing Chrome processes for Chrome Frame builds since |
| + // that is unlikely to help. Instead, schedule files for deletion and |
| + // return a value that will trigger a reboot prompt. |
| + FileEnumerator::FindInfo find_info; |
| + file_enumerator.GetFindInfo(&find_info); |
| + if (FileEnumerator::IsDirectory(find_info)) |
| + ScheduleDirectoryForDeletion(to_delete.value().c_str()); |
| + else |
| + ScheduleFileSystemEntityForDeletion(to_delete.value().c_str()); |
| + result = DELETE_REQUIRES_REBOOT; |
| + } else { |
| + // Try closing any running Chrome processes and deleting files once |
| + // again. |
| + CloseAllChromeProcesses(); |
| + if (!file_util::Delete(to_delete, true)) { |
| + LOG(ERROR) << "Failed to delete path (2nd try): " |
| + << to_delete.value(); |
| + result = DELETE_FAILED; |
| + break; |
| + } |
| } |
| } |
| } |
| @@ -497,7 +551,7 @@ bool ShouldDeleteProfile(const InstallerState& installer_state, |
| // UI to prompt otherwise and the profile stores no useful data anyway) |
| // unless they are managed by MSI. MSI uninstalls will explicitly include |
| // the --delete-profile flag to distinguish them from MSI upgrades. |
| - if (!product.is_chrome() && !installer_state.is_msi()) { |
| + if (product.is_chrome_frame() && !installer_state.is_msi()) { |
| should_delete = true; |
| } else { |
| should_delete = |
| @@ -840,7 +894,7 @@ InstallStatus UninstallProduct(const InstallationState& original_state, |
| ProcessDelegateExecuteWorkItems(installer_state, product); |
| - if (!is_chrome) { |
| + if (product.is_chrome_frame()) { |
| ProcessChromeFrameWorkItems(original_state, installer_state, setup_path, |
| product); |
| } |
| @@ -888,7 +942,7 @@ InstallStatus UninstallProduct(const InstallationState& original_state, |
| unreg_work_item_list->Do(); |
| } |
| - if (!is_chrome) |
| + if (product.is_chrome_frame()) |
| ProcessIELowRightsPolicyWorkItems(installer_state); |
| } |
| @@ -908,41 +962,25 @@ InstallStatus UninstallProduct(const InstallationState& original_state, |
| ret = installer::UNINSTALL_SUCCESSFUL; |
| // When deleting files, we must make sure that we're either a "single" |
| - // (aka non-multi) installation or, in the case of multi, that no other |
| - // "multi" products share the binaries we are about to delete. |
| + // (aka non-multi) installation or we are the Chrome Binaries. |
| - bool can_delete_files = true; |
| - if (installer_state.is_multi_install()) { |
| - ProductState prod_state; |
| - for (size_t i = 0; i < BrowserDistribution::kNumProductTypes; ++i) { |
| - if (prod_state.Initialize(installer_state.system_install(), |
| - BrowserDistribution::kProductTypes[i]) && |
| - prod_state.is_multi_install()) { |
| - can_delete_files = false; |
| - break; |
| - } |
| - } |
| - LOG(INFO) << (can_delete_files ? "Shared binaries will be deleted." : |
| - "Shared binaries still in use."); |
| - if (can_delete_files) { |
| - BrowserDistribution* multi_dist = |
| - installer_state.multi_package_binaries_distribution(); |
| - InstallUtil::DeleteRegistryKey(reg_root, multi_dist->GetVersionKey()); |
| - } |
| - } |
| - |
| - FilePath backup_state_file(BackupLocalStateFile( |
| - GetLocalStateFolder(product))); |
| + FilePath backup_state_file( |
| + BackupLocalStateFile(GetLocalStateFolder(product))); |
| DeleteResult delete_result = DELETE_SUCCEEDED; |
| - if (can_delete_files) { |
| + |
| + if (product.is_chrome_app_host()) { |
| + DeleteAppHostFilesAndFolders(installer_state, product_state->version()); |
| + } else if (!installer_state.is_multi_install() || |
| + product.is_chrome_binaries()) { |
| + |
| // In order to be able to remove the folder in which we're running, we |
| // need to move setup.exe out of the install folder. |
| // TODO(tommi): What if the temp folder is on a different volume? |
| MoveSetupOutOfInstallFolder(installer_state, setup_path, |
| product_state->version()); |
| - delete_result = DeleteFilesAndFolders(installer_state, |
| - product_state->version()); |
| + delete_result = DeleteChromeFilesAndFolders(installer_state, |
| + product_state->version()); |
| } |
| if (delete_profile) |
| @@ -955,7 +993,7 @@ InstallStatus UninstallProduct(const InstallationState& original_state, |
| } |
| if (!force_uninstall) { |
| - VLOG(1) << "Uninstallation complete. Launching Uninstall survey."; |
| + VLOG(1) << "Uninstallation complete. Launching post-uninstall operations."; |
| browser_dist->DoPostUninstallOperations(product_state->version(), |
| backup_state_file, distribution_data); |
| } |