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