Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Windows implementation #1

Merged
merged 18 commits into from Jan 22, 2019
8 changes: 8 additions & 0 deletions .travis.yml
Expand Up @@ -20,6 +20,9 @@ jobs:
- stage: test
os: osx
rust: stable
- stage: test
os: windows
rust: stable

- stage: test
os: linux
Expand All @@ -33,3 +36,8 @@ jobs:
rust: stable
before_script: rustup component add clippy
script: cargo clippy --all-targets
- stage: lint
os: windows
rust: stable
before_script: rustup component add clippy
script: cargo clippy --all-targets
5 changes: 5 additions & 0 deletions CHANGELOG.md
Expand Up @@ -5,6 +5,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Add Windows implementation (see [GH-1]).

[Gh-1]: https://github.com/lunaryorn/gethostname.rs/pull/1

## 0.1.0 – 2019-01-20
Initial release.

Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Expand Up @@ -17,3 +17,6 @@ pretty_assertions = "^0.5"

[target.'cfg(not(windows))'.dependencies]
libc = "^0.2"

[target.'cfg(windows)'.dependencies]
winapi = {version = "^0.3", features = ["sysinfoapi"]}
60 changes: 55 additions & 5 deletions src/lib.rs
Expand Up @@ -23,10 +23,10 @@ use std::io::Error;

/// Get the standard host name for the current machine.
///
/// Wraps POSIX [gethostname] in a safe interface. The function doesn’t fail but
/// it may `panic!` if the internal buffer for the hostname is too small, but we
/// use a buffer large enough to hold the maximum hostname, so we consider any
/// panics from this function as bug which you should report.
/// Wraps POSIX [gethostname] in a safe interface. The function may `panic!` if
/// the internal buffer for the hostname is too small, but we use a buffer large
/// enough to hold the maximum hostname, so we consider any panics from this
/// function as bug which you should report.
///
/// [gethostname]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html
#[cfg(not(windows))]
Expand Down Expand Up @@ -59,13 +59,63 @@ pub fn gethostname() -> OsString {
OsString::from_vec(buffer)
}

/// Get the standard hostname for the current machine.
///
/// Returns the DNS host name of the local computer, as returned by
/// [GetComputerNameExW] with `ComputerNamePhysicalDnsHostname` flag has name
/// type. This function may `panic!` if the internal buffer for the hostname is
/// too small. Since we try to allocate a buffer large enough to hold the host
/// name we consider panics a bug which you should report.
///
/// [GetComputerNameExW]: https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getcomputernameexw
#[cfg(windows)]
pub fn gethostname() -> OsString {
use std::os::windows::ffi::OsStringExt;
use winapi::ctypes::{c_ulong, wchar_t};
use winapi::um::sysinfoapi::{ComputerNamePhysicalDnsHostname, GetComputerNameExW};

let mut buffer_size: c_ulong = 0;

unsafe {
// This call always fails with ERROR_MORE_DATA, because we pass NULL to
// get the required buffer size.
GetComputerNameExW(
ComputerNamePhysicalDnsHostname,
std::ptr::null_mut(),
&mut buffer_size,
)
};

let mut buffer = vec![0 as wchar_t; buffer_size as usize];
let returncode = unsafe {
GetComputerNameExW(
ComputerNamePhysicalDnsHostname,
buffer.as_mut_ptr() as *mut wchar_t,
&mut buffer_size,
)
};
// GetComputerNameExW returns a non-zero value on success!
if returncode == 0 {
panic!(
"GetComputerNameExW failed to read hostname: {}
Please report this issue to <https://github.com/lunaryorn/gethostname.rs/issues>!",
Error::last_os_error()
);
}

let end = buffer
.iter()
.position(|&b| b == 0)
.unwrap_or_else(|| buffer.len());
OsString::from_wide(&buffer[0..end])
}

#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use std::process::Command;

#[test]
#[cfg(not(windows))]
fn gethostname_matches_system_hostname() {
let output = Command::new("hostname")
.output()
Expand Down