diff options
author | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-18 14:54:50 +0000 |
---|---|---|
committer | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-18 14:54:50 +0000 |
commit | bdddb676d97056742f83d280843ff099768b07f3 (patch) | |
tree | 42b9dc58c818226653c2388d7716ec729e3836cf /chrome | |
parent | 7e91c5937f1f9587acda5a0a732d07bed8cafe46 (diff) | |
download | chromium_src-bdddb676d97056742f83d280843ff099768b07f3.zip chromium_src-bdddb676d97056742f83d280843ff099768b07f3.tar.gz chromium_src-bdddb676d97056742f83d280843ff099768b07f3.tar.bz2 |
Temp dir cleanup:
- use ScopedTempDir in work items that need backup space for rollback
- all work items that need backup space take a parent dir in which they create temp dirs
- use ScopedTempDir in a few other places
- renamed some parameters in certain functions so that the same name is used everywhere
While I was at it, I couldn't help but replace Append(UTF8ToWide(version.GetString())) with the more pleasing AppendASCII(version.GetString())
BUG=70368
TEST=existing tests in installer_util_unittests cover the changes
Review URL: http://codereview.chromium.org/6538025
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75392 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
21 files changed, 296 insertions, 262 deletions
diff --git a/chrome/installer/setup/chrome_frame_quick_enable.cc b/chrome/installer/setup/chrome_frame_quick_enable.cc index 22b4615..d100392 100644 --- a/chrome/installer/setup/chrome_frame_quick_enable.cc +++ b/chrome/installer/setup/chrome_frame_quick_enable.cc @@ -7,6 +7,7 @@ #include <windows.h> #include "base/logging.h" +#include "base/scoped_temp_dir.h" #include "base/string_util.h" #include "base/win/registry.h" #include "chrome/installer/setup/install_worker.h" @@ -79,6 +80,11 @@ InstallStatus ChromeFrameQuickEnable(const InstallationState& machine_state, LOG(ERROR) << "AddProduct failed"; status = INSTALL_FAILED; } else { + ScopedTempDir temp_path; + if (!temp_path.CreateUniqueTempDir()) { + PLOG(ERROR) << "Failed to create Temp directory"; + return INSTALL_FAILED; + } scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList()); const ProductState* chrome_state = machine_state.GetProductState(installer_state->system_install(), @@ -106,7 +112,7 @@ InstallStatus ChromeFrameQuickEnable(const InstallationState& machine_state, const Version* opv = chrome_state->old_version(); AppendPostInstallTasks(*installer_state, setup_path, new_chrome_exe, opv, - new_version, item_list.get()); + new_version, temp_path.path(), item_list.get()); // Before updating the channel values, add Chrome back to the mix so that // all multi-installed products' channel values get updated. diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc index d9b55fe..e9b394b 100644 --- a/chrome/installer/setup/install.cc +++ b/chrome/installer/setup/install.cc @@ -57,30 +57,6 @@ void AddChromeToMediaPlayerList() { LOG(ERROR) << "Could not add Chrome to media player inclusion list."; } -void AddInstallerCopyTasks(const InstallerState& installer_state, - const FilePath& setup_path, - const FilePath& archive_path, - const FilePath& temp_path, - const Version& new_version, - WorkItemList* install_list) { - DCHECK(install_list); - FilePath installer_dir(installer_state.GetInstallerDirectory(new_version)); - install_list->AddCreateDirWorkItem(installer_dir); - - FilePath exe_dst(installer_dir.Append(setup_path.BaseName())); - FilePath archive_dst(installer_dir.Append(archive_path.BaseName())); - - install_list->AddCopyTreeWorkItem(setup_path.value(), exe_dst.value(), - temp_path.value(), WorkItem::ALWAYS); - if (installer_state.system_install()) { - install_list->AddCopyTreeWorkItem(archive_path.value(), archive_dst.value(), - temp_path.value(), WorkItem::ALWAYS); - } else { - install_list->AddMoveTreeWorkItem(archive_path.value(), archive_dst.value(), - temp_path.value()); - } -} - // Copy master preferences file provided to installer, in the same folder // as chrome.exe so Chrome first run can find it. This function will be called // only on the first install of Chrome. @@ -263,8 +239,8 @@ void RegisterChromeOnMachine(const InstallerState& installer_state, // to Chrome install folder after install is complete // src_path: the path that contains a complete and unpacked Chrome package // to be installed. -// temp_dir: the path of working directory used during installation. This path -// does not need to exist. +// temp_path: the path of working directory used during installation. This path +// does not need to exist. // new_version: new Chrome version that needs to be installed // current_version: returns the current active version (if any) // @@ -281,7 +257,7 @@ installer::InstallStatus InstallNewVersion( const FilePath& setup_path, const FilePath& archive_path, const FilePath& src_path, - const FilePath& temp_dir, + const FilePath& temp_path, const Version& new_version, scoped_ptr<Version>* current_version) { DCHECK(current_version); @@ -294,7 +270,7 @@ installer::InstallStatus InstallNewVersion( setup_path, archive_path, src_path, - temp_dir, + temp_path, new_version, current_version, install_list.get()); @@ -425,7 +401,7 @@ InstallStatus InstallOrUpdateProduct( } installer_state.RemoveOldVersionDirectories(existing_version.get() ? - *existing_version.get() : new_version); + *existing_version.get() : new_version, install_temp_path); } return result; diff --git a/chrome/installer/setup/install_worker.cc b/chrome/installer/setup/install_worker.cc index 46eb559..0717a34 100644 --- a/chrome/installer/setup/install_worker.cc +++ b/chrome/installer/setup/install_worker.cc @@ -79,8 +79,8 @@ void AddRegisterComDllWorkItemsForPackage(const InstallerState& installer_state, // saved state instead of assuming it is the same as the registration list. if (!com_dll_list.empty()) { if (old_version) { - FilePath old_dll_path(installer_state.target_path().Append( - UTF8ToWide(old_version->GetString()))); + FilePath old_dll_path(installer_state.target_path().AppendASCII( + old_version->GetString())); installer::AddRegisterComDllWorkItems(old_dll_path, com_dll_list, @@ -90,8 +90,8 @@ void AddRegisterComDllWorkItemsForPackage(const InstallerState& installer_state, work_item_list); } - FilePath dll_path(installer_state.target_path().Append( - UTF8ToWide(new_version.GetString()))); + FilePath dll_path(installer_state.target_path().AppendASCII( + new_version.GetString())); installer::AddRegisterComDllWorkItems(dll_path, com_dll_list, installer_state.system_install(), @@ -358,6 +358,7 @@ void AddGoogleUpdateWorkItems(const InstallerState& installer_state, void AddDeleteUninstallShortcutsForMSIWorkItems( const InstallerState& installer_state, const Product& product, + const FilePath& temp_path, WorkItemList* work_item_list) { DCHECK(installer_state.is_msi()) << "This must only be called for MSI installations!"; @@ -388,7 +389,7 @@ void AddDeleteUninstallShortcutsForMSIWorkItems( VLOG(1) << "Deleting old uninstall shortcut (if present): " << uninstall_link.value(); WorkItem* delete_link = work_item_list->AddDeleteTreeWorkItem( - uninstall_link); + uninstall_link, temp_path); delete_link->set_ignore_failure(true); delete_link->set_log_message( "Failed to delete old uninstall shortcut."); @@ -409,6 +410,7 @@ bool AppendPostInstallTasks(const InstallerState& installer_state, const FilePath& new_chrome_exe, const Version* current_version, const Version& new_version, + const FilePath& temp_path, WorkItemList* post_install_task_list) { DCHECK(post_install_task_list); @@ -514,6 +516,7 @@ bool AppendPostInstallTasks(const InstallerState& installer_state, // previous non-MSI installations for the same type of install (system or // per user). AddDeleteUninstallShortcutsForMSIWorkItems(installer_state, *product, + temp_path, post_install_task_list); } if (installer_state.is_multi_install()) { @@ -531,7 +534,7 @@ void AddInstallWorkItems(const InstallationState& original_state, const FilePath& setup_path, const FilePath& archive_path, const FilePath& src_path, - const FilePath& temp_dir, + const FilePath& temp_path, const Version& new_version, scoped_ptr<Version>* current_version, WorkItemList* install_list) { @@ -540,7 +543,7 @@ void AddInstallWorkItems(const InstallationState& original_state, const FilePath& target_path = installer_state.target_path(); // A temp directory that work items need and the actual install directory. - install_list->AddCreateDirWorkItem(temp_dir); + install_list->AddCreateDirWorkItem(temp_path); install_list->AddCreateDirWorkItem(target_path); // Delete any new_chrome.exe if present (we will end up creating a new one @@ -548,47 +551,47 @@ void AddInstallWorkItems(const InstallationState& original_state, FilePath new_chrome_exe( target_path.Append(installer::kChromeNewExe)); - install_list->AddDeleteTreeWorkItem(new_chrome_exe); + install_list->AddDeleteTreeWorkItem(new_chrome_exe, temp_path); install_list->AddCopyTreeWorkItem( src_path.Append(installer::kChromeExe).value(), target_path.Append(installer::kChromeExe).value(), - temp_dir.value(), WorkItem::NEW_NAME_IF_IN_USE, new_chrome_exe.value()); + temp_path.value(), WorkItem::NEW_NAME_IF_IN_USE, new_chrome_exe.value()); // Extra executable for 64 bit systems. if (Is64bit()) { install_list->AddCopyTreeWorkItem( src_path.Append(installer::kWowHelperExe).value(), target_path.Append(installer::kWowHelperExe).value(), - temp_dir.value(), WorkItem::ALWAYS); + temp_path.value(), WorkItem::ALWAYS); } // If it is system level install copy the version folder (since we want to // take the permissions of %ProgramFiles% folder) otherwise just move it. if (installer_state.system_install()) { install_list->AddCopyTreeWorkItem( - src_path.Append(UTF8ToWide(new_version.GetString())).value(), - target_path.Append(UTF8ToWide(new_version.GetString())).value(), - temp_dir.value(), WorkItem::ALWAYS); + src_path.AppendASCII(new_version.GetString()).value(), + target_path.AppendASCII(new_version.GetString()).value(), + temp_path.value(), WorkItem::ALWAYS); } else { install_list->AddMoveTreeWorkItem( - src_path.Append(UTF8ToWide(new_version.GetString())).value(), - target_path.Append(UTF8ToWide(new_version.GetString())).value(), - temp_dir.value()); + src_path.AppendASCII(new_version.GetString()).value(), + target_path.AppendASCII(new_version.GetString()).value(), + temp_path.value()); } // Copy the default Dictionaries only if the folder doesn't exist already. install_list->AddCopyTreeWorkItem( src_path.Append(installer::kDictionaries).value(), target_path.Append(installer::kDictionaries).value(), - temp_dir.value(), WorkItem::IF_NOT_PRESENT); + temp_path.value(), WorkItem::IF_NOT_PRESENT); // Delete any old_chrome.exe if present. install_list->AddDeleteTreeWorkItem( - target_path.Append(installer::kChromeOldExe)); + target_path.Append(installer::kChromeOldExe), temp_path); // Copy installer in install directory and // add shortcut in Control Panel->Add/Remove Programs. - AddInstallerCopyTasks(installer_state, setup_path, archive_path, temp_dir, + AddInstallerCopyTasks(installer_state, setup_path, archive_path, temp_path, new_version, install_list); const HKEY root = installer_state.root_key(); @@ -623,6 +626,7 @@ void AddInstallWorkItems(const InstallationState& original_state, new_chrome_exe, current_version->get(), new_version, + temp_path, install_list); } diff --git a/chrome/installer/setup/install_worker.h b/chrome/installer/setup/install_worker.h index 596b367..fd78922 100644 --- a/chrome/installer/setup/install_worker.h +++ b/chrome/installer/setup/install_worker.h @@ -51,6 +51,7 @@ bool AppendPostInstallTasks(const InstallerState& installer_state, const FilePath& new_chrome_exe, const Version* current_version, const Version& new_version, + const FilePath& temp_path, WorkItemList* post_install_task_list); // Builds the complete WorkItemList used to build the set of installation steps @@ -62,14 +63,14 @@ bool AppendPostInstallTasks(const InstallerState& installer_state, // to Chrome install folder after install is complete // src_path: the path that contains a complete and unpacked Chrome package // to be installed. -// temp_dir: the path of working directory used during installation. This path -// does not need to exist. +// temp_path: the path of working directory used during installation. This path +// does not need to exist. void AddInstallWorkItems(const InstallationState& original_state, const InstallerState& installer_state, const FilePath& setup_path, const FilePath& archive_path, const FilePath& src_path, - const FilePath& temp_dir, + const FilePath& temp_path, const Version& new_version, scoped_ptr<Version>* current_version, WorkItemList* install_list); diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index 6377114..b34759e 100644 --- a/chrome/installer/setup/setup_main.cc +++ b/chrome/installer/setup/setup_main.cc @@ -16,6 +16,7 @@ #include "base/file_version_info.h" #include "base/path_service.h" #include "base/process_util.h" +#include "base/scoped_temp_dir.h" #include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" @@ -114,8 +115,8 @@ DWORD UnPackArchive(const FilePath& archive, return installer::CHROME_NOT_INSTALLED; } - FilePath existing_archive(installer_state.target_path().Append( - UTF8ToWide(archive_version->GetString()))); + FilePath existing_archive(installer_state.target_path().AppendASCII( + archive_version->GetString())); existing_archive = existing_archive.Append(installer::kInstallerDir); existing_archive = existing_archive.Append(installer::kChromeArchive); if (int i = installer::ApplyDiffPatch(FilePath(existing_archive), @@ -142,23 +143,23 @@ installer::InstallStatus RenameChromeExecutables( const InstallerState& installer_state) { const FilePath &target_path = installer_state.target_path(); FilePath chrome_exe(target_path.Append(installer::kChromeExe)); - FilePath chrome_old_exe(target_path.Append(installer::kChromeOldExe)); FilePath chrome_new_exe(target_path.Append(installer::kChromeNewExe)); - scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList()); - install_list->AddDeleteTreeWorkItem(chrome_old_exe); - FilePath temp_path; - if (!file_util::CreateNewTempDirectory(L"chrome_", &temp_path)) { - LOG(ERROR) << "Failed to create Temp directory " << temp_path.value(); + // TODO(grt): Create the temp dir in the target_path rather than %TMP% and + // friends since it/they may be on another volume, which prevents us from + // moving an in-use chrome.exe out of the way. + ScopedTempDir temp_path; + if (!temp_path.CreateUniqueTempDir()) { + PLOG(ERROR) << "Failed to create Temp directory"; return installer::RENAME_FAILED; } - + scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList()); install_list->AddCopyTreeWorkItem(chrome_new_exe.value(), chrome_exe.value(), - temp_path.value(), + temp_path.path().value(), WorkItem::IF_DIFFERENT, std::wstring()); - install_list->AddDeleteTreeWorkItem(chrome_new_exe); + install_list->AddDeleteTreeWorkItem(chrome_new_exe, temp_path.path()); HKEY reg_root = installer_state.root_key(); const Products& products = installer_state.products(); @@ -179,7 +180,6 @@ installer::InstallStatus RenameChromeExecutables( install_list->Rollback(); ret = installer::RENAME_FAILED; } - file_util::Delete(temp_path, true); return ret; } @@ -479,18 +479,18 @@ installer::InstallStatus InstallProductsHelper( // 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. - FilePath temp_path; - if (!file_util::CreateNewTempDirectory(L"chrome_", &temp_path)) { - LOG(ERROR) << "Could not create temporary path."; + ScopedTempDir temp_path; + if (!temp_path.CreateUniqueTempDir()) { + PLOG(ERROR) << "Could not create temporary path."; InstallUtil::WriteInstallerResult(system_install, installer_state.state_key(), installer::TEMP_DIR_FAILED, IDS_INSTALL_TEMP_DIR_FAILED_BASE, NULL); return installer::TEMP_DIR_FAILED; } - VLOG(1) << "created path " << temp_path.value(); + VLOG(1) << "created path " << temp_path.path().value(); - FilePath unpack_path(temp_path.Append(installer::kInstallSourceDir)); - if (UnPackArchive(archive, installer_state, temp_path, unpack_path, + FilePath unpack_path(temp_path.path().Append(installer::kInstallSourceDir)); + if (UnPackArchive(archive, installer_state, temp_path.path(), unpack_path, archive_type)) { install_status = installer::UNCOMPRESSION_FAILED; InstallUtil::WriteInstallerResult(system_install, @@ -543,12 +543,13 @@ installer::InstallStatus InstallProductsHelper( if (!higher_version_installed) { // We want to keep uncompressed archive (chrome.7z) that we get after // uncompressing and binary patching. Get the location for this file. - FilePath archive_to_copy(temp_path.Append(installer::kChromeArchive)); + FilePath archive_to_copy( + temp_path.path().Append(installer::kChromeArchive)); FilePath prefs_source_path(cmd_line.GetSwitchValueNative( installer::switches::kInstallerData)); install_status = installer::InstallOrUpdateProduct(original_state, - installer_state, cmd_line.GetProgram(), archive_to_copy, temp_path, - prefs_source_path, prefs, *installer_version); + installer_state, cmd_line.GetProgram(), archive_to_copy, + temp_path.path(), prefs_source_path, prefs, *installer_version); int install_msg_base = IDS_INSTALL_FAILED_BASE; std::wstring chrome_exe; @@ -633,8 +634,8 @@ installer::InstallStatus InstallProductsHelper( // and master profile file if present. Note that we do not care about rollback // here and we schedule for deletion on reboot below if the deletes fail. As // such, we do not use DeleteTreeWorkItem. - VLOG(1) << "Deleting temporary directory " << temp_path.value(); - bool cleanup_success = file_util::Delete(temp_path, true); + VLOG(1) << "Deleting temporary directory " << temp_path.path().value(); + bool cleanup_success = temp_path.Delete(); if (cmd_line.HasSwitch(installer::switches::kInstallerData)) { std::wstring prefs_path = cmd_line.GetSwitchValueNative( installer::switches::kInstallerData); @@ -648,7 +649,7 @@ installer::InstallStatus InstallProductsHelper( // this, if we fail to delete the temp folders, then schedule them for // deletion at next reboot. if (!cleanup_success) { - ScheduleDirectoryForDeletion(temp_path.value().c_str()); + ScheduleDirectoryForDeletion(temp_path.path().value().c_str()); if (cmd_line.HasSwitch(installer::switches::kInstallerData)) { std::wstring prefs_path = cmd_line.GetSwitchValueNative( installer::switches::kInstallerData); @@ -758,15 +759,15 @@ bool HandleNonInstallCmdLineOptions(const InstallationState& original_state, // patch to current exe, and store the resulting binary in the path // specified by --new-setup-exe. But we need to first unpack the file // given in --update-setup-exe. - FilePath temp_path; - if (!file_util::CreateNewTempDirectory(L"chrome_", &temp_path)) { - LOG(ERROR) << "Could not create temporary path."; + ScopedTempDir temp_path; + if (!temp_path.CreateUniqueTempDir()) { + PLOG(ERROR) << "Could not create temporary path."; } else { std::wstring setup_patch = cmd_line.GetSwitchValueNative( installer::switches::kUpdateSetupExe); VLOG(1) << "Opening archive " << setup_patch; std::wstring uncompressed_patch; - if (LzmaUtil::UnPackArchive(setup_patch, temp_path.value(), + if (LzmaUtil::UnPackArchive(setup_patch, temp_path.path().value(), &uncompressed_patch) == NO_ERROR) { FilePath old_setup_exe = cmd_line.GetProgram(); FilePath new_setup_exe = cmd_line.GetSwitchValuePath( @@ -785,7 +786,6 @@ bool HandleNonInstallCmdLineOptions(const InstallationState& original_state, installer_state->state_key(), status, IDS_SETUP_PATCH_FAILED_BASE, NULL); } - file_util::Delete(temp_path, true); } else if (cmd_line.HasSwitch(installer::switches::kShowEula)) { // Check if we need to show the EULA. If it is passed as a command line // then the dialog is shown and regardless of the outcome setup exits here. diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc index 21a1dcb..46bb73d 100644 --- a/chrome/installer/setup/uninstall.cc +++ b/chrome/installer/setup/uninstall.cc @@ -690,8 +690,8 @@ InstallStatus UninstallProduct(const InstallationState& original_state, if (product_state != NULL) { std::vector<FilePath> com_dll_list; product.AddComDllList(&com_dll_list); - FilePath dll_folder = installer_state.target_path().Append( - UTF8ToWide(product_state->version().GetString())); + FilePath dll_folder = installer_state.target_path().AppendASCII( + product_state->version().GetString()); scoped_ptr<WorkItemList> unreg_work_item_list( WorkItem::CreateWorkItemList()); diff --git a/chrome/installer/util/copy_tree_work_item.cc b/chrome/installer/util/copy_tree_work_item.cc index f60c822..6461cd6 100644 --- a/chrome/installer/util/copy_tree_work_item.cc +++ b/chrome/installer/util/copy_tree_work_item.cc @@ -11,9 +11,6 @@ #include "chrome/installer/util/logging_installer.h" CopyTreeWorkItem::~CopyTreeWorkItem() { - if (file_util::PathExists(backup_path_)) { - file_util::Delete(backup_path_, true); - } } CopyTreeWorkItem::CopyTreeWorkItem(const FilePath& source_path, @@ -40,7 +37,7 @@ bool CopyTreeWorkItem::Do() { bool dest_exist = file_util::PathExists(dest_path_); // handle overwrite_option_ = IF_DIFFERENT case. if ((dest_exist) && - (overwrite_option_ == WorkItem::IF_DIFFERENT) && // only for single file + (overwrite_option_ == WorkItem::IF_DIFFERENT) && // only for single file (!file_util::DirectoryExists(source_path_)) && (!file_util::DirectoryExists(dest_path_)) && (file_util::ContentsEqual(source_path_, dest_path_))) { @@ -74,16 +71,20 @@ bool CopyTreeWorkItem::Do() { // In all cases that reach here, move dest to a backup path. if (dest_exist) { - if (!GetBackupPath()) + if (!backup_path_.CreateUniqueTempDirUnderPath(temp_dir_)) { + PLOG(ERROR) << "Failed to get backup path in folder " + << temp_dir_.value(); return false; + } - if (file_util::Move(dest_path_, backup_path_)) { + FilePath backup = backup_path_.path().Append(dest_path_.BaseName()); + if (file_util::Move(dest_path_, backup)) { moved_to_backup_ = true; VLOG(1) << "Moved destination " << dest_path_.value() << - " to backup path " << backup_path_.value(); + " to backup path " << backup.value(); } else { LOG(ERROR) << "failed moving " << dest_path_.value() - << " to " << backup_path_.value(); + << " to " << backup.value(); return false; } } @@ -104,16 +105,19 @@ bool CopyTreeWorkItem::Do() { void CopyTreeWorkItem::Rollback() { // Normally the delete operations below should not fail unless some - // programs like anti-virus are inpecting the files we just copied. + // programs like anti-virus are inspecting the files we just copied. // If this does happen sometimes, we may consider using Move instead of // Delete here. For now we just log the error and continue with the // rest of rollback operation. if (copied_to_dest_path_ && !file_util::Delete(dest_path_, true)) { LOG(ERROR) << "Can not delete " << dest_path_.value(); } - if (moved_to_backup_ && !file_util::Move(backup_path_, dest_path_)) { - LOG(ERROR) << "failed move " << backup_path_.value() - << " to " << dest_path_.value(); + if (moved_to_backup_) { + FilePath backup(backup_path_.path().Append(dest_path_.BaseName())); + if (!file_util::Move(backup, dest_path_)) { + LOG(ERROR) << "failed move " << backup.value() + << " to " << dest_path_.value(); + } } if (copied_to_alternate_path_ && !file_util::Delete(alternative_path_, true)) { @@ -133,18 +137,3 @@ bool CopyTreeWorkItem::IsFileInUse(const FilePath& path) { CloseHandle(handle); return false; } - -bool CopyTreeWorkItem::GetBackupPath() { - backup_path_ = temp_dir_.Append(dest_path_.BaseName()); - - if (file_util::PathExists(backup_path_)) { - // Ideally we should not fail immediately. Instead we could try some - // random paths under temp_dir_ until we reach certain limit. - // For now our caller always provides a good temporary directory so - // we don't bother. - LOG(ERROR) << "backup path " << backup_path_.value() << " already exists"; - return false; - } - - return true; -} diff --git a/chrome/installer/util/copy_tree_work_item.h b/chrome/installer/util/copy_tree_work_item.h index 830a0d4..1e248ce 100644 --- a/chrome/installer/util/copy_tree_work_item.h +++ b/chrome/installer/util/copy_tree_work_item.h @@ -6,11 +6,9 @@ #define CHROME_INSTALLER_UTIL_COPY_TREE_WORK_ITEM_H_ #pragma once -#include <windows.h> - -#include <string> - #include "base/file_path.h" +#include "base/gtest_prod_util.h" +#include "base/scoped_temp_dir.h" #include "chrome/installer/util/work_item.h" // A WorkItem subclass that recursively copies a file system hierarchy from @@ -46,10 +44,6 @@ class CopyTreeWorkItem : public WorkItem { // Checks if the path specified is in use (and hence can not be deleted) bool IsFileInUse(const FilePath& path); - // Get a backup path that can keep the original files under dest_path_, - // and set backup_path_ with the result. - bool GetBackupPath(); - // Source path to copy files from. FilePath source_path_; @@ -78,9 +72,14 @@ class CopyTreeWorkItem : public WorkItem { // existed and was in use. Needed during rollback. bool copied_to_alternate_path_; - // The full path in temporary directory that the original dest_path_ has - // been moved to. - FilePath backup_path_; + // The temporary directory into which the original dest_path_ has been moved. + ScopedTempDir backup_path_; + + FRIEND_TEST_ALL_PREFIXES(CopyTreeWorkItemTest, CopyFileSameContent); + FRIEND_TEST_ALL_PREFIXES(CopyTreeWorkItemTest, CopyFileInUse); + FRIEND_TEST_ALL_PREFIXES(CopyTreeWorkItemTest, CopyFileAndCleanup); + FRIEND_TEST_ALL_PREFIXES(CopyTreeWorkItemTest, NewNameAndCopyTest); + FRIEND_TEST_ALL_PREFIXES(CopyTreeWorkItemTest, CopyFileInUseAndCleanup); }; #endif // CHROME_INSTALLER_UTIL_COPY_TREE_WORK_ITEM_H_ diff --git a/chrome/installer/util/copy_tree_work_item_unittest.cc b/chrome/installer/util/copy_tree_work_item_unittest.cc index 931dff8..ee1eae7 100644 --- a/chrome/installer/util/copy_tree_work_item_unittest.cc +++ b/chrome/installer/util/copy_tree_work_item_unittest.cc @@ -217,10 +217,6 @@ TEST_F(CopyTreeWorkItemTest, CopyFileSameContent) { CreateTextFile(file_name_to.value(), text_content_1); ASSERT_TRUE(file_util::PathExists(file_name_to)); - // Get the path of backup file - FilePath backup_file(temp_dir_); - backup_file = backup_file.AppendASCII("File_To.txt"); - // test Do() with always_overwrite being true. scoped_ptr<CopyTreeWorkItem> work_item( WorkItem::CreateCopyTreeWorkItem(file_name_from, @@ -231,6 +227,11 @@ TEST_F(CopyTreeWorkItemTest, CopyFileSameContent) { EXPECT_TRUE(work_item->Do()); + // Get the path of backup file + FilePath backup_file(work_item->backup_path_.path()); + EXPECT_FALSE(backup_file.empty()); + backup_file = backup_file.AppendASCII("File_To.txt"); + EXPECT_TRUE(file_util::PathExists(file_name_from)); EXPECT_TRUE(file_util::PathExists(file_name_to)); EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1)); @@ -297,9 +298,7 @@ TEST_F(CopyTreeWorkItemTest, CopyFileAndCleanup) { CreateTextFile(file_name_to.value(), text_content_2); ASSERT_TRUE(file_util::PathExists(file_name_to)); - // Get the path of backup file - FilePath backup_file(temp_dir_); - backup_file = backup_file.AppendASCII("File_To.txt"); + FilePath backup_file; { // test Do(). @@ -312,6 +311,11 @@ TEST_F(CopyTreeWorkItemTest, CopyFileAndCleanup) { EXPECT_TRUE(work_item->Do()); + // Get the path of backup file + backup_file = work_item->backup_path_.path(); + EXPECT_FALSE(backup_file.empty()); + backup_file = backup_file.AppendASCII("File_To.txt"); + EXPECT_TRUE(file_util::PathExists(file_name_from)); EXPECT_TRUE(file_util::PathExists(file_name_to)); EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1)); @@ -361,10 +365,6 @@ TEST_F(CopyTreeWorkItemTest, CopyFileInUse) { NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_SUSPENDED, NULL, NULL, &si, &pi)); - // Get the path of backup file - FilePath backup_file(temp_dir_); - backup_file = backup_file.AppendASCII("File_To"); - // test Do(). scoped_ptr<CopyTreeWorkItem> work_item( WorkItem::CreateCopyTreeWorkItem(file_name_from, @@ -375,6 +375,11 @@ TEST_F(CopyTreeWorkItemTest, CopyFileInUse) { EXPECT_TRUE(work_item->Do()); + // Get the path of backup file + FilePath backup_file(work_item->backup_path_.path()); + EXPECT_FALSE(backup_file.empty()); + backup_file = backup_file.AppendASCII("File_To"); + EXPECT_TRUE(file_util::PathExists(file_name_from)); EXPECT_TRUE(file_util::PathExists(file_name_to)); EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1)); @@ -440,10 +445,6 @@ TEST_F(CopyTreeWorkItemTest, NewNameAndCopyTest) { NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_SUSPENDED, NULL, NULL, &si, &pi)); - // Get the path of backup file - FilePath backup_file(temp_dir_); - backup_file = backup_file.AppendASCII("File_To"); - // test Do(). scoped_ptr<CopyTreeWorkItem> work_item( WorkItem::CreateCopyTreeWorkItem(file_name_from, @@ -459,7 +460,7 @@ TEST_F(CopyTreeWorkItemTest, NewNameAndCopyTest) { EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1)); EXPECT_TRUE(file_util::ContentsEqual(exe_full_path, file_name_to)); // verify that the backup path does not exist - EXPECT_FALSE(file_util::PathExists(backup_file)); + EXPECT_TRUE(work_item->backup_path_.path().empty()); EXPECT_TRUE(file_util::ContentsEqual(file_name_from, alternate_to)); // test rollback() @@ -469,7 +470,7 @@ TEST_F(CopyTreeWorkItemTest, NewNameAndCopyTest) { EXPECT_TRUE(file_util::PathExists(file_name_to)); EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1)); EXPECT_TRUE(file_util::ContentsEqual(exe_full_path, file_name_to)); - EXPECT_FALSE(file_util::PathExists(backup_file)); + EXPECT_TRUE(work_item->backup_path_.path().empty()); // the alternate file should be gone after rollback EXPECT_FALSE(file_util::PathExists(alternate_to)); @@ -490,6 +491,11 @@ TEST_F(CopyTreeWorkItemTest, NewNameAndCopyTest) { ASSERT_FALSE(IsFileInUse(file_name_to)); EXPECT_TRUE(work_item->Do()); + // Get the path of backup file + FilePath backup_file(work_item->backup_path_.path()); + EXPECT_FALSE(backup_file.empty()); + backup_file = backup_file.AppendASCII("File_To"); + EXPECT_TRUE(file_util::PathExists(file_name_from)); EXPECT_TRUE(file_util::PathExists(file_name_to)); EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1)); @@ -631,9 +637,7 @@ TEST_F(CopyTreeWorkItemTest, FLAKY_CopyFileInUseAndCleanup) { NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_SUSPENDED, NULL, NULL, &si, &pi)); - // Get the path of backup file - FilePath backup_file(temp_dir_); - backup_file = backup_file.AppendASCII("File_To"); + FilePath backup_file; // test Do(). { @@ -646,6 +650,11 @@ TEST_F(CopyTreeWorkItemTest, FLAKY_CopyFileInUseAndCleanup) { EXPECT_TRUE(work_item->Do()); + // Get the path of backup file + backup_file = work_item->backup_path_.path(); + EXPECT_FALSE(backup_file.empty()); + backup_file = backup_file.AppendASCII("File_To"); + EXPECT_TRUE(file_util::PathExists(file_name_from)); EXPECT_TRUE(file_util::PathExists(file_name_to)); EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1)); diff --git a/chrome/installer/util/delete_tree_work_item.cc b/chrome/installer/util/delete_tree_work_item.cc index 76d5a8c..e288ee4 100644 --- a/chrome/installer/util/delete_tree_work_item.cc +++ b/chrome/installer/util/delete_tree_work_item.cc @@ -2,38 +2,47 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/installer/util/delete_tree_work_item.h" + +#include <algorithm> +#include <limits> + #include "base/file_util.h" #include "base/logging.h" -#include "chrome/installer/util/delete_tree_work_item.h" + +namespace { + +// Casts a value of an unsigned type to a signed type of the same size provided +// that there is no overflow. +template<typename L, typename R> +bool SafeCast(L left, R* right) { + DCHECK(right); + COMPILE_ASSERT(sizeof(left) == sizeof(right), + must_add_support_for_crazy_data_types); + if (left > static_cast<L>(std::numeric_limits<R>::max())) + return false; + *right = static_cast<L>(left); + return true; +} + +} // namespace DeleteTreeWorkItem::DeleteTreeWorkItem( const FilePath& root_path, + const FilePath& temp_path, const std::vector<FilePath>& key_paths) - : root_path_(root_path) { - // Populate our key_paths_ list with empty backup path values. - std::vector<FilePath>::const_iterator it(key_paths.begin()); - for (; it != key_paths.end(); ++it) { - key_paths_.push_back(KeyFileList::value_type(*it, FilePath())); + : root_path_(root_path), + temp_path_(temp_path) { + if (!SafeCast(key_paths.size(), &num_key_files_)) { + NOTREACHED() << "Impossibly large key_paths collection"; + } else if (num_key_files_ != 0) { + key_paths_.reset(new FilePath[num_key_files_]); + key_backup_paths_.reset(new ScopedTempDir[num_key_files_]); + std::copy(key_paths.begin(), key_paths.end(), &key_paths_[0]); } } DeleteTreeWorkItem::~DeleteTreeWorkItem() { - if (!backup_path_.empty()) { - FilePath tmp_dir = backup_path_.DirName(); - if (file_util::PathExists(tmp_dir)) { - file_util::Delete(tmp_dir, true); - } - } - - KeyFileList::const_iterator it(key_paths_.begin()); - for (; it != key_paths_.end(); ++it) { - if (!it->second.empty()) { - FilePath tmp_dir = it->second.DirName(); - if (file_util::PathExists(tmp_dir)) { - file_util::Delete(tmp_dir, true); - } - } - } } // We first try to move key_path_ to backup_path. If it succeeds, we go ahead @@ -42,26 +51,31 @@ bool DeleteTreeWorkItem::Do() { // Go through all the key files and see if we can open them exclusively // with only the FILE_SHARE_DELETE flag. Once we know we have all of them, // we can delete them. - KeyFileList::iterator it(key_paths_.begin()); std::vector<HANDLE> opened_key_files; + opened_key_files.reserve(num_key_files_); bool abort = false; - for (; !abort && it != key_paths_.end(); ++it) { - if (!GetBackupPath(it->first, &it->second) || - !file_util::CopyFile(it->first, it->second)) { - PLOG(ERROR) << "Could not back up: " << it->first.value(); + for (ptrdiff_t i = 0; !abort && i != num_key_files_; ++i) { + FilePath& key_file = key_paths_[i]; + ScopedTempDir& backup = key_backup_paths_[i]; + if (!backup.CreateUniqueTempDirUnderPath(temp_path_)) { + PLOG(ERROR) << "Could not create temp dir in " << temp_path_.value(); + abort = true; + } else if (!file_util::CopyFile(key_file, + backup.path().Append(key_file.BaseName()))) { + PLOG(ERROR) << "Could not back up " << key_file.value() + << " to directory " << backup.path().value(); abort = true; } else { - HANDLE file = ::CreateFile(it->first.value().c_str(), FILE_ALL_ACCESS, + HANDLE file = ::CreateFile(key_file.value().c_str(), FILE_ALL_ACCESS, FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); if (file != INVALID_HANDLE_VALUE) { - VLOG(1) << "Acquired exclusive lock for key file: " - << it->first.value(); + VLOG(1) << "Acquired exclusive lock for key file: " << key_file.value(); opened_key_files.push_back(file); } else { if (::GetLastError() != ERROR_FILE_NOT_FOUND) abort = true; - PLOG(INFO) << "Failed to open " << it->first.value(); + PLOG(INFO) << "Failed to open " << key_file.value(); } } } @@ -70,21 +84,17 @@ bool DeleteTreeWorkItem::Do() { // We now hold exclusive locks with "share delete" permissions for each // of the key files and also have created backups of those files. // We can safely delete the key files now. - it = key_paths_.begin(); - for (; !abort && it != key_paths_.end(); ++it) { - if (!file_util::Delete(it->first, true)) { + for (ptrdiff_t i = 0; !abort && i != num_key_files_; ++i) { + FilePath& key_file = key_paths_[i]; + if (!file_util::Delete(key_file, true)) { // This should not really be possible because of the above. - NOTREACHED(); - PLOG(ERROR) << "Unexpectedly could not delete " << it->first.value(); + PLOG(DFATAL) << "Unexpectedly could not delete " << key_file.value(); abort = true; } } } - std::vector<HANDLE>::const_iterator file_it(opened_key_files.begin()); - for (; file_it != opened_key_files.end(); ++file_it) - ::CloseHandle(*file_it); - + std::for_each(opened_key_files.begin(), opened_key_files.end(), CloseHandle); opened_key_files.clear(); if (abort) { @@ -94,12 +104,18 @@ bool DeleteTreeWorkItem::Do() { // Now that we've taken care of the key files, take care of the rest. if (!root_path_.empty() && file_util::PathExists(root_path_)) { - if (!GetBackupPath(root_path_, &backup_path_) || - !file_util::CopyDirectory(root_path_, backup_path_, true) || - !file_util::Delete(root_path_, true)) { - LOG(ERROR) << "can not delete " << root_path_.value() - << " OR copy it to backup path " << backup_path_.value(); + if (!backup_path_.CreateUniqueTempDirUnderPath(temp_path_)) { + PLOG(ERROR) << "Failed to get backup path in folder " + << temp_path_.value(); return false; + } else { + FilePath backup = backup_path_.path().Append(root_path_.BaseName()); + if (!file_util::CopyDirectory(root_path_, backup, true) || + !file_util::Delete(root_path_, true)) { + LOG(ERROR) << "can not delete " << root_path_.value() + << " OR copy it to backup path " << backup.value(); + return false; + } } } @@ -108,30 +124,23 @@ bool DeleteTreeWorkItem::Do() { // If there are files in backup paths move them back. void DeleteTreeWorkItem::Rollback() { - if (!backup_path_.empty() && file_util::PathExists(backup_path_)) { - file_util::Move(backup_path_, root_path_); + if (!backup_path_.path().empty()) { + FilePath backup = backup_path_.path().Append(root_path_.BaseName()); + if (file_util::PathExists(backup)) + file_util::Move(backup, root_path_); } - KeyFileList::const_iterator it(key_paths_.begin()); - for (; it != key_paths_.end(); ++it) { - if (!it->second.empty() && file_util::PathExists(it->second)) { - if (!file_util::Move(it->second, it->first)) { + for (ptrdiff_t i = 0; i != num_key_files_; ++i) { + ScopedTempDir& backup_dir = key_backup_paths_[i]; + if (!backup_dir.path().empty()) { + FilePath& key_file = key_paths_[i]; + FilePath backup_file = backup_dir.path().Append(key_file.BaseName()); + if (file_util::PathExists(backup_file) && + !file_util::Move(backup_file, key_file)) { // This could happen if we could not delete the key file to begin with. PLOG(WARNING) << "Rollback: Failed to move backup file back in place: " - << it->second.value() << " to " << it->first.value(); + << backup_file.value() << " to " << key_file.value(); } } } } - -bool DeleteTreeWorkItem::GetBackupPath(const FilePath& for_path, - FilePath* backup_path) { - if (!file_util::CreateNewTempDirectory(L"", backup_path)) { - // We assume that CreateNewTempDirectory() is doing its job well. - LOG(ERROR) << "Couldn't get backup path for delete."; - return false; - } - - *backup_path = backup_path->Append(for_path.BaseName()); - return true; -} diff --git a/chrome/installer/util/delete_tree_work_item.h b/chrome/installer/util/delete_tree_work_item.h index f57a722..508b885 100644 --- a/chrome/installer/util/delete_tree_work_item.h +++ b/chrome/installer/util/delete_tree_work_item.h @@ -6,20 +6,18 @@ #define CHROME_INSTALLER_UTIL_DELETE_TREE_WORK_ITEM_H_ #pragma once -#include <windows.h> - -#include <string> -#include <utility> #include <vector> #include "base/file_path.h" +#include "base/scoped_ptr.h" +#include "base/scoped_temp_dir.h" #include "chrome/installer/util/work_item.h" // A WorkItem subclass that recursively deletes a file system hierarchy at the // given root path. The file system hierarchy could be a single file, or a // directory. -// The file system hierarchy to be deleted can have a key file. If the key file -// is specified, deletion will be performed only if the key file is not in use. +// The file system hierarchy to be deleted can have one or more key files. If +// specified, deletion will be performed only if all key files are not in use. class DeleteTreeWorkItem : public WorkItem { public: virtual ~DeleteTreeWorkItem(); @@ -31,28 +29,30 @@ class DeleteTreeWorkItem : public WorkItem { private: friend class WorkItem; - // A list of key file paths and paths to a backup of a key file. - // the 'first' member of the pair has the key file path, the 'second' has - // the path to the backup. - typedef std::vector<std::pair<FilePath, FilePath> > KeyFileList; - - // Get a backup path that can keep root_path_ or key_paths_ - bool GetBackupPath(const FilePath& for_path, FilePath* backup_path); - DeleteTreeWorkItem(const FilePath& root_path, + const FilePath& temp_path, const std::vector<FilePath>& key_paths); // Root path to delete. FilePath root_path_; - // Contains the path to key files and their backups once Do() has been called. - // If key files are specified, deletion will be performed only if none of the - // key files are in use. - KeyFileList key_paths_; + // Temporary directory that can be used. + FilePath temp_path_; + + // The number of key files. + ptrdiff_t num_key_files_; + + // Contains the paths to the key files. If specified, deletion will be + // performed only if none of the key files are in use. + scoped_array<FilePath> key_paths_; + + // Contains the temp directories for the backed-up key files. The directories + // are created and populated in Do() as-needed. We don't use a standard + // container for this since ScopedTempDir isn't CopyConstructible. + scoped_array<ScopedTempDir> key_backup_paths_; - // The full path in temporary directory that the original root_path_ has - // been moved to. - FilePath backup_path_; + // The temporary directory into which the original root_path_ has been moved. + ScopedTempDir backup_path_; }; #endif // CHROME_INSTALLER_UTIL_DELETE_TREE_WORK_ITEM_H_ diff --git a/chrome/installer/util/delete_tree_work_item_unittest.cc b/chrome/installer/util/delete_tree_work_item_unittest.cc index f87fe93..e2b0074 100644 --- a/chrome/installer/util/delete_tree_work_item_unittest.cc +++ b/chrome/installer/util/delete_tree_work_item_unittest.cc @@ -12,6 +12,7 @@ #include "base/path_service.h" #include "base/process_util.h" #include "base/scoped_ptr.h" +#include "base/scoped_temp_dir.h" #include "base/string_util.h" #include "chrome/installer/util/delete_tree_work_item.h" #include "chrome/installer/util/work_item.h" @@ -85,9 +86,13 @@ TEST_F(DeleteTreeWorkItemTest, DeleteTreeNoKeyPath) { ASSERT_TRUE(file_util::PathExists(file_name_delete_2)); // test Do() + ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + std::vector<FilePath> key_files; scoped_ptr<DeleteTreeWorkItem> work_item( - WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, key_files)); + WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, temp_dir.path(), + key_files)); EXPECT_TRUE(work_item->Do()); // everything should be gone @@ -133,9 +138,13 @@ TEST_F(DeleteTreeWorkItemTest, DeleteTree) { ASSERT_TRUE(file_util::PathExists(file_name_delete_2)); // test Do() + ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + std::vector<FilePath> key_files(1, file_name_delete_1); scoped_ptr<DeleteTreeWorkItem> work_item( - WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, key_files)); + WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, temp_dir.path(), + key_files)); EXPECT_TRUE(work_item->Do()); // everything should be gone @@ -202,9 +211,13 @@ TEST_F(DeleteTreeWorkItemTest, DeleteTreeInUse) { // test Do(). { + ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + std::vector<FilePath> key_paths(1, key_path); scoped_ptr<DeleteTreeWorkItem> work_item( - WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, key_paths)); + WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, temp_dir.path(), + key_paths)); // delete should fail as file in use. EXPECT_FALSE(work_item->Do()); diff --git a/chrome/installer/util/installer_state.cc b/chrome/installer/util/installer_state.cc index 9137b29..65bc51e 100644 --- a/chrome/installer/util/installer_state.cc +++ b/chrome/installer/util/installer_state.cc @@ -388,7 +388,8 @@ FilePath InstallerState::GetInstallerDirectory(const Version& version) const { } void InstallerState::RemoveOldVersionDirectories( - const Version& latest_version) const { + const Version& latest_version, + const FilePath& temp_path) const { file_util::FileEnumerator version_enum(target_path(), false, file_util::FileEnumerator::DIRECTORIES); scoped_ptr<Version> version; @@ -417,7 +418,8 @@ void InstallerState::RemoveOldVersionDirectories( VLOG(1) << "Deleting directory: " << next_version.value(); scoped_ptr<WorkItem> item( - WorkItem::CreateDeleteTreeWorkItem(next_version, key_files)); + WorkItem::CreateDeleteTreeWorkItem(next_version, temp_path, + key_files)); if (!item->Do()) item->Rollback(); } diff --git a/chrome/installer/util/installer_state.h b/chrome/installer/util/installer_state.h index 0b4ea0b..05b8626 100644 --- a/chrome/installer/util/installer_state.h +++ b/chrome/installer/util/installer_state.h @@ -145,7 +145,8 @@ class InstallerState { // Try to delete all directories whose versions are lower than // |latest_version|. - void RemoveOldVersionDirectories(const Version& latest_version) const; + void RemoveOldVersionDirectories(const Version& latest_version, + const FilePath& temp_path) const; // Adds to |com_dll_list| the list of COM DLLs that are to be registered // and/or unregistered. The list may be empty. diff --git a/chrome/installer/util/installer_state_unittest.cc b/chrome/installer/util/installer_state_unittest.cc index 25efc07..700bffb 100644 --- a/chrome/installer/util/installer_state_unittest.cc +++ b/chrome/installer/util/installer_state_unittest.cc @@ -11,6 +11,7 @@ #include "base/file_util.h" #include "base/path_service.h" #include "base/process_util.h" +#include "base/scoped_temp_dir.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "base/version.h" @@ -118,7 +119,12 @@ TEST_F(InstallerStateTest, Delete) { MockInstallerState installer_state; BuildSingleChromeState(chrome_dir, &installer_state); scoped_ptr<Version> latest_version(Version::GetVersionFromString("1.0.4.0")); - installer_state.RemoveOldVersionDirectories(*latest_version.get()); + { + ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + installer_state.RemoveOldVersionDirectories(*latest_version.get(), + temp_dir.path()); + } // old versions should be gone EXPECT_FALSE(file_util::PathExists(chrome_dir_1)); @@ -193,7 +199,12 @@ TEST_F(InstallerStateTest, DeleteInUsed) { MockInstallerState installer_state; BuildSingleChromeState(chrome_dir, &installer_state); scoped_ptr<Version> latest_version(Version::GetVersionFromString("1.0.4.0")); - installer_state.RemoveOldVersionDirectories(*latest_version.get()); + { + ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + installer_state.RemoveOldVersionDirectories(*latest_version.get(), + temp_dir.path()); + } // old versions not in used should be gone EXPECT_FALSE(file_util::PathExists(chrome_dir_1)); @@ -265,7 +276,12 @@ TEST_F(InstallerStateTest, Basic) { EXPECT_TRUE(file.IsValid()); EXPECT_TRUE(file_util::PathExists(old_chrome_dll)); - installer_state.RemoveOldVersionDirectories(*new_version.get()); + ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + + installer_state.RemoveOldVersionDirectories(*new_version.get(), + temp_dir.path()); + // The old directory should still exist. EXPECT_TRUE(file_util::PathExists(old_version_dir)); EXPECT_TRUE(file_util::PathExists(new_version_dir)); @@ -273,7 +289,8 @@ TEST_F(InstallerStateTest, Basic) { // Now close the file handle to make it possible to delete our key file. file.Close(); - installer_state.RemoveOldVersionDirectories(*new_version.get()); + installer_state.RemoveOldVersionDirectories(*new_version.get(), + temp_dir.path()); // The new directory should still exist. EXPECT_TRUE(file_util::PathExists(new_version_dir)); diff --git a/chrome/installer/util/move_tree_work_item.cc b/chrome/installer/util/move_tree_work_item.cc index 027de2f..b4a7cc6 100644 --- a/chrome/installer/util/move_tree_work_item.cc +++ b/chrome/installer/util/move_tree_work_item.cc @@ -11,9 +11,6 @@ #include "chrome/installer/util/logging_installer.h" MoveTreeWorkItem::~MoveTreeWorkItem() { - if (file_util::PathExists(backup_path_)) { - file_util::Delete(backup_path_, true); - } } MoveTreeWorkItem::MoveTreeWorkItem(const FilePath& source_path, @@ -35,19 +32,21 @@ bool MoveTreeWorkItem::Do() { // If dest_path_ exists, move destination to a backup path. if (file_util::PathExists(dest_path_)) { // Generate a backup path that can keep the original files under dest_path_. - if (!file_util::CreateTemporaryFileInDir(FilePath(temp_dir_), - &backup_path_)) { - LOG(ERROR) << "Failed to get backup path in folder " << temp_dir_.value(); + if (!backup_path_.CreateUniqueTempDirUnderPath(temp_dir_)) { + PLOG(ERROR) << "Failed to get backup path in folder " + << temp_dir_.value(); return false; } - if (file_util::Move(dest_path_, backup_path_)) { + FilePath backup = backup_path_.path().Append(dest_path_.BaseName()); + + if (file_util::Move(dest_path_, backup)) { moved_to_backup_ = true; VLOG(1) << "Moved destination " << dest_path_.value() - << " to backup path " << backup_path_.value(); + << " to backup path " << backup.value(); } else { LOG(ERROR) << "failed moving " << dest_path_.value() - << " to " << backup_path_.value(); + << " to " << backup.value(); return false; } } @@ -71,7 +70,11 @@ void MoveTreeWorkItem::Rollback() { LOG(ERROR) << "Can not move " << dest_path_.value() << " to " << source_path_.value(); - if (moved_to_backup_ && !file_util::Move(backup_path_, dest_path_)) - LOG(ERROR) << "failed move " << backup_path_.value() - << " to " << dest_path_.value(); + if (moved_to_backup_) { + FilePath backup = backup_path_.path().Append(dest_path_.BaseName()); + if (!file_util::Move(backup, dest_path_)) { + LOG(ERROR) << "failed move " << backup.value() + << " to " << dest_path_.value(); + } + } } diff --git a/chrome/installer/util/move_tree_work_item.h b/chrome/installer/util/move_tree_work_item.h index f1941cd8..b4d97cf 100644 --- a/chrome/installer/util/move_tree_work_item.h +++ b/chrome/installer/util/move_tree_work_item.h @@ -6,11 +6,8 @@ #define CHROME_INSTALLER_UTIL_MOVE_TREE_WORK_ITEM_H_ #pragma once -#include <windows.h> - -#include <string> - #include "base/file_path.h" +#include "base/scoped_temp_dir.h" #include "chrome/installer/util/work_item.h" // A WorkItem subclass that recursively move a file system hierarchy from @@ -49,9 +46,8 @@ class MoveTreeWorkItem : public WorkItem { // Temporary directory to backup dest_path_ (if it already exists). FilePath temp_dir_; - // The full path in temp_dir_ where the original dest_path_ has - // been moved to. - FilePath backup_path_; + // The temporary directory into which the original dest_path_ has been moved. + ScopedTempDir backup_path_; // Whether the source was moved to dest_path_ bool moved_to_dest_path_; diff --git a/chrome/installer/util/work_item.cc b/chrome/installer/util/work_item.cc index 2d40d36..59583f9 100644 --- a/chrome/installer/util/work_item.cc +++ b/chrome/installer/util/work_item.cc @@ -54,8 +54,10 @@ DeleteRegValueWorkItem* WorkItem::CreateDeleteRegValueWorkItem( } DeleteTreeWorkItem* WorkItem::CreateDeleteTreeWorkItem( - const FilePath& root_path, const std::vector<FilePath>& key_paths) { - return new DeleteTreeWorkItem(root_path, key_paths); + const FilePath& root_path, + const FilePath& temp_path, + const std::vector<FilePath>& key_paths) { + return new DeleteTreeWorkItem(root_path, temp_path, key_paths); } MoveTreeWorkItem* WorkItem::CreateMoveTreeWorkItem( diff --git a/chrome/installer/util/work_item.h b/chrome/installer/util/work_item.h index 9b98cc6..66925ed 100644 --- a/chrome/installer/util/work_item.h +++ b/chrome/installer/util/work_item.h @@ -88,7 +88,9 @@ class WorkItem { // hierarchy at the given root path. A key file can be optionally specified // by key_path. static DeleteTreeWorkItem* CreateDeleteTreeWorkItem( - const FilePath& root_path, const std::vector<FilePath>& key_paths); + const FilePath& root_path, + const FilePath& temp_path, + const std::vector<FilePath>& key_paths); // Create a MoveTreeWorkItem that recursively moves a file system hierarchy // from source path to destination path. diff --git a/chrome/installer/util/work_item_list.cc b/chrome/installer/util/work_item_list.cc index 39249c4..3156f7d 100644 --- a/chrome/installer/util/work_item_list.cc +++ b/chrome/installer/util/work_item_list.cc @@ -119,15 +119,18 @@ WorkItem* WorkItemList::AddDeleteRegValueWorkItem( WorkItem* WorkItemList::AddDeleteTreeWorkItem( const FilePath& root_path, + const FilePath& temp_path, const std::vector<FilePath>& key_paths) { - WorkItem* item = WorkItem::CreateDeleteTreeWorkItem(root_path, key_paths); + WorkItem* item = WorkItem::CreateDeleteTreeWorkItem(root_path, temp_path, + key_paths); AddWorkItem(item); return item; } -WorkItem* WorkItemList::AddDeleteTreeWorkItem(const FilePath& root_path) { +WorkItem* WorkItemList::AddDeleteTreeWorkItem(const FilePath& root_path, + const FilePath& temp_path) { std::vector<FilePath> no_key_files; - return AddDeleteTreeWorkItem(root_path, no_key_files); + return AddDeleteTreeWorkItem(root_path, temp_path, no_key_files); } WorkItem* WorkItemList::AddMoveTreeWorkItem(const std::wstring& source_path, diff --git a/chrome/installer/util/work_item_list.h b/chrome/installer/util/work_item_list.h index 23af15b..fc826ed 100644 --- a/chrome/installer/util/work_item_list.h +++ b/chrome/installer/util/work_item_list.h @@ -69,10 +69,12 @@ class WorkItemList : public WorkItem { // by key_path. virtual WorkItem* AddDeleteTreeWorkItem( const FilePath& root_path, + const FilePath& temp_path, const std::vector<FilePath>& key_paths); // Same as above but without support for key files. - virtual WorkItem* AddDeleteTreeWorkItem(const FilePath& root_path); + virtual WorkItem* AddDeleteTreeWorkItem(const FilePath& root_path, + const FilePath& temp_path); // Add a MoveTreeWorkItem to the list of work items. virtual WorkItem* AddMoveTreeWorkItem(const std::wstring& source_path, |