@@ -2,7 +2,7 @@ use crate::ffi::OsStr;
22use crate :: os:: unix:: ffi:: OsStrExt ;
33use crate :: path:: Path ;
44use crate :: sys:: cvt;
5- use crate :: { ascii, fmt, io, iter , mem } ;
5+ use crate :: { ascii, fmt, io, mem , ptr } ;
66
77// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
88#[ cfg( not( unix) ) ]
@@ -22,8 +22,9 @@ fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
2222 path - base
2323}
2424
25- pub ( super ) unsafe fn sockaddr_un ( path : & Path ) -> io:: Result < ( libc:: sockaddr_un , libc:: socklen_t ) > {
26- let mut addr: libc:: sockaddr_un = mem:: zeroed ( ) ;
25+ pub ( super ) fn sockaddr_un ( path : & Path ) -> io:: Result < ( libc:: sockaddr_un , libc:: socklen_t ) > {
26+ // SAFETY: All zeros is a valid representation for `sockaddr_un`.
27+ let mut addr: libc:: sockaddr_un = unsafe { mem:: zeroed ( ) } ;
2728 addr. sun_family = libc:: AF_UNIX as libc:: sa_family_t ;
2829
2930 let bytes = path. as_os_str ( ) . as_bytes ( ) ;
@@ -41,11 +42,13 @@ pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un,
4142 & "path must be shorter than SUN_LEN" ,
4243 ) ) ;
4344 }
44- for ( dst, src) in iter:: zip ( & mut addr. sun_path , bytes) {
45- * dst = * src as libc:: c_char ;
46- }
47- // null byte for pathname addresses is already there because we zeroed the
48- // struct
45+ // SAFETY: `bytes` and `addr.sun_path` are not overlapping and
46+ // both point to valid memory.
47+ // NOTE: We zeroed the memory above, so the path is already null
48+ // terminated.
49+ unsafe {
50+ ptr:: copy_nonoverlapping ( bytes. as_ptr ( ) , addr. sun_path . as_mut_ptr ( ) . cast ( ) , bytes. len ( ) )
51+ } ;
4952
5053 let mut len = sun_path_offset ( & addr) + bytes. len ( ) ;
5154 match bytes. get ( 0 ) {
@@ -127,6 +130,43 @@ impl SocketAddr {
127130 Ok ( SocketAddr { addr, len } )
128131 }
129132
133+ /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
134+ ///
135+ /// # Errors
136+ ///
137+ /// Returns an error if the path is longer than `SUN_LEN` or if it contains
138+ /// NULL bytes.
139+ ///
140+ /// # Examples
141+ ///
142+ /// ```
143+ /// #![feature(unix_socket_creation)]
144+ /// use std::os::unix::net::SocketAddr;
145+ /// use std::path::Path;
146+ ///
147+ /// # fn main() -> std::io::Result<()> {
148+ /// let address = SocketAddr::from_path("/path/to/socket")?;
149+ /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket")));
150+ /// # Ok(())
151+ /// # }
152+ /// ```
153+ ///
154+ /// Creating a `SocketAddr` with a NULL byte results in an error.
155+ ///
156+ /// ```
157+ /// #![feature(unix_socket_creation)]
158+ /// use std::os::unix::net::SocketAddr;
159+ ///
160+ /// assert!(SocketAddr::from_path("/path/with/\0/bytes").is_err());
161+ /// ```
162+ #[ unstable( feature = "unix_socket_creation" , issue = "93423" ) ]
163+ pub fn from_path < P > ( path : P ) -> io:: Result < SocketAddr >
164+ where
165+ P : AsRef < Path > ,
166+ {
167+ sockaddr_un ( path. as_ref ( ) ) . map ( |( addr, len) | SocketAddr { addr, len } )
168+ }
169+
130170 /// Returns `true` if the address is unnamed.
131171 ///
132172 /// # Examples
0 commit comments