xref: /aosp_15_r20/external/cronet/third_party/rust/chromium_crates_io/vendor/winapi-util-0.1.6/src/sysinfo.rs (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 use std::{ffi::OsString, io};
2 
3 use winapi::um::sysinfoapi::{GetComputerNameExW, COMPUTER_NAME_FORMAT};
4 
5 /// The type of name to be retrieved by [`get_computer_name`].
6 #[derive(Clone, Copy, Debug)]
7 #[non_exhaustive]
8 pub enum ComputerNameKind {
9     /// The name of the DNS domain assigned to the local computer. If the local
10     /// computer is a node in a cluster, lpBuffer receives the DNS domain name
11     /// of the cluster virtual server.
12     DnsDomain,
13     /// The fully qualified DNS name that uniquely identifies the local
14     /// computer. This name is a combination of the DNS host name and the DNS
15     /// domain name, using the form HostName.DomainName. If the local computer
16     /// is a node in a cluster, lpBuffer receives the fully qualified DNS name
17     /// of the cluster virtual server.
18     DnsFullyQualified,
19     /// The DNS host name of the local computer. If the local computer is a
20     /// node in a cluster, lpBuffer receives the DNS host name of the cluster
21     /// virtual server.
22     DnsHostname,
23     /// The NetBIOS name of the local computer. If the local computer is a node
24     /// in a cluster, lpBuffer receives the NetBIOS name of the cluster virtual
25     /// server.
26     NetBios,
27     /// The name of the DNS domain assigned to the local computer. If the local
28     /// computer is a node in a cluster, lpBuffer receives the DNS domain name
29     /// of the local computer, not the name of the cluster virtual server.
30     PhysicalDnsDomain,
31     /// The fully qualified DNS name that uniquely identifies the computer. If
32     /// the local computer is a node in a cluster, lpBuffer receives the fully
33     /// qualified DNS name of the local computer, not the name of the cluster
34     /// virtual server.
35     ///
36     /// The fully qualified DNS name is a combination of the DNS host name and
37     /// the DNS domain name, using the form HostName.DomainName.
38     PhysicalDnsFullyQualified,
39     /// The DNS host name of the local computer. If the local computer is a
40     /// node in a cluster, lpBuffer receives the DNS host name of the local
41     /// computer, not the name of the cluster virtual server.
42     PhysicalDnsHostname,
43     /// The NetBIOS name of the local computer. If the local computer is a node
44     /// in a cluster, lpBuffer receives the NetBIOS name of the local computer,
45     /// not the name of the cluster virtual server.
46     PhysicalNetBios,
47 }
48 
49 impl ComputerNameKind {
to_format(&self) -> COMPUTER_NAME_FORMAT50     fn to_format(&self) -> COMPUTER_NAME_FORMAT {
51         use self::ComputerNameKind::*;
52         use winapi::um::sysinfoapi;
53 
54         match *self {
55             DnsDomain => sysinfoapi::ComputerNameDnsDomain,
56             DnsFullyQualified => sysinfoapi::ComputerNameDnsFullyQualified,
57             DnsHostname => sysinfoapi::ComputerNameDnsHostname,
58             NetBios => sysinfoapi::ComputerNameNetBIOS,
59             PhysicalDnsDomain => sysinfoapi::ComputerNamePhysicalDnsDomain,
60             PhysicalDnsFullyQualified => {
61                 sysinfoapi::ComputerNamePhysicalDnsFullyQualified
62             }
63             PhysicalDnsHostname => sysinfoapi::ComputerNamePhysicalDnsHostname,
64             PhysicalNetBios => sysinfoapi::ComputerNamePhysicalNetBIOS,
65         }
66     }
67 }
68 /// Retrieves a NetBIOS or DNS name associated with the local computer.
69 ///
70 /// The names are established at system startup, when the system reads them
71 /// from the registry.
72 ///
73 /// This corresponds to calling [`GetComputerNameExW`].
74 ///
75 /// [`GetComputerNameExW`]: https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getcomputernameexw
get_computer_name(kind: ComputerNameKind) -> io::Result<OsString>76 pub fn get_computer_name(kind: ComputerNameKind) -> io::Result<OsString> {
77     use std::os::windows::ffi::OsStringExt;
78 
79     let format = kind.to_format();
80     let mut len1 = 0;
81     // SAFETY: As documented, we call this with a null pointer which will in
82     // turn cause this routine to write the required buffer size fo `len1`.
83     // Also, we explicitly ignore the return value since we expect this call to
84     // fail given that the destination buffer is too small by design.
85     let _ =
86         unsafe { GetComputerNameExW(format, std::ptr::null_mut(), &mut len1) };
87 
88     let len = match usize::try_from(len1) {
89         Ok(len) => len,
90         Err(_) => {
91             return Err(io::Error::new(
92                 io::ErrorKind::Other,
93                 "GetComputerNameExW buffer length overflowed usize",
94             ))
95         }
96     };
97     let mut buf = vec![0; len];
98     let mut len2 = len1;
99     // SAFETY: We pass a valid pointer to an appropriately sized Vec<u16>.
100     let rc =
101         unsafe { GetComputerNameExW(format, buf.as_mut_ptr(), &mut len2) };
102     if rc == 0 {
103         return Err(io::Error::last_os_error());
104     }
105     // Apparently, the subsequent call writes the number of characters written
106     // to the buffer to `len2` but not including the NUL terminator. Notice
107     // that in the first call above, the length written to `len1` *does*
108     // include the NUL terminator. Therefore, we expect `len1` to be at least
109     // one greater than `len2`. If not, then something weird has happened and
110     // we report an error.
111     if len1 <= len2 {
112         let msg = format!(
113             "GetComputerNameExW buffer length mismatch, \
114              expected length strictly less than {} \
115              but got {}",
116             len1, len2,
117         );
118         return Err(io::Error::new(io::ErrorKind::Other, msg));
119     }
120     let len = usize::try_from(len2).expect("len1 fits implies len2 fits");
121     Ok(OsString::from_wide(&buf[..len]))
122 }
123 
124 #[cfg(test)]
125 mod tests {
126     use super::*;
127 
128     // This test doesn't really check anything other than that we can
129     // successfully query all kinds of computer names. We just print them out
130     // since there aren't really any properties about the names that we can
131     // assert.
132     //
133     // We specifically run this test in CI with --nocapture so that we can see
134     // the output.
135     #[test]
itworks()136     fn itworks() {
137         let kinds = [
138             ComputerNameKind::DnsDomain,
139             ComputerNameKind::DnsFullyQualified,
140             ComputerNameKind::DnsHostname,
141             ComputerNameKind::NetBios,
142             ComputerNameKind::PhysicalDnsDomain,
143             ComputerNameKind::PhysicalDnsFullyQualified,
144             ComputerNameKind::PhysicalDnsHostname,
145             ComputerNameKind::PhysicalNetBios,
146         ];
147         for kind in kinds {
148             let result = get_computer_name(kind);
149             let name = result.unwrap();
150             println!("{kind:?}: {name:?}");
151         }
152     }
153 }
154