From 3e2e73c97de91c7846d8e519417b72f1cd0c73d3 Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Sat, 10 Jan 2026 03:35:44 +0100 Subject: [PATCH] Win: Add GetHostNameW fallback for win7 using gethostname --- library/std/src/sys/pal/windows/c.rs | 12 ++++++ .../std/src/sys/pal/windows/c/bindings.txt | 2 + .../std/src/sys/pal/windows/c/windows_sys.rs | 2 + library/std/src/sys/pal/windows/winsock.rs | 43 +++++++++++++++++++ 4 files changed, 59 insertions(+) diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 25c1a82cc426a..31efb0acc5599 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -227,6 +227,18 @@ compat_fn_with_fallback! { } } +#[cfg(target_vendor = "win7")] +compat_fn_with_fallback! { + pub static WS2_32: &CStr = c"ws2_32"; + + #[cfg(target_vendor = "win7")] + pub fn GetHostNameW(name: PWSTR, namelen: i32) -> i32 { + unsafe { + crate::sys::winsock::hostname_fallback(name, namelen) + } + } +} + cfg_select! { target_vendor = "uwp" => { windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS); diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index 9009aa09f48ed..30c72c80ed58b 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -33,6 +33,7 @@ CONSOLE_MODE CONSOLE_READCONSOLE_CONTROL CONTEXT CopyFileExW +CP_ACP CP_UTF8 CREATE_ALWAYS CREATE_BREAKAWAY_FROM_JOB @@ -2170,6 +2171,7 @@ GetFileType GETFINALPATHNAMEBYHANDLE_FLAGS GetFinalPathNameByHandleW GetFullPathNameW +gethostname GetHostNameW GetLastError GetModuleFileNameW diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 98f277b33780c..b136776c9c9e3 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -130,6 +130,7 @@ windows_targets::link!("ws2_32.dll" "system" fn closesocket(s : SOCKET) -> i32); windows_targets::link!("ws2_32.dll" "system" fn connect(s : SOCKET, name : *const SOCKADDR, namelen : i32) -> i32); windows_targets::link!("ws2_32.dll" "system" fn freeaddrinfo(paddrinfo : *const ADDRINFOA)); windows_targets::link!("ws2_32.dll" "system" fn getaddrinfo(pnodename : PCSTR, pservicename : PCSTR, phints : *const ADDRINFOA, ppresult : *mut *mut ADDRINFOA) -> i32); +windows_targets::link!("ws2_32.dll" "system" fn gethostname(name : PSTR, namelen : i32) -> i32); windows_targets::link!("ws2_32.dll" "system" fn getpeername(s : SOCKET, name : *mut SOCKADDR, namelen : *mut i32) -> i32); windows_targets::link!("ws2_32.dll" "system" fn getsockname(s : SOCKET, name : *mut SOCKADDR, namelen : *mut i32) -> i32); windows_targets::link!("ws2_32.dll" "system" fn getsockopt(s : SOCKET, level : i32, optname : i32, optval : PSTR, optlen : *mut i32) -> i32); @@ -444,6 +445,7 @@ pub struct CONTEXT_0_0 { pub type CONTEXT_FLAGS = u32; pub type COPYFILE_FLAGS = u32; pub type COPYPROGRESSROUTINE_PROGRESS = u32; +pub const CP_ACP: u32 = 0u32; pub const CP_UTF8: u32 = 65001u32; pub const CREATE_ALWAYS: FILE_CREATION_DISPOSITION = 2u32; pub const CREATE_BREAKAWAY_FROM_JOB: PROCESS_CREATION_FLAGS = 16777216u32; diff --git a/library/std/src/sys/pal/windows/winsock.rs b/library/std/src/sys/pal/windows/winsock.rs index b110a43ef3aa8..a2b7bb03346f0 100644 --- a/library/std/src/sys/pal/windows/winsock.rs +++ b/library/std/src/sys/pal/windows/winsock.rs @@ -78,3 +78,46 @@ where { cvt(f()) } + +#[cfg(target_vendor = "win7")] +pub unsafe fn hostname_fallback(name: c::PWSTR, namelen: i32) -> i32 { + assert!(namelen >= 1); + + // The documentation of gethostname says that a buffer size of 256 is + // always enough. + let mut buffer = [const { mem::MaybeUninit::::uninit() }; 256]; + + // SAFETY: these parameters specify a valid, writable region of memory. + unsafe { + if c::gethostname(buffer.as_mut_ptr().cast(), buffer.len() as i32) == c::SOCKET_ERROR { + return c::SOCKET_ERROR; + } + + // Subtract one to leave space for the null terminator, as MultiByteToWideChar doesn't terminate the output buffer + // if the number of output characters is equal to the buffer length. + let len = c::MultiByteToWideChar( + c::CP_ACP, + c::MB_ERR_INVALID_CHARS, + buffer.as_mut_ptr().cast(), + -1, + name, + namelen - 1, + ); + + if len <= 0 { + // GetHostNameW reports WSAEFAULT if the buffer is too small + if c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER { + c::SetLastError(c::WSAEFAULT as _); + } + return c::SOCKET_ERROR; + } + + // Ensure the output is always null terminated. + // If MultiByteToWideChar has already written a null terminator, that null terminator will be included in len + // and this will add a second one, but writing a zero is cheap enough to omit the length comparison. + name.add(len as _).write(0); + } + + // Success + 0 +}