summaryrefslogtreecommitdiffstats
path: root/chrome/installer
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/installer')
-rw-r--r--chrome/installer/setup/install.cc74
-rwxr-xr-x[-rw-r--r--]chrome/installer/setup/main.cc54
-rw-r--r--chrome/installer/setup/setup_constants.cc2
-rw-r--r--chrome/installer/setup/setup_constants.h2
-rw-r--r--chrome/installer/util/copy_tree_work_item.cc29
-rw-r--r--chrome/installer/util/copy_tree_work_item.h2
-rw-r--r--chrome/installer/util/copy_tree_work_item_unittest.cc34
-rw-r--r--chrome/installer/util/delete_reg_value_work_item.cc82
-rw-r--r--chrome/installer/util/delete_reg_value_work_item.h65
-rw-r--r--chrome/installer/util/delete_reg_value_work_item_unittest.cc105
-rw-r--r--chrome/installer/util/google_update_constants.cc2
-rw-r--r--chrome/installer/util/google_update_constants.h2
-rw-r--r--chrome/installer/util/installer_unittests.vcproj4
-rw-r--r--chrome/installer/util/util.vcproj8
-rwxr-xr-xchrome/installer/util/util_constants.cc6
-rwxr-xr-xchrome/installer/util/util_constants.h5
-rw-r--r--chrome/installer/util/work_item.cc9
-rw-r--r--chrome/installer/util/work_item.h23
-rw-r--r--chrome/installer/util/work_item_list.cc10
-rw-r--r--chrome/installer/util/work_item_list.h5
20 files changed, 470 insertions, 53 deletions
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc
index 34429b3..b051f82 100644
--- a/chrome/installer/setup/install.cc
+++ b/chrome/installer/setup/install.cc
@@ -5,13 +5,16 @@
#include <time.h>
#include "base/file_util.h"
+#include "base/registry.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "chrome/installer/setup/setup.h"
#include "chrome/installer/setup/setup_constants.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/google_update_constants.h"
+#include "chrome/installer/util/set_reg_value_work_item.h"
#include "chrome/installer/util/shell_util.h"
+#include "chrome/installer/util/work_item.h"
namespace {
std::wstring AppendPath(const std::wstring parent_path,
@@ -154,13 +157,22 @@ bool installer::InstallNewVersion(const std::wstring& exe_path,
// Delete any new_chrome.exe if present (we will end up create a new one
// if required) and then copy chrome.exe
- install_list->AddDeleteTreeWorkItem(
- AppendPath(install_path, installer::kChromeNewExe), std::wstring());
+ std::wstring new_chrome_exe = AppendPath(install_path,
+ installer_util::kChromeNewExe);
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ RegKey chrome_key(reg_root, dist->GetVersionKey().c_str(),
+ KEY_READ | KEY_WRITE);
+ std::wstring current_version;
+ if (file_util::PathExists(new_chrome_exe))
+ chrome_key.ReadValue(google_update::kRegOldVersionField, &current_version);
+ if (current_version.empty())
+ chrome_key.ReadValue(google_update::kRegVersionField, &current_version);
+
+ install_list->AddDeleteTreeWorkItem(new_chrome_exe, std::wstring());
install_list->AddCopyTreeWorkItem(
AppendPath(src_path, installer_util::kChromeExe),
AppendPath(install_path, installer_util::kChromeExe),
- temp_dir, WorkItem::RENAME_IF_IN_USE,
- AppendPath(install_path, installer::kChromeNewExe));
+ temp_dir, WorkItem::NEW_NAME_IF_IN_USE, new_chrome_exe);
// Extra executable for 64 bit systems.
if (Is64bit()) {
@@ -180,14 +192,13 @@ bool installer::InstallNewVersion(const std::wstring& exe_path,
// add shortcut in Control Panel->Add/Remove Programs.
AddInstallerCopyTasks(exe_path, archive_path, temp_dir, install_path,
new_version.GetString(), install_list.get());
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
std::wstring product_name = dist->GetApplicationName();
AddUninstallShortcutWorkItems(reg_root, exe_path, install_path,
product_name, new_version.GetString(), install_list.get());
// Delete any old_chrome.exe if present.
install_list->AddDeleteTreeWorkItem(
- AppendPath(install_path, installer::kChromeOldExe), std::wstring());
+ AppendPath(install_path, installer_util::kChromeOldExe), std::wstring());
// Create Version key (if not already present) and set the new Chrome
// version as last step.
@@ -203,13 +214,56 @@ bool installer::InstallNewVersion(const std::wstring& exe_path,
true); // overwrite version
// Perform install operations.
- if (!install_list->Do()) {
+ bool success = install_list->Do();
+
+ // If the installation worked, handle the in-use update case:
+ // * If new_chrome.exe exists, then currently Chrome was in use so save
+ // current version in old version key.
+ // * If new_chrome.exe doesnt exist, then delete old version key.
+ if (success) {
+ if (file_util::PathExists(new_chrome_exe)) {
+ if (current_version.empty()) {
+ LOG(ERROR) << "New chrome.exe exists but current version is empty!";
+ success = false;
+ } else {
+ scoped_ptr<WorkItemList> inuse_list(WorkItem::CreateWorkItemList());
+ inuse_list->AddSetRegValueWorkItem(reg_root,
+ version_key,
+ google_update::kRegOldVersionField,
+ current_version.c_str(),
+ true);
+ std::wstring rename_cmd(installer::GetInstallerPathUnderChrome(
+ install_path, new_version.GetString()));
+ file_util::AppendToPath(&rename_cmd,
+ file_util::GetFilenameFromPath(exe_path));
+ rename_cmd = L"\"" + rename_cmd + L"\" --" +
+ installer_util::switches::kRenameChromeExe;
+ inuse_list->AddSetRegValueWorkItem(reg_root,
+ version_key,
+ google_update::kRegRenameCmdField,
+ rename_cmd.c_str(),
+ true);
+ if (!inuse_list->Do()) {
+ LOG(ERROR) << "Couldn't write old version/rename value to registry.";
+ success = false;
+ inuse_list->Rollback();
+ }
+ }
+ } else {
+ if (chrome_key.ValueExists(google_update::kRegOldVersionField) &&
+ !chrome_key.DeleteValue(google_update::kRegOldVersionField)) {
+ LOG(ERROR) << "New chrome.exe doesn't exist but failed to delete "
+ << "old version value in registry.";
+ success = false;
+ }
+ }
+ }
+
+ if (!success) {
LOG(ERROR) << "Install failed, rolling back... ";
install_list->Rollback();
LOG(ERROR) << "Rollback complete. ";
- return false;
}
-
- return true;
+ return success;
}
diff --git a/chrome/installer/setup/main.cc b/chrome/installer/setup/main.cc
index 57730e3..730f4ff 100644..100755
--- a/chrome/installer/setup/main.cc
+++ b/chrome/installer/setup/main.cc
@@ -161,6 +161,55 @@ installer::Version* GetVersionFromDir(const std::wstring& chrome_path) {
return version;
}
+// This function is called when --rename-chrome-exe option is specified on
+// setup.exe command line. This function assumes an in-use update has happened
+// for Chrome so there should be a file called new_chrome.exe on the file
+// system and a key called 'opv' in the registry. This function will move
+// new_chrome.exe to chrome.exe and delete 'opv' key in one atomic operation.
+installer_util::InstallStatus RenameChromeExecutables(bool system_install) {
+ std::wstring chrome_path(installer::GetChromeInstallPath(system_install));
+
+ std::wstring chrome_exe(chrome_path);
+ file_util::AppendToPath(&chrome_exe, installer_util::kChromeExe);
+ std::wstring chrome_old_exe(chrome_path);
+ file_util::AppendToPath(&chrome_old_exe, installer_util::kChromeOldExe);
+ std::wstring chrome_new_exe(chrome_path);
+ file_util::AppendToPath(&chrome_new_exe, installer_util::kChromeNewExe);
+
+ scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
+ install_list->AddDeleteTreeWorkItem(chrome_old_exe, std::wstring());
+ std::wstring temp_path;
+ if (!file_util::CreateNewTempDirectory(std::wstring(L"chrome_"),
+ &temp_path)) {
+ LOG(ERROR) << "Failed to create Temp directory " << temp_path;
+ return installer_util::RENAME_FAILED;
+ }
+ install_list->AddCopyTreeWorkItem(chrome_new_exe,
+ chrome_exe,
+ temp_path,
+ WorkItem::IF_DIFFERENT,
+ std::wstring());
+ HKEY reg_root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ BrowserDistribution *dist = BrowserDistribution::GetDistribution();
+ install_list->AddDeleteRegValueWorkItem(reg_root,
+ dist->GetVersionKey(),
+ google_update::kRegOldVersionField,
+ true);
+ install_list->AddDeleteTreeWorkItem(chrome_new_exe, std::wstring());
+ install_list->AddDeleteRegValueWorkItem(reg_root,
+ dist->GetVersionKey(),
+ google_update::kRegRenameCmdField,
+ true);
+ installer_util::InstallStatus ret = installer_util::RENAME_SUCCESSFUL;
+ if (!install_list->Do()) {
+ LOG(ERROR) << "Renaming of executables failed. Rolling back any changes.";
+ install_list->Rollback();
+ ret = installer_util::RENAME_FAILED;
+ }
+ file_util::Delete(temp_path, true);
+ return ret;
+}
+
// Parse command line and read master profile, if present, to get distribution
// related install options.
int GetInstallOptions(const CommandLine& cmd_line) {
@@ -450,6 +499,11 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
std::wstring chrome_exe(parsed_command_line.GetSwitchValue(
installer_util::switches::kRegisterChromeBrowser));
return ShellUtil::AddChromeToSetAccessDefaults(chrome_exe, true);
+ // If --rename-chrome-exe is specified, we want to rename the executables
+ // and exit.
+ } else if (parsed_command_line.HasSwitch(
+ installer_util::switches::kRenameChromeExe)) {
+ return RenameChromeExecutables(system_install);
}
if (system_install &&
diff --git a/chrome/installer/setup/setup_constants.cc b/chrome/installer/setup/setup_constants.cc
index 4240022..a307b44 100644
--- a/chrome/installer/setup/setup_constants.cc
+++ b/chrome/installer/setup/setup_constants.cc
@@ -6,8 +6,6 @@
namespace installer {
// Elements that makes up install target path.
-const wchar_t kChromeOldExe[] = L"old_chrome.exe";
-const wchar_t kChromeNewExe[] = L"new_chrome.exe";
const wchar_t kWowHelperExe[] = L"wow_helper.exe";
const wchar_t kDictionaries[] = L"Dictionaries";
const wchar_t kChromeArchive[] = L"chrome.7z";
diff --git a/chrome/installer/setup/setup_constants.h b/chrome/installer/setup/setup_constants.h
index b8a90e8..b95d774 100644
--- a/chrome/installer/setup/setup_constants.h
+++ b/chrome/installer/setup/setup_constants.h
@@ -9,8 +9,6 @@
namespace installer {
-extern const wchar_t kChromeOldExe[];
-extern const wchar_t kChromeNewExe[];
extern const wchar_t kWowHelperExe[];
extern const wchar_t kDictionaries[];
extern const wchar_t kChromeArchive[];
diff --git a/chrome/installer/util/copy_tree_work_item.cc b/chrome/installer/util/copy_tree_work_item.cc
index 3e49a30..fc1d5e3 100644
--- a/chrome/installer/util/copy_tree_work_item.cc
+++ b/chrome/installer/util/copy_tree_work_item.cc
@@ -36,7 +36,7 @@ bool CopyTreeWorkItem::Do() {
}
bool dest_exist = file_util::PathExists(dest_path_);
- // handle overwrite_option_ = IF_DIFFERENT case
+ // handle overwrite_option_ = IF_DIFFERENT case.
if ((dest_exist) &&
(overwrite_option_ == WorkItem::IF_DIFFERENT) && // only for single file
(!PathIsDirectory(source_path_.c_str())) &&
@@ -46,14 +46,12 @@ bool CopyTreeWorkItem::Do() {
<< " and destination file " << dest_path_
<< " are exactly same. Returning true.";
return true;
- }
-
- // handle overwrite_option_ = RENAME_IF_IN_USE case
- if ((dest_exist) &&
- (overwrite_option_ == WorkItem::RENAME_IF_IN_USE) && // only for a file
- (!PathIsDirectory(source_path_.c_str())) &&
- (!PathIsDirectory(dest_path_.c_str())) &&
- (IsFileInUse(dest_path_))) {
+ } else if ((dest_exist) &&
+ (overwrite_option_ == WorkItem::NEW_NAME_IF_IN_USE) &&
+ (!PathIsDirectory(source_path_.c_str())) &&
+ (!PathIsDirectory(dest_path_.c_str())) &&
+ (IsFileInUse(dest_path_))) {
+ // handle overwrite_option_ = NEW_NAME_IF_IN_USE case.
if (alternative_path_.empty() ||
file_util::PathExists(alternative_path_) ||
!file_util::CopyFile(source_path_, alternative_path_)) {
@@ -66,15 +64,13 @@ bool CopyTreeWorkItem::Do() {
<< " to alternative path " << alternative_path_;
return true;
}
- }
-
- // handle overwrite_option_ = IF_NOT_PRESENT case
- if ((dest_exist) &&
- (overwrite_option_ == WorkItem::IF_NOT_PRESENT)) {
+ } else if ((dest_exist) &&
+ (overwrite_option_ == WorkItem::IF_NOT_PRESENT)) {
+ // handle overwrite_option_ = IF_NOT_PRESENT case.
return true;
- }
+ }
- // All other cases where we move dest if it exists, and copy the files
+ // In all cases that reach here, move dest to a backup path.
if (dest_exist) {
if (!GetBackupPath())
return false;
@@ -89,6 +85,7 @@ bool CopyTreeWorkItem::Do() {
}
}
+ // In all cases that reach here, copy source to destination.
if (file_util::CopyDirectory(source_path_, dest_path_, true)) {
copied_to_dest_path_ = true;
LOG(INFO) << "Copied source " << source_path_
diff --git a/chrome/installer/util/copy_tree_work_item.h b/chrome/installer/util/copy_tree_work_item.h
index e463822..c7b5e41 100644
--- a/chrome/installer/util/copy_tree_work_item.h
+++ b/chrome/installer/util/copy_tree_work_item.h
@@ -56,7 +56,7 @@ class CopyTreeWorkItem : public WorkItem {
// Controls the behavior for overwriting.
CopyOverWriteOption overwrite_option_;
- // If overwrite_option_ = RENAME_IF_IN_USE, this variables stores the path
+ // If overwrite_option_ = NEW_NAME_IF_IN_USE, this variables stores the path
// to be used if the file is in use and hence we want to copy it to a
// different path.
std::wstring alternative_path_;
diff --git a/chrome/installer/util/copy_tree_work_item_unittest.cc b/chrome/installer/util/copy_tree_work_item_unittest.cc
index db3e8c5..1e0c04a 100644
--- a/chrome/installer/util/copy_tree_work_item_unittest.cc
+++ b/chrome/installer/util/copy_tree_work_item_unittest.cc
@@ -307,7 +307,7 @@ TEST_F(CopyTreeWorkItemTest, CopyFileInUse) {
// Create an executable in destination path by copying ourself to it.
wchar_t exe_full_path_str[MAX_PATH];
- ::GetModuleFileNameW(NULL, 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 dir_name_to(test_dir_);
@@ -326,7 +326,7 @@ TEST_F(CopyTreeWorkItemTest, CopyFileInUse) {
STARTUPINFOW si = {sizeof(si)};
PROCESS_INFORMATION pi = {0};
ASSERT_TRUE(
- ::CreateProcessW(NULL, const_cast<wchar_t*>(file_name_to.c_str()),
+ ::CreateProcess(NULL, const_cast<wchar_t*>(file_name_to.c_str()),
NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_SUSPENDED,
NULL, NULL, &si, &pi));
@@ -361,16 +361,18 @@ TEST_F(CopyTreeWorkItemTest, CopyFileInUse) {
TerminateProcess(pi.hProcess, 0);
// make sure the handle is closed.
- WaitForSingleObject(pi.hProcess, INFINITE);
+ EXPECT_TRUE(WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
}
-// Test overwrite option RENAME_IF_IN_USE:
+// Test overwrite option NEW_NAME_IF_IN_USE:
// 1. If destination file is in use, the source should be copied with the
// new name after Do() and this new name file should be deleted
// after rollback.
// 2. If destination file is not in use, the source should be copied in the
// destination folder after Do() and should be rolled back after Rollback().
-TEST_F(CopyTreeWorkItemTest, RenameAndCopyTest) {
+TEST_F(CopyTreeWorkItemTest, NewNameAndCopyTest) {
// Create source file
std::wstring file_name_from(test_dir_);
file_util::AppendToPath(&file_name_from, L"File_From");
@@ -379,7 +381,7 @@ TEST_F(CopyTreeWorkItemTest, RenameAndCopyTest) {
// Create an executable in destination path by copying ourself to it.
wchar_t exe_full_path_str[MAX_PATH];
- ::GetModuleFileNameW(NULL, 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 dir_name_to(test_dir_);
@@ -399,7 +401,7 @@ TEST_F(CopyTreeWorkItemTest, RenameAndCopyTest) {
STARTUPINFOW si = {sizeof(si)};
PROCESS_INFORMATION pi = {0};
ASSERT_TRUE(
- ::CreateProcessW(NULL, const_cast<wchar_t*>(file_name_to.c_str()),
+ ::CreateProcess(NULL, const_cast<wchar_t*>(file_name_to.c_str()),
NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_SUSPENDED,
NULL, NULL, &si, &pi));
@@ -410,7 +412,7 @@ TEST_F(CopyTreeWorkItemTest, RenameAndCopyTest) {
// test Do().
scoped_ptr<CopyTreeWorkItem> work_item(
WorkItem::CreateCopyTreeWorkItem(file_name_from, file_name_to,
- temp_dir_, WorkItem::RENAME_IF_IN_USE,
+ temp_dir_, WorkItem::NEW_NAME_IF_IN_USE,
alternate_to));
EXPECT_TRUE(work_item->Do());
@@ -436,11 +438,13 @@ TEST_F(CopyTreeWorkItemTest, RenameAndCopyTest) {
TerminateProcess(pi.hProcess, 0);
// make sure the handle is closed.
- WaitForSingleObject(pi.hProcess, INFINITE);
+ EXPECT_TRUE(WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
// Now the process has terminated, lets try overwriting the file again
work_item.reset(WorkItem::CreateCopyTreeWorkItem(
- file_name_from, file_name_to, temp_dir_, WorkItem::RENAME_IF_IN_USE,
+ file_name_from, file_name_to, temp_dir_, WorkItem::NEW_NAME_IF_IN_USE,
alternate_to));
EXPECT_TRUE(work_item->Do());
@@ -478,7 +482,7 @@ TEST_F(CopyTreeWorkItemTest, IfNotPresentTest) {
// Create an executable in destination path by copying ourself to it.
wchar_t exe_full_path_str[MAX_PATH];
- ::GetModuleFileNameW(NULL, 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 dir_name_to(test_dir_);
file_util::AppendToPath(&dir_name_to, L"Copy_To_Subdir");
@@ -554,7 +558,7 @@ TEST_F(CopyTreeWorkItemTest, CopyFileInUseAndCleanup) {
// Create an executable in destination path by copying ourself to it.
wchar_t exe_full_path_str[MAX_PATH];
- ::GetModuleFileNameW(NULL, 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 dir_name_to(test_dir_);
@@ -573,7 +577,7 @@ TEST_F(CopyTreeWorkItemTest, CopyFileInUseAndCleanup) {
STARTUPINFOW si = {sizeof(si)};
PROCESS_INFORMATION pi = {0};
ASSERT_TRUE(
- ::CreateProcessW(NULL, const_cast<wchar_t*>(file_name_to.c_str()),
+ ::CreateProcess(NULL, const_cast<wchar_t*>(file_name_to.c_str()),
NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_SUSPENDED,
NULL, NULL, &si, &pi));
@@ -604,7 +608,9 @@ TEST_F(CopyTreeWorkItemTest, CopyFileInUseAndCleanup) {
TerminateProcess(pi.hProcess, 0);
// make sure the handle is closed.
- WaitForSingleObject(pi.hProcess, INFINITE);
+ EXPECT_TRUE(WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
}
// Copy a tree from source to destination.
diff --git a/chrome/installer/util/delete_reg_value_work_item.cc b/chrome/installer/util/delete_reg_value_work_item.cc
new file mode 100644
index 0000000..b2f162a
--- /dev/null
+++ b/chrome/installer/util/delete_reg_value_work_item.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2006-2008 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/delete_reg_value_work_item.h"
+
+#include "base/registry.h"
+#include "chrome/installer/util/logging_installer.h"
+
+DeleteRegValueWorkItem::DeleteRegValueWorkItem(HKEY predefined_root,
+ std::wstring key_path,
+ std::wstring value_name,
+ bool is_str_type)
+ : predefined_root_(predefined_root),
+ key_path_(key_path),
+ value_name_(value_name),
+ is_str_type_(is_str_type),
+ status_(DELETE_VALUE) {
+}
+
+DeleteRegValueWorkItem::~DeleteRegValueWorkItem() {
+}
+
+bool DeleteRegValueWorkItem::Do() {
+ if (status_ != DELETE_VALUE) {
+ // we already did something.
+ LOG(ERROR) << "multiple calls to Do()";
+ return false;
+ }
+
+ RegKey key;
+ status_ = VALUE_UNCHANGED;
+ bool result = false;
+ if (!key.Open(predefined_root_, key_path_.c_str(), KEY_READ | KEY_WRITE)) {
+ LOG(ERROR) << "can not open " << key_path_;
+ } else if (!key.ValueExists(value_name_.c_str())) {
+ status_ = VALUE_NOT_FOUND;
+ result = true;
+ // Read previous value for rollback and delete
+ } else if (((is_str_type_ && key.ReadValue(value_name_.c_str(),
+ &old_str_)) ||
+ (!is_str_type_ && key.ReadValueDW(value_name_.c_str(),
+ &old_dw_))) &&
+ (key.DeleteValue(value_name_.c_str()))) {
+ status_ = VALUE_DELETED;
+ result = true;
+ } else {
+ LOG(ERROR) << "failed to read/delete value " << value_name_;
+ }
+
+ key.Close();
+ return result;
+}
+
+void DeleteRegValueWorkItem::Rollback() {
+ if (status_ == DELETE_VALUE || status_ == VALUE_ROLLED_BACK) {
+ return;
+ } else if (status_ == VALUE_UNCHANGED || status_ == VALUE_NOT_FOUND) {
+ status_ = VALUE_ROLLED_BACK;
+ LOG(INFO) << "rollback: setting unchanged, nothing to do";
+ return;
+ }
+
+ // At this point only possible state is VALUE_DELETED.
+ RegKey key;
+ if (!key.Open(predefined_root_, key_path_.c_str(), KEY_READ | KEY_WRITE)) {
+ LOG(ERROR) << "rollback: can not open " << key_path_;
+ // try to restore the previous value
+ } else if ((is_str_type_ && key.WriteValue(value_name_.c_str(),
+ old_str_.c_str())) ||
+ (!is_str_type_ && key.WriteValue(value_name_.c_str(),
+ old_dw_))) {
+ status_ = VALUE_ROLLED_BACK;
+ LOG(INFO) << "rollback: restored " << value_name_;
+ } else {
+ LOG(ERROR) << "failed to restore value " << value_name_;
+ }
+
+ key.Close();
+ return;
+}
+
diff --git a/chrome/installer/util/delete_reg_value_work_item.h b/chrome/installer/util/delete_reg_value_work_item.h
new file mode 100644
index 0000000..164279a
--- /dev/null
+++ b/chrome/installer/util/delete_reg_value_work_item.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2006-2008 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_DELETE_REG_VALUE_WORK_ITEM_H_
+#define CHROME_INSTALLER_UTIL_DELETE_REG_VALUE_WORK_ITEM_H_
+
+#include <string>
+#include <windows.h>
+#include "chrome/installer/util/work_item.h"
+
+// A WorkItem subclass that sets a registry value with REG_SZ or REG_DWORD
+// type at the specified path. The value is only set if the target key exists.
+class DeleteRegValueWorkItem : public WorkItem {
+ public:
+ virtual ~DeleteRegValueWorkItem();
+
+ virtual bool Do();
+
+ virtual void Rollback();
+
+ private:
+ friend class WorkItem;
+
+ enum DeletionStatus {
+ // The status before Do is called.
+ DELETE_VALUE,
+ // One possible outcome after Do(). Value is deleted.
+ VALUE_DELETED,
+ // One possible outcome after Do(). Value is not found.
+ VALUE_NOT_FOUND,
+ // The status after Do() and Rollback() is called.
+ VALUE_ROLLED_BACK,
+ // Another possible outcome after Do() (when there is an error).
+ VALUE_UNCHANGED
+ };
+
+ DeleteRegValueWorkItem(HKEY predefined_root, std::wstring key_path,
+ std::wstring value_name, bool is_str_type);
+
+ // Root key of the target key under which the value is set. The root key can
+ // only be one of the predefined keys on Windows.
+ HKEY predefined_root_;
+
+ // Path of the target key under which the value is set.
+ std::wstring key_path_;
+
+ // Name of the value to be set.
+ std::wstring value_name_;
+
+ // boolean that tells whether data value is of type REG_SZ or REG_DWORD.
+ // Ideally we do not need this information from user of this class and can
+ // check the registry for the type. But to simpify implementation we are
+ // going to put the burden on the caller for now to provide us the type.
+ bool is_str_type_;
+
+ DeletionStatus status_;
+
+ // Data of the previous value.
+ std::wstring old_str_; // if data is of type REG_SZ
+ DWORD old_dw_; // if data is of type REG_DWORD
+};
+
+#endif // CHROME_INSTALLER_UTIL_DELETE_REG_VALUE_WORK_ITEM_H_
+
diff --git a/chrome/installer/util/delete_reg_value_work_item_unittest.cc b/chrome/installer/util/delete_reg_value_work_item_unittest.cc
new file mode 100644
index 0000000..a5c05b6
--- /dev/null
+++ b/chrome/installer/util/delete_reg_value_work_item_unittest.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2006-2008 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 "base/file_util.h"
+#include "base/logging.h"
+#include "base/registry.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "chrome/installer/util/delete_reg_value_work_item.h"
+#include "chrome/installer/util/work_item.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+ wchar_t test_root[] = L"DeleteRegValueWorkItemTest";
+ class DeleteRegValueWorkItemTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // Create a temporary key for testing
+ RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS);
+ key.DeleteKey(test_root);
+ ASSERT_FALSE(key.Open(HKEY_CURRENT_USER, test_root, KEY_READ));
+ ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, test_root, KEY_READ));
+ }
+ virtual void TearDown() {
+ logging::CloseLogFile();
+ // Clean up the temporary key
+ RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS);
+ ASSERT_TRUE(key.DeleteKey(test_root));
+ }
+ };
+};
+
+// Delete a value. The value should get deleted after Do() and should be
+// recreated after Rollback().
+TEST_F(DeleteRegValueWorkItemTest, DeleteExistingValue) {
+ RegKey key;
+ std::wstring parent_key(test_root);
+ file_util::AppendToPath(&parent_key, L"WriteNew");
+ ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, parent_key.c_str(),
+ KEY_READ | KEY_WRITE));
+ std::wstring name_str(L"name_str");
+ std::wstring data_str(L"data_111");
+ ASSERT_TRUE(key.WriteValue(name_str.c_str(), data_str.c_str()));
+ std::wstring name_dword(L"name_dword");
+ DWORD data_dword = 100;
+ ASSERT_TRUE(key.WriteValue(name_dword.c_str(), data_dword));
+
+ scoped_ptr<DeleteRegValueWorkItem> work_item1(
+ WorkItem::CreateDeleteRegValueWorkItem(HKEY_CURRENT_USER, parent_key,
+ name_str, true));
+ scoped_ptr<DeleteRegValueWorkItem> work_item2(
+ WorkItem::CreateDeleteRegValueWorkItem(HKEY_CURRENT_USER, parent_key,
+ name_dword, false));
+
+ EXPECT_TRUE(work_item1->Do());
+ EXPECT_TRUE(work_item2->Do());
+
+ EXPECT_FALSE(key.ValueExists(name_str.c_str()));
+ EXPECT_FALSE(key.ValueExists(name_dword.c_str()));
+
+ work_item1->Rollback();
+ work_item2->Rollback();
+
+ std::wstring read_str;
+ DWORD read_dword;
+ EXPECT_TRUE(key.ReadValue(name_str.c_str(), &read_str));
+ EXPECT_TRUE(key.ReadValueDW(name_dword.c_str(), &read_dword));
+ EXPECT_EQ(read_str, data_str);
+ EXPECT_EQ(read_dword, data_dword);
+}
+
+// Try deleting a value that doesn't exist.
+TEST_F(DeleteRegValueWorkItemTest, DeleteNonExistentValue) {
+ RegKey key;
+ std::wstring parent_key(test_root);
+ file_util::AppendToPath(&parent_key, L"WriteNew");
+ ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, parent_key.c_str(),
+ KEY_READ | KEY_WRITE));
+ std::wstring name_str(L"name_str");
+ std::wstring name_dword(L"name_dword");
+ EXPECT_FALSE(key.ValueExists(name_str.c_str()));
+ EXPECT_FALSE(key.ValueExists(name_dword.c_str()));
+
+ scoped_ptr<DeleteRegValueWorkItem> work_item1(
+ WorkItem::CreateDeleteRegValueWorkItem(HKEY_CURRENT_USER, parent_key,
+ name_str, true));
+ scoped_ptr<DeleteRegValueWorkItem> work_item2(
+ WorkItem::CreateDeleteRegValueWorkItem(HKEY_CURRENT_USER, parent_key,
+ name_dword, false));
+
+ EXPECT_TRUE(work_item1->Do());
+ EXPECT_TRUE(work_item2->Do());
+
+ EXPECT_FALSE(key.ValueExists(name_str.c_str()));
+ EXPECT_FALSE(key.ValueExists(name_dword.c_str()));
+
+ work_item1->Rollback();
+ work_item2->Rollback();
+
+ EXPECT_FALSE(key.ValueExists(name_str.c_str()));
+ EXPECT_FALSE(key.ValueExists(name_dword.c_str()));
+}
diff --git a/chrome/installer/util/google_update_constants.cc b/chrome/installer/util/google_update_constants.cc
index ee75f0c..a8ab8a8 100644
--- a/chrome/installer/util/google_update_constants.cc
+++ b/chrome/installer/util/google_update_constants.cc
@@ -18,6 +18,8 @@ const wchar_t kRegDidRunField[] = L"dr";
const wchar_t kRegLangField[] = L"lang";
const wchar_t kRegLastCheckedField[] = L"LastChecked";
const wchar_t kRegNameField[] = L"name";
+const wchar_t kRegOldVersionField[] = L"opv";
+const wchar_t kRegRenameCmdField[] = L"rename";
const wchar_t kRegRLZBrandField[] = L"brand";
const wchar_t kRegUsageStatsField[] = L"usagestats";
const wchar_t kRegVersionField[] = L"pv";
diff --git a/chrome/installer/util/google_update_constants.h b/chrome/installer/util/google_update_constants.h
index 2b24540..bf4f0f7 100644
--- a/chrome/installer/util/google_update_constants.h
+++ b/chrome/installer/util/google_update_constants.h
@@ -23,6 +23,8 @@ extern const wchar_t kRegDidRunField[];
extern const wchar_t kRegLangField[];
extern const wchar_t kRegLastCheckedField[];
extern const wchar_t kRegNameField[];
+extern const wchar_t kRegOldVersionField[];
+extern const wchar_t kRegRenameCmdField[];
extern const wchar_t kRegRLZBrandField[];
extern const wchar_t kRegUsageStatsField[];
extern const wchar_t kRegVersionField[];
diff --git a/chrome/installer/util/installer_unittests.vcproj b/chrome/installer/util/installer_unittests.vcproj
index 4f710ac..5ac125b 100644
--- a/chrome/installer/util/installer_unittests.vcproj
+++ b/chrome/installer/util/installer_unittests.vcproj
@@ -164,6 +164,10 @@
>
</File>
<File
+ RelativePath="delete_reg_value_work_item_unittest.cc"
+ >
+ </File>
+ <File
RelativePath="delete_tree_work_item_unittest.cc"
>
</File>
diff --git a/chrome/installer/util/util.vcproj b/chrome/installer/util/util.vcproj
index 284eb6a..e99dde8 100644
--- a/chrome/installer/util/util.vcproj
+++ b/chrome/installer/util/util.vcproj
@@ -81,6 +81,14 @@
>
</File>
<File
+ RelativePath="delete_reg_value_work_item.cc"
+ >
+ </File>
+ <File
+ RelativePath="delete_reg_value_work_item.h"
+ >
+ </File>
+ <File
RelativePath="google_chrome_distribution.cc"
>
</File>
diff --git a/chrome/installer/util/util_constants.cc b/chrome/installer/util/util_constants.cc
index 886795e..4ee1b02 100755
--- a/chrome/installer/util/util_constants.cc
+++ b/chrome/installer/util/util_constants.cc
@@ -49,6 +49,10 @@ const wchar_t kMakeChromeDefault[] = L"make-chrome-default";
// options kInstallArchive and kUninstall are ignored.
const wchar_t kRegisterChromeBrowser[] = L"register-chrome-browser";
+// Renames chrome.exe to old_chrome.exe and renames new_chrome.exe to chrome.exe
+// to support in-use updates. Also deletes opv key.
+const wchar_t kRenameChromeExe[] = L"rename-chrome-exe";
+
// Install Chrome to system wise location. The default is per user install.
const wchar_t kSystemLevel[] = L"system-level";
@@ -62,6 +66,8 @@ const wchar_t kVerboseLogging[] = L"verbose-logging";
const wchar_t kInstallBinaryDir[] = L"Application";
const wchar_t kChromeExe[] = L"chrome.exe";
+const wchar_t kChromeOldExe[] = L"old_chrome.exe";
+const wchar_t kChromeNewExe[] = L"new_chrome.exe";
const wchar_t kChromeDll[] = L"chrome.dll";
const wchar_t kSetupExe[] = L"setup.exe";
diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h
index 941cfe2..662029f 100755
--- a/chrome/installer/util/util_constants.h
+++ b/chrome/installer/util/util_constants.h
@@ -31,6 +31,8 @@ enum InstallStatus {
UNINSTALL_FAILED, // Chrome uninstallation failed
UNINSTALL_CANCELLED, // User cancelled Chrome uninstallation
UNKNOWN_STATUS, // Unknown status (this should never happen)
+ RENAME_SUCCESSFUL, // Rename of new_chrome.exe to chrome.exe worked
+ RENAME_FAILED // Rename of new_chrome.exe failed
};
// These are distibution related install options specified through command
@@ -64,6 +66,7 @@ extern const wchar_t kInstallerData[];
extern const wchar_t kLogFile[];
extern const wchar_t kMakeChromeDefault[];
extern const wchar_t kRegisterChromeBrowser[];
+extern const wchar_t kRenameChromeExe[];
extern const wchar_t kSystemLevel[];
extern const wchar_t kUninstall[];
extern const wchar_t kVerboseLogging[];
@@ -71,6 +74,8 @@ extern const wchar_t kVerboseLogging[];
extern const wchar_t kInstallBinaryDir[];
extern const wchar_t kChromeExe[];
+extern const wchar_t kChromeOldExe[];
+extern const wchar_t kChromeNewExe[];
extern const wchar_t kChromeDll[];
extern const wchar_t kSetupExe[];
diff --git a/chrome/installer/util/work_item.cc b/chrome/installer/util/work_item.cc
index e02bb5b..7905405 100644
--- a/chrome/installer/util/work_item.cc
+++ b/chrome/installer/util/work_item.cc
@@ -3,10 +3,12 @@
// found in the LICENSE file.
#include "chrome/installer/util/work_item.h"
+
#include "chrome/installer/util/copy_tree_work_item.h"
#include "chrome/installer/util/create_dir_work_item.h"
#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/set_reg_value_work_item.h"
#include "chrome/installer/util/work_item_list.h"
@@ -32,6 +34,13 @@ CreateRegKeyWorkItem* WorkItem::CreateCreateRegKeyWorkItem(
return new CreateRegKeyWorkItem(predefined_root, path);
}
+DeleteRegValueWorkItem* WorkItem::CreateDeleteRegValueWorkItem(
+ HKEY predefined_root, std::wstring key_path,
+ std::wstring value_name, bool is_str_type) {
+ return new DeleteRegValueWorkItem(predefined_root, key_path,
+ value_name, is_str_type);
+}
+
DeleteTreeWorkItem* WorkItem::CreateDeleteTreeWorkItem(std::wstring root_path,
std::wstring key_path) {
return new DeleteTreeWorkItem(root_path, key_path);
diff --git a/chrome/installer/util/work_item.h b/chrome/installer/util/work_item.h
index 267b61b..08942a1 100644
--- a/chrome/installer/util/work_item.h
+++ b/chrome/installer/util/work_item.h
@@ -6,8 +6,8 @@
// out during install/update/uninstall. Supports rollback of actions if this
// process fails.
-#ifndef CHROME_INSTALLER_UTIL_WORK_ITEM_H__
-#define CHROME_INSTALLER_UTIL_WORK_ITEM_H__
+#ifndef CHROME_INSTALLER_UTIL_WORK_ITEM_H_
+#define CHROME_INSTALLER_UTIL_WORK_ITEM_H_
#include <string>
#include <windows.h>
@@ -16,6 +16,7 @@ class CopyTreeWorkItem;
class CreateDirWorkItem;
class CreateRegKeyWorkItem;
class DeleteTreeWorkItem;
+class DeleteRegValueWorkItem;
class SetRegValueWorkItem;
class WorkItemList;
@@ -29,16 +30,17 @@ class WorkItem {
NEVER, // Not used currently.
IF_DIFFERENT, // Overwrite if different. Currently only applies to file.
IF_NOT_PRESENT, // Copy only if file/directory do not exist already.
- RENAME_IF_IN_USE // Copy to a new path instead of overwriting (only files).
+ NEW_NAME_IF_IN_USE // Copy to a new path if dest is in use(only files).
};
virtual ~WorkItem();
// Create a CopyTreeWorkItem that recursively copies a file system hierarchy
- // from source path to destination path. If overwrite_option is ALWAYS, the
- // created CopyTreeWorkItem always overwrites files. If overwrite_option is
- // RENAME_IF_IN_USE, file is copied with an alternate name specified by
- // alternative_path.
+ // from source path to destination path.
+ // * If overwrite_option is ALWAYS, the created CopyTreeWorkItem always
+ // overwrites files.
+ // * If overwrite_option is NEW_NAME_IF_IN_USE, file is copied with an
+ // alternate name specified by alternative_path.
static CopyTreeWorkItem* CreateCopyTreeWorkItem(std::wstring source_path,
std::wstring dest_path, std::wstring temp_dir,
CopyOverWriteOption overwrite_option,
@@ -52,6 +54,11 @@ class WorkItem {
static CreateRegKeyWorkItem* CreateCreateRegKeyWorkItem(
HKEY predefined_root, std::wstring path);
+ // Create a DeleteRegValueWorkItem that deletes a registry value
+ static DeleteRegValueWorkItem* CreateDeleteRegValueWorkItem(
+ HKEY predefined_root, std::wstring key_path,
+ std::wstring value_name, bool is_str_type);
+
// Create a DeleteTreeWorkItem that recursively deletes a file system
// hierarchy at the given root path. A key file can be optionally specified
// by key_path.
@@ -97,5 +104,5 @@ class WorkItem {
WorkItem();
};
-#endif // CHROME_INSTALLER_UTIL_WORK_ITEM_H__
+#endif // CHROME_INSTALLER_UTIL_WORK_ITEM_H_
diff --git a/chrome/installer/util/work_item_list.cc b/chrome/installer/util/work_item_list.cc
index 1975048..ef0a9c4 100644
--- a/chrome/installer/util/work_item_list.cc
+++ b/chrome/installer/util/work_item_list.cc
@@ -87,6 +87,16 @@ bool WorkItemList::AddCreateRegKeyWorkItem(HKEY predefined_root,
return AddWorkItem(item);
}
+bool WorkItemList::AddDeleteRegValueWorkItem(HKEY predefined_root,
+ std::wstring key_path,
+ std::wstring value_name,
+ bool is_str_type) {
+ WorkItem* item = reinterpret_cast<WorkItem*>(
+ WorkItem::CreateDeleteRegValueWorkItem(predefined_root, key_path,
+ value_name, is_str_type));
+ return AddWorkItem(item);
+}
+
bool WorkItemList::AddDeleteTreeWorkItem(std::wstring root_path,
std::wstring key_path) {
WorkItem* item = reinterpret_cast<WorkItem*>(
diff --git a/chrome/installer/util/work_item_list.h b/chrome/installer/util/work_item_list.h
index 5d1b071..227533c 100644
--- a/chrome/installer/util/work_item_list.h
+++ b/chrome/installer/util/work_item_list.h
@@ -44,6 +44,11 @@ class WorkItemList : public WorkItem {
// path.
bool AddCreateRegKeyWorkItem(HKEY predefined_root, std::wstring path);
+ // Add a DeleteRegValueWorkItem that deletes registry value of type REG_SZ
+ // or REG_DWORD.
+ bool AddDeleteRegValueWorkItem(HKEY predefined_root, std::wstring key_path,
+ std::wstring value_name, bool it_str_type);
+
// Add a DeleteTreeWorkItem that recursively deletes a file system
// hierarchy at the given root path. A key file can be optionally specified
// by key_path.