]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/back/msvc/registry.rs
Auto merge of #27273 - tshepang:claim-not-accurate, r=steveklabnik
[rust.git] / src / librustc_trans / back / msvc / registry.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use std::io;
12 use std::ffi::{OsString, OsStr};
13 use std::os::windows::prelude::*;
14 use std::ops::RangeFrom;
15 use std::ptr;
16 use libc::{DWORD, LPCWSTR, LONG, LPDWORD, LPBYTE, ERROR_SUCCESS};
17 use libc::c_void;
18
19 const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY;
20 const KEY_WOW64_32KEY: REGSAM = 0x0200;
21 const KEY_READ: REGSAM = (STANDARD_RIGTS_READ | KEY_QUERY_VALUE |
22                           KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & !SYNCHRONIZE;
23 const STANDARD_RIGTS_READ: REGSAM = READ_CONTROL;
24 const READ_CONTROL: REGSAM = 0x00020000;
25 const KEY_QUERY_VALUE: REGSAM = 0x0001;
26 const KEY_ENUMERATE_SUB_KEYS: REGSAM = 0x0008;
27 const KEY_NOTIFY: REGSAM = 0x0010;
28 const SYNCHRONIZE: REGSAM = 0x00100000;
29 const REG_SZ: DWORD = 1;
30 const ERROR_NO_MORE_ITEMS: DWORD = 259;
31
32 enum __HKEY__ {}
33 pub type HKEY = *mut __HKEY__;
34 pub type PHKEY = *mut HKEY;
35 pub type REGSAM = DWORD;
36 pub type LPWSTR = *mut u16;
37 pub type PFILETIME = *mut c_void;
38
39 #[link(name = "advapi32")]
40 extern "system" {
41     fn RegOpenKeyExW(hKey: HKEY,
42                      lpSubKey: LPCWSTR,
43                      ulOptions: DWORD,
44                      samDesired: REGSAM,
45                      phkResult: PHKEY) -> LONG;
46     fn RegQueryValueExW(hKey: HKEY,
47                         lpValueName: LPCWSTR,
48                         lpReserved: LPDWORD,
49                         lpType: LPDWORD,
50                         lpData: LPBYTE,
51                         lpcbData: LPDWORD) -> LONG;
52     fn RegEnumKeyExW(hKey: HKEY,
53                      dwIndex: DWORD,
54                      lpName: LPWSTR,
55                      lpcName: LPDWORD,
56                      lpReserved: LPDWORD,
57                      lpClass: LPWSTR,
58                      lpcClass: LPDWORD,
59                      lpftLastWriteTime: PFILETIME) -> LONG;
60     fn RegCloseKey(hKey: HKEY) -> LONG;
61 }
62
63 pub struct RegistryKey(Repr);
64
65 struct OwnedKey(HKEY);
66
67 enum Repr {
68     Const(HKEY),
69     Owned(OwnedKey),
70 }
71
72 pub struct Iter<'a> {
73     idx: RangeFrom<DWORD>,
74     key: &'a RegistryKey,
75 }
76
77 unsafe impl Sync for RegistryKey {}
78 unsafe impl Send for RegistryKey {}
79
80 pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE));
81
82 impl RegistryKey {
83     fn raw(&self) -> HKEY {
84         match self.0 {
85             Repr::Const(val) => val,
86             Repr::Owned(ref val) => val.0,
87         }
88     }
89
90     pub fn open(&self, key: &OsStr) -> io::Result<RegistryKey> {
91         let key = key.encode_wide().chain(Some(0)).collect::<Vec<_>>();
92         let mut ret = ptr::null_mut();
93         let err = unsafe {
94             RegOpenKeyExW(self.raw(), key.as_ptr(), 0,
95                           KEY_READ | KEY_WOW64_32KEY, &mut ret)
96         };
97         if err == ERROR_SUCCESS {
98             Ok(RegistryKey(Repr::Owned(OwnedKey(ret))))
99         } else {
100             Err(io::Error::from_raw_os_error(err as i32))
101         }
102     }
103
104     pub fn iter(&self) -> Iter {
105         Iter { idx: 0.., key: self }
106     }
107
108     pub fn query_str(&self, name: &str) -> io::Result<OsString> {
109         let name: &OsStr = name.as_ref();
110         let name = name.encode_wide().chain(Some(0)).collect::<Vec<_>>();
111         let mut len = 0;
112         let mut kind = 0;
113         unsafe {
114             let err = RegQueryValueExW(self.raw(), name.as_ptr(), ptr::null_mut(),
115                                        &mut kind, ptr::null_mut(), &mut len);
116             if err != ERROR_SUCCESS {
117                 return Err(io::Error::from_raw_os_error(err as i32))
118             }
119             if kind != REG_SZ {
120                 return Err(io::Error::new(io::ErrorKind::Other,
121                                           "registry key wasn't a string"))
122             }
123
124             // The length here is the length in bytes, but we're using wide
125             // characters so we need to be sure to halve it for the capacity
126             // passed in.
127             let mut v = Vec::with_capacity(len as usize / 2);
128             let err = RegQueryValueExW(self.raw(), name.as_ptr(), ptr::null_mut(),
129                                        ptr::null_mut(), v.as_mut_ptr() as *mut _,
130                                        &mut len);
131             if err != ERROR_SUCCESS {
132                 return Err(io::Error::from_raw_os_error(err as i32))
133             }
134             v.set_len(len as usize / 2);
135
136             // Some registry keys may have a terminating nul character, but
137             // we're not interested in that, so chop it off if it's there.
138             if v[v.len() - 1] == 0 {
139                 v.pop();
140             }
141             Ok(OsString::from_wide(&v))
142         }
143     }
144 }
145
146 impl Drop for OwnedKey {
147     fn drop(&mut self) {
148         unsafe { RegCloseKey(self.0); }
149     }
150 }
151
152 impl<'a> Iterator for Iter<'a> {
153     type Item = io::Result<OsString>;
154
155     fn next(&mut self) -> Option<io::Result<OsString>> {
156         self.idx.next().and_then(|i| unsafe {
157             let mut v = Vec::with_capacity(256);
158             let mut len = v.capacity() as DWORD;
159             let ret = RegEnumKeyExW(self.key.raw(), i, v.as_mut_ptr(), &mut len,
160                                     ptr::null_mut(), ptr::null_mut(), ptr::null_mut(),
161                                     ptr::null_mut());
162             if ret == ERROR_NO_MORE_ITEMS as LONG {
163                 None
164             } else if ret != ERROR_SUCCESS {
165                 Some(Err(io::Error::from_raw_os_error(ret as i32)))
166             } else {
167                 v.set_len(len as usize);
168                 Some(Ok(OsString::from_wide(&v)))
169             }
170         })
171     }
172 }