// Copyright (c) 2010 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 #include "base/files/file_path.h" #include "base/logging.h" #include "base/win/registry.h" #include "chrome/installer/util/create_reg_key_work_item.h" #include "chrome/installer/util/install_util.h" #include "chrome/installer/util/logging_installer.h" using base::win::RegKey; namespace { // TODO: refactor this because it is only used once. void UpOneDirectoryOrEmpty(std::wstring* dir) { base::FilePath path = base::FilePath(*dir); base::FilePath directory = path.DirName(); // If there is no separator, we will get back kCurrentDirectory. // In this case, clear dir. if (directory == path || directory.value() == base::FilePath::kCurrentDirectory) dir->clear(); else *dir = directory.value(); } } // namespace CreateRegKeyWorkItem::~CreateRegKeyWorkItem() { } CreateRegKeyWorkItem::CreateRegKeyWorkItem(HKEY predefined_root, const std::wstring& path, REGSAM wow64_access) : predefined_root_(predefined_root), path_(path), wow64_access_(wow64_access), key_created_(false) { DCHECK(wow64_access == 0 || wow64_access == KEY_WOW64_32KEY || wow64_access == KEY_WOW64_64KEY); } bool CreateRegKeyWorkItem::Do() { if (!InitKeyList()) { // Nothing needs to be done here. VLOG(1) << "no key to create"; return true; } RegKey key; std::wstring key_path; // To create keys, we iterate from back to front. for (size_t i = key_list_.size(); i > 0; i--) { DWORD disposition; key_path.assign(key_list_[i - 1]); if (key.CreateWithDisposition(predefined_root_, key_path.c_str(), &disposition, KEY_READ | wow64_access_) == ERROR_SUCCESS) { if (disposition == REG_OPENED_EXISTING_KEY) { if (key_created_) { // This should not happen. Someone created a subkey under the key // we just created? LOG(ERROR) << key_path << " exists, this is not expected."; return false; } // Remove the key path from list if it is already present. key_list_.pop_back(); } else if (disposition == REG_CREATED_NEW_KEY) { VLOG(1) << "created " << key_path; key_created_ = true; } else { LOG(ERROR) << "unkown disposition"; return false; } } else { LOG(ERROR) << "Failed to create " << key_path; return false; } } return true; } void CreateRegKeyWorkItem::Rollback() { if (!key_created_) return; std::wstring key_path; // To delete keys, we iterate from front to back. std::vector::iterator itr; for (itr = key_list_.begin(); itr != key_list_.end(); ++itr) { key_path.assign(*itr); RegKey key(predefined_root_, L"", KEY_WRITE | wow64_access_); if (key.DeleteEmptyKey(key_path.c_str()) == ERROR_SUCCESS) { VLOG(1) << "rollback: delete " << key_path; } else { VLOG(1) << "rollback: can not delete " << key_path; // The key might have been deleted, but we don't reliably know what // error code(s) are returned in this case. So we just keep tring delete // the rest. } } key_created_ = false; key_list_.clear(); return; } bool CreateRegKeyWorkItem::InitKeyList() { if (path_.empty()) return false; std::wstring key_path(path_); do { key_list_.push_back(key_path); // This is pure string operation so it does not matter whether the // path is file path or registry path. UpOneDirectoryOrEmpty(&key_path); } while (!key_path.empty()); return true; }