|
| 1 | +use { |
| 2 | + super::*, |
| 3 | + libc::mode_t, |
| 4 | + std::{ |
| 5 | + ffi::CStr, |
| 6 | + io, |
| 7 | + mem::MaybeUninit, |
| 8 | + os::unix::{ffi::OsStrExt as _, net::UnixListener, prelude::*}, |
| 9 | + path::Path, |
| 10 | + }, |
| 11 | +}; |
| 12 | + |
| 13 | +trait RetExt: Sized { |
| 14 | + fn is_ok(&self) -> bool; |
| 15 | + fn val_or_errno<T>(self, f: impl FnOnce(Self) -> T) -> io::Result<T> { |
| 16 | + if self.is_ok() { |
| 17 | + Ok(f(self)) |
| 18 | + } else { |
| 19 | + Err(io::Error::last_os_error()) |
| 20 | + } |
| 21 | + } |
| 22 | + fn ok_or_errno(self) -> io::Result<()> { self.val_or_errno(drop) } |
| 23 | +} |
| 24 | +impl RetExt for c_int { |
| 25 | + fn is_ok(&self) -> bool { *self >= 0 } |
| 26 | +} |
| 27 | + |
| 28 | +pub fn stat(path: &CStr) -> io::Result<libc::stat> { |
| 29 | + let mut out = MaybeUninit::uninit(); |
| 30 | + unsafe { libc::stat(path.as_ptr(), out.as_mut_ptr()) } |
| 31 | + .val_or_errno(|_| unsafe { out.assume_init() }) |
| 32 | +} |
| 33 | +pub fn fstat(fd: BorrowedFd<'_>) -> io::Result<libc::stat> { |
| 34 | + let mut out = MaybeUninit::uninit(); |
| 35 | + unsafe { libc::fstat(fd.as_raw_fd(), out.as_mut_ptr()) } |
| 36 | + .val_or_errno(|_| unsafe { out.assume_init() }) |
| 37 | +} |
| 38 | +pub fn fchmod(fd: BorrowedFd<'_>, mode: mode_t) -> io::Result<()> { |
| 39 | + unsafe { libc::fchmod(fd.as_raw_fd(), mode) }.ok_or_errno() |
| 40 | +} |
| 41 | + |
| 42 | +#[allow(clippy::as_conversions)] |
| 43 | +fn sockaddr_un_init( |
| 44 | + sau: &mut MaybeUninit<libc::sockaddr_un>, |
| 45 | + path: &Path, |
| 46 | +) -> io::Result<libc::socklen_t> { |
| 47 | + const SUN_PATH_LEN: usize = { |
| 48 | + let sau = unsafe { std::mem::zeroed::<libc::sockaddr_un>() }; |
| 49 | + std::mem::size_of_val(&sau.sun_path) |
| 50 | + }; |
| 51 | + |
| 52 | + std::os::unix::net::SocketAddr::from_pathname(path)?; |
| 53 | + |
| 54 | + let sauptr = sau.as_mut_ptr(); |
| 55 | + let path_bytes = path.as_os_str().as_bytes(); |
| 56 | + let pathlen = path_bytes.len(); |
| 57 | + assert!(pathlen <= SUN_PATH_LEN); |
| 58 | + unsafe { |
| 59 | + (&raw mut (*sauptr).sun_family).write(libc::AF_UNIX as _); |
| 60 | + let pathbase = (&raw mut (*sauptr).sun_path).cast::<c_char>(); |
| 61 | + std::ptr::copy_nonoverlapping(path_bytes.as_ptr().cast(), pathbase, path_bytes.len()); |
| 62 | + if path_bytes.len() != SUN_PATH_LEN { |
| 63 | + pathbase.add(pathlen).write(0); |
| 64 | + } |
| 65 | + } |
| 66 | + let addrlen = std::mem::offset_of!(libc::sockaddr_un, sun_path) + pathlen; |
| 67 | + Ok(addrlen as _) |
| 68 | +} |
| 69 | + |
| 70 | +pub fn bind_with_hook( |
| 71 | + path: &Path, |
| 72 | + f: impl FnOnce(BorrowedFd<'_>) -> io::Result<()>, |
| 73 | +) -> io::Result<UnixListener> { |
| 74 | + let mut sau = MaybeUninit::<libc::sockaddr_un>::uninit(); |
| 75 | + let addrlen = sockaddr_un_init(&mut sau, path)?; |
| 76 | + |
| 77 | + let fd = unsafe { libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0) } |
| 78 | + .val_or_errno(|fd| unsafe { OwnedFd::from_raw_fd(fd) })?; |
| 79 | + f(fd.as_fd())?; |
| 80 | + unsafe { libc::bind(fd.as_raw_fd(), sau.as_ptr().cast(), addrlen) }.ok_or_errno()?; |
| 81 | + Ok(fd.into()) |
| 82 | +} |
| 83 | + |
| 84 | +pub fn umask(mask: mode_t) -> UmaskGuard { UmaskGuard(unsafe { libc::umask(mask) }) } |
| 85 | +#[derive(Debug)] |
| 86 | +#[repr(transparent)] |
| 87 | +pub struct UmaskGuard(mode_t); |
| 88 | +impl Drop for UmaskGuard { |
| 89 | + fn drop(&mut self) { std::mem::forget(umask(self.0)) } |
| 90 | +} |
0 commit comments