summaryrefslogtreecommitdiffstats
path: root/vendor/winapi-util/src/sysinfo.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:47:55 +0000
commit2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4 (patch)
tree033cc839730fda84ff08db877037977be94e5e3a /vendor/winapi-util/src/sysinfo.rs
parentInitial commit. (diff)
downloadcargo-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.rs153
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:?}");
+ }
+ }
+}