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