1use super::builder::RegistryKeyBuilder;
4use super::types::Hive;
5use super::values::RegistryValue;
6use crate::error::{Error as CrateError, SecurityError, SecurityUnsupportedError};
7use crate::security::{
8 ApplyMode, DescriptorEditResult, PermissionEditPlan, PermissionTarget, SecurityDescriptor,
9};
10use crate::{Error, Result};
11use windows::Win32::Foundation::{ERROR_FILE_NOT_FOUND, ERROR_NO_MORE_ITEMS};
12use windows::Win32::System::Registry::*;
13use windows::core::{HSTRING, PCWSTR};
14
15pub struct RegistryKey {
17 pub(crate) handle: HKEY,
18 close_on_drop: bool,
19 hive: Option<Hive>,
20 subkey: Option<String>,
21}
22
23impl RegistryKey {
24 pub(crate) fn from_handle_with_metadata(
26 handle: HKEY,
27 close_on_drop: bool,
28 hive: Option<Hive>,
29 subkey: Option<String>,
30 ) -> Self {
31 RegistryKey {
32 handle,
33 close_on_drop,
34 hive,
35 subkey,
36 }
37 }
38
39 pub fn builder() -> RegistryKeyBuilder {
54 RegistryKeyBuilder::new()
55 }
56
57 pub fn open(hive: Hive, subkey: &str) -> Result<Self> {
71 let subkey_wide = HSTRING::from(subkey);
72 let mut handle = HKEY::default();
73
74 unsafe {
75 let result = RegOpenKeyExW(hive.as_hkey(), &subkey_wide, 0, KEY_READ, &mut handle);
76
77 if result.is_err() {
78 if result == ERROR_FILE_NOT_FOUND {
79 return Err(Error::Registry(crate::error::RegistryError::KeyNotFound(
80 crate::error::RegistryKeyNotFoundError::new(subkey.to_string()),
81 )));
82 }
83 return Err(Error::WindowsApi(crate::error::WindowsApiError::new(
84 result.into(),
85 )));
86 }
87 }
88
89 Ok(RegistryKey {
90 handle,
91 close_on_drop: true,
92 hive: Some(hive),
93 subkey: Some(subkey.to_string()),
94 })
95 }
96
97 pub fn create(hive: Hive, subkey: &str) -> Result<Self> {
108 let subkey_wide = HSTRING::from(subkey);
109 let mut handle = HKEY::default();
110 let mut disposition = REG_CREATED_NEW_KEY;
111
112 unsafe {
113 let result = RegCreateKeyExW(
114 hive.as_hkey(),
115 &subkey_wide,
116 0,
117 PCWSTR::null(),
118 REG_OPTION_NON_VOLATILE,
119 KEY_READ | KEY_WRITE,
120 None,
121 &mut handle,
122 Some(&mut disposition),
123 );
124
125 if result.is_err() {
126 return Err(Error::WindowsApi(
127 crate::error::WindowsApiError::with_context(result.into(), "RegCreateKeyExW"),
128 ));
129 }
130 }
131
132 Ok(RegistryKey {
133 handle,
134 close_on_drop: true,
135 hive: Some(hive),
136 subkey: Some(subkey.to_string()),
137 })
138 }
139
140 pub fn security_descriptor(&self) -> Result<SecurityDescriptor> {
142 let target = self.security_target()?;
143 target.read_descriptor()
144 }
145
146 pub fn set_security_descriptor(&self, descriptor: &SecurityDescriptor) -> Result<()> {
148 let target = self.security_target()?;
149 target.write_descriptor(descriptor)
150 }
151
152 pub fn apply_permissions(
154 &self,
155 plan: &PermissionEditPlan,
156 mode: ApplyMode,
157 ) -> Result<DescriptorEditResult> {
158 let target = self.security_target()?;
159 plan.execute_against_target(&target, mode)
160 }
161
162 fn security_target(&self) -> Result<PermissionTarget> {
163 let hive = self.hive.ok_or_else(|| {
164 CrateError::Security(SecurityError::Unsupported(
165 SecurityUnsupportedError::with_reason(
166 "registry_key".to_string(),
167 "security_target".to_string(),
168 "registry key metadata is unavailable for this handle",
169 ),
170 ))
171 })?;
172
173 let path = match &self.subkey {
174 Some(subkey) if subkey.is_empty() => hive.as_short_name().to_string(),
175 Some(subkey) => format!("{}\\{}", hive.as_short_name(), subkey),
176 None => {
177 return Err(CrateError::Security(SecurityError::Unsupported(
178 SecurityUnsupportedError::with_reason(
179 "registry_key".to_string(),
180 "security_target".to_string(),
181 "registry key path metadata is unavailable",
182 ),
183 )));
184 }
185 };
186
187 Ok(PermissionTarget::registry(path))
188 }
189
190 pub fn get_value<T: RegistryValue>(&self, name: &str) -> Result<T> {
201 T::read_from_key(self, name)
202 }
203
204 pub fn set_value<T: RegistryValue>(&self, name: &str, value: T) -> Result<()> {
216 value.write_to_key(self, name)
217 }
218
219 pub fn delete_value(&self, name: &str) -> Result<()> {
221 let name_wide = HSTRING::from(name);
222 unsafe {
223 let result = RegDeleteValueW(self.handle, &name_wide);
224 if result.is_err() {
225 return Err(Error::WindowsApi(crate::error::WindowsApiError::new(
226 result.into(),
227 )));
228 }
229 }
230 Ok(())
231 }
232
233 pub fn value_exists(&self, name: &str) -> Result<bool> {
246 let name_wide = HSTRING::from(name);
247 let mut typ = REG_NONE;
248
249 unsafe {
250 let result =
251 RegQueryValueExW(self.handle, &name_wide, None, Some(&mut typ), None, None);
252
253 if result == ERROR_FILE_NOT_FOUND {
254 return Ok(false);
255 }
256
257 if result.is_err() {
258 return Err(Error::WindowsApi(crate::error::WindowsApiError::new(
259 result.into(),
260 )));
261 }
262
263 Ok(true)
264 }
265 }
266
267 pub fn try_get_value<T: RegistryValue>(&self, name: &str) -> Option<T> {
280 T::read_from_key(self, name).ok()
281 }
282
283 pub fn get_value_or<T: RegistryValue>(&self, name: &str, default: T) -> T {
294 self.try_get_value(name).unwrap_or(default)
295 }
296
297 pub fn delete_key(hive: Hive, subkey: &str) -> Result<()> {
302 let subkey_wide = HSTRING::from(subkey);
303 unsafe {
304 let result = RegDeleteKeyW(hive.as_hkey(), &subkey_wide);
305 if result.is_err() {
306 return Err(Error::WindowsApi(crate::error::WindowsApiError::new(
307 result.into(),
308 )));
309 }
310 }
311 Ok(())
312 }
313
314 pub fn delete_tree(hive: Hive, subkey: &str) -> Result<()> {
316 let subkey_wide = HSTRING::from(subkey);
317 unsafe {
318 let result = RegDeleteTreeW(hive.as_hkey(), &subkey_wide);
319 if result.is_err() {
320 return Err(Error::WindowsApi(crate::error::WindowsApiError::new(
321 result.into(),
322 )));
323 }
324 }
325 Ok(())
326 }
327
328 pub fn subkeys(&self) -> Result<Vec<String>> {
330 let mut subkeys = Vec::new();
331 let mut index = 0u32;
332
333 loop {
334 let mut name_buf = vec![0u16; 256];
335 let mut name_len = name_buf.len() as u32;
336
337 unsafe {
338 let result = RegEnumKeyExW(
339 self.handle,
340 index,
341 windows::core::PWSTR(name_buf.as_mut_ptr()),
342 &mut name_len,
343 None,
344 windows::core::PWSTR::null(),
345 None,
346 None,
347 );
348
349 if result == ERROR_NO_MORE_ITEMS {
350 break;
351 }
352
353 if result.is_err() {
354 return Err(Error::WindowsApi(crate::error::WindowsApiError::new(
355 result.into(),
356 )));
357 }
358
359 name_buf.truncate(name_len as usize);
360 subkeys.push(String::from_utf16_lossy(&name_buf));
361 }
362
363 index += 1;
364 }
365
366 Ok(subkeys)
367 }
368
369 pub fn value_names(&self) -> Result<Vec<String>> {
371 let mut names = Vec::new();
372 let mut index = 0u32;
373
374 loop {
375 let mut name_buf = vec![0u16; 256];
376 let mut name_len = name_buf.len() as u32;
377
378 unsafe {
379 let result = RegEnumValueW(
380 self.handle,
381 index,
382 windows::core::PWSTR(name_buf.as_mut_ptr()),
383 &mut name_len,
384 None,
385 None,
386 None,
387 None,
388 );
389
390 if result == ERROR_NO_MORE_ITEMS {
391 break;
392 }
393
394 if result.is_err() {
395 return Err(Error::WindowsApi(crate::error::WindowsApiError::new(
396 result.into(),
397 )));
398 }
399
400 name_buf.truncate(name_len as usize);
401 names.push(String::from_utf16_lossy(&name_buf));
402 }
403
404 index += 1;
405 }
406
407 Ok(names)
408 }
409}
410
411impl Drop for RegistryKey {
412 fn drop(&mut self) {
413 if self.close_on_drop {
414 unsafe {
415 let _ = RegCloseKey(self.handle);
416 }
417 }
418 }
419}