create_reg_key_work_item.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/file_util.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 FilePath path = FilePath::FromWStringHack(*dir); 21 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() == FilePath::kCurrentDirectory) 25 dir->clear(); 26 else 27 *dir = directory.value(); 28} 29 30} // namespace 31 32CreateRegKeyWorkItem::~CreateRegKeyWorkItem() { 33} 34 35CreateRegKeyWorkItem::CreateRegKeyWorkItem(HKEY predefined_root, 36 const std::wstring& path) 37 : predefined_root_(predefined_root), 38 path_(path), 39 key_created_(false) { 40} 41 42bool CreateRegKeyWorkItem::Do() { 43 if (!InitKeyList()) { 44 // Nothing needs to be done here. 45 VLOG(1) << "no key to create"; 46 return true; 47 } 48 49 RegKey key; 50 std::wstring key_path; 51 52 // To create keys, we iterate from back to front. 53 for (size_t i = key_list_.size(); i > 0; i--) { 54 DWORD disposition; 55 key_path.assign(key_list_[i - 1]); 56 57 if (key.CreateWithDisposition(predefined_root_, key_path.c_str(), 58 &disposition, KEY_READ) == ERROR_SUCCESS) { 59 if (disposition == REG_OPENED_EXISTING_KEY) { 60 if (key_created_) { 61 // This should not happen. Someone created a subkey under the key 62 // we just created? 63 LOG(ERROR) << key_path << " exists, this is not expected."; 64 return false; 65 } 66 VLOG(1) << key_path << " exists"; 67 // Remove the key path from list if it is already present. 68 key_list_.pop_back(); 69 } else if (disposition == REG_CREATED_NEW_KEY) { 70 VLOG(1) << "created " << key_path; 71 key_created_ = true; 72 } else { 73 LOG(ERROR) << "unkown disposition"; 74 return false; 75 } 76 } else { 77 LOG(ERROR) << "Failed to create " << key_path; 78 return false; 79 } 80 } 81 82 return true; 83} 84 85void CreateRegKeyWorkItem::Rollback() { 86 if (!key_created_) 87 return; 88 89 std::wstring key_path; 90 // To delete keys, we iterate from front to back. 91 std::vector<std::wstring>::iterator itr; 92 for (itr = key_list_.begin(); itr != key_list_.end(); ++itr) { 93 key_path.assign(*itr); 94 if (SHDeleteEmptyKey(predefined_root_, key_path.c_str()) == 95 ERROR_SUCCESS) { 96 VLOG(1) << "rollback: delete " << key_path; 97 } else { 98 VLOG(1) << "rollback: can not delete " << key_path; 99 // The key might have been deleted, but we don't reliably know what 100 // error code(s) are returned in this case. So we just keep tring delete 101 // the rest. 102 } 103 } 104 105 key_created_ = false; 106 key_list_.clear(); 107 return; 108} 109 110bool CreateRegKeyWorkItem::InitKeyList() { 111 if (path_.empty()) 112 return false; 113 114 std::wstring key_path(path_); 115 116 do { 117 key_list_.push_back(key_path); 118 // This is pure string operation so it does not matter whether the 119 // path is file path or registry path. 120 UpOneDirectoryOrEmpty(&key_path); 121 } while (!key_path.empty()); 122 123 return true; 124} 125