Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/installer/util/set_reg_value_work_item.h" | 5 #include "chrome/installer/util/set_reg_value_work_item.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/string_util.h" | |
| 8 #include "base/win/registry.h" | 9 #include "base/win/registry.h" |
| 9 #include "chrome/installer/util/logging_installer.h" | 10 #include "chrome/installer/util/logging_installer.h" |
| 10 | 11 |
| 11 SetRegValueWorkItem::~SetRegValueWorkItem() { | 12 SetRegValueWorkItem::~SetRegValueWorkItem() { |
| 12 } | 13 } |
| 13 | 14 |
| 14 SetRegValueWorkItem::SetRegValueWorkItem(HKEY predefined_root, | 15 SetRegValueWorkItem::SetRegValueWorkItem(HKEY predefined_root, |
| 15 const std::wstring& key_path, | 16 const std::wstring& key_path, |
| 16 const std::wstring& value_name, | 17 const std::wstring& value_name, |
| 17 const std::wstring& value_data, | 18 const std::wstring& value_data, |
| 18 bool overwrite) | 19 bool overwrite) |
| 19 : predefined_root_(predefined_root), | 20 : predefined_root_(predefined_root), |
| 20 key_path_(key_path), | 21 key_path_(key_path), |
| 21 value_name_(value_name), | 22 value_name_(value_name), |
| 22 value_data_str_(value_data), | |
| 23 value_data_dword_(0), | |
| 24 value_data_qword_(0), | |
| 25 overwrite_(overwrite), | 23 overwrite_(overwrite), |
| 26 status_(SET_VALUE), | 24 status_(SET_VALUE), |
| 27 type_(REG_SZ), | 25 type_(REG_SZ), |
| 28 previous_value_dword_(0), | 26 previous_type_(0) { |
| 29 previous_value_qword_(0) { | 27 const uint8* data = reinterpret_cast<const uint8*>(value_data.c_str()); |
| 28 value_.assign(data, data + (value_data.length() + 1) * sizeof(wchar_t)); | |
| 30 } | 29 } |
| 31 | 30 |
| 32 SetRegValueWorkItem::SetRegValueWorkItem(HKEY predefined_root, | 31 SetRegValueWorkItem::SetRegValueWorkItem(HKEY predefined_root, |
| 33 const std::wstring& key_path, | 32 const std::wstring& key_path, |
| 34 const std::wstring& value_name, | 33 const std::wstring& value_name, |
| 35 DWORD value_data, | 34 DWORD value_data, |
| 36 bool overwrite) | 35 bool overwrite) |
| 37 : predefined_root_(predefined_root), | 36 : predefined_root_(predefined_root), |
| 38 key_path_(key_path), | 37 key_path_(key_path), |
| 39 value_name_(value_name), | 38 value_name_(value_name), |
| 40 value_data_dword_(value_data), | |
| 41 value_data_qword_(0), | |
| 42 overwrite_(overwrite), | 39 overwrite_(overwrite), |
| 43 status_(SET_VALUE), | 40 status_(SET_VALUE), |
| 44 type_(REG_DWORD), | 41 type_(REG_DWORD), |
| 45 previous_value_dword_(0), | 42 previous_type_(0) { |
| 46 previous_value_qword_(0) { | 43 const uint8* data = reinterpret_cast<const uint8*>(&value_data); |
| 44 value_.assign(data, data + sizeof(value_data)); | |
| 47 } | 45 } |
| 48 | 46 |
| 49 SetRegValueWorkItem::SetRegValueWorkItem(HKEY predefined_root, | 47 SetRegValueWorkItem::SetRegValueWorkItem(HKEY predefined_root, |
| 50 const std::wstring& key_path, | 48 const std::wstring& key_path, |
| 51 const std::wstring& value_name, | 49 const std::wstring& value_name, |
| 52 int64 value_data, | 50 int64 value_data, |
| 53 bool overwrite) | 51 bool overwrite) |
| 54 : predefined_root_(predefined_root), | 52 : predefined_root_(predefined_root), |
| 55 key_path_(key_path), | 53 key_path_(key_path), |
| 56 value_name_(value_name), | 54 value_name_(value_name), |
| 57 value_data_dword_(0), | |
| 58 value_data_qword_(value_data), | |
| 59 overwrite_(overwrite), | 55 overwrite_(overwrite), |
| 60 status_(SET_VALUE), | 56 status_(SET_VALUE), |
| 61 type_(REG_QWORD), | 57 type_(REG_QWORD), |
| 62 previous_value_dword_(0), | 58 previous_type_(0) { |
| 63 previous_value_qword_(0) { | 59 const uint8* data = reinterpret_cast<const uint8*>(&value_data); |
| 60 value_.assign(data, data + sizeof(value_data)); | |
| 64 } | 61 } |
| 65 | 62 |
| 66 bool SetRegValueWorkItem::Do() { | 63 bool SetRegValueWorkItem::Do() { |
| 67 bool success = true; | 64 LONG result = ERROR_SUCCESS; |
| 68 | 65 base::win::RegKey key; |
| 69 if (status_ != SET_VALUE) { | 66 if (status_ != SET_VALUE) { |
| 70 // we already did something. | 67 // we already did something. |
| 71 LOG(ERROR) << "multiple calls to Do()"; | 68 VLOG(1) << "multiple calls to Do()"; |
| 72 success = false; | 69 result = ERROR_CANTWRITE; |
| 70 return ignore_failure_; | |
| 71 } | |
| 72 | |
| 73 status_ = VALUE_UNCHANGED; | |
| 74 result = key.Open(predefined_root_, key_path_.c_str(), | |
| 75 KEY_READ | KEY_SET_VALUE); | |
| 76 if (result != ERROR_SUCCESS) { | |
| 77 VLOG(1) << "can not open " << key_path_ << " error: " << result; | |
| 78 return ignore_failure_; | |
| 79 } | |
| 80 | |
| 81 DWORD type = 0; | |
| 82 DWORD size = 0; | |
| 83 result = key.ReadValue(value_name_.c_str(), NULL, &size, &type); | |
| 84 // If the value exists but we don't want to overwrite then there's | |
| 85 // nothing more to do. | |
| 86 if ((result != ERROR_FILE_NOT_FOUND) && !overwrite_) { | |
| 87 return true; | |
|
grt (UTC plus 2)
2011/01/16 04:19:48
Nice catch!
| |
| 88 } | |
| 89 | |
| 90 // If there's something to be saved, save it. | |
| 91 if (result == ERROR_SUCCESS) { | |
| 92 previous_value_.resize(size); | |
| 93 result = key.ReadValue(value_name_.c_str(), &previous_value_[0], &size, | |
| 94 &previous_type_); | |
| 95 if (result != ERROR_SUCCESS) { | |
| 96 previous_value_.clear(); | |
| 97 VLOG(1) << "Failed to save original value. Error: " << result; | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 result = key.WriteValue(value_name_.c_str(), &value_[0], | |
| 102 static_cast<DWORD>(value_.size()), type_); | |
| 103 if (result != ERROR_SUCCESS) { | |
| 104 VLOG(1) << "Failed to write value " << key_path_ << " error: " << result; | |
| 105 return ignore_failure_; | |
| 106 } | |
| 107 | |
| 108 status_ = previous_type_ ? VALUE_OVERWRITTEN : NEW_VALUE_CREATED; | |
| 109 return true; | |
| 110 } | |
| 111 | |
| 112 void SetRegValueWorkItem::Rollback() { | |
| 113 if (ignore_failure_) | |
| 114 return; | |
| 115 | |
| 116 if (status_ == SET_VALUE || status_ == VALUE_ROLL_BACK) | |
| 117 return; | |
| 118 | |
| 119 if (status_ == VALUE_UNCHANGED) { | |
| 120 status_ = VALUE_ROLL_BACK; | |
| 121 VLOG(1) << "rollback: setting unchanged, nothing to do"; | |
| 122 return; | |
| 73 } | 123 } |
| 74 | 124 |
| 75 base::win::RegKey key; | 125 base::win::RegKey key; |
| 76 if (success && !key.Open(predefined_root_, key_path_.c_str(), | 126 LONG result = key.Open(predefined_root_, key_path_.c_str(), KEY_SET_VALUE); |
| 77 KEY_READ | KEY_SET_VALUE)) { | 127 if (result != ERROR_SUCCESS) { |
| 78 LOG(ERROR) << "can not open " << key_path_; | 128 VLOG(1) << "rollback: can not open " << key_path_ << " error: " << result; |
| 79 status_ = VALUE_UNCHANGED; | 129 return; |
| 80 success = false; | |
| 81 } | 130 } |
| 82 | 131 |
| 83 if (success) { | 132 if (status_ == NEW_VALUE_CREATED) { |
| 84 if (key.ValueExists(value_name_.c_str())) { | 133 result = key.DeleteValue(value_name_.c_str()); |
| 85 if (overwrite_) { | 134 VLOG(1) << "rollback: deleting " << value_name_ << " error: " << result; |
| 86 // Read previous value for rollback and write new value | 135 } else if (status_ == VALUE_OVERWRITTEN) { |
| 87 if (type_ == REG_SZ) { | 136 result = key.WriteValue(value_name_.c_str(), &previous_value_[0], |
| 88 std::wstring data; | 137 static_cast<DWORD>(previous_value_.size()), |
| 89 if (key.ReadValue(value_name_.c_str(), &data)) { | 138 previous_type_); |
| 90 previous_value_str_.assign(data); | 139 VLOG(1) << "rollback: restoring " << value_name_ << " error: " << result; |
| 91 } | 140 } else { |
| 92 success = key.WriteValue(value_name_.c_str(), | 141 NOTREACHED(); |
| 93 value_data_str_.c_str()); | |
| 94 } else if (type_ == REG_DWORD) { | |
| 95 DWORD data; | |
| 96 if (key.ReadValueDW(value_name_.c_str(), &data)) { | |
| 97 previous_value_dword_ = data; | |
| 98 } | |
| 99 success = key.WriteValue(value_name_.c_str(), value_data_dword_); | |
| 100 } else if (type_ == REG_QWORD) { | |
| 101 int64 data; | |
| 102 DWORD data_size = sizeof(data); | |
| 103 DWORD data_type = NULL; | |
| 104 | |
| 105 if (key.ReadValue(value_name_.c_str(), &data, &data_size, | |
| 106 &data_type)) { | |
| 107 previous_value_qword_ = data; | |
| 108 } | |
| 109 success = key.WriteValue(value_name_.c_str(), | |
| 110 &value_data_qword_, | |
| 111 sizeof(value_data_qword_), | |
| 112 REG_QWORD); | |
| 113 } | |
| 114 if (success) { | |
| 115 VLOG(1) << "overwritten value for " << value_name_; | |
| 116 status_ = VALUE_OVERWRITTEN; | |
| 117 } else { | |
| 118 LOG(ERROR) << "failed to overwrite value for " << value_name_; | |
| 119 status_ = VALUE_UNCHANGED; | |
| 120 } | |
| 121 } else { | |
| 122 VLOG(1) << value_name_ << " exists. not changed "; | |
| 123 status_ = VALUE_UNCHANGED; | |
| 124 } | |
| 125 } else { | |
| 126 if (type_ == REG_SZ) { | |
| 127 success = key.WriteValue(value_name_.c_str(), value_data_str_.c_str()); | |
| 128 } else if (type_ == REG_DWORD) { | |
| 129 success = key.WriteValue(value_name_.c_str(), value_data_dword_); | |
| 130 } else if (type_ == REG_QWORD) { | |
| 131 success = key.WriteValue(value_name_.c_str(), | |
| 132 &value_data_qword_, | |
| 133 sizeof(value_data_qword_), | |
| 134 REG_QWORD); | |
| 135 } else { | |
| 136 NOTREACHED() << "Unsupported value type."; | |
| 137 } | |
| 138 if (success) { | |
| 139 VLOG(1) << "created value for " << value_name_; | |
| 140 status_ = NEW_VALUE_CREATED; | |
| 141 } else { | |
| 142 LOG(ERROR) << "failed to create value for " << value_name_; | |
| 143 status_ = VALUE_UNCHANGED; | |
| 144 } | |
| 145 } | |
| 146 } | 142 } |
| 147 | 143 |
| 148 LOG_IF(ERROR, !success && !log_message_.empty()) << log_message_; | 144 status_ = VALUE_ROLL_BACK; |
| 149 | |
| 150 if (ignore_failure_) { | |
| 151 success = true; | |
| 152 } | |
| 153 | |
| 154 return success; | |
| 155 } | 145 } |
| 156 | |
| 157 void SetRegValueWorkItem::Rollback() { | |
| 158 if (!ignore_failure_) { | |
| 159 if (status_ == SET_VALUE || status_ == VALUE_ROLL_BACK) | |
| 160 return; | |
| 161 | |
| 162 if (status_ == VALUE_UNCHANGED) { | |
| 163 status_ = VALUE_ROLL_BACK; | |
| 164 VLOG(1) << "rollback: setting unchanged, nothing to do"; | |
| 165 return; | |
| 166 } | |
| 167 | |
| 168 base::win::RegKey key; | |
| 169 if (!key.Open(predefined_root_, key_path_.c_str(), KEY_SET_VALUE)) { | |
| 170 status_ = VALUE_ROLL_BACK; | |
| 171 VLOG(1) << "rollback: can not open " << key_path_; | |
| 172 return; | |
| 173 } | |
| 174 | |
| 175 std::wstring result_str(L" failed"); | |
| 176 if (status_ == NEW_VALUE_CREATED) { | |
| 177 if (key.DeleteValue(value_name_.c_str())) | |
| 178 result_str.assign(L" succeeded"); | |
| 179 VLOG(1) << "rollback: deleting " << value_name_ << result_str; | |
| 180 } else if (status_ == VALUE_OVERWRITTEN) { | |
| 181 // try restore the previous value | |
| 182 bool success = true; | |
| 183 if (type_ == REG_SZ) { | |
| 184 success = key.WriteValue(value_name_.c_str(), | |
| 185 previous_value_str_.c_str()); | |
| 186 } else if (type_ == REG_DWORD) { | |
| 187 success = key.WriteValue(value_name_.c_str(), previous_value_dword_); | |
| 188 } else if (type_ == REG_QWORD) { | |
| 189 success = key.WriteValue(value_name_.c_str(), | |
| 190 &previous_value_qword_, | |
| 191 sizeof(previous_value_qword_), | |
| 192 REG_QWORD); | |
| 193 } else { | |
| 194 NOTREACHED(); | |
| 195 } | |
| 196 if (success) | |
| 197 result_str.assign(L" succeeded"); | |
| 198 VLOG(1) << "rollback: restoring " << value_name_ << result_str; | |
| 199 | |
| 200 status_ = VALUE_ROLL_BACK; | |
| 201 return; | |
| 202 } | |
| 203 } | |
| 204 } | |
| OLD | NEW |