Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(187)

Side by Side Diff: chrome/installer/util/delete_reg_key_work_item.cc

Issue 6598065: Add rollback support to DeleteRegKeyWorkItem.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 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 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/delete_reg_key_work_item.h"
6
5 #include <shlwapi.h> 7 #include <shlwapi.h>
6 8 #include <algorithm>
7 #include "chrome/installer/util/delete_reg_key_work_item.h" 9 #include <limits>
10 #include <vector>
8 11
9 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/rand_util.h"
14 #include "base/stringprintf.h"
15 #include "base/win/registry.h"
10 #include "chrome/installer/util/logging_installer.h" 16 #include "chrome/installer/util/logging_installer.h"
11 17
18 using base::win::RegKey;
19
20 // A container for a registry key, its values, and its subkeys. We don't use
21 // more obvious methods for various reasons:
22 // - RegCopyTree isn't supported pre-Vista, so we'd have to do something
23 // different for XP anyway.
24 // - SHCopyKey can't copy subkeys into a volatile destination, so we'd have to
25 // worry about polluting the registry. Also, we've observed crashes in other
26 // shell lightweight API funcs, so perhaps it's best to avoid them.
robertshield 2011/03/01 16:04:43 I feel we have insufficient evidence for shlwapi p
grt (UTC plus 2) 2011/03/01 20:54:02 Done.
27 // We don't persist security attributes since we only delete keys that we own,
28 // and we don't set custom attributes on them anyway.
29 class DeleteRegKeyWorkItem::RegKeyBackup {
30 public:
31 RegKeyBackup();
32 bool Initialize(const RegKey& key);
33 bool WriteTo(RegKey* key) const;
34
35 private:
36 // A container for a registry value.
37 class RegValueBackup {
38 public:
39 RegValueBackup();
40 void Initialize(const wchar_t* name_buffer, DWORD name_size,
41 DWORD type, const uint8* data, DWORD data_size);
42 const std::wstring& name_str() const { return name_; }
43 const wchar_t* name() const { return name_.empty() ? NULL : name_.c_str(); }
44 DWORD type() const { return type_; }
45 const uint8* data() const { return data_.empty() ? NULL : &data_[0]; }
46 DWORD data_len() const { return static_cast<DWORD>(data_.size()); }
47
48 private:
49 std::wstring name_;
50 std::vector<uint8> data_;
51 DWORD type_;
52
53 DISALLOW_COPY_AND_ASSIGN(RegValueBackup);
54 };
55
56 scoped_array<RegValueBackup> values_;
57 scoped_array<std::wstring> subkey_names_;
58 scoped_array<RegKeyBackup> subkeys_;
59 ptrdiff_t num_values_;
60 ptrdiff_t num_subkeys_;
61
62 DISALLOW_COPY_AND_ASSIGN(RegKeyBackup);
63 };
64
65 DeleteRegKeyWorkItem::RegKeyBackup::RegValueBackup::RegValueBackup()
66 : type_(REG_NONE) {
67 }
68
69 void DeleteRegKeyWorkItem::RegKeyBackup::RegValueBackup::Initialize(
70 const wchar_t* name_buffer,
71 DWORD name_size,
72 DWORD type, const uint8* data,
73 DWORD data_size) {
74 name_.assign(name_buffer, name_size);
75 type_ = type;
76 data_.assign(data, data + data_size);
77 }
78
79 DeleteRegKeyWorkItem::RegKeyBackup::RegKeyBackup()
80 : num_values_(0),
81 num_subkeys_(0) {
82 }
83
84 // Initializes this object by reading the values and subkeys of |key|.
85 // Security descriptors are not backed up.
86 bool DeleteRegKeyWorkItem::RegKeyBackup::Initialize(const RegKey& key) {
87 DCHECK(key.Valid());
88
89 scoped_array<RegValueBackup> values;
90 scoped_array<std::wstring> subkey_names;
91 scoped_array<RegKeyBackup> subkeys;
92
93 DWORD num_subkeys = 0;
94 DWORD max_subkey_name_len = 0;
95 DWORD num_values = 0;
96 DWORD max_value_name_len = 0;
97 DWORD max_value_len = 0;
98 LONG result = RegQueryInfoKey(key.Handle(), NULL, NULL, NULL,
99 &num_subkeys, &max_subkey_name_len, NULL,
100 &num_values, &max_value_name_len,
101 &max_value_len, NULL, NULL);
102 if (result != ERROR_SUCCESS) {
103 LOG(ERROR) << "Failed getting info of key to backup, result: " << result;
104 return false;
105 }
106 if (max_subkey_name_len >= std::numeric_limits<DWORD>::max() - 1 ||
107 max_value_name_len >= std::numeric_limits<DWORD>::max() - 1) {
108 LOG(ERROR)
109 << "Failed backing up key; subkeys and/or names are out of range.";
110 return false;
111 }
112 DWORD max_name_len = std::max(max_subkey_name_len, max_value_name_len) + 1;
113 scoped_array<wchar_t> name_buffer(new wchar_t[max_name_len]);
114
115 // Backup the values.
116 if (num_values != 0) {
117 values.reset(new RegValueBackup[num_values]);
118 scoped_array<uint8> value_buffer(new uint8[max_value_len]);
119 DWORD name_size = 0;
120 DWORD value_type = REG_NONE;
121 DWORD value_size = 0;
122
123 for (DWORD i = 0; i < num_values; ++i) {
124 name_size = max_name_len;
125 value_size = max_value_len;
126 result = RegEnumValue(key.Handle(), i, name_buffer.get(), &name_size,
127 NULL, &value_type, value_buffer.get(), &value_size);
128 if (result != ERROR_SUCCESS) {
robertshield 2011/03/01 16:04:43 do you want to handle ERROR_MORE_DATA here (which
grt (UTC plus 2) 2011/03/01 20:54:02 Done. Also handles the case where values and/or k
129 LOG(ERROR) << "Failed backing up value " << i << ", result: " << result;
130 return false;
131 }
132 values[i].Initialize(name_buffer.get(), name_size, value_type,
133 value_buffer.get(), value_size);
134 }
135 DLOG_IF(WARNING, RegEnumValue(key.Handle(), num_values, NULL, NULL, NULL,
136 &value_type, NULL, NULL) == ERROR_SUCCESS)
137 << "Concurrent modifications to registry key during backup operation.";
138 }
139
140 // Backup the subkeys.
141 if (num_subkeys != 0) {
142 subkey_names.reset(new std::wstring[num_subkeys]);
143 subkeys.reset(new RegKeyBackup[num_subkeys]);
144 DWORD name_size = 0;
145
146 // Get the names of them.
147 for (DWORD i = 0; i < num_subkeys; ++i) {
148 name_size = max_name_len;
149 result = RegEnumKeyEx(key.Handle(), i, name_buffer.get(), &name_size,
150 NULL, NULL, NULL, NULL);
robertshield 2011/03/01 16:04:43 ditto
grt (UTC plus 2) 2011/03/01 20:54:02 Done.
151 if (result != ERROR_SUCCESS) {
152 LOG(ERROR) << "Failed getting name of up subkey " << i
153 << " for backup, result: " << result;
154 return false;
155 }
156 subkey_names[i].assign(name_buffer.get(), name_size);
157 }
158 DLOG_IF(WARNING, RegEnumKeyEx(key.Handle(), num_subkeys, NULL, &name_size,
159 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
160 << "Concurrent modifications to registry key during backup operation.";
161
162 // Get their values.
163 RegKey subkey;
164 for (DWORD i = 0; i < num_subkeys; ++i) {
165 result = subkey.Open(key.Handle(), subkey_names[i].c_str(), KEY_READ);
166 if (result != ERROR_SUCCESS) {
167 LOG(ERROR) << "Failed opening subkey \"" << subkey_names[i]
168 << "\" for backup, result: " << result;
169 return false;
170 }
171 if (!subkeys[i].Initialize(subkey)) {
172 LOG(ERROR) << "Failed backing up subkey \"" << subkey_names[i] << "\"";
173 return false;
174 }
175 }
176 }
177
178 values_.swap(values);
179 subkey_names_.swap(subkey_names);
180 subkeys_.swap(subkeys);
181 num_values_ = num_values;
182 num_subkeys_ = num_subkeys;
183
184 return true;
185 }
186
187 // Writes the values and subkeys of this object into |key|.
188 bool DeleteRegKeyWorkItem::RegKeyBackup::WriteTo(RegKey* key) const {
189 LONG result = ERROR_SUCCESS;
190
191 // Write the values.
192 for (int i = 0; i < num_values_; ++i) {
193 const RegValueBackup& value = values_[i];
194 result = RegSetValueEx(key->Handle(), value.name(), 0, value.type(),
195 value.data(), value.data_len());
196 if (result != ERROR_SUCCESS) {
197 LOG(ERROR) << "Failed writing value \"" << value.name_str()
198 << "\", result: " << result;
199 return false;
200 }
201 }
202
203 // Write the subkeys.
204 RegKey subkey;
205 for (int i = 0; i < num_subkeys_; ++i) {
206 const std::wstring& name = subkey_names_[i];
207
208 result = subkey.Create(key->Handle(), name.c_str(), KEY_WRITE);
209 if (result != ERROR_SUCCESS) {
210 LOG(ERROR) << "Failed creating subkey \"" << name << "\", result: "
211 << result;
212 return false;
213 }
214 if (!subkeys_[i].WriteTo(&subkey)) {
215 LOG(ERROR) << "Failed writing subkey \"" << name << "\", result: "
216 << result;
217 return false;
218 }
219 }
220
221 return true;
222 }
12 223
13 DeleteRegKeyWorkItem::~DeleteRegKeyWorkItem() { 224 DeleteRegKeyWorkItem::~DeleteRegKeyWorkItem() {
14 } 225 }
15 226
16 DeleteRegKeyWorkItem::DeleteRegKeyWorkItem(HKEY predefined_root, 227 DeleteRegKeyWorkItem::DeleteRegKeyWorkItem(HKEY predefined_root,
17 const std::wstring& path) 228 const std::wstring& path)
18 : predefined_root_(predefined_root), 229 : predefined_root_(predefined_root),
19 path_(path) { 230 path_(path) {
231 // It's a safe bet that we don't want to delete one of the root trees.
232 DCHECK(!path.empty());
20 } 233 }
21 234
22 bool DeleteRegKeyWorkItem::Do() { 235 bool DeleteRegKeyWorkItem::Do() {
23 // TODO(robertshield): Implement rollback for this work item. Consider using 236 scoped_ptr<RegKeyBackup> backup;
robertshield 2011/03/01 16:04:43 nit: 1 space
grt (UTC plus 2) 2011/03/01 20:54:02 Nice catch. Done.
24 // RegSaveKey or RegCopyKey. 237
238 // Only try to make a backup if we're not configured to ignore failures.
25 if (!ignore_failure_) { 239 if (!ignore_failure_) {
26 NOTREACHED(); 240 RegKey original_key;
27 LOG(ERROR) << "Unexpected configuration in DeleteRegKeyWorkItem."; 241
28 return false; 242 // Does the key exist?
243 LONG result = original_key.Open(predefined_root_, path_.c_str(), KEY_READ);
244 if (result == ERROR_SUCCESS) {
245 backup.reset(new RegKeyBackup());
246 if (!backup->Initialize(original_key)) {
247 LOG(ERROR) << "Failed to backup key at " << path_;
248 return ignore_failure_;
249 }
250 } else if (result != ERROR_FILE_NOT_FOUND) {
251 LOG(ERROR) << "Failed to open key at " << path_
252 << " to create backup, result: " << result;
253 return ignore_failure_;
254 }
29 } 255 }
30 256
31 LSTATUS result = SHDeleteKey(predefined_root_, path_.c_str()); 257 // Delete the key.
32 if (result != ERROR_SUCCESS) { 258 LONG result = SHDeleteKey(predefined_root_, path_.c_str());
33 LOG(ERROR) << "Failed to delete key at " << path_ << ", result: " << result; 259 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) {
260 LOG(ERROR) << "Failed to delete key at " << path_ << ", result: "
261 << result;
262 return ignore_failure_;
34 } 263 }
35 264
265 // We've succeeded, so rememeber any backup we may have made.
266 backup_.swap(backup);
267
36 return true; 268 return true;
37 } 269 }
38 270
39 void DeleteRegKeyWorkItem::Rollback() { 271 void DeleteRegKeyWorkItem::Rollback() {
40 if (ignore_failure_) 272 if (ignore_failure_ || backup_.get() == NULL)
41 return; 273 return;
42 NOTREACHED(); 274
275 // Delete anything in the key before restoring the backup in case someone else
276 // put new data in the key after Do().
277 LONG result = SHDeleteKey(predefined_root_, path_.c_str());
278 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) {
279 LOG(ERROR) << "Failed to delete key at " << path_ << " in rollback, "
280 "result: " << result;
281 }
282
283 // Restore the old contents. The restoration takes on its default security
284 // attributes; any custom attributes are lost.
285 RegKey original_key;
286 result = original_key.Create(predefined_root_, path_.c_str(), KEY_WRITE);
287 if (result != ERROR_SUCCESS) {
288 LOG(ERROR) << "Failed to create original key at " << path_
289 << " in rollback, result: " << result;
290 } else {
291 if (!backup_->WriteTo(&original_key))
292 LOG(ERROR) << "Failed to restore key in rollback, result: " << result;
293 }
43 } 294 }
44
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698