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/registry_key_backup.h" | 5 #include "chrome/installer/util/registry_key_backup.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <map> | 8 #include <limits> |
9 #include <utility> | |
10 #include <vector> | 9 #include <vector> |
11 | 10 |
12 #include "base/logging.h" | 11 #include "base/logging.h" |
13 #include "base/win/registry.h" | 12 #include "base/win/registry.h" |
14 | 13 |
15 using base::win::RegKey; | 14 using base::win::RegKey; |
16 | 15 |
17 namespace { | 16 namespace { |
| 17 const REGSAM kKeyReadNoNotify = (KEY_READ) & ~(KEY_NOTIFY); |
| 18 } // namespace |
18 | 19 |
19 const REGSAM kKeyReadNoNotify = (KEY_READ) & ~(KEY_NOTIFY); | 20 // A container for a registry key, its values, and its subkeys. |
| 21 class RegistryKeyBackup::KeyData { |
| 22 public: |
| 23 KeyData(); |
| 24 ~KeyData(); |
| 25 |
| 26 // Initializes this object by reading the values and subkeys of |key|. |
| 27 // Security descriptors are not backed up. Returns true if the operation was |
| 28 // successful; false otherwise, in which case the state of this object is not |
| 29 // modified. |
| 30 bool Initialize(const RegKey& key); |
| 31 |
| 32 // Writes the contents of this object to |key|, which must have been opened |
| 33 // with at least REG_SET_VALUE and KEY_CREATE_SUB_KEY access rights. Returns |
| 34 // true if the operation was successful; false otherwise, in which case the |
| 35 // contents of |key| may have been modified. |
| 36 bool WriteTo(RegKey* key) const; |
| 37 |
| 38 private: |
| 39 class ValueData; |
| 40 |
| 41 // The values of this key. |
| 42 scoped_array<ValueData> values_; |
| 43 // The names of this key's sub-keys (the data for subkey_names_[i] is in |
| 44 // subkeys_[i]). |
| 45 scoped_array<std::wstring> subkey_names_; |
| 46 // The key data of this key's sub-keys. |
| 47 scoped_array<KeyData> subkeys_; |
| 48 // The number of values for this key. |
| 49 DWORD num_values_; |
| 50 // The number of subkeys for this key. |
| 51 DWORD num_subkeys_; |
| 52 |
| 53 DISALLOW_COPY_AND_ASSIGN(KeyData); |
| 54 }; |
20 | 55 |
21 // A container for a registry value. | 56 // A container for a registry value. |
22 class ValueData { | 57 class RegistryKeyBackup::KeyData::ValueData { |
23 public: | 58 public: |
24 ValueData(); | 59 ValueData(); |
25 ~ValueData(); | 60 ~ValueData(); |
26 | 61 |
27 // Initializes this object with a name (the first |name_size| characters in | 62 // Initializes this object with a name (the first |name_size| characters in |
28 // |name_buffer|, |type|, and data (the first |data_size| bytes in |data|). | 63 // |name_buffer|, |type|, and data (the first |data_size| bytes in |data|). |
29 void Initialize(const wchar_t* name_buffer, DWORD name_size, | 64 void Initialize(const wchar_t* name_buffer, DWORD name_size, |
30 DWORD type, const uint8* data, DWORD data_size); | 65 DWORD type, const uint8* data, DWORD data_size); |
31 | 66 |
32 // The possibly empty name of this value. | 67 // The possibly empty name of this value. |
(...skipping 14 matching lines...) Expand all Loading... |
47 | 82 |
48 private: | 83 private: |
49 // This value's name, or the empty string if this is the default (unnamed) | 84 // This value's name, or the empty string if this is the default (unnamed) |
50 // value. | 85 // value. |
51 std::wstring name_; | 86 std::wstring name_; |
52 // This value's data. | 87 // This value's data. |
53 std::vector<uint8> data_; | 88 std::vector<uint8> data_; |
54 // This value's type (e.g., REG_DWORD, REG_SZ, REG_QWORD, etc). | 89 // This value's type (e.g., REG_DWORD, REG_SZ, REG_QWORD, etc). |
55 DWORD type_; | 90 DWORD type_; |
56 | 91 |
57 // Copy constructible and assignable for use in STL containers. | 92 DISALLOW_COPY_AND_ASSIGN(ValueData); |
58 }; | 93 }; |
59 | 94 |
60 } // namespace | 95 RegistryKeyBackup::KeyData::ValueData::ValueData() |
61 | 96 : type_(REG_NONE) { |
62 // A container for a registry key, its values, and its subkeys. | |
63 class RegistryKeyBackup::KeyData { | |
64 public: | |
65 KeyData(); | |
66 ~KeyData(); | |
67 | |
68 // Initializes this object by reading the values and subkeys of |key|. | |
69 // Security descriptors are not backed up. Returns true if the operation was | |
70 // successful; false otherwise, in which case the state of this object is not | |
71 // modified. | |
72 bool Initialize(const RegKey& key); | |
73 | |
74 // Writes the contents of this object to |key|, which must have been opened | |
75 // with at least REG_SET_VALUE and KEY_CREATE_SUB_KEY access rights. Returns | |
76 // true if the operation was successful; false otherwise, in which case the | |
77 // contents of |key| may have been modified. | |
78 bool WriteTo(RegKey* key) const; | |
79 | |
80 private: | |
81 // The values of this key. | |
82 std::vector<ValueData> values_; | |
83 // Map of subkey names to the corresponding KeyData. | |
84 std::map<std::wstring, KeyData> subkeys_; | |
85 | |
86 // Copy constructible and assignable for use in STL containers. | |
87 }; | |
88 | |
89 ValueData::ValueData() : type_(REG_NONE) { | |
90 } | 97 } |
91 | 98 |
92 ValueData::~ValueData() { | 99 RegistryKeyBackup::KeyData::ValueData::~ValueData() |
| 100 { |
93 } | 101 } |
94 | 102 |
95 void ValueData::Initialize( | 103 void RegistryKeyBackup::KeyData::ValueData::Initialize( |
96 const wchar_t* name_buffer, | 104 const wchar_t* name_buffer, |
97 DWORD name_size, | 105 DWORD name_size, |
98 DWORD type, | 106 DWORD type, |
99 const uint8* data, | 107 const uint8* data, |
100 DWORD data_size) { | 108 DWORD data_size) { |
101 name_.assign(name_buffer, name_size); | 109 name_.assign(name_buffer, name_size); |
102 type_ = type; | 110 type_ = type; |
103 data_.assign(data, data + data_size); | 111 data_.assign(data, data + data_size); |
104 } | 112 } |
105 | 113 |
106 RegistryKeyBackup::KeyData::KeyData() { | 114 RegistryKeyBackup::KeyData::KeyData() |
| 115 : num_values_(0), |
| 116 num_subkeys_(0) { |
107 } | 117 } |
108 | 118 |
109 RegistryKeyBackup::KeyData::~KeyData() { | 119 RegistryKeyBackup::KeyData::~KeyData() |
| 120 { |
110 } | 121 } |
111 | 122 |
112 bool RegistryKeyBackup::KeyData::Initialize(const RegKey& key) { | 123 bool RegistryKeyBackup::KeyData::Initialize(const RegKey& key) { |
113 std::vector<ValueData> values; | 124 scoped_array<ValueData> values; |
114 std::map<std::wstring, KeyData> subkeys; | 125 scoped_array<std::wstring> subkey_names; |
| 126 scoped_array<KeyData> subkeys; |
115 | 127 |
116 DWORD num_subkeys = 0; | 128 DWORD num_subkeys = 0; |
117 DWORD max_subkey_name_len = 0; | 129 DWORD max_subkey_name_len = 0; |
118 DWORD num_values = 0; | 130 DWORD num_values = 0; |
119 DWORD max_value_name_len = 0; | 131 DWORD max_value_name_len = 0; |
120 DWORD max_value_len = 0; | 132 DWORD max_value_len = 0; |
121 LONG result = RegQueryInfoKey(key.Handle(), NULL, NULL, NULL, | 133 LONG result = RegQueryInfoKey(key.Handle(), NULL, NULL, NULL, |
122 &num_subkeys, &max_subkey_name_len, NULL, | 134 &num_subkeys, &max_subkey_name_len, NULL, |
123 &num_values, &max_value_name_len, | 135 &num_values, &max_value_name_len, |
124 &max_value_len, NULL, NULL); | 136 &max_value_len, NULL, NULL); |
125 if (result != ERROR_SUCCESS) { | 137 if (result != ERROR_SUCCESS) { |
126 LOG(ERROR) << "Failed getting info of key to backup, result: " << result; | 138 LOG(ERROR) << "Failed getting info of key to backup, result: " << result; |
127 return false; | 139 return false; |
128 } | 140 } |
| 141 if (max_subkey_name_len >= std::numeric_limits<DWORD>::max() - 1 || |
| 142 max_value_name_len >= std::numeric_limits<DWORD>::max() - 1) { |
| 143 LOG(ERROR) |
| 144 << "Failed backing up key; subkeys and/or names are out of range."; |
| 145 return false; |
| 146 } |
129 DWORD max_name_len = std::max(max_subkey_name_len, max_value_name_len) + 1; | 147 DWORD max_name_len = std::max(max_subkey_name_len, max_value_name_len) + 1; |
130 std::vector<wchar_t> name_buffer(max_name_len); | 148 scoped_array<wchar_t> name_buffer(new wchar_t[max_name_len]); |
131 | 149 |
132 // Backup the values. | 150 // Backup the values. |
133 if (num_values != 0) { | 151 if (num_values != 0) { |
134 values.reserve(num_values); | 152 values.reset(new ValueData[num_values]); |
135 std::vector<uint8> value_buffer(max_value_len != 0 ? max_value_len : 1); | 153 scoped_array<uint8> value_buffer(new uint8[max_value_len]); |
136 DWORD name_size = 0; | 154 DWORD name_size = 0; |
137 DWORD value_type = REG_NONE; | 155 DWORD value_type = REG_NONE; |
138 DWORD value_size = 0; | 156 DWORD value_size = 0; |
139 | 157 |
140 for (DWORD i = 0; i < num_values; ) { | 158 for (DWORD i = 0; i < num_values; ) { |
141 name_size = name_buffer.size(); | 159 name_size = max_name_len; |
142 value_size = value_buffer.size(); | 160 value_size = max_value_len; |
143 result = RegEnumValue(key.Handle(), i, &name_buffer[0], &name_size, | 161 result = RegEnumValue(key.Handle(), i, name_buffer.get(), &name_size, |
144 NULL, &value_type, &value_buffer[0], &value_size); | 162 NULL, &value_type, value_buffer.get(), &value_size); |
145 switch (result) { | 163 switch (result) { |
146 case ERROR_NO_MORE_ITEMS: | 164 case ERROR_NO_MORE_ITEMS: |
147 num_values = i; | 165 num_values = i; |
148 break; | 166 break; |
149 case ERROR_SUCCESS: | 167 case ERROR_SUCCESS: |
150 values.push_back(ValueData()); | 168 values[i].Initialize(name_buffer.get(), name_size, value_type, |
151 values.back().Initialize(&name_buffer[0], name_size, value_type, | 169 value_buffer.get(), value_size); |
152 &value_buffer[0], value_size); | |
153 ++i; | 170 ++i; |
154 break; | 171 break; |
155 case ERROR_MORE_DATA: | 172 case ERROR_MORE_DATA: |
156 if (value_size > value_buffer.size()) | 173 if (value_size > max_value_len) { |
157 value_buffer.resize(value_size); | 174 max_value_len = value_size; |
158 // |name_size| does not include space for the terminating NULL. | 175 value_buffer.reset(); // Release to heap before new allocation. |
159 if (name_size + 1 > name_buffer.size()) | 176 value_buffer.reset(new uint8[max_value_len]); |
160 name_buffer.resize(name_size + 1); | 177 } else { |
| 178 DCHECK_LT(max_name_len - 1, name_size); |
| 179 if (name_size >= std::numeric_limits<DWORD>::max() - 1) { |
| 180 LOG(ERROR) << "Failed backing up key; value name out of range."; |
| 181 return false; |
| 182 } |
| 183 max_name_len = name_size + 1; |
| 184 name_buffer.reset(); // Release to heap before new allocation. |
| 185 name_buffer.reset(new wchar_t[max_name_len]); |
| 186 } |
161 break; | 187 break; |
162 default: | 188 default: |
163 LOG(ERROR) << "Failed backing up value " << i << ", result: " | 189 LOG(ERROR) << "Failed backing up value " << i << ", result: " |
164 << result; | 190 << result; |
165 return false; | 191 return false; |
166 } | 192 } |
167 } | 193 } |
168 DLOG_IF(WARNING, RegEnumValue(key.Handle(), num_values, &name_buffer[0], | 194 DLOG_IF(WARNING, RegEnumValue(key.Handle(), num_values, name_buffer.get(), |
169 &name_size, NULL, &value_type, NULL, | 195 &name_size, NULL, &value_type, NULL, |
170 NULL) != ERROR_NO_MORE_ITEMS) | 196 NULL) != ERROR_NO_MORE_ITEMS) |
171 << "Concurrent modifications to registry key during backup operation."; | 197 << "Concurrent modifications to registry key during backup operation."; |
172 } | 198 } |
173 | 199 |
174 // Backup the subkeys. | 200 // Backup the subkeys. |
175 if (num_subkeys != 0) { | 201 if (num_subkeys != 0) { |
| 202 subkey_names.reset(new std::wstring[num_subkeys]); |
| 203 subkeys.reset(new KeyData[num_subkeys]); |
176 DWORD name_size = 0; | 204 DWORD name_size = 0; |
177 | 205 |
178 // Get the names of them. | 206 // Get the names of them. |
179 for (DWORD i = 0; i < num_subkeys; ) { | 207 for (DWORD i = 0; i < num_subkeys; ) { |
180 name_size = name_buffer.size(); | 208 name_size = max_name_len; |
181 result = RegEnumKeyEx(key.Handle(), i, &name_buffer[0], &name_size, | 209 result = RegEnumKeyEx(key.Handle(), i, name_buffer.get(), &name_size, |
182 NULL, NULL, NULL, NULL); | 210 NULL, NULL, NULL, NULL); |
183 switch (result) { | 211 switch (result) { |
184 case ERROR_NO_MORE_ITEMS: | 212 case ERROR_NO_MORE_ITEMS: |
185 num_subkeys = i; | 213 num_subkeys = i; |
186 break; | 214 break; |
187 case ERROR_SUCCESS: | 215 case ERROR_SUCCESS: |
188 subkeys.insert(std::make_pair(&name_buffer[0], KeyData())); | 216 subkey_names[i].assign(name_buffer.get(), name_size); |
189 ++i; | 217 ++i; |
190 break; | 218 break; |
191 case ERROR_MORE_DATA: | 219 case ERROR_MORE_DATA: |
192 name_buffer.resize(name_size + 1); | 220 if (name_size >= std::numeric_limits<DWORD>::max() - 1) { |
| 221 LOG(ERROR) << "Failed backing up key; subkey name out of range."; |
| 222 return false; |
| 223 } |
| 224 max_name_len = name_size + 1; |
| 225 name_buffer.reset(new wchar_t[max_name_len]); |
193 break; | 226 break; |
194 default: | 227 default: |
195 LOG(ERROR) << "Failed getting name of subkey " << i | 228 LOG(ERROR) << "Failed getting name of subkey " << i |
196 << " for backup, result: " << result; | 229 << " for backup, result: " << result; |
197 return false; | 230 return false; |
198 } | 231 } |
199 } | 232 } |
200 DLOG_IF(WARNING, | 233 DLOG_IF(WARNING, |
201 RegEnumKeyEx(key.Handle(), num_subkeys, NULL, &name_size, NULL, | 234 RegEnumKeyEx(key.Handle(), num_subkeys, NULL, &name_size, NULL, |
202 NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS) | 235 NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS) |
203 << "Concurrent modifications to registry key during backup operation."; | 236 << "Concurrent modifications to registry key during backup operation."; |
204 | 237 |
205 // Get their values. | 238 // Get their values. |
206 RegKey subkey; | 239 RegKey subkey; |
207 for (std::map<std::wstring, KeyData>::iterator it = subkeys.begin(); | 240 for (DWORD i = 0; i < num_subkeys; ++i) { |
208 it != subkeys.end(); ++it) { | 241 result = subkey.Open(key.Handle(), subkey_names[i].c_str(), |
209 result = subkey.Open(key.Handle(), it->first.c_str(), kKeyReadNoNotify); | 242 kKeyReadNoNotify); |
210 if (result != ERROR_SUCCESS) { | 243 if (result != ERROR_SUCCESS) { |
211 LOG(ERROR) << "Failed opening subkey \"" << it->first | 244 LOG(ERROR) << "Failed opening subkey \"" << subkey_names[i] |
212 << "\" for backup, result: " << result; | 245 << "\" for backup, result: " << result; |
213 return false; | 246 return false; |
214 } | 247 } |
215 if (!it->second.Initialize(subkey)) { | 248 if (!subkeys[i].Initialize(subkey)) { |
216 LOG(ERROR) << "Failed backing up subkey \"" << it->first << "\""; | 249 LOG(ERROR) << "Failed backing up subkey \"" << subkey_names[i] << "\""; |
217 return false; | 250 return false; |
218 } | 251 } |
219 } | 252 } |
220 } | 253 } |
221 | 254 |
222 values_.swap(values); | 255 values_.swap(values); |
| 256 subkey_names_.swap(subkey_names); |
223 subkeys_.swap(subkeys); | 257 subkeys_.swap(subkeys); |
| 258 num_values_ = num_values; |
| 259 num_subkeys_ = num_subkeys; |
224 | 260 |
225 return true; | 261 return true; |
226 } | 262 } |
227 | 263 |
228 bool RegistryKeyBackup::KeyData::WriteTo(RegKey* key) const { | 264 bool RegistryKeyBackup::KeyData::WriteTo(RegKey* key) const { |
229 DCHECK(key); | 265 DCHECK(key); |
230 | 266 |
231 LONG result = ERROR_SUCCESS; | 267 LONG result = ERROR_SUCCESS; |
232 | 268 |
233 // Write the values. | 269 // Write the values. |
234 for (std::vector<ValueData>::const_iterator it = values_.begin(); | 270 for (DWORD i = 0; i < num_values_; ++i) { |
235 it != values_.end(); ++it) { | 271 const ValueData& value = values_[i]; |
236 const ValueData& value = *it; | |
237 result = RegSetValueEx(key->Handle(), value.name(), 0, value.type(), | 272 result = RegSetValueEx(key->Handle(), value.name(), 0, value.type(), |
238 value.data(), value.data_len()); | 273 value.data(), value.data_len()); |
239 if (result != ERROR_SUCCESS) { | 274 if (result != ERROR_SUCCESS) { |
240 LOG(ERROR) << "Failed writing value \"" << value.name_str() | 275 LOG(ERROR) << "Failed writing value \"" << value.name_str() |
241 << "\", result: " << result; | 276 << "\", result: " << result; |
242 return false; | 277 return false; |
243 } | 278 } |
244 } | 279 } |
245 | 280 |
246 // Write the subkeys. | 281 // Write the subkeys. |
247 RegKey subkey; | 282 RegKey subkey; |
248 for (std::map<std::wstring, KeyData>::const_iterator it = subkeys_.begin(); | 283 for (DWORD i = 0; i < num_subkeys_; ++i) { |
249 it != subkeys_.end(); ++it) { | 284 const std::wstring& name = subkey_names_[i]; |
250 const std::wstring& name = it->first; | |
251 | 285 |
252 result = subkey.Create(key->Handle(), name.c_str(), KEY_WRITE); | 286 result = subkey.Create(key->Handle(), name.c_str(), KEY_WRITE); |
253 if (result != ERROR_SUCCESS) { | 287 if (result != ERROR_SUCCESS) { |
254 LOG(ERROR) << "Failed creating subkey \"" << name << "\", result: " | 288 LOG(ERROR) << "Failed creating subkey \"" << name << "\", result: " |
255 << result; | 289 << result; |
256 return false; | 290 return false; |
257 } | 291 } |
258 if (!it->second.WriteTo(&subkey)) { | 292 if (!subkeys_[i].WriteTo(&subkey)) { |
259 LOG(ERROR) << "Failed writing subkey \"" << name << "\", result: " | 293 LOG(ERROR) << "Failed writing subkey \"" << name << "\", result: " |
260 << result; | 294 << result; |
261 return false; | 295 return false; |
262 } | 296 } |
263 } | 297 } |
264 | 298 |
265 return true; | 299 return true; |
266 } | 300 } |
267 | 301 |
268 RegistryKeyBackup::RegistryKeyBackup() { | 302 RegistryKeyBackup::RegistryKeyBackup() { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
309 } else { | 343 } else { |
310 success = key_data_->WriteTo(&dest_key); | 344 success = key_data_->WriteTo(&dest_key); |
311 LOG_IF(ERROR, !success) << "Failed to write key data."; | 345 LOG_IF(ERROR, !success) << "Failed to write key data."; |
312 } | 346 } |
313 } else { | 347 } else { |
314 success = true; | 348 success = true; |
315 } | 349 } |
316 | 350 |
317 return success; | 351 return success; |
318 } | 352 } |
OLD | NEW |