xref: /aosp_15_r20/external/cronet/base/win/registry.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/win/registry.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <ntstatus.h>
8*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include <algorithm>
11*6777b538SAndroid Build Coastguard Worker #include <iterator>
12*6777b538SAndroid Build Coastguard Worker #include <memory>
13*6777b538SAndroid Build Coastguard Worker #include <string>
14*6777b538SAndroid Build Coastguard Worker #include <utility>
15*6777b538SAndroid Build Coastguard Worker #include <vector>
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util_win.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/win/object_watcher.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/win/scoped_handle.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/win/shlwapi.h"
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker extern "C" NTSTATUS WINAPI NtDeleteKey(IN HANDLE KeyHandle);
28*6777b538SAndroid Build Coastguard Worker 
29*6777b538SAndroid Build Coastguard Worker namespace base::win {
30*6777b538SAndroid Build Coastguard Worker 
31*6777b538SAndroid Build Coastguard Worker namespace {
32*6777b538SAndroid Build Coastguard Worker 
33*6777b538SAndroid Build Coastguard Worker // RegEnumValue() reports the number of characters from the name that were
34*6777b538SAndroid Build Coastguard Worker // written to the buffer, not how many there are. This constant is the maximum
35*6777b538SAndroid Build Coastguard Worker // name size, such that a buffer with this size should read any name.
36*6777b538SAndroid Build Coastguard Worker constexpr DWORD MAX_REGISTRY_NAME_SIZE = 16384;
37*6777b538SAndroid Build Coastguard Worker 
38*6777b538SAndroid Build Coastguard Worker // Registry values are read as BYTE* but can have wchar_t* data whose last
39*6777b538SAndroid Build Coastguard Worker // wchar_t is truncated. This function converts the reported |byte_size| to
40*6777b538SAndroid Build Coastguard Worker // a size in wchar_t that can store a truncated wchar_t if necessary.
to_wchar_size(DWORD byte_size)41*6777b538SAndroid Build Coastguard Worker inline DWORD to_wchar_size(DWORD byte_size) {
42*6777b538SAndroid Build Coastguard Worker   return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t);
43*6777b538SAndroid Build Coastguard Worker }
44*6777b538SAndroid Build Coastguard Worker 
45*6777b538SAndroid Build Coastguard Worker // Mask to pull WOW64 access flags out of REGSAM access.
46*6777b538SAndroid Build Coastguard Worker constexpr REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
47*6777b538SAndroid Build Coastguard Worker 
48*6777b538SAndroid Build Coastguard Worker constexpr DWORD kInvalidIterValue = static_cast<DWORD>(-1);
49*6777b538SAndroid Build Coastguard Worker 
50*6777b538SAndroid Build Coastguard Worker }  // namespace
51*6777b538SAndroid Build Coastguard Worker 
52*6777b538SAndroid Build Coastguard Worker // Watches for modifications to a key.
53*6777b538SAndroid Build Coastguard Worker class RegKey::Watcher : public ObjectWatcher::Delegate {
54*6777b538SAndroid Build Coastguard Worker  public:
55*6777b538SAndroid Build Coastguard Worker   Watcher() = default;
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker   Watcher(const Watcher&) = delete;
58*6777b538SAndroid Build Coastguard Worker   Watcher& operator=(const Watcher&) = delete;
59*6777b538SAndroid Build Coastguard Worker 
60*6777b538SAndroid Build Coastguard Worker   ~Watcher() override = default;
61*6777b538SAndroid Build Coastguard Worker 
62*6777b538SAndroid Build Coastguard Worker   bool StartWatching(HKEY key, ChangeCallback callback);
63*6777b538SAndroid Build Coastguard Worker 
64*6777b538SAndroid Build Coastguard Worker   // ObjectWatcher::Delegate:
OnObjectSignaled(HANDLE object)65*6777b538SAndroid Build Coastguard Worker   void OnObjectSignaled(HANDLE object) override {
66*6777b538SAndroid Build Coastguard Worker     DCHECK(watch_event_.is_valid());
67*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(watch_event_.get(), object);
68*6777b538SAndroid Build Coastguard Worker     std::move(callback_).Run();
69*6777b538SAndroid Build Coastguard Worker   }
70*6777b538SAndroid Build Coastguard Worker 
71*6777b538SAndroid Build Coastguard Worker  private:
72*6777b538SAndroid Build Coastguard Worker   ScopedHandle watch_event_;
73*6777b538SAndroid Build Coastguard Worker   ObjectWatcher object_watcher_;
74*6777b538SAndroid Build Coastguard Worker   ChangeCallback callback_;
75*6777b538SAndroid Build Coastguard Worker };
76*6777b538SAndroid Build Coastguard Worker 
StartWatching(HKEY key,ChangeCallback callback)77*6777b538SAndroid Build Coastguard Worker bool RegKey::Watcher::StartWatching(HKEY key, ChangeCallback callback) {
78*6777b538SAndroid Build Coastguard Worker   DCHECK(key);
79*6777b538SAndroid Build Coastguard Worker   DCHECK(callback_.is_null());
80*6777b538SAndroid Build Coastguard Worker 
81*6777b538SAndroid Build Coastguard Worker   if (!watch_event_.is_valid()) {
82*6777b538SAndroid Build Coastguard Worker     watch_event_.Set(CreateEvent(nullptr, TRUE, FALSE, nullptr));
83*6777b538SAndroid Build Coastguard Worker   }
84*6777b538SAndroid Build Coastguard Worker 
85*6777b538SAndroid Build Coastguard Worker   if (!watch_event_.is_valid()) {
86*6777b538SAndroid Build Coastguard Worker     return false;
87*6777b538SAndroid Build Coastguard Worker   }
88*6777b538SAndroid Build Coastguard Worker 
89*6777b538SAndroid Build Coastguard Worker   DWORD filter = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES |
90*6777b538SAndroid Build Coastguard Worker                  REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY |
91*6777b538SAndroid Build Coastguard Worker                  REG_NOTIFY_THREAD_AGNOSTIC;
92*6777b538SAndroid Build Coastguard Worker   // Watch the registry key for a change of value.
93*6777b538SAndroid Build Coastguard Worker   LONG result =
94*6777b538SAndroid Build Coastguard Worker       RegNotifyChangeKeyValue(key, /*bWatchSubtree=*/TRUE, filter,
95*6777b538SAndroid Build Coastguard Worker                               watch_event_.get(), /*fAsynchronous=*/TRUE);
96*6777b538SAndroid Build Coastguard Worker   if (result != ERROR_SUCCESS) {
97*6777b538SAndroid Build Coastguard Worker     watch_event_.Close();
98*6777b538SAndroid Build Coastguard Worker     return false;
99*6777b538SAndroid Build Coastguard Worker   }
100*6777b538SAndroid Build Coastguard Worker 
101*6777b538SAndroid Build Coastguard Worker   callback_ = std::move(callback);
102*6777b538SAndroid Build Coastguard Worker   return object_watcher_.StartWatchingOnce(watch_event_.get(), this);
103*6777b538SAndroid Build Coastguard Worker }
104*6777b538SAndroid Build Coastguard Worker 
105*6777b538SAndroid Build Coastguard Worker // RegKey ----------------------------------------------------------------------
106*6777b538SAndroid Build Coastguard Worker 
107*6777b538SAndroid Build Coastguard Worker RegKey::RegKey() = default;
108*6777b538SAndroid Build Coastguard Worker 
RegKey(HKEY key)109*6777b538SAndroid Build Coastguard Worker RegKey::RegKey(HKEY key) : key_(key) {}
110*6777b538SAndroid Build Coastguard Worker 
RegKey(HKEY rootkey,const wchar_t * subkey,REGSAM access)111*6777b538SAndroid Build Coastguard Worker RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
112*6777b538SAndroid Build Coastguard Worker   if (rootkey) {
113*6777b538SAndroid Build Coastguard Worker     if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) {
114*6777b538SAndroid Build Coastguard Worker       (void)Create(rootkey, subkey, access);
115*6777b538SAndroid Build Coastguard Worker     } else {
116*6777b538SAndroid Build Coastguard Worker       (void)Open(rootkey, subkey, access);
117*6777b538SAndroid Build Coastguard Worker     }
118*6777b538SAndroid Build Coastguard Worker   } else {
119*6777b538SAndroid Build Coastguard Worker     DCHECK(!subkey);
120*6777b538SAndroid Build Coastguard Worker     wow64access_ = access & kWow64AccessMask;
121*6777b538SAndroid Build Coastguard Worker   }
122*6777b538SAndroid Build Coastguard Worker }
123*6777b538SAndroid Build Coastguard Worker 
RegKey(RegKey && other)124*6777b538SAndroid Build Coastguard Worker RegKey::RegKey(RegKey&& other) noexcept
125*6777b538SAndroid Build Coastguard Worker     : key_(other.key_),
126*6777b538SAndroid Build Coastguard Worker       wow64access_(other.wow64access_),
127*6777b538SAndroid Build Coastguard Worker       key_watcher_(std::move(other.key_watcher_)) {
128*6777b538SAndroid Build Coastguard Worker   other.key_ = nullptr;
129*6777b538SAndroid Build Coastguard Worker   other.wow64access_ = 0;
130*6777b538SAndroid Build Coastguard Worker }
131*6777b538SAndroid Build Coastguard Worker 
operator =(RegKey && other)132*6777b538SAndroid Build Coastguard Worker RegKey& RegKey::operator=(RegKey&& other) {
133*6777b538SAndroid Build Coastguard Worker   Close();
134*6777b538SAndroid Build Coastguard Worker   std::swap(key_, other.key_);
135*6777b538SAndroid Build Coastguard Worker   std::swap(wow64access_, other.wow64access_);
136*6777b538SAndroid Build Coastguard Worker   key_watcher_ = std::move(other.key_watcher_);
137*6777b538SAndroid Build Coastguard Worker   return *this;
138*6777b538SAndroid Build Coastguard Worker }
139*6777b538SAndroid Build Coastguard Worker 
~RegKey()140*6777b538SAndroid Build Coastguard Worker RegKey::~RegKey() {
141*6777b538SAndroid Build Coastguard Worker   Close();
142*6777b538SAndroid Build Coastguard Worker }
143*6777b538SAndroid Build Coastguard Worker 
Create(HKEY rootkey,const wchar_t * subkey,REGSAM access)144*6777b538SAndroid Build Coastguard Worker LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
145*6777b538SAndroid Build Coastguard Worker   DWORD disposition_value;
146*6777b538SAndroid Build Coastguard Worker   return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
147*6777b538SAndroid Build Coastguard Worker }
148*6777b538SAndroid Build Coastguard Worker 
CreateWithDisposition(HKEY rootkey,const wchar_t * subkey,DWORD * disposition,REGSAM access)149*6777b538SAndroid Build Coastguard Worker LONG RegKey::CreateWithDisposition(HKEY rootkey,
150*6777b538SAndroid Build Coastguard Worker                                    const wchar_t* subkey,
151*6777b538SAndroid Build Coastguard Worker                                    DWORD* disposition,
152*6777b538SAndroid Build Coastguard Worker                                    REGSAM access) {
153*6777b538SAndroid Build Coastguard Worker   DCHECK(rootkey && subkey && access && disposition);
154*6777b538SAndroid Build Coastguard Worker   HKEY subhkey = nullptr;
155*6777b538SAndroid Build Coastguard Worker   LONG result =
156*6777b538SAndroid Build Coastguard Worker       RegCreateKeyEx(rootkey, subkey, 0, nullptr, REG_OPTION_NON_VOLATILE,
157*6777b538SAndroid Build Coastguard Worker                      access, nullptr, &subhkey, disposition);
158*6777b538SAndroid Build Coastguard Worker   if (result == ERROR_SUCCESS) {
159*6777b538SAndroid Build Coastguard Worker     Close();
160*6777b538SAndroid Build Coastguard Worker     key_ = subhkey;
161*6777b538SAndroid Build Coastguard Worker     wow64access_ = access & kWow64AccessMask;
162*6777b538SAndroid Build Coastguard Worker   }
163*6777b538SAndroid Build Coastguard Worker 
164*6777b538SAndroid Build Coastguard Worker   return result;
165*6777b538SAndroid Build Coastguard Worker }
166*6777b538SAndroid Build Coastguard Worker 
CreateKey(const wchar_t * name,REGSAM access)167*6777b538SAndroid Build Coastguard Worker LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
168*6777b538SAndroid Build Coastguard Worker   DCHECK(name && access);
169*6777b538SAndroid Build Coastguard Worker 
170*6777b538SAndroid Build Coastguard Worker   if (!Valid()) {
171*6777b538SAndroid Build Coastguard Worker     // The parent key has not been opened or created.
172*6777b538SAndroid Build Coastguard Worker     return ERROR_INVALID_HANDLE;
173*6777b538SAndroid Build Coastguard Worker   }
174*6777b538SAndroid Build Coastguard Worker 
175*6777b538SAndroid Build Coastguard Worker   // After the application has accessed an alternate registry view using one
176*6777b538SAndroid Build Coastguard Worker   // of the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent
177*6777b538SAndroid Build Coastguard Worker   // operations (create, delete, or open) on child registry keys must
178*6777b538SAndroid Build Coastguard Worker   // explicitly use the same flag. Otherwise, there can be unexpected
179*6777b538SAndroid Build Coastguard Worker   // behavior.
180*6777b538SAndroid Build Coastguard Worker   // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
181*6777b538SAndroid Build Coastguard Worker   if ((access & kWow64AccessMask) != wow64access_) {
182*6777b538SAndroid Build Coastguard Worker     NOTREACHED();
183*6777b538SAndroid Build Coastguard Worker     return ERROR_INVALID_PARAMETER;
184*6777b538SAndroid Build Coastguard Worker   }
185*6777b538SAndroid Build Coastguard Worker   HKEY subkey = nullptr;
186*6777b538SAndroid Build Coastguard Worker   LONG result = RegCreateKeyEx(key_, name, 0, nullptr, REG_OPTION_NON_VOLATILE,
187*6777b538SAndroid Build Coastguard Worker                                access, nullptr, &subkey, nullptr);
188*6777b538SAndroid Build Coastguard Worker   if (result == ERROR_SUCCESS) {
189*6777b538SAndroid Build Coastguard Worker     Close();
190*6777b538SAndroid Build Coastguard Worker     key_ = subkey;
191*6777b538SAndroid Build Coastguard Worker     wow64access_ = access & kWow64AccessMask;
192*6777b538SAndroid Build Coastguard Worker   }
193*6777b538SAndroid Build Coastguard Worker 
194*6777b538SAndroid Build Coastguard Worker   return result;
195*6777b538SAndroid Build Coastguard Worker }
196*6777b538SAndroid Build Coastguard Worker 
Open(HKEY rootkey,const wchar_t * subkey,REGSAM access)197*6777b538SAndroid Build Coastguard Worker LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
198*6777b538SAndroid Build Coastguard Worker   return Open(rootkey, subkey, /*options=*/0, access);
199*6777b538SAndroid Build Coastguard Worker }
200*6777b538SAndroid Build Coastguard Worker 
OpenKey(const wchar_t * relative_key_name,REGSAM access)201*6777b538SAndroid Build Coastguard Worker LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) {
202*6777b538SAndroid Build Coastguard Worker   DCHECK(relative_key_name && access);
203*6777b538SAndroid Build Coastguard Worker 
204*6777b538SAndroid Build Coastguard Worker   if (!Valid()) {
205*6777b538SAndroid Build Coastguard Worker     // The parent key has not been opened or created.
206*6777b538SAndroid Build Coastguard Worker     return ERROR_INVALID_HANDLE;
207*6777b538SAndroid Build Coastguard Worker   }
208*6777b538SAndroid Build Coastguard Worker 
209*6777b538SAndroid Build Coastguard Worker   // After the application has accessed an alternate registry view using one
210*6777b538SAndroid Build Coastguard Worker   // of the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent
211*6777b538SAndroid Build Coastguard Worker   // operations (create, delete, or open) on child registry keys must
212*6777b538SAndroid Build Coastguard Worker   // explicitly use the same flag. Otherwise, there can be unexpected
213*6777b538SAndroid Build Coastguard Worker   // behavior.
214*6777b538SAndroid Build Coastguard Worker   // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
215*6777b538SAndroid Build Coastguard Worker   if ((access & kWow64AccessMask) != wow64access_) {
216*6777b538SAndroid Build Coastguard Worker     NOTREACHED();
217*6777b538SAndroid Build Coastguard Worker     return ERROR_INVALID_PARAMETER;
218*6777b538SAndroid Build Coastguard Worker   }
219*6777b538SAndroid Build Coastguard Worker   HKEY subkey = nullptr;
220*6777b538SAndroid Build Coastguard Worker   LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey);
221*6777b538SAndroid Build Coastguard Worker 
222*6777b538SAndroid Build Coastguard Worker   // We have to close the current opened key before replacing it with the new
223*6777b538SAndroid Build Coastguard Worker   // one.
224*6777b538SAndroid Build Coastguard Worker   if (result == ERROR_SUCCESS) {
225*6777b538SAndroid Build Coastguard Worker     Close();
226*6777b538SAndroid Build Coastguard Worker     key_ = subkey;
227*6777b538SAndroid Build Coastguard Worker     wow64access_ = access & kWow64AccessMask;
228*6777b538SAndroid Build Coastguard Worker   }
229*6777b538SAndroid Build Coastguard Worker   return result;
230*6777b538SAndroid Build Coastguard Worker }
231*6777b538SAndroid Build Coastguard Worker 
Close()232*6777b538SAndroid Build Coastguard Worker void RegKey::Close() {
233*6777b538SAndroid Build Coastguard Worker   if (key_) {
234*6777b538SAndroid Build Coastguard Worker     ::RegCloseKey(key_);
235*6777b538SAndroid Build Coastguard Worker     key_ = nullptr;
236*6777b538SAndroid Build Coastguard Worker     wow64access_ = 0;
237*6777b538SAndroid Build Coastguard Worker   }
238*6777b538SAndroid Build Coastguard Worker }
239*6777b538SAndroid Build Coastguard Worker 
240*6777b538SAndroid Build Coastguard Worker // TODO(wfh): Remove this and other unsafe methods. See http://crbug.com/375400
Set(HKEY key)241*6777b538SAndroid Build Coastguard Worker void RegKey::Set(HKEY key) {
242*6777b538SAndroid Build Coastguard Worker   if (key_ != key) {
243*6777b538SAndroid Build Coastguard Worker     Close();
244*6777b538SAndroid Build Coastguard Worker     key_ = key;
245*6777b538SAndroid Build Coastguard Worker   }
246*6777b538SAndroid Build Coastguard Worker }
247*6777b538SAndroid Build Coastguard Worker 
Take()248*6777b538SAndroid Build Coastguard Worker HKEY RegKey::Take() {
249*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(wow64access_, 0u);
250*6777b538SAndroid Build Coastguard Worker   HKEY key = key_;
251*6777b538SAndroid Build Coastguard Worker   key_ = nullptr;
252*6777b538SAndroid Build Coastguard Worker   return key;
253*6777b538SAndroid Build Coastguard Worker }
254*6777b538SAndroid Build Coastguard Worker 
HasValue(const wchar_t * name) const255*6777b538SAndroid Build Coastguard Worker bool RegKey::HasValue(const wchar_t* name) const {
256*6777b538SAndroid Build Coastguard Worker   return RegQueryValueEx(key_, name, nullptr, nullptr, nullptr, nullptr) ==
257*6777b538SAndroid Build Coastguard Worker          ERROR_SUCCESS;
258*6777b538SAndroid Build Coastguard Worker }
259*6777b538SAndroid Build Coastguard Worker 
GetValueCount() const260*6777b538SAndroid Build Coastguard Worker base::expected<DWORD, LONG> RegKey::GetValueCount() const {
261*6777b538SAndroid Build Coastguard Worker   DWORD count = 0;
262*6777b538SAndroid Build Coastguard Worker   LONG result =
263*6777b538SAndroid Build Coastguard Worker       RegQueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr, nullptr,
264*6777b538SAndroid Build Coastguard Worker                       nullptr, &count, nullptr, nullptr, nullptr, nullptr);
265*6777b538SAndroid Build Coastguard Worker   if (result == ERROR_SUCCESS) {
266*6777b538SAndroid Build Coastguard Worker     return base::ok(count);
267*6777b538SAndroid Build Coastguard Worker   }
268*6777b538SAndroid Build Coastguard Worker   return base::unexpected(result);
269*6777b538SAndroid Build Coastguard Worker }
270*6777b538SAndroid Build Coastguard Worker 
GetValueNameAt(DWORD index,std::wstring * name) const271*6777b538SAndroid Build Coastguard Worker LONG RegKey::GetValueNameAt(DWORD index, std::wstring* name) const {
272*6777b538SAndroid Build Coastguard Worker   wchar_t buf[256];
273*6777b538SAndroid Build Coastguard Worker   DWORD bufsize = std::size(buf);
274*6777b538SAndroid Build Coastguard Worker   LONG r = ::RegEnumValue(key_, index, buf, &bufsize, nullptr, nullptr, nullptr,
275*6777b538SAndroid Build Coastguard Worker                           nullptr);
276*6777b538SAndroid Build Coastguard Worker   if (r == ERROR_SUCCESS) {
277*6777b538SAndroid Build Coastguard Worker     name->assign(buf, bufsize);
278*6777b538SAndroid Build Coastguard Worker   }
279*6777b538SAndroid Build Coastguard Worker 
280*6777b538SAndroid Build Coastguard Worker   return r;
281*6777b538SAndroid Build Coastguard Worker }
282*6777b538SAndroid Build Coastguard Worker 
DeleteKey(const wchar_t * name,RecursiveDelete recursive)283*6777b538SAndroid Build Coastguard Worker LONG RegKey::DeleteKey(const wchar_t* name, RecursiveDelete recursive) {
284*6777b538SAndroid Build Coastguard Worker   DCHECK(name);
285*6777b538SAndroid Build Coastguard Worker 
286*6777b538SAndroid Build Coastguard Worker   if (!Valid()) {
287*6777b538SAndroid Build Coastguard Worker     return ERROR_INVALID_HANDLE;
288*6777b538SAndroid Build Coastguard Worker   }
289*6777b538SAndroid Build Coastguard Worker 
290*6777b538SAndroid Build Coastguard Worker   // Verify the key exists before attempting delete to replicate previous
291*6777b538SAndroid Build Coastguard Worker   // behavior.
292*6777b538SAndroid Build Coastguard Worker   RegKey target_key;
293*6777b538SAndroid Build Coastguard Worker   LONG result = target_key.Open(key_, name, REG_OPTION_OPEN_LINK,
294*6777b538SAndroid Build Coastguard Worker                                 wow64access_ | KEY_QUERY_VALUE | DELETE);
295*6777b538SAndroid Build Coastguard Worker   if (result != ERROR_SUCCESS) {
296*6777b538SAndroid Build Coastguard Worker     return result;
297*6777b538SAndroid Build Coastguard Worker   }
298*6777b538SAndroid Build Coastguard Worker 
299*6777b538SAndroid Build Coastguard Worker   if (recursive.value()) {
300*6777b538SAndroid Build Coastguard Worker     target_key.Close();
301*6777b538SAndroid Build Coastguard Worker     return RegDelRecurse(key_, name, wow64access_);
302*6777b538SAndroid Build Coastguard Worker   }
303*6777b538SAndroid Build Coastguard Worker 
304*6777b538SAndroid Build Coastguard Worker   // Next, try to delete the key if it is a symbolic link.
305*6777b538SAndroid Build Coastguard Worker   if (auto deleted_link = target_key.DeleteIfLink(); deleted_link.has_value()) {
306*6777b538SAndroid Build Coastguard Worker     return deleted_link.value();
307*6777b538SAndroid Build Coastguard Worker   }
308*6777b538SAndroid Build Coastguard Worker 
309*6777b538SAndroid Build Coastguard Worker   // It's not a symbolic link, so try to delete it without recursing.
310*6777b538SAndroid Build Coastguard Worker   return ::RegDeleteKeyEx(target_key.key_, L"", wow64access_, 0);
311*6777b538SAndroid Build Coastguard Worker }
312*6777b538SAndroid Build Coastguard Worker 
DeleteValue(const wchar_t * value_name)313*6777b538SAndroid Build Coastguard Worker LONG RegKey::DeleteValue(const wchar_t* value_name) {
314*6777b538SAndroid Build Coastguard Worker   // `RegDeleteValue()` will return an error if `key_` is invalid.
315*6777b538SAndroid Build Coastguard Worker   LONG result = RegDeleteValue(key_, value_name);
316*6777b538SAndroid Build Coastguard Worker   return result;
317*6777b538SAndroid Build Coastguard Worker }
318*6777b538SAndroid Build Coastguard Worker 
ReadValueDW(const wchar_t * name,DWORD * out_value) const319*6777b538SAndroid Build Coastguard Worker LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const {
320*6777b538SAndroid Build Coastguard Worker   DCHECK(out_value);
321*6777b538SAndroid Build Coastguard Worker   DWORD type = REG_DWORD;
322*6777b538SAndroid Build Coastguard Worker   DWORD size = sizeof(DWORD);
323*6777b538SAndroid Build Coastguard Worker   DWORD local_value = 0;
324*6777b538SAndroid Build Coastguard Worker   LONG result = ReadValue(name, &local_value, &size, &type);
325*6777b538SAndroid Build Coastguard Worker   if (result == ERROR_SUCCESS) {
326*6777b538SAndroid Build Coastguard Worker     if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD)) {
327*6777b538SAndroid Build Coastguard Worker       *out_value = local_value;
328*6777b538SAndroid Build Coastguard Worker     } else {
329*6777b538SAndroid Build Coastguard Worker       result = ERROR_CANTREAD;
330*6777b538SAndroid Build Coastguard Worker     }
331*6777b538SAndroid Build Coastguard Worker   }
332*6777b538SAndroid Build Coastguard Worker 
333*6777b538SAndroid Build Coastguard Worker   return result;
334*6777b538SAndroid Build Coastguard Worker }
335*6777b538SAndroid Build Coastguard Worker 
ReadInt64(const wchar_t * name,int64_t * out_value) const336*6777b538SAndroid Build Coastguard Worker LONG RegKey::ReadInt64(const wchar_t* name, int64_t* out_value) const {
337*6777b538SAndroid Build Coastguard Worker   DCHECK(out_value);
338*6777b538SAndroid Build Coastguard Worker   DWORD type = REG_QWORD;
339*6777b538SAndroid Build Coastguard Worker   int64_t local_value = 0;
340*6777b538SAndroid Build Coastguard Worker   DWORD size = sizeof(local_value);
341*6777b538SAndroid Build Coastguard Worker   LONG result = ReadValue(name, &local_value, &size, &type);
342*6777b538SAndroid Build Coastguard Worker   if (result == ERROR_SUCCESS) {
343*6777b538SAndroid Build Coastguard Worker     if ((type == REG_QWORD || type == REG_BINARY) &&
344*6777b538SAndroid Build Coastguard Worker         size == sizeof(local_value)) {
345*6777b538SAndroid Build Coastguard Worker       *out_value = local_value;
346*6777b538SAndroid Build Coastguard Worker     } else {
347*6777b538SAndroid Build Coastguard Worker       result = ERROR_CANTREAD;
348*6777b538SAndroid Build Coastguard Worker     }
349*6777b538SAndroid Build Coastguard Worker   }
350*6777b538SAndroid Build Coastguard Worker 
351*6777b538SAndroid Build Coastguard Worker   return result;
352*6777b538SAndroid Build Coastguard Worker }
353*6777b538SAndroid Build Coastguard Worker 
ReadValue(const wchar_t * name,std::wstring * out_value) const354*6777b538SAndroid Build Coastguard Worker LONG RegKey::ReadValue(const wchar_t* name, std::wstring* out_value) const {
355*6777b538SAndroid Build Coastguard Worker   DCHECK(out_value);
356*6777b538SAndroid Build Coastguard Worker   const size_t kMaxStringLength = 1024;  // This is after expansion.
357*6777b538SAndroid Build Coastguard Worker   // Use the one of the other forms of ReadValue if 1024 is too small for you.
358*6777b538SAndroid Build Coastguard Worker   wchar_t raw_value[kMaxStringLength];
359*6777b538SAndroid Build Coastguard Worker   DWORD type = REG_SZ, size = sizeof(raw_value);
360*6777b538SAndroid Build Coastguard Worker   LONG result = ReadValue(name, raw_value, &size, &type);
361*6777b538SAndroid Build Coastguard Worker   if (result == ERROR_SUCCESS) {
362*6777b538SAndroid Build Coastguard Worker     if (type == REG_SZ) {
363*6777b538SAndroid Build Coastguard Worker       *out_value = raw_value;
364*6777b538SAndroid Build Coastguard Worker     } else if (type == REG_EXPAND_SZ) {
365*6777b538SAndroid Build Coastguard Worker       wchar_t expanded[kMaxStringLength];
366*6777b538SAndroid Build Coastguard Worker       size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
367*6777b538SAndroid Build Coastguard Worker       // Success: returns the number of wchar_t's copied
368*6777b538SAndroid Build Coastguard Worker       // Fail: buffer too small, returns the size required
369*6777b538SAndroid Build Coastguard Worker       // Fail: other, returns 0
370*6777b538SAndroid Build Coastguard Worker       if (size == 0 || size > kMaxStringLength) {
371*6777b538SAndroid Build Coastguard Worker         result = ERROR_MORE_DATA;
372*6777b538SAndroid Build Coastguard Worker       } else {
373*6777b538SAndroid Build Coastguard Worker         *out_value = expanded;
374*6777b538SAndroid Build Coastguard Worker       }
375*6777b538SAndroid Build Coastguard Worker     } else {
376*6777b538SAndroid Build Coastguard Worker       // Not a string. Oops.
377*6777b538SAndroid Build Coastguard Worker       result = ERROR_CANTREAD;
378*6777b538SAndroid Build Coastguard Worker     }
379*6777b538SAndroid Build Coastguard Worker   }
380*6777b538SAndroid Build Coastguard Worker 
381*6777b538SAndroid Build Coastguard Worker   return result;
382*6777b538SAndroid Build Coastguard Worker }
383*6777b538SAndroid Build Coastguard Worker 
ReadValue(const wchar_t * name,void * data,DWORD * dsize,DWORD * dtype) const384*6777b538SAndroid Build Coastguard Worker LONG RegKey::ReadValue(const wchar_t* name,
385*6777b538SAndroid Build Coastguard Worker                        void* data,
386*6777b538SAndroid Build Coastguard Worker                        DWORD* dsize,
387*6777b538SAndroid Build Coastguard Worker                        DWORD* dtype) const {
388*6777b538SAndroid Build Coastguard Worker   LONG result = RegQueryValueEx(key_, name, nullptr, dtype,
389*6777b538SAndroid Build Coastguard Worker                                 reinterpret_cast<LPBYTE>(data), dsize);
390*6777b538SAndroid Build Coastguard Worker   return result;
391*6777b538SAndroid Build Coastguard Worker }
392*6777b538SAndroid Build Coastguard Worker 
ReadValues(const wchar_t * name,std::vector<std::wstring> * values)393*6777b538SAndroid Build Coastguard Worker LONG RegKey::ReadValues(const wchar_t* name,
394*6777b538SAndroid Build Coastguard Worker                         std::vector<std::wstring>* values) {
395*6777b538SAndroid Build Coastguard Worker   values->clear();
396*6777b538SAndroid Build Coastguard Worker 
397*6777b538SAndroid Build Coastguard Worker   DWORD type = REG_MULTI_SZ;
398*6777b538SAndroid Build Coastguard Worker   DWORD size = 0;
399*6777b538SAndroid Build Coastguard Worker   LONG result = ReadValue(name, nullptr, &size, &type);
400*6777b538SAndroid Build Coastguard Worker   if (result != ERROR_SUCCESS || size == 0) {
401*6777b538SAndroid Build Coastguard Worker     return result;
402*6777b538SAndroid Build Coastguard Worker   }
403*6777b538SAndroid Build Coastguard Worker 
404*6777b538SAndroid Build Coastguard Worker   if (type != REG_MULTI_SZ) {
405*6777b538SAndroid Build Coastguard Worker     return ERROR_CANTREAD;
406*6777b538SAndroid Build Coastguard Worker   }
407*6777b538SAndroid Build Coastguard Worker 
408*6777b538SAndroid Build Coastguard Worker   std::vector<wchar_t> buffer(size / sizeof(wchar_t));
409*6777b538SAndroid Build Coastguard Worker   result = ReadValue(name, buffer.data(), &size, nullptr);
410*6777b538SAndroid Build Coastguard Worker   if (result != ERROR_SUCCESS || size == 0) {
411*6777b538SAndroid Build Coastguard Worker     return result;
412*6777b538SAndroid Build Coastguard Worker   }
413*6777b538SAndroid Build Coastguard Worker 
414*6777b538SAndroid Build Coastguard Worker   // Parse the double-null-terminated list of strings.
415*6777b538SAndroid Build Coastguard Worker   // Note: This code is paranoid to not read outside of |buf|, in the case where
416*6777b538SAndroid Build Coastguard Worker   // it may not be properly terminated.
417*6777b538SAndroid Build Coastguard Worker   auto entry = buffer.cbegin();
418*6777b538SAndroid Build Coastguard Worker   auto buffer_end = buffer.cend();
419*6777b538SAndroid Build Coastguard Worker   while (entry < buffer_end && *entry != '\0') {
420*6777b538SAndroid Build Coastguard Worker     auto entry_end = std::find(entry, buffer_end, '\0');
421*6777b538SAndroid Build Coastguard Worker     values->emplace_back(entry, entry_end);
422*6777b538SAndroid Build Coastguard Worker     entry = entry_end + 1;
423*6777b538SAndroid Build Coastguard Worker   }
424*6777b538SAndroid Build Coastguard Worker   return 0;
425*6777b538SAndroid Build Coastguard Worker }
426*6777b538SAndroid Build Coastguard Worker 
WriteValue(const wchar_t * name,DWORD in_value)427*6777b538SAndroid Build Coastguard Worker LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) {
428*6777b538SAndroid Build Coastguard Worker   return WriteValue(name, &in_value, static_cast<DWORD>(sizeof(in_value)),
429*6777b538SAndroid Build Coastguard Worker                     REG_DWORD);
430*6777b538SAndroid Build Coastguard Worker }
431*6777b538SAndroid Build Coastguard Worker 
WriteValue(const wchar_t * name,const wchar_t * in_value)432*6777b538SAndroid Build Coastguard Worker LONG RegKey::WriteValue(const wchar_t* name, const wchar_t* in_value) {
433*6777b538SAndroid Build Coastguard Worker   return WriteValue(
434*6777b538SAndroid Build Coastguard Worker       name, in_value,
435*6777b538SAndroid Build Coastguard Worker       static_cast<DWORD>(sizeof(*in_value) *
436*6777b538SAndroid Build Coastguard Worker                          (std::char_traits<wchar_t>::length(in_value) + 1)),
437*6777b538SAndroid Build Coastguard Worker       REG_SZ);
438*6777b538SAndroid Build Coastguard Worker }
439*6777b538SAndroid Build Coastguard Worker 
WriteValue(const wchar_t * name,const void * data,DWORD dsize,DWORD dtype)440*6777b538SAndroid Build Coastguard Worker LONG RegKey::WriteValue(const wchar_t* name,
441*6777b538SAndroid Build Coastguard Worker                         const void* data,
442*6777b538SAndroid Build Coastguard Worker                         DWORD dsize,
443*6777b538SAndroid Build Coastguard Worker                         DWORD dtype) {
444*6777b538SAndroid Build Coastguard Worker   DCHECK(data || !dsize);
445*6777b538SAndroid Build Coastguard Worker 
446*6777b538SAndroid Build Coastguard Worker   LONG result =
447*6777b538SAndroid Build Coastguard Worker       RegSetValueEx(key_, name, 0, dtype,
448*6777b538SAndroid Build Coastguard Worker                     reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
449*6777b538SAndroid Build Coastguard Worker   return result;
450*6777b538SAndroid Build Coastguard Worker }
451*6777b538SAndroid Build Coastguard Worker 
StartWatching(ChangeCallback callback)452*6777b538SAndroid Build Coastguard Worker bool RegKey::StartWatching(ChangeCallback callback) {
453*6777b538SAndroid Build Coastguard Worker   if (!key_watcher_) {
454*6777b538SAndroid Build Coastguard Worker     key_watcher_ = std::make_unique<Watcher>();
455*6777b538SAndroid Build Coastguard Worker   }
456*6777b538SAndroid Build Coastguard Worker 
457*6777b538SAndroid Build Coastguard Worker   if (!key_watcher_->StartWatching(key_, std::move(callback))) {
458*6777b538SAndroid Build Coastguard Worker     return false;
459*6777b538SAndroid Build Coastguard Worker   }
460*6777b538SAndroid Build Coastguard Worker 
461*6777b538SAndroid Build Coastguard Worker   return true;
462*6777b538SAndroid Build Coastguard Worker }
463*6777b538SAndroid Build Coastguard Worker 
Open(HKEY rootkey,const wchar_t * subkey,DWORD options,REGSAM access)464*6777b538SAndroid Build Coastguard Worker LONG RegKey::Open(HKEY rootkey,
465*6777b538SAndroid Build Coastguard Worker                   const wchar_t* subkey,
466*6777b538SAndroid Build Coastguard Worker                   DWORD options,
467*6777b538SAndroid Build Coastguard Worker                   REGSAM access) {
468*6777b538SAndroid Build Coastguard Worker   DCHECK(options == 0 || options == REG_OPTION_OPEN_LINK) << options;
469*6777b538SAndroid Build Coastguard Worker   DCHECK(rootkey && subkey && access);
470*6777b538SAndroid Build Coastguard Worker   HKEY subhkey = nullptr;
471*6777b538SAndroid Build Coastguard Worker 
472*6777b538SAndroid Build Coastguard Worker   LONG result = RegOpenKeyEx(rootkey, subkey, options, access, &subhkey);
473*6777b538SAndroid Build Coastguard Worker   if (result == ERROR_SUCCESS) {
474*6777b538SAndroid Build Coastguard Worker     Close();
475*6777b538SAndroid Build Coastguard Worker     key_ = subhkey;
476*6777b538SAndroid Build Coastguard Worker     wow64access_ = access & kWow64AccessMask;
477*6777b538SAndroid Build Coastguard Worker   }
478*6777b538SAndroid Build Coastguard Worker 
479*6777b538SAndroid Build Coastguard Worker   return result;
480*6777b538SAndroid Build Coastguard Worker }
481*6777b538SAndroid Build Coastguard Worker 
IsLink() const482*6777b538SAndroid Build Coastguard Worker expected<bool, LONG> RegKey::IsLink() const {
483*6777b538SAndroid Build Coastguard Worker   DWORD value_type = 0;
484*6777b538SAndroid Build Coastguard Worker   LONG result = ::RegQueryValueEx(key_, L"SymbolicLinkValue",
485*6777b538SAndroid Build Coastguard Worker                                   /*lpReserved=*/nullptr, &value_type,
486*6777b538SAndroid Build Coastguard Worker                                   /*lpData=*/nullptr, /*lpcbData=*/nullptr);
487*6777b538SAndroid Build Coastguard Worker   if (result == ERROR_FILE_NOT_FOUND) {
488*6777b538SAndroid Build Coastguard Worker     return ok(false);
489*6777b538SAndroid Build Coastguard Worker   }
490*6777b538SAndroid Build Coastguard Worker   if (result == ERROR_SUCCESS) {
491*6777b538SAndroid Build Coastguard Worker     return ok(value_type == REG_LINK);
492*6777b538SAndroid Build Coastguard Worker   }
493*6777b538SAndroid Build Coastguard Worker   return unexpected(result);
494*6777b538SAndroid Build Coastguard Worker }
495*6777b538SAndroid Build Coastguard Worker 
DeleteIfLink()496*6777b538SAndroid Build Coastguard Worker std::optional<LONG> RegKey::DeleteIfLink() {
497*6777b538SAndroid Build Coastguard Worker   if (auto is_link = IsLink(); !is_link.has_value()) {
498*6777b538SAndroid Build Coastguard Worker     return is_link.error();  // Failed to determine if a link.
499*6777b538SAndroid Build Coastguard Worker   } else if (is_link.value() == false) {
500*6777b538SAndroid Build Coastguard Worker     return std::nullopt;  // Not a link.
501*6777b538SAndroid Build Coastguard Worker   }
502*6777b538SAndroid Build Coastguard Worker 
503*6777b538SAndroid Build Coastguard Worker   const NTSTATUS delete_result = ::NtDeleteKey(key_);
504*6777b538SAndroid Build Coastguard Worker   if (delete_result == STATUS_SUCCESS) {
505*6777b538SAndroid Build Coastguard Worker     return ERROR_SUCCESS;
506*6777b538SAndroid Build Coastguard Worker   }
507*6777b538SAndroid Build Coastguard Worker   using RtlNtStatusToDosErrorFunction = ULONG(WINAPI*)(NTSTATUS);
508*6777b538SAndroid Build Coastguard Worker   static const RtlNtStatusToDosErrorFunction rtl_nt_status_to_dos_error =
509*6777b538SAndroid Build Coastguard Worker       reinterpret_cast<RtlNtStatusToDosErrorFunction>(::GetProcAddress(
510*6777b538SAndroid Build Coastguard Worker           ::GetModuleHandle(L"ntdll.dll"), "RtlNtStatusToDosError"));
511*6777b538SAndroid Build Coastguard Worker   // The most common cause of failure is the presence of subkeys, which is
512*6777b538SAndroid Build Coastguard Worker   // reported as `STATUS_CANNOT_DELETE` and maps to `ERROR_ACCESS_DENIED`.
513*6777b538SAndroid Build Coastguard Worker   return rtl_nt_status_to_dos_error
514*6777b538SAndroid Build Coastguard Worker              ? static_cast<LONG>(rtl_nt_status_to_dos_error(delete_result))
515*6777b538SAndroid Build Coastguard Worker              : ERROR_ACCESS_DENIED;
516*6777b538SAndroid Build Coastguard Worker }
517*6777b538SAndroid Build Coastguard Worker 
518*6777b538SAndroid Build Coastguard Worker // static
RegDelRecurse(HKEY root_key,const wchar_t * name,REGSAM access)519*6777b538SAndroid Build Coastguard Worker LONG RegKey::RegDelRecurse(HKEY root_key, const wchar_t* name, REGSAM access) {
520*6777b538SAndroid Build Coastguard Worker   // First, open the key; taking care not to traverse symbolic links.
521*6777b538SAndroid Build Coastguard Worker   RegKey target_key;
522*6777b538SAndroid Build Coastguard Worker   LONG result = target_key.Open(
523*6777b538SAndroid Build Coastguard Worker       root_key, name, REG_OPTION_OPEN_LINK,
524*6777b538SAndroid Build Coastguard Worker       access | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | DELETE);
525*6777b538SAndroid Build Coastguard Worker   if (result == ERROR_FILE_NOT_FOUND) {  // The key doesn't exist.
526*6777b538SAndroid Build Coastguard Worker     return ERROR_SUCCESS;
527*6777b538SAndroid Build Coastguard Worker   }
528*6777b538SAndroid Build Coastguard Worker   if (result != ERROR_SUCCESS) {
529*6777b538SAndroid Build Coastguard Worker     return result;
530*6777b538SAndroid Build Coastguard Worker   }
531*6777b538SAndroid Build Coastguard Worker 
532*6777b538SAndroid Build Coastguard Worker   // Next, try to delete the key if it is a symbolic link.
533*6777b538SAndroid Build Coastguard Worker   if (auto deleted_link = target_key.DeleteIfLink(); deleted_link.has_value()) {
534*6777b538SAndroid Build Coastguard Worker     return deleted_link.value();
535*6777b538SAndroid Build Coastguard Worker   }
536*6777b538SAndroid Build Coastguard Worker 
537*6777b538SAndroid Build Coastguard Worker   // It's not a symbolic link, so try to delete it without recursing.
538*6777b538SAndroid Build Coastguard Worker   result = ::RegDeleteKeyEx(target_key.key_, L"", access, 0);
539*6777b538SAndroid Build Coastguard Worker   if (result == ERROR_SUCCESS) {
540*6777b538SAndroid Build Coastguard Worker     return result;
541*6777b538SAndroid Build Coastguard Worker   }
542*6777b538SAndroid Build Coastguard Worker 
543*6777b538SAndroid Build Coastguard Worker   // Enumerate the keys.
544*6777b538SAndroid Build Coastguard Worker   const DWORD kMaxKeyNameLength = 256;  // Includes string terminator.
545*6777b538SAndroid Build Coastguard Worker   auto subkey_buffer = std::make_unique<wchar_t[]>(kMaxKeyNameLength);
546*6777b538SAndroid Build Coastguard Worker   while (true) {
547*6777b538SAndroid Build Coastguard Worker     DWORD key_size = kMaxKeyNameLength;
548*6777b538SAndroid Build Coastguard Worker     if (::RegEnumKeyEx(target_key.key_, 0, &subkey_buffer[0], &key_size,
549*6777b538SAndroid Build Coastguard Worker                        nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS) {
550*6777b538SAndroid Build Coastguard Worker       break;
551*6777b538SAndroid Build Coastguard Worker     }
552*6777b538SAndroid Build Coastguard Worker     CHECK_LT(key_size, kMaxKeyNameLength);
553*6777b538SAndroid Build Coastguard Worker     CHECK_EQ(subkey_buffer[key_size], L'\0');
554*6777b538SAndroid Build Coastguard Worker     if (RegDelRecurse(target_key.key_, &subkey_buffer[0], access) !=
555*6777b538SAndroid Build Coastguard Worker         ERROR_SUCCESS) {
556*6777b538SAndroid Build Coastguard Worker       break;
557*6777b538SAndroid Build Coastguard Worker     }
558*6777b538SAndroid Build Coastguard Worker   }
559*6777b538SAndroid Build Coastguard Worker 
560*6777b538SAndroid Build Coastguard Worker   // Try again to delete the key.
561*6777b538SAndroid Build Coastguard Worker   return ::RegDeleteKeyEx(target_key.key_, L"", access, 0);
562*6777b538SAndroid Build Coastguard Worker }
563*6777b538SAndroid Build Coastguard Worker 
564*6777b538SAndroid Build Coastguard Worker // RegistryValueIterator ------------------------------------------------------
565*6777b538SAndroid Build Coastguard Worker 
RegistryValueIterator(HKEY root_key,const wchar_t * folder_key,REGSAM wow64access)566*6777b538SAndroid Build Coastguard Worker RegistryValueIterator::RegistryValueIterator(HKEY root_key,
567*6777b538SAndroid Build Coastguard Worker                                              const wchar_t* folder_key,
568*6777b538SAndroid Build Coastguard Worker                                              REGSAM wow64access)
569*6777b538SAndroid Build Coastguard Worker     : name_(MAX_PATH, '\0'), value_(MAX_PATH, '\0') {
570*6777b538SAndroid Build Coastguard Worker   Initialize(root_key, folder_key, wow64access);
571*6777b538SAndroid Build Coastguard Worker }
572*6777b538SAndroid Build Coastguard Worker 
RegistryValueIterator(HKEY root_key,const wchar_t * folder_key)573*6777b538SAndroid Build Coastguard Worker RegistryValueIterator::RegistryValueIterator(HKEY root_key,
574*6777b538SAndroid Build Coastguard Worker                                              const wchar_t* folder_key)
575*6777b538SAndroid Build Coastguard Worker     : name_(MAX_PATH, '\0'), value_(MAX_PATH, '\0') {
576*6777b538SAndroid Build Coastguard Worker   Initialize(root_key, folder_key, 0);
577*6777b538SAndroid Build Coastguard Worker }
578*6777b538SAndroid Build Coastguard Worker 
Initialize(HKEY root_key,const wchar_t * folder_key,REGSAM wow64access)579*6777b538SAndroid Build Coastguard Worker void RegistryValueIterator::Initialize(HKEY root_key,
580*6777b538SAndroid Build Coastguard Worker                                        const wchar_t* folder_key,
581*6777b538SAndroid Build Coastguard Worker                                        REGSAM wow64access) {
582*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(wow64access & ~kWow64AccessMask, static_cast<REGSAM>(0));
583*6777b538SAndroid Build Coastguard Worker   LONG result =
584*6777b538SAndroid Build Coastguard Worker       RegOpenKeyEx(root_key, folder_key, 0, KEY_READ | wow64access, &key_);
585*6777b538SAndroid Build Coastguard Worker   if (result != ERROR_SUCCESS) {
586*6777b538SAndroid Build Coastguard Worker     key_ = nullptr;
587*6777b538SAndroid Build Coastguard Worker   } else {
588*6777b538SAndroid Build Coastguard Worker     DWORD count = 0;
589*6777b538SAndroid Build Coastguard Worker     result =
590*6777b538SAndroid Build Coastguard Worker         ::RegQueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr, nullptr,
591*6777b538SAndroid Build Coastguard Worker                           nullptr, &count, nullptr, nullptr, nullptr, nullptr);
592*6777b538SAndroid Build Coastguard Worker 
593*6777b538SAndroid Build Coastguard Worker     if (result != ERROR_SUCCESS) {
594*6777b538SAndroid Build Coastguard Worker       ::RegCloseKey(key_);
595*6777b538SAndroid Build Coastguard Worker       key_ = nullptr;
596*6777b538SAndroid Build Coastguard Worker     } else {
597*6777b538SAndroid Build Coastguard Worker       index_ = count - 1;
598*6777b538SAndroid Build Coastguard Worker     }
599*6777b538SAndroid Build Coastguard Worker   }
600*6777b538SAndroid Build Coastguard Worker 
601*6777b538SAndroid Build Coastguard Worker   Read();
602*6777b538SAndroid Build Coastguard Worker }
603*6777b538SAndroid Build Coastguard Worker 
~RegistryValueIterator()604*6777b538SAndroid Build Coastguard Worker RegistryValueIterator::~RegistryValueIterator() {
605*6777b538SAndroid Build Coastguard Worker   if (key_)
606*6777b538SAndroid Build Coastguard Worker     ::RegCloseKey(key_);
607*6777b538SAndroid Build Coastguard Worker }
608*6777b538SAndroid Build Coastguard Worker 
ValueCount() const609*6777b538SAndroid Build Coastguard Worker DWORD RegistryValueIterator::ValueCount() const {
610*6777b538SAndroid Build Coastguard Worker   DWORD count = 0;
611*6777b538SAndroid Build Coastguard Worker   LONG result =
612*6777b538SAndroid Build Coastguard Worker       ::RegQueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr, nullptr,
613*6777b538SAndroid Build Coastguard Worker                         nullptr, &count, nullptr, nullptr, nullptr, nullptr);
614*6777b538SAndroid Build Coastguard Worker   if (result != ERROR_SUCCESS)
615*6777b538SAndroid Build Coastguard Worker     return 0;
616*6777b538SAndroid Build Coastguard Worker 
617*6777b538SAndroid Build Coastguard Worker   return count;
618*6777b538SAndroid Build Coastguard Worker }
619*6777b538SAndroid Build Coastguard Worker 
Valid() const620*6777b538SAndroid Build Coastguard Worker bool RegistryValueIterator::Valid() const {
621*6777b538SAndroid Build Coastguard Worker   return key_ != nullptr && index_ != kInvalidIterValue;
622*6777b538SAndroid Build Coastguard Worker }
623*6777b538SAndroid Build Coastguard Worker 
operator ++()624*6777b538SAndroid Build Coastguard Worker void RegistryValueIterator::operator++() {
625*6777b538SAndroid Build Coastguard Worker   if (index_ != kInvalidIterValue)
626*6777b538SAndroid Build Coastguard Worker     --index_;
627*6777b538SAndroid Build Coastguard Worker   Read();
628*6777b538SAndroid Build Coastguard Worker }
629*6777b538SAndroid Build Coastguard Worker 
Read()630*6777b538SAndroid Build Coastguard Worker bool RegistryValueIterator::Read() {
631*6777b538SAndroid Build Coastguard Worker   if (Valid()) {
632*6777b538SAndroid Build Coastguard Worker     DWORD capacity = static_cast<DWORD>(name_.capacity());
633*6777b538SAndroid Build Coastguard Worker     DWORD name_size = capacity;
634*6777b538SAndroid Build Coastguard Worker     // |value_size_| is in bytes. Reserve the last character for a NUL.
635*6777b538SAndroid Build Coastguard Worker     value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
636*6777b538SAndroid Build Coastguard Worker     LONG result = ::RegEnumValue(
637*6777b538SAndroid Build Coastguard Worker         key_, index_, WriteInto(&name_, name_size), &name_size, nullptr, &type_,
638*6777b538SAndroid Build Coastguard Worker         reinterpret_cast<BYTE*>(value_.data()), &value_size_);
639*6777b538SAndroid Build Coastguard Worker 
640*6777b538SAndroid Build Coastguard Worker     if (result == ERROR_MORE_DATA) {
641*6777b538SAndroid Build Coastguard Worker       // Registry key names are limited to 255 characters and fit within
642*6777b538SAndroid Build Coastguard Worker       // MAX_PATH (which is 260) but registry value names can use up to 16,383
643*6777b538SAndroid Build Coastguard Worker       // characters and the value itself is not limited
644*6777b538SAndroid Build Coastguard Worker       // (from http://msdn.microsoft.com/en-us/library/windows/desktop/
645*6777b538SAndroid Build Coastguard Worker       // ms724872(v=vs.85).aspx).
646*6777b538SAndroid Build Coastguard Worker       // Resize the buffers and retry if their size caused the failure.
647*6777b538SAndroid Build Coastguard Worker       DWORD value_size_in_wchars = to_wchar_size(value_size_);
648*6777b538SAndroid Build Coastguard Worker       if (value_size_in_wchars + 1 > value_.size())
649*6777b538SAndroid Build Coastguard Worker         value_.resize(value_size_in_wchars + 1, '\0');
650*6777b538SAndroid Build Coastguard Worker       value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
651*6777b538SAndroid Build Coastguard Worker       name_size = name_size == capacity ? MAX_REGISTRY_NAME_SIZE : capacity;
652*6777b538SAndroid Build Coastguard Worker       result = ::RegEnumValue(
653*6777b538SAndroid Build Coastguard Worker           key_, index_, WriteInto(&name_, name_size), &name_size, nullptr,
654*6777b538SAndroid Build Coastguard Worker           &type_, reinterpret_cast<BYTE*>(value_.data()), &value_size_);
655*6777b538SAndroid Build Coastguard Worker     }
656*6777b538SAndroid Build Coastguard Worker 
657*6777b538SAndroid Build Coastguard Worker     if (result == ERROR_SUCCESS) {
658*6777b538SAndroid Build Coastguard Worker       DCHECK_LT(to_wchar_size(value_size_), value_.size());
659*6777b538SAndroid Build Coastguard Worker       value_[to_wchar_size(value_size_)] = '\0';
660*6777b538SAndroid Build Coastguard Worker       return true;
661*6777b538SAndroid Build Coastguard Worker     }
662*6777b538SAndroid Build Coastguard Worker   }
663*6777b538SAndroid Build Coastguard Worker 
664*6777b538SAndroid Build Coastguard Worker   name_[0] = '\0';
665*6777b538SAndroid Build Coastguard Worker   value_[0] = '\0';
666*6777b538SAndroid Build Coastguard Worker   value_size_ = 0;
667*6777b538SAndroid Build Coastguard Worker   return false;
668*6777b538SAndroid Build Coastguard Worker }
669*6777b538SAndroid Build Coastguard Worker 
670*6777b538SAndroid Build Coastguard Worker // RegistryKeyIterator --------------------------------------------------------
671*6777b538SAndroid Build Coastguard Worker 
RegistryKeyIterator(HKEY root_key,const wchar_t * folder_key)672*6777b538SAndroid Build Coastguard Worker RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
673*6777b538SAndroid Build Coastguard Worker                                          const wchar_t* folder_key) {
674*6777b538SAndroid Build Coastguard Worker   Initialize(root_key, folder_key, 0);
675*6777b538SAndroid Build Coastguard Worker }
676*6777b538SAndroid Build Coastguard Worker 
RegistryKeyIterator(HKEY root_key,const wchar_t * folder_key,REGSAM wow64access)677*6777b538SAndroid Build Coastguard Worker RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
678*6777b538SAndroid Build Coastguard Worker                                          const wchar_t* folder_key,
679*6777b538SAndroid Build Coastguard Worker                                          REGSAM wow64access) {
680*6777b538SAndroid Build Coastguard Worker   Initialize(root_key, folder_key, wow64access);
681*6777b538SAndroid Build Coastguard Worker }
682*6777b538SAndroid Build Coastguard Worker 
~RegistryKeyIterator()683*6777b538SAndroid Build Coastguard Worker RegistryKeyIterator::~RegistryKeyIterator() {
684*6777b538SAndroid Build Coastguard Worker   if (key_)
685*6777b538SAndroid Build Coastguard Worker     ::RegCloseKey(key_);
686*6777b538SAndroid Build Coastguard Worker }
687*6777b538SAndroid Build Coastguard Worker 
SubkeyCount() const688*6777b538SAndroid Build Coastguard Worker DWORD RegistryKeyIterator::SubkeyCount() const {
689*6777b538SAndroid Build Coastguard Worker   DWORD count = 0;
690*6777b538SAndroid Build Coastguard Worker   LONG result =
691*6777b538SAndroid Build Coastguard Worker       ::RegQueryInfoKey(key_, nullptr, nullptr, nullptr, &count, nullptr,
692*6777b538SAndroid Build Coastguard Worker                         nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
693*6777b538SAndroid Build Coastguard Worker   if (result != ERROR_SUCCESS)
694*6777b538SAndroid Build Coastguard Worker     return 0;
695*6777b538SAndroid Build Coastguard Worker 
696*6777b538SAndroid Build Coastguard Worker   return count;
697*6777b538SAndroid Build Coastguard Worker }
698*6777b538SAndroid Build Coastguard Worker 
Valid() const699*6777b538SAndroid Build Coastguard Worker bool RegistryKeyIterator::Valid() const {
700*6777b538SAndroid Build Coastguard Worker   return key_ != nullptr && index_ != kInvalidIterValue;
701*6777b538SAndroid Build Coastguard Worker }
702*6777b538SAndroid Build Coastguard Worker 
operator ++()703*6777b538SAndroid Build Coastguard Worker void RegistryKeyIterator::operator++() {
704*6777b538SAndroid Build Coastguard Worker   if (index_ != kInvalidIterValue)
705*6777b538SAndroid Build Coastguard Worker     --index_;
706*6777b538SAndroid Build Coastguard Worker   Read();
707*6777b538SAndroid Build Coastguard Worker }
708*6777b538SAndroid Build Coastguard Worker 
Read()709*6777b538SAndroid Build Coastguard Worker bool RegistryKeyIterator::Read() {
710*6777b538SAndroid Build Coastguard Worker   if (Valid()) {
711*6777b538SAndroid Build Coastguard Worker     DWORD ncount = static_cast<DWORD>(std::size(name_));
712*6777b538SAndroid Build Coastguard Worker     FILETIME written;
713*6777b538SAndroid Build Coastguard Worker     LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, nullptr, nullptr,
714*6777b538SAndroid Build Coastguard Worker                             nullptr, &written);
715*6777b538SAndroid Build Coastguard Worker     if (ERROR_SUCCESS == r)
716*6777b538SAndroid Build Coastguard Worker       return true;
717*6777b538SAndroid Build Coastguard Worker   }
718*6777b538SAndroid Build Coastguard Worker 
719*6777b538SAndroid Build Coastguard Worker   name_[0] = '\0';
720*6777b538SAndroid Build Coastguard Worker   return false;
721*6777b538SAndroid Build Coastguard Worker }
722*6777b538SAndroid Build Coastguard Worker 
Initialize(HKEY root_key,const wchar_t * folder_key,REGSAM wow64access)723*6777b538SAndroid Build Coastguard Worker void RegistryKeyIterator::Initialize(HKEY root_key,
724*6777b538SAndroid Build Coastguard Worker                                      const wchar_t* folder_key,
725*6777b538SAndroid Build Coastguard Worker                                      REGSAM wow64access) {
726*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(wow64access & ~kWow64AccessMask, static_cast<REGSAM>(0));
727*6777b538SAndroid Build Coastguard Worker   LONG result =
728*6777b538SAndroid Build Coastguard Worker       RegOpenKeyEx(root_key, folder_key, 0, KEY_READ | wow64access, &key_);
729*6777b538SAndroid Build Coastguard Worker   if (result != ERROR_SUCCESS) {
730*6777b538SAndroid Build Coastguard Worker     key_ = nullptr;
731*6777b538SAndroid Build Coastguard Worker   } else {
732*6777b538SAndroid Build Coastguard Worker     DWORD count = 0;
733*6777b538SAndroid Build Coastguard Worker     result =
734*6777b538SAndroid Build Coastguard Worker         ::RegQueryInfoKey(key_, nullptr, nullptr, nullptr, &count, nullptr,
735*6777b538SAndroid Build Coastguard Worker                           nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
736*6777b538SAndroid Build Coastguard Worker 
737*6777b538SAndroid Build Coastguard Worker     if (result != ERROR_SUCCESS) {
738*6777b538SAndroid Build Coastguard Worker       ::RegCloseKey(key_);
739*6777b538SAndroid Build Coastguard Worker       key_ = nullptr;
740*6777b538SAndroid Build Coastguard Worker     } else {
741*6777b538SAndroid Build Coastguard Worker       index_ = count - 1;
742*6777b538SAndroid Build Coastguard Worker     }
743*6777b538SAndroid Build Coastguard Worker   }
744*6777b538SAndroid Build Coastguard Worker 
745*6777b538SAndroid Build Coastguard Worker   Read();
746*6777b538SAndroid Build Coastguard Worker }
747*6777b538SAndroid Build Coastguard Worker 
748*6777b538SAndroid Build Coastguard Worker }  // namespace base::win
749