diff options
author | kuchhal@chromium.org <kuchhal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-04 21:36:56 +0000 |
---|---|---|
committer | kuchhal@chromium.org <kuchhal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-04 21:36:56 +0000 |
commit | f65f7dadd39f0f06391fd289faccb07b7b4468fd (patch) | |
tree | f0d6357441fc22bf4c364edc81140e3844dceac1 /chrome/installer | |
parent | 32aa8cc65e23a45c5e20f7ff22aa98ca4935eb0a (diff) | |
download | chromium_src-f65f7dadd39f0f06391fd289faccb07b7b4468fd.zip chromium_src-f65f7dadd39f0f06391fd289faccb07b7b4468fd.tar.gz chromium_src-f65f7dadd39f0f06391fd289faccb07b7b4468fd.tar.bz2 |
Move files instead of copying them.
BUG=1184319,8218
Review URL: http://codereview.chromium.org/39048
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10921 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/installer')
-rw-r--r-- | chrome/installer/setup/install.cc | 13 | ||||
-rw-r--r-- | chrome/installer/util/installer_unittests.vcproj | 4 | ||||
-rw-r--r-- | chrome/installer/util/move_tree_work_item.cc | 70 | ||||
-rw-r--r-- | chrome/installer/util/move_tree_work_item.h | 62 | ||||
-rw-r--r-- | chrome/installer/util/move_tree_work_item_unittest.cc | 387 | ||||
-rw-r--r-- | chrome/installer/util/util.vcproj | 8 | ||||
-rw-r--r-- | chrome/installer/util/work_item.cc | 7 | ||||
-rw-r--r-- | chrome/installer/util/work_item.h | 6 | ||||
-rw-r--r-- | chrome/installer/util/work_item_list.cc | 8 | ||||
-rw-r--r-- | chrome/installer/util/work_item_list.h | 4 |
10 files changed, 562 insertions, 7 deletions
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc index 1c17b81..e58c56d 100644 --- a/chrome/installer/setup/install.cc +++ b/chrome/installer/setup/install.cc @@ -108,8 +108,7 @@ void AddInstallerCopyTasks(const std::wstring& exe_path, install_list->AddCopyTreeWorkItem(exe_path, exe_dst, temp_path, WorkItem::ALWAYS); - install_list->AddCopyTreeWorkItem(archive_path, archive_dst, temp_path, - WorkItem::ALWAYS); + install_list->AddMoveTreeWorkItem(archive_path, archive_dst, temp_path); } @@ -149,11 +148,11 @@ bool installer::InstallNewVersion(const std::wstring& exe_path, install_list->AddCreateDirWorkItem(temp_dir); install_list->AddCreateDirWorkItem(install_path); - // Copy the version folder - install_list->AddCopyTreeWorkItem( + // Move the version folder + install_list->AddMoveTreeWorkItem( AppendPath(src_path, new_version.GetString()), AppendPath(install_path, new_version.GetString()), - temp_dir, WorkItem::ALWAYS); // Always overwrite. + temp_dir); // Delete any new_chrome.exe if present (we will end up create a new one // if required) and then copy chrome.exe @@ -176,10 +175,10 @@ bool installer::InstallNewVersion(const std::wstring& exe_path, // Extra executable for 64 bit systems. if (Is64bit()) { - install_list->AddCopyTreeWorkItem( + install_list->AddMoveTreeWorkItem( AppendPath(src_path, installer::kWowHelperExe), AppendPath(install_path, installer::kWowHelperExe), - temp_dir, WorkItem::ALWAYS); + temp_dir); } // Copy the default Dictionaries only if the folder doesnt exist already diff --git a/chrome/installer/util/installer_unittests.vcproj b/chrome/installer/util/installer_unittests.vcproj index 62ac85a..8078508 100644 --- a/chrome/installer/util/installer_unittests.vcproj +++ b/chrome/installer/util/installer_unittests.vcproj @@ -184,6 +184,10 @@ > </File> <File + RelativePath="move_tree_work_item_unittest.cc" + > + </File> + <File RelativePath="set_reg_value_work_item_unittest.cc" > </File> diff --git a/chrome/installer/util/move_tree_work_item.cc b/chrome/installer/util/move_tree_work_item.cc new file mode 100644 index 0000000..da35ec1 --- /dev/null +++ b/chrome/installer/util/move_tree_work_item.cc @@ -0,0 +1,70 @@ +// Copyright (c) 2009 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/util/move_tree_work_item.h" + +#include <shlwapi.h> +#include "base/file_util.h" +#include "chrome/installer/util/logging_installer.h" + +MoveTreeWorkItem::~MoveTreeWorkItem() { + if (file_util::PathExists(backup_path_)) { + file_util::Delete(backup_path_, true); + } +} + +MoveTreeWorkItem::MoveTreeWorkItem(const std::wstring& source_path, + const std::wstring& dest_path, + const std::wstring& temp_dir) + : source_path_(source_path), + dest_path_(dest_path), + temp_dir_(temp_dir), + moved_to_dest_path_(false), + moved_to_backup_(false) { +} + +bool MoveTreeWorkItem::Do() { + if (!file_util::PathExists(source_path_)) { + LOG(ERROR) << source_path_ << " does not exist"; + return false; + } + + // 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::CreateTemporaryFileNameInDir(temp_dir_, &backup_path_)) { + LOG(ERROR) << "Failed to get backup path in folder " << temp_dir_; + return false; + } + + if (file_util::Move(dest_path_, backup_path_)) { + moved_to_backup_ = true; + LOG(INFO) << "Moved destination " << dest_path_ + << " to backup path " << backup_path_; + } else { + LOG(ERROR) << "failed moving " << dest_path_ << " to " << backup_path_; + return false; + } + } + + // Now move source to destination. + if (file_util::Move(source_path_, dest_path_)) { + moved_to_dest_path_ = true; + LOG(INFO) << "Moved source " << source_path_ + << " to destination " << dest_path_; + } else { + LOG(ERROR) << "failed move " << source_path_ << " to " << dest_path_; + return false; + } + + return true; +} + +void MoveTreeWorkItem::Rollback() { + if (moved_to_dest_path_ && !file_util::Move(dest_path_, source_path_)) + LOG(ERROR) << "Can not move " << dest_path_ << " to " << source_path_; + + if (moved_to_backup_ && !file_util::Move(backup_path_, dest_path_)) + LOG(ERROR) << "failed move " << backup_path_ << " to " << dest_path_; +} diff --git a/chrome/installer/util/move_tree_work_item.h b/chrome/installer/util/move_tree_work_item.h new file mode 100644 index 0000000..fd938d2 --- /dev/null +++ b/chrome/installer/util/move_tree_work_item.h @@ -0,0 +1,62 @@ +// Copyright (c) 2009 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_UTIL_MOVE_TREE_WORK_ITEM_H_ +#define CHROME_INSTALLER_UTIL_MOVE_TREE_WORK_ITEM_H_ + +#include <string> +#include <windows.h> + +#include "chrome/installer/util/work_item.h" + +// A WorkItem subclass that recursively move a file system hierarchy from +// source path to destination path. The file system hierarchy could be a +// single file, or a directory. +// +// Under the cover MoveTreeWorkItem moves the destination path, if existing, +// to the temporary directory passed in, and then moves the source hierarchy +// to the destination location. During rollback the original destination +// hierarchy is moved back. +class MoveTreeWorkItem : public WorkItem { + public: + virtual ~MoveTreeWorkItem(); + + virtual bool Do(); + + virtual void Rollback(); + + private: + friend class WorkItem; + + // source_path specifies file or directory that will be moved to location + // specified by dest_path. To facilitate rollback, the caller needs to supply + // a temporary directory (temp_dir) to save the original files if they exist + // under dest_path. + MoveTreeWorkItem(const std::wstring& source_path, + const std::wstring& dest_path, + const std::wstring& temp_dir); + + // Source path to move files from. + std::wstring source_path_; + + // Destination path to move files to. + std::wstring dest_path_; + + // Temporary directory to backup dest_path_ (if it already exists). + std::wstring temp_dir_; + + // The full path in temp_dir_ where the original dest_path_ has + // been moved to. + std::wstring backup_path_; + + // Whether the source was moved to dest_path_ + bool moved_to_dest_path_; + + // Whether the original files have been moved to backup path under + // temporary directory. If true, moving back is needed during rollback. + bool moved_to_backup_; +}; + +#endif // CHROME_INSTALLER_UTIL_MOVE_TREE_WORK_ITEM_H_ + diff --git a/chrome/installer/util/move_tree_work_item_unittest.cc b/chrome/installer/util/move_tree_work_item_unittest.cc new file mode 100644 index 0000000..642b2a2 --- /dev/null +++ b/chrome/installer/util/move_tree_work_item_unittest.cc @@ -0,0 +1,387 @@ +// Copyright (c) 2009 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 <windows.h> + +#include <fstream> +#include <iostream> + +#include "base/base_paths.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/process_util.h" +#include "base/scoped_ptr.h" +#include "base/string_util.h" +#include "chrome/installer/util/work_item.h" +#include "chrome/installer/util/move_tree_work_item.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + class MoveTreeWorkItemTest : public testing::Test { + protected: + virtual void SetUp() { + // Name a subdirectory of the user temp directory. + ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_)); + file_util::AppendToPath(&test_dir_, L"MoveTreeWorkItemTest"); + + // Create a fresh, empty copy of this test directory. + file_util::Delete(test_dir_, true); + CreateDirectory(test_dir_.c_str(), NULL); + + // Create a tempory directory under the test directory. + temp_dir_.assign(test_dir_); + file_util::AppendToPath(&temp_dir_, L"temp"); + CreateDirectory(temp_dir_.c_str(), NULL); + + ASSERT_TRUE(file_util::PathExists(test_dir_)); + ASSERT_TRUE(file_util::PathExists(temp_dir_)); + } + + virtual void TearDown() { + // Clean up test directory + ASSERT_TRUE(file_util::Delete(test_dir_, false)); + ASSERT_FALSE(file_util::PathExists(test_dir_)); + } + + // the path to temporary directory used to contain the test operations + std::wstring test_dir_; + std::wstring temp_dir_; + }; + + // Simple function to dump some text into a new file. + void CreateTextFile(const std::wstring& filename, + const std::wstring& contents) { + std::ofstream file; + file.open(filename.c_str()); + ASSERT_TRUE(file.is_open()); + file << contents; + file.close(); + } + + // Simple function to read text from a file. + std::wstring ReadTextFile(const std::wstring& filename) { + WCHAR contents[64]; + std::wifstream file; + file.open(filename.c_str()); + EXPECT_TRUE(file.is_open()); + file.getline(contents, 64); + file.close(); + return std::wstring(contents); + } + + wchar_t text_content_1[] = L"Gooooooooooooooooooooogle"; + wchar_t text_content_2[] = L"Overwrite Me"; +}; + +// Move one directory from source to destination when destination does not +// exist. +TEST_F(MoveTreeWorkItemTest, MoveDirectory) { + // Create two level deep source dir + std::wstring from_dir1(test_dir_); + file_util::AppendToPath(&from_dir1, L"From_Dir1"); + CreateDirectory(from_dir1.c_str(), NULL); + ASSERT_TRUE(file_util::PathExists(from_dir1)); + + std::wstring from_dir2(from_dir1); + file_util::AppendToPath(&from_dir2, L"From_Dir2"); + CreateDirectory(from_dir2.c_str(), NULL); + ASSERT_TRUE(file_util::PathExists(from_dir2)); + + std::wstring from_file(from_dir2); + file_util::AppendToPath(&from_file, L"From_File"); + CreateTextFile(from_file, text_content_1); + ASSERT_TRUE(file_util::PathExists(from_file)); + + // Generate destination path + std::wstring to_dir(test_dir_); + file_util::AppendToPath(&to_dir, L"To_Dir"); + ASSERT_FALSE(file_util::PathExists(to_dir)); + + std::wstring to_file(to_dir); + file_util::AppendToPath(&to_file, L"From_Dir2"); + file_util::AppendToPath(&to_file, L"From_File"); + ASSERT_FALSE(file_util::PathExists(to_file)); + + // test Do() + scoped_ptr<MoveTreeWorkItem> work_item(WorkItem::CreateMoveTreeWorkItem( + from_dir1, to_dir, temp_dir_)); + EXPECT_TRUE(work_item->Do()); + + EXPECT_FALSE(file_util::PathExists(from_dir1)); + EXPECT_TRUE(file_util::PathExists(to_dir)); + EXPECT_TRUE(file_util::PathExists(to_file)); + + // test rollback() + work_item->Rollback(); + + EXPECT_TRUE(file_util::PathExists(from_dir1)); + EXPECT_TRUE(file_util::PathExists(from_file)); + EXPECT_FALSE(file_util::PathExists(to_dir)); +} + +// Move one directory from source to destination when destination already +// exists. +TEST_F(MoveTreeWorkItemTest, MoveDirectoryDestExists) { + // Create two level deep source dir + std::wstring from_dir1(test_dir_); + file_util::AppendToPath(&from_dir1, L"From_Dir1"); + CreateDirectory(from_dir1.c_str(), NULL); + ASSERT_TRUE(file_util::PathExists(from_dir1)); + + std::wstring from_dir2(from_dir1); + file_util::AppendToPath(&from_dir2, L"From_Dir2"); + CreateDirectory(from_dir2.c_str(), NULL); + ASSERT_TRUE(file_util::PathExists(from_dir2)); + + std::wstring from_file(from_dir2); + file_util::AppendToPath(&from_file, L"From_File"); + CreateTextFile(from_file, text_content_1); + ASSERT_TRUE(file_util::PathExists(from_file)); + + // Create destination path + std::wstring to_dir(test_dir_); + file_util::AppendToPath(&to_dir, L"To_Dir"); + CreateDirectory(to_dir.c_str(), NULL); + ASSERT_TRUE(file_util::PathExists(to_dir)); + + std::wstring orig_to_file(to_dir); + file_util::AppendToPath(&orig_to_file, L"To_File"); + CreateTextFile(orig_to_file, text_content_2); + ASSERT_TRUE(file_util::PathExists(orig_to_file)); + + std::wstring new_to_file(to_dir); + file_util::AppendToPath(&new_to_file, L"From_Dir2"); + file_util::AppendToPath(&new_to_file, L"From_File"); + ASSERT_FALSE(file_util::PathExists(new_to_file)); + + // test Do() + scoped_ptr<MoveTreeWorkItem> work_item(WorkItem::CreateMoveTreeWorkItem( + from_dir1, to_dir, temp_dir_)); + EXPECT_TRUE(work_item->Do()); + + EXPECT_FALSE(file_util::PathExists(from_dir1)); + EXPECT_TRUE(file_util::PathExists(to_dir)); + EXPECT_TRUE(file_util::PathExists(new_to_file)); + EXPECT_FALSE(file_util::PathExists(orig_to_file)); + + // test rollback() + work_item->Rollback(); + + EXPECT_TRUE(file_util::PathExists(from_dir1)); + EXPECT_TRUE(file_util::PathExists(to_dir)); + EXPECT_FALSE(file_util::PathExists(new_to_file)); + EXPECT_TRUE(file_util::PathExists(orig_to_file)); + EXPECT_EQ(0, ReadTextFile(orig_to_file).compare(text_content_2)); + EXPECT_EQ(0, ReadTextFile(from_file).compare(text_content_1)); +} + +// Move one file from source to destination when destination does not +// exist. +TEST_F(MoveTreeWorkItemTest, MoveAFile) { + // Create a file inside source dir + std::wstring from_dir(test_dir_); + file_util::AppendToPath(&from_dir, L"From_Dir"); + CreateDirectory(from_dir.c_str(), NULL); + ASSERT_TRUE(file_util::PathExists(from_dir)); + + std::wstring from_file(from_dir); + file_util::AppendToPath(&from_file, L"From_File"); + CreateTextFile(from_file, text_content_1); + ASSERT_TRUE(file_util::PathExists(from_file)); + + // Generate destination file name + std::wstring to_file(test_dir_); + file_util::AppendToPath(&to_file, L"To_File"); + ASSERT_FALSE(file_util::PathExists(to_file)); + + // test Do() + scoped_ptr<MoveTreeWorkItem> work_item(WorkItem::CreateMoveTreeWorkItem( + from_file, to_file, temp_dir_)); + EXPECT_TRUE(work_item->Do()); + + EXPECT_TRUE(file_util::PathExists(from_dir)); + EXPECT_FALSE(file_util::PathExists(from_file)); + EXPECT_TRUE(file_util::PathExists(to_file)); + EXPECT_EQ(0, ReadTextFile(to_file).compare(text_content_1)); + + // test rollback() + work_item->Rollback(); + + EXPECT_TRUE(file_util::PathExists(from_dir)); + EXPECT_TRUE(file_util::PathExists(from_file)); + EXPECT_FALSE(file_util::PathExists(to_file)); + EXPECT_EQ(0, ReadTextFile(from_file).compare(text_content_1)); +} + +// Move one file from source to destination when destination already +// exists. +TEST_F(MoveTreeWorkItemTest, MoveFileDestExists) { + // Create a file inside source dir + std::wstring from_dir(test_dir_); + file_util::AppendToPath(&from_dir, L"From_Dir"); + CreateDirectory(from_dir.c_str(), NULL); + ASSERT_TRUE(file_util::PathExists(from_dir)); + + std::wstring from_file(from_dir); + file_util::AppendToPath(&from_file, L"From_File"); + CreateTextFile(from_file, text_content_1); + ASSERT_TRUE(file_util::PathExists(from_file)); + + // Create destination path + std::wstring to_dir(test_dir_); + file_util::AppendToPath(&to_dir, L"To_Dir"); + CreateDirectory(to_dir.c_str(), NULL); + ASSERT_TRUE(file_util::PathExists(to_dir)); + + std::wstring to_file(to_dir); + file_util::AppendToPath(&to_file, L"To_File"); + CreateTextFile(to_file, text_content_2); + ASSERT_TRUE(file_util::PathExists(to_file)); + + // test Do() + scoped_ptr<MoveTreeWorkItem> work_item(WorkItem::CreateMoveTreeWorkItem( + from_file, to_dir, temp_dir_)); + EXPECT_TRUE(work_item->Do()); + + EXPECT_TRUE(file_util::PathExists(from_dir)); + EXPECT_FALSE(file_util::PathExists(from_file)); + EXPECT_TRUE(file_util::PathExists(to_dir)); + EXPECT_FALSE(file_util::PathExists(to_file)); + EXPECT_EQ(0, ReadTextFile(to_dir).compare(text_content_1)); + + // test rollback() + work_item->Rollback(); + + EXPECT_TRUE(file_util::PathExists(from_dir)); + EXPECT_EQ(0, ReadTextFile(from_file).compare(text_content_1)); + EXPECT_TRUE(file_util::PathExists(to_dir)); + EXPECT_EQ(0, ReadTextFile(to_file).compare(text_content_2)); +} + +// Move one file from source to destination when destination already +// exists and is in use. +TEST_F(MoveTreeWorkItemTest, MoveFileDestInUse) { + // Create a file inside source dir + std::wstring from_dir(test_dir_); + file_util::AppendToPath(&from_dir, L"From_Dir"); + CreateDirectory(from_dir.c_str(), NULL); + ASSERT_TRUE(file_util::PathExists(from_dir)); + + std::wstring from_file(from_dir); + file_util::AppendToPath(&from_file, L"From_File"); + CreateTextFile(from_file, text_content_1); + ASSERT_TRUE(file_util::PathExists(from_file)); + + // Create an executable in destination path by copying ourself to it. + std::wstring to_dir(test_dir_); + file_util::AppendToPath(&to_dir, L"To_Dir"); + CreateDirectory(to_dir.c_str(), NULL); + ASSERT_TRUE(file_util::PathExists(to_dir)); + + wchar_t exe_full_path_str[MAX_PATH]; + ::GetModuleFileName(NULL, exe_full_path_str, MAX_PATH); + std::wstring exe_full_path(exe_full_path_str); + std::wstring to_file(to_dir); + file_util::AppendToPath(&to_file, L"To_File"); + file_util::CopyFile(exe_full_path, to_file); + ASSERT_TRUE(file_util::PathExists(to_file)); + + // Run the executable in destination path + STARTUPINFOW si = {sizeof(si)}; + PROCESS_INFORMATION pi = {0}; + ASSERT_TRUE(::CreateProcess(NULL, const_cast<wchar_t*>(to_file.c_str()), + NULL, NULL, FALSE, + CREATE_NO_WINDOW | CREATE_SUSPENDED, + NULL, NULL, &si, &pi)); + + // test Do() + scoped_ptr<MoveTreeWorkItem> work_item(WorkItem::CreateMoveTreeWorkItem( + from_file, to_file, temp_dir_)); + EXPECT_TRUE(work_item->Do()); + + EXPECT_TRUE(file_util::PathExists(from_dir)); + EXPECT_FALSE(file_util::PathExists(from_file)); + EXPECT_TRUE(file_util::PathExists(to_dir)); + EXPECT_EQ(0, ReadTextFile(to_file).compare(text_content_1)); + + // test rollback() + work_item->Rollback(); + + EXPECT_TRUE(file_util::PathExists(from_dir)); + EXPECT_EQ(0, ReadTextFile(from_file).compare(text_content_1)); + EXPECT_TRUE(file_util::PathExists(to_dir)); + EXPECT_TRUE(file_util::ContentsEqual(exe_full_path, to_file)); + + TerminateProcess(pi.hProcess, 0); + EXPECT_TRUE(WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); +} + +// Move one file that is in use to destination. +TEST_F(MoveTreeWorkItemTest, MoveFileInUse) { + // Create an executable for source by copying ourself to a new source dir. + std::wstring from_dir(test_dir_); + file_util::AppendToPath(&from_dir, L"From_Dir"); + CreateDirectory(from_dir.c_str(), NULL); + ASSERT_TRUE(file_util::PathExists(from_dir)); + + wchar_t exe_full_path_str[MAX_PATH]; + ::GetModuleFileName(NULL, exe_full_path_str, MAX_PATH); + std::wstring exe_full_path(exe_full_path_str); + std::wstring from_file(from_dir); + file_util::AppendToPath(&from_file, L"From_File"); + file_util::CopyFile(exe_full_path, from_file); + ASSERT_TRUE(file_util::PathExists(from_file)); + + // Create a destination source dir and generate destination file name. + std::wstring to_dir(test_dir_); + file_util::AppendToPath(&to_dir, L"To_Dir"); + CreateDirectory(to_dir.c_str(), NULL); + ASSERT_TRUE(file_util::PathExists(to_dir)); + + std::wstring to_file(to_dir); + file_util::AppendToPath(&to_file, L"To_File"); + CreateTextFile(to_file, text_content_1); + ASSERT_TRUE(file_util::PathExists(to_file)); + + // Run the executable in source path + STARTUPINFOW si = {sizeof(si)}; + PROCESS_INFORMATION pi = {0}; + ASSERT_TRUE(::CreateProcess(NULL, const_cast<wchar_t*>(from_file.c_str()), + NULL, NULL, FALSE, + CREATE_NO_WINDOW | CREATE_SUSPENDED, + NULL, NULL, &si, &pi)); + + // test Do() + scoped_ptr<MoveTreeWorkItem> work_item(WorkItem::CreateMoveTreeWorkItem( + from_file, to_file, temp_dir_)); + EXPECT_TRUE(work_item->Do()); + + EXPECT_TRUE(file_util::PathExists(from_dir)); + EXPECT_FALSE(file_util::PathExists(from_file)); + EXPECT_TRUE(file_util::PathExists(to_dir)); + EXPECT_TRUE(file_util::ContentsEqual(exe_full_path, to_file)); + + // Close the process and make sure all the conditions after Do() are + // still true. + TerminateProcess(pi.hProcess, 0); + EXPECT_TRUE(WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + EXPECT_TRUE(file_util::PathExists(from_dir)); + EXPECT_FALSE(file_util::PathExists(from_file)); + EXPECT_TRUE(file_util::PathExists(to_dir)); + EXPECT_TRUE(file_util::ContentsEqual(exe_full_path, to_file)); + + // test rollback() + work_item->Rollback(); + + EXPECT_TRUE(file_util::PathExists(from_dir)); + EXPECT_TRUE(file_util::ContentsEqual(exe_full_path, from_file)); + EXPECT_TRUE(file_util::PathExists(to_dir)); + EXPECT_EQ(0, ReadTextFile(to_file).compare(text_content_1)); +} diff --git a/chrome/installer/util/util.vcproj b/chrome/installer/util/util.vcproj index 99c7fe3..59f72da 100644 --- a/chrome/installer/util/util.vcproj +++ b/chrome/installer/util/util.vcproj @@ -265,6 +265,14 @@ > </File> <File + RelativePath=".\move_tree_work_item.cc" + > + </File> + <File + RelativePath=".\move_tree_work_item.h" + > + </File> + <File RelativePath=".\set_reg_value_work_item.cc" > </File> diff --git a/chrome/installer/util/work_item.cc b/chrome/installer/util/work_item.cc index 7905405..568a79d 100644 --- a/chrome/installer/util/work_item.cc +++ b/chrome/installer/util/work_item.cc @@ -9,6 +9,7 @@ #include "chrome/installer/util/create_reg_key_work_item.h" #include "chrome/installer/util/delete_tree_work_item.h" #include "chrome/installer/util/delete_reg_value_work_item.h" +#include "chrome/installer/util/move_tree_work_item.h" #include "chrome/installer/util/set_reg_value_work_item.h" #include "chrome/installer/util/work_item_list.h" @@ -46,6 +47,12 @@ DeleteTreeWorkItem* WorkItem::CreateDeleteTreeWorkItem(std::wstring root_path, return new DeleteTreeWorkItem(root_path, key_path); } +MoveTreeWorkItem* WorkItem::CreateMoveTreeWorkItem(std::wstring source_path, + std::wstring dest_path, + std::wstring temp_dir) { + return new MoveTreeWorkItem(source_path, dest_path, temp_dir); +} + SetRegValueWorkItem* WorkItem::CreateSetRegValueWorkItem( HKEY predefined_root, std::wstring key_path, std::wstring value_name, std::wstring value_data, bool overwrite) { diff --git a/chrome/installer/util/work_item.h b/chrome/installer/util/work_item.h index 08942a1..f23e181 100644 --- a/chrome/installer/util/work_item.h +++ b/chrome/installer/util/work_item.h @@ -17,6 +17,7 @@ class CreateDirWorkItem; class CreateRegKeyWorkItem; class DeleteTreeWorkItem; class DeleteRegValueWorkItem; +class MoveTreeWorkItem; class SetRegValueWorkItem; class WorkItemList; @@ -65,6 +66,11 @@ class WorkItem { static DeleteTreeWorkItem* CreateDeleteTreeWorkItem(std::wstring root_path, std::wstring key_path); + // Create a MoveTreeWorkItem that recursively moves a file system hierarchy + // from source path to destination path. + static MoveTreeWorkItem* CreateMoveTreeWorkItem(std::wstring source_path, + std::wstring dest_path, std::wstring temp_dir); + // Create a SetRegValueWorkItem that sets a registry value with REG_SZ type // at the key with specified path. static SetRegValueWorkItem* CreateSetRegValueWorkItem( diff --git a/chrome/installer/util/work_item_list.cc b/chrome/installer/util/work_item_list.cc index ef0a9c4..0115e81 100644 --- a/chrome/installer/util/work_item_list.cc +++ b/chrome/installer/util/work_item_list.cc @@ -104,6 +104,14 @@ bool WorkItemList::AddDeleteTreeWorkItem(std::wstring root_path, return AddWorkItem(item); } +bool WorkItemList::AddMoveTreeWorkItem(std::wstring source_path, + std::wstring dest_path, + std::wstring temp_dir) { + WorkItem* item = reinterpret_cast<WorkItem*>( + WorkItem::CreateMoveTreeWorkItem(source_path, dest_path, temp_dir)); + return AddWorkItem(item); +} + bool WorkItemList::AddSetRegValueWorkItem(HKEY predefined_root, std::wstring key_path, std::wstring value_name, diff --git a/chrome/installer/util/work_item_list.h b/chrome/installer/util/work_item_list.h index 18cb186..c59272f 100644 --- a/chrome/installer/util/work_item_list.h +++ b/chrome/installer/util/work_item_list.h @@ -54,6 +54,10 @@ class WorkItemList : public WorkItem { // by key_path. bool AddDeleteTreeWorkItem(std::wstring root_path, std::wstring key_path); + // Add a MoveTreeWorkItem to the list of work items. + bool AddMoveTreeWorkItem(std::wstring source_path, std::wstring dest_path, + std::wstring temp_dir); + // Add a SetRegValueWorkItem that sets a registry value with REG_SZ type // at the key with specified path. bool AddSetRegValueWorkItem(HKEY predefined_root, std::wstring key_path, |