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; |
| 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 |