diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
commit | 2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4 (patch) | |
tree | 033cc839730fda84ff08db877037977be94e5e3a /vendor/winapi-util/src/sysinfo.rs | |
parent | Initial commit. (diff) | |
download | cargo-upstream.tar.xz cargo-upstream.zip |
Adding upstream version 0.70.1+ds1.upstream/0.70.1+ds1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/winapi-util/src/sysinfo.rs')
-rw-r--r-- | vendor/winapi-util/src/sysinfo.rs | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/vendor/winapi-util/src/sysinfo.rs b/vendor/winapi-util/src/sysinfo.rs new file mode 100644 index 0000000..eb3a564 --- /dev/null +++ b/vendor/winapi-util/src/sysinfo.rs @@ -0,0 +1,153 @@ +use std::{ffi::OsString, io}; + +use winapi::um::sysinfoapi::{GetComputerNameExW, COMPUTER_NAME_FORMAT}; + +/// The type of name to be retrieved by [`get_computer_name`]. +#[derive(Clone, Copy, Debug)] +#[non_exhaustive] +pub enum ComputerNameKind { + /// The name of the DNS domain assigned to the local computer. If the local + /// computer is a node in a cluster, lpBuffer receives the DNS domain name + /// of the cluster virtual server. + DnsDomain, + /// The fully qualified DNS name that uniquely identifies the local + /// computer. This name is a combination of the DNS host name and the DNS + /// domain name, using the form HostName.DomainName. If the local computer + /// is a node in a cluster, lpBuffer receives the fully qualified DNS name + /// of the cluster virtual server. + DnsFullyQualified, + /// The DNS host name of the local computer. If the local computer is a + /// node in a cluster, lpBuffer receives the DNS host name of the cluster + /// virtual server. + DnsHostname, + /// The NetBIOS name of the local computer. If the local computer is a node + /// in a cluster, lpBuffer receives the NetBIOS name of the cluster virtual + /// server. + NetBios, + /// The name of the DNS domain assigned to the local computer. If the local + /// computer is a node in a cluster, lpBuffer receives the DNS domain name + /// of the local computer, not the name of the cluster virtual server. + PhysicalDnsDomain, + /// The fully qualified DNS name that uniquely identifies the computer. If + /// the local computer is a node in a cluster, lpBuffer receives the fully + /// qualified DNS name of the local computer, not the name of the cluster + /// virtual server. + /// + /// The fully qualified DNS name is a combination of the DNS host name and + /// the DNS domain name, using the form HostName.DomainName. + PhysicalDnsFullyQualified, + /// The DNS host name of the local computer. If the local computer is a + /// node in a cluster, lpBuffer receives the DNS host name of the local + /// computer, not the name of the cluster virtual server. + PhysicalDnsHostname, + /// The NetBIOS name of the local computer. If the local computer is a node + /// in a cluster, lpBuffer receives the NetBIOS name of the local computer, + /// not the name of the cluster virtual server. + PhysicalNetBios, +} + +impl ComputerNameKind { + fn to_format(&self) -> COMPUTER_NAME_FORMAT { + use self::ComputerNameKind::*; + use winapi::um::sysinfoapi; + + match *self { + DnsDomain => sysinfoapi::ComputerNameDnsDomain, + DnsFullyQualified => sysinfoapi::ComputerNameDnsFullyQualified, + DnsHostname => sysinfoapi::ComputerNameDnsHostname, + NetBios => sysinfoapi::ComputerNameNetBIOS, + PhysicalDnsDomain => sysinfoapi::ComputerNamePhysicalDnsDomain, + PhysicalDnsFullyQualified => { + sysinfoapi::ComputerNamePhysicalDnsFullyQualified + } + PhysicalDnsHostname => sysinfoapi::ComputerNamePhysicalDnsHostname, + PhysicalNetBios => sysinfoapi::ComputerNamePhysicalNetBIOS, + } + } +} +/// Retrieves a NetBIOS or DNS name associated with the local computer. +/// +/// The names are established at system startup, when the system reads them +/// from the registry. +/// +/// This corresponds to calling [`GetComputerNameExW`]. +/// +/// [`GetComputerNameExW`]: https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getcomputernameexw +pub fn get_computer_name(kind: ComputerNameKind) -> io::Result<OsString> { + use std::os::windows::ffi::OsStringExt; + + let format = kind.to_format(); + let mut len1 = 0; + // SAFETY: As documented, we call this with a null pointer which will in + // turn cause this routine to write the required buffer size fo `len1`. + // Also, we explicitly ignore the return value since we expect this call to + // fail given that the destination buffer is too small by design. + let _ = + unsafe { GetComputerNameExW(format, std::ptr::null_mut(), &mut len1) }; + + let len = match usize::try_from(len1) { + Ok(len) => len, + Err(_) => { + return Err(io::Error::new( + io::ErrorKind::Other, + "GetComputerNameExW buffer length overflowed usize", + )) + } + }; + let mut buf = vec![0; len]; + let mut len2 = len1; + // SAFETY: We pass a valid pointer to an appropriately sized Vec<u16>. + let rc = + unsafe { GetComputerNameExW(format, buf.as_mut_ptr(), &mut len2) }; + if rc == 0 { + return Err(io::Error::last_os_error()); + } + // Apparently, the subsequent call writes the number of characters written + // to the buffer to `len2` but not including the NUL terminator. Notice + // that in the first call above, the length written to `len1` *does* + // include the NUL terminator. Therefore, we expect `len1` to be at least + // one greater than `len2`. If not, then something weird has happened and + // we report an error. + if len1 <= len2 { + let msg = format!( + "GetComputerNameExW buffer length mismatch, \ + expected length strictly less than {} \ + but got {}", + len1, len2, + ); + return Err(io::Error::new(io::ErrorKind::Other, msg)); + } + let len = usize::try_from(len2).expect("len1 fits implies len2 fits"); + Ok(OsString::from_wide(&buf[..len])) +} + +#[cfg(test)] +mod tests { + use super::*; + + // This test doesn't really check anything other than that we can + // successfully query all kinds of computer names. We just print them out + // since there aren't really any properties about the names that we can + // assert. + // + // We specifically run this test in CI with --nocapture so that we can see + // the output. + #[test] + fn itworks() { + let kinds = [ + ComputerNameKind::DnsDomain, + ComputerNameKind::DnsFullyQualified, + ComputerNameKind::DnsHostname, + ComputerNameKind::NetBios, + ComputerNameKind::PhysicalDnsDomain, + ComputerNameKind::PhysicalDnsFullyQualified, + ComputerNameKind::PhysicalDnsHostname, + ComputerNameKind::PhysicalNetBios, + ]; + for kind in kinds { + let result = get_computer_name(kind); + let name = result.unwrap(); + println!("{kind:?}: {name:?}"); + } + } +} |