Enable password generation only if sync for passwords is enabled.
[chromium-blink-merge.git] / base / win / registry.cc
blob3f6a22367d498847c95b793599d855b52210552d
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/win/registry.h"
7 #include <shlwapi.h>
8 #include <algorithm>
10 #include "base/logging.h"
11 #include "base/threading/thread_restrictions.h"
13 #pragma comment(lib, "shlwapi.lib") // for SHDeleteKey
15 namespace base {
16 namespace win {
18 // RegKey ----------------------------------------------------------------------
20 RegKey::RegKey()
21 : key_(NULL),
22 watch_event_(0) {
25 RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
26 : key_(NULL),
27 watch_event_(0) {
28 base::ThreadRestrictions::AssertIOAllowed();
29 if (rootkey) {
30 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
31 Create(rootkey, subkey, access);
32 else
33 Open(rootkey, subkey, access);
34 } else {
35 DCHECK(!subkey);
39 RegKey::~RegKey() {
40 Close();
43 LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
44 DWORD disposition_value;
45 return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
48 LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
49 DWORD* disposition, REGSAM access) {
50 base::ThreadRestrictions::AssertIOAllowed();
51 DCHECK(rootkey && subkey && access && disposition);
52 Close();
54 LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL,
55 REG_OPTION_NON_VOLATILE, access, NULL, &key_,
56 disposition);
57 return result;
60 LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
61 base::ThreadRestrictions::AssertIOAllowed();
62 DCHECK(name && access);
64 HKEY subkey = NULL;
65 LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
66 access, NULL, &subkey, NULL);
67 Close();
69 key_ = subkey;
70 return result;
73 LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
74 base::ThreadRestrictions::AssertIOAllowed();
75 DCHECK(rootkey && subkey && access);
76 Close();
78 LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_);
79 return result;
82 LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) {
83 base::ThreadRestrictions::AssertIOAllowed();
84 DCHECK(relative_key_name && access);
86 HKEY subkey = NULL;
87 LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey);
89 // We have to close the current opened key before replacing it with the new
90 // one.
91 Close();
93 key_ = subkey;
94 return result;
97 void RegKey::Close() {
98 base::ThreadRestrictions::AssertIOAllowed();
99 StopWatching();
100 if (key_) {
101 ::RegCloseKey(key_);
102 key_ = NULL;
106 bool RegKey::HasValue(const wchar_t* name) const {
107 base::ThreadRestrictions::AssertIOAllowed();
108 return RegQueryValueEx(key_, name, 0, NULL, NULL, NULL) == ERROR_SUCCESS;
111 DWORD RegKey::GetValueCount() const {
112 base::ThreadRestrictions::AssertIOAllowed();
113 DWORD count = 0;
114 LONG result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
115 NULL, NULL, NULL, NULL);
116 return (result == ERROR_SUCCESS) ? count : 0;
119 LONG RegKey::GetValueNameAt(int index, std::wstring* name) const {
120 base::ThreadRestrictions::AssertIOAllowed();
121 wchar_t buf[256];
122 DWORD bufsize = arraysize(buf);
123 LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL);
124 if (r == ERROR_SUCCESS)
125 *name = buf;
127 return r;
130 LONG RegKey::DeleteKey(const wchar_t* name) {
131 base::ThreadRestrictions::AssertIOAllowed();
132 DCHECK(key_);
133 DCHECK(name);
134 LONG result = SHDeleteKey(key_, name);
135 return result;
138 LONG RegKey::DeleteValue(const wchar_t* value_name) {
139 base::ThreadRestrictions::AssertIOAllowed();
140 DCHECK(key_);
141 DCHECK(value_name);
142 LONG result = RegDeleteValue(key_, value_name);
143 return result;
146 LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const {
147 DCHECK(out_value);
148 DWORD type = REG_DWORD;
149 DWORD size = sizeof(DWORD);
150 DWORD local_value = 0;
151 LONG result = ReadValue(name, &local_value, &size, &type);
152 if (result == ERROR_SUCCESS) {
153 if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD))
154 *out_value = local_value;
155 else
156 result = ERROR_CANTREAD;
159 return result;
162 LONG RegKey::ReadInt64(const wchar_t* name, int64* out_value) const {
163 DCHECK(out_value);
164 DWORD type = REG_QWORD;
165 int64 local_value = 0;
166 DWORD size = sizeof(local_value);
167 LONG result = ReadValue(name, &local_value, &size, &type);
168 if (result == ERROR_SUCCESS) {
169 if ((type == REG_QWORD || type == REG_BINARY) &&
170 size == sizeof(local_value))
171 *out_value = local_value;
172 else
173 result = ERROR_CANTREAD;
176 return result;
179 LONG RegKey::ReadValue(const wchar_t* name, std::wstring* out_value) const {
180 base::ThreadRestrictions::AssertIOAllowed();
181 DCHECK(out_value);
182 const size_t kMaxStringLength = 1024; // This is after expansion.
183 // Use the one of the other forms of ReadValue if 1024 is too small for you.
184 wchar_t raw_value[kMaxStringLength];
185 DWORD type = REG_SZ, size = sizeof(raw_value);
186 LONG result = ReadValue(name, raw_value, &size, &type);
187 if (result == ERROR_SUCCESS) {
188 if (type == REG_SZ) {
189 *out_value = raw_value;
190 } else if (type == REG_EXPAND_SZ) {
191 wchar_t expanded[kMaxStringLength];
192 size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
193 // Success: returns the number of wchar_t's copied
194 // Fail: buffer too small, returns the size required
195 // Fail: other, returns 0
196 if (size == 0 || size > kMaxStringLength) {
197 result = ERROR_MORE_DATA;
198 } else {
199 *out_value = expanded;
201 } else {
202 // Not a string. Oops.
203 result = ERROR_CANTREAD;
207 return result;
210 LONG RegKey::ReadValue(const wchar_t* name,
211 void* data,
212 DWORD* dsize,
213 DWORD* dtype) const {
214 base::ThreadRestrictions::AssertIOAllowed();
215 LONG result = RegQueryValueEx(key_, name, 0, dtype,
216 reinterpret_cast<LPBYTE>(data), dsize);
217 return result;
220 LONG RegKey::ReadValues(const wchar_t* name,
221 std::vector<std::wstring>* values) {
222 base::ThreadRestrictions::AssertIOAllowed();
223 values->clear();
225 DWORD type = REG_MULTI_SZ;
226 DWORD size = 0;
227 LONG result = ReadValue(name, NULL, &size, &type);
228 if (FAILED(result) || size == 0)
229 return result;
231 if (type != REG_MULTI_SZ)
232 return ERROR_CANTREAD;
234 std::vector<wchar_t> buffer(size / sizeof(wchar_t));
235 result = ReadValue(name, &buffer[0], &size, NULL);
236 if (FAILED(result) || size == 0)
237 return result;
239 // Parse the double-null-terminated list of strings.
240 // Note: This code is paranoid to not read outside of |buf|, in the case where
241 // it may not be properly terminated.
242 const wchar_t* entry = &buffer[0];
243 const wchar_t* buffer_end = entry + (size / sizeof(wchar_t));
244 while (entry < buffer_end && entry[0] != '\0') {
245 const wchar_t* entry_end = std::find(entry, buffer_end, L'\0');
246 values->push_back(std::wstring(entry, entry_end));
247 entry = entry_end + 1;
249 return 0;
252 LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) {
253 return WriteValue(
254 name, &in_value, static_cast<DWORD>(sizeof(in_value)), REG_DWORD);
257 LONG RegKey::WriteValue(const wchar_t * name, const wchar_t* in_value) {
258 return WriteValue(name, in_value,
259 static_cast<DWORD>(sizeof(*in_value) * (wcslen(in_value) + 1)), REG_SZ);
262 LONG RegKey::WriteValue(const wchar_t* name,
263 const void* data,
264 DWORD dsize,
265 DWORD dtype) {
266 base::ThreadRestrictions::AssertIOAllowed();
267 DCHECK(data || !dsize);
269 LONG result = RegSetValueEx(key_, name, 0, dtype,
270 reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
271 return result;
274 LONG RegKey::StartWatching() {
275 DCHECK(key_);
276 if (!watch_event_)
277 watch_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
279 DWORD filter = REG_NOTIFY_CHANGE_NAME |
280 REG_NOTIFY_CHANGE_ATTRIBUTES |
281 REG_NOTIFY_CHANGE_LAST_SET |
282 REG_NOTIFY_CHANGE_SECURITY;
284 // Watch the registry key for a change of value.
285 LONG result = RegNotifyChangeKeyValue(key_, TRUE, filter, watch_event_, TRUE);
286 if (result != ERROR_SUCCESS) {
287 CloseHandle(watch_event_);
288 watch_event_ = 0;
291 return result;
294 bool RegKey::HasChanged() {
295 if (watch_event_) {
296 if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) {
297 StartWatching();
298 return true;
301 return false;
304 LONG RegKey::StopWatching() {
305 LONG result = ERROR_INVALID_HANDLE;
306 if (watch_event_) {
307 CloseHandle(watch_event_);
308 watch_event_ = 0;
309 result = ERROR_SUCCESS;
311 return result;
314 // RegistryValueIterator ------------------------------------------------------
316 RegistryValueIterator::RegistryValueIterator(HKEY root_key,
317 const wchar_t* folder_key) {
318 base::ThreadRestrictions::AssertIOAllowed();
320 LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
321 if (result != ERROR_SUCCESS) {
322 key_ = NULL;
323 } else {
324 DWORD count = 0;
325 result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
326 NULL, NULL, NULL, NULL);
328 if (result != ERROR_SUCCESS) {
329 ::RegCloseKey(key_);
330 key_ = NULL;
331 } else {
332 index_ = count - 1;
336 Read();
339 RegistryValueIterator::~RegistryValueIterator() {
340 base::ThreadRestrictions::AssertIOAllowed();
341 if (key_)
342 ::RegCloseKey(key_);
345 DWORD RegistryValueIterator::ValueCount() const {
346 base::ThreadRestrictions::AssertIOAllowed();
347 DWORD count = 0;
348 LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
349 &count, NULL, NULL, NULL, NULL);
350 if (result != ERROR_SUCCESS)
351 return 0;
353 return count;
356 bool RegistryValueIterator::Valid() const {
357 return key_ != NULL && index_ >= 0;
360 void RegistryValueIterator::operator++() {
361 --index_;
362 Read();
365 bool RegistryValueIterator::Read() {
366 base::ThreadRestrictions::AssertIOAllowed();
367 if (Valid()) {
368 DWORD ncount = arraysize(name_);
369 value_size_ = sizeof(value_);
370 LONG r = ::RegEnumValue(key_, index_, name_, &ncount, NULL, &type_,
371 reinterpret_cast<BYTE*>(value_), &value_size_);
372 if (ERROR_SUCCESS == r)
373 return true;
376 name_[0] = '\0';
377 value_[0] = '\0';
378 value_size_ = 0;
379 return false;
382 // RegistryKeyIterator --------------------------------------------------------
384 RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
385 const wchar_t* folder_key) {
386 base::ThreadRestrictions::AssertIOAllowed();
387 LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
388 if (result != ERROR_SUCCESS) {
389 key_ = NULL;
390 } else {
391 DWORD count = 0;
392 LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
393 NULL, NULL, NULL, NULL, NULL);
395 if (result != ERROR_SUCCESS) {
396 ::RegCloseKey(key_);
397 key_ = NULL;
398 } else {
399 index_ = count - 1;
403 Read();
406 RegistryKeyIterator::~RegistryKeyIterator() {
407 base::ThreadRestrictions::AssertIOAllowed();
408 if (key_)
409 ::RegCloseKey(key_);
412 DWORD RegistryKeyIterator::SubkeyCount() const {
413 base::ThreadRestrictions::AssertIOAllowed();
414 DWORD count = 0;
415 LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
416 NULL, NULL, NULL, NULL, NULL);
417 if (result != ERROR_SUCCESS)
418 return 0;
420 return count;
423 bool RegistryKeyIterator::Valid() const {
424 return key_ != NULL && index_ >= 0;
427 void RegistryKeyIterator::operator++() {
428 --index_;
429 Read();
432 bool RegistryKeyIterator::Read() {
433 base::ThreadRestrictions::AssertIOAllowed();
434 if (Valid()) {
435 DWORD ncount = arraysize(name_);
436 FILETIME written;
437 LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
438 NULL, &written);
439 if (ERROR_SUCCESS == r)
440 return true;
443 name_[0] = '\0';
444 return false;
447 } // namespace win
448 } // namespace base