1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <shlwapi.h> 6 7#include "base/files/file_path.h" 8#include "base/logging.h" 9#include "base/win/registry.h" 10#include "chrome/installer/util/create_reg_key_work_item.h" 11#include "chrome/installer/util/install_util.h" 12#include "chrome/installer/util/logging_installer.h" 13 14using base::win::RegKey; 15 16namespace { 17 18// TODO: refactor this because it is only used once. 19void UpOneDirectoryOrEmpty(std::wstring* dir) { 20 base::FilePath path = base::FilePath(*dir); 21 base::FilePath directory = path.DirName(); 22 // If there is no separator, we will get back kCurrentDirectory. 23 // In this case, clear dir. 24 if (directory == path || directory.value() == 25 base::FilePath::kCurrentDirectory) 26 dir->clear(); 27 else 28 *dir = directory.value(); 29} 30 31} // namespace 32 33CreateRegKeyWorkItem::~CreateRegKeyWorkItem() { 34} 35 36CreateRegKeyWorkItem::CreateRegKeyWorkItem(HKEY predefined_root, 37 const std::wstring& path, 38 REGSAM wow64_access) 39 : predefined_root_(predefined_root), 40 path_(path), 41 wow64_access_(wow64_access), 42 key_created_(false) { 43 DCHECK(wow64_access == 0 || 44 wow64_access == KEY_WOW64_32KEY || 45 wow64_access == KEY_WOW64_64KEY); 46} 47 48bool CreateRegKeyWorkItem::Do() { 49 if (!InitKeyList()) { 50 // Nothing needs to be done here. 51 VLOG(1) << "no key to create"; 52 return true; 53 } 54 55 RegKey key; 56 std::wstring key_path; 57 58 // To create keys, we iterate from back to front. 59 for (size_t i = key_list_.size(); i > 0; i--) { 60 DWORD disposition; 61 key_path.assign(key_list_[i - 1]); 62 63 if (key.CreateWithDisposition(predefined_root_, 64 key_path.c_str(), 65 &disposition, 66 KEY_READ | wow64_access_) == ERROR_SUCCESS) { 67 if (disposition == REG_OPENED_EXISTING_KEY) { 68 if (key_created_) { 69 // This should not happen. Someone created a subkey under the key 70 // we just created? 71 LOG(ERROR) << key_path << " exists, this is not expected."; 72 return false; 73 } 74 // Remove the key path from list if it is already present. 75 key_list_.pop_back(); 76 } else if (disposition == REG_CREATED_NEW_KEY) { 77 VLOG(1) << "created " << key_path; 78 key_created_ = true; 79 } else { 80 LOG(ERROR) << "unkown disposition"; 81 return false; 82 } 83 } else { 84 LOG(ERROR) << "Failed to create " << key_path; 85 return false; 86 } 87 } 88 89 return true; 90} 91 92void CreateRegKeyWorkItem::Rollback() { 93 if (!key_created_) 94 return; 95 96 std::wstring key_path; 97 // To delete keys, we iterate from front to back. 98 std::vector<std::wstring>::iterator itr; 99 for (itr = key_list_.begin(); itr != key_list_.end(); ++itr) { 100 key_path.assign(*itr); 101 RegKey key(predefined_root_, L"", KEY_WRITE | wow64_access_); 102 if (key.DeleteEmptyKey(key_path.c_str()) == ERROR_SUCCESS) { 103 VLOG(1) << "rollback: delete " << key_path; 104 } else { 105 VLOG(1) << "rollback: can not delete " << key_path; 106 // The key might have been deleted, but we don't reliably know what 107 // error code(s) are returned in this case. So we just keep tring delete 108 // the rest. 109 } 110 } 111 112 key_created_ = false; 113 key_list_.clear(); 114 return; 115} 116 117bool CreateRegKeyWorkItem::InitKeyList() { 118 if (path_.empty()) 119 return false; 120 121 std::wstring key_path(path_); 122 123 do { 124 key_list_.push_back(key_path); 125 // This is pure string operation so it does not matter whether the 126 // path is file path or registry path. 127 UpOneDirectoryOrEmpty(&key_path); 128 } while (!key_path.empty()); 129 130 return true; 131} 132