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