From 7d451b0ae6cbf27168bd2b339a1e5620c7a5a6da Mon Sep 17 00:00:00 2001 From: Anthony Riley II Date: Sun, 11 Apr 2021 16:36:48 -0700 Subject: [PATCH] Add new linux symbol for multicast-all unistd: Increase maximum passwd/group buffer to 1MB We have one UNIX group that contains most of our users whose size is about 20 kB, so `Group::from_name` is failing with ERANGE. The discussion on PR #864 suggests that 1 MB is a reasonable maximum - it follows what FreeBSD's libc does. (glibc appears to have no maximum on the _r function and will just double the buffer until malloc fails, but that's not particularly Rusty.) Use memoffset::offset_of instead of homegrown macro The homegrown macro was fine in 2016, but at some point it technically became UB. The memoffset crate does the same thing, but avoids UB when using rustc 1.51.0 or later. Fixes #1415 Check all tests in CI Travis didn't compile check tests on platforms that couldn't run tests in CI, so they bitrotted. Let's see how bad they are. Most annoyingly, 32-bit Android defines mode_t as 16 bits, but stat.st_mode as 32-bits. Fix spurious errors using `sendmmsg` with multiple cmsgs Before this fix, the buffer that holds cmsgs may move due to the resize() call. That causes msg_hdr pointing to invalid memory, which ends up breaking the sendmmsg() call, resulting in EINVAL. This change fixes it by avoiding re-allocating the buffers. Support TIMESTAMPNS for linux --- .cirrus.yml | 7 +- CHANGELOG.md | 6 ++ Cargo.toml | 5 +- src/macros.rs | 13 ---- src/sys/socket/addr.rs | 1 + src/sys/socket/mod.rs | 24 +++++-- src/sys/socket/sockopt.rs | 4 ++ src/unistd.rs | 8 +-- test/sys/mod.rs | 2 +- test/sys/test_socket.rs | 133 ++++++++++++++++++++++++++++++++++++-- test/test_fcntl.rs | 70 ++++++++++---------- test/test_stat.rs | 15 +++-- test/test_unistd.rs | 12 ++-- 13 files changed, 215 insertions(+), 85 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index f598e2e6fb..381fb62919 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -22,6 +22,7 @@ task: - cargo test --target i686-unknown-freebsd before_cache_script: rm -rf $CARGO_HOME/registry/index +# Test OSX and iOS in a full VM task: matrix: - name: OSX x86_64 @@ -162,14 +163,12 @@ task: - name: Linux x32 env: TARGET: x86_64-unknown-linux-gnux32 - CHECK_TESTS: true - name: NetBSD x86_64 env: TARGET: x86_64-unknown-netbsd - name: Fuchsia x86_64 env: TARGET: x86_64-fuchsia - CHECK_TESTS: true container: image: rust:1.40 setup_script: @@ -177,9 +176,7 @@ task: script: - cargo +$TOOLCHAIN check --target $TARGET - cargo +$TOOLCHAIN check --target $TARGET --release - - 'if [ "$CHECK_TESTS" == true ]; then cargo +$TOOLCHAIN check --all-targets --target $TARGET; fi' - # TODO: check the tests, too. The old Travis CI setup didn't do that, so - # they don't build on all platforms. + - cargo +$TOOLCHAIN check --all-targets --target $TARGET before_cache_script: rm -rf $CARGO_HOME/registry/index # illumos toolchain isn't available via rustup until 1.50 diff --git a/CHANGELOG.md b/CHANGELOG.md index 9636942d5f..2a46003606 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Add new symbol for linux IP_MULTICAST_ALL + (#[]()) +- Added TIMESTAMPNS support for linux + (#[1402](https://github.com/nix-rust/nix/pull/1402)) ### Changed - Made `forkpty` unsafe, like `fork` @@ -13,6 +17,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Allow `sockaddr_ll` size, as reported by the Linux kernel, to be smaller then it's definition (#[1395](https://github.com/nix-rust/nix/pull/1395)) +- Fix spurious errors using `sendmmsg` with multiple cmsgs + (#[1414](https://github.com/nix-rust/nix/pull/1414)) ### Removed diff --git a/Cargo.toml b/Cargo.toml index 5b052473e4..f5f6dd893b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,10 +32,13 @@ targets = [ ] [dependencies] -libc = { version = "0.2.82", features = [ "extra_traits" ] } +libc = { version = "0.2.93", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" +[target.'cfg(not(target_os = "redox"))'.dependencies] +memoffset = "0.6.3" + [target.'cfg(target_os = "dragonfly")'.build-dependencies] cc = "1" diff --git a/src/macros.rs b/src/macros.rs index feb02ea745..7d6ac8dfbf 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -203,16 +203,3 @@ macro_rules! libc_enum { } }; } - -/// A Rust version of the familiar C `offset_of` macro. It returns the byte -/// offset of `field` within struct `ty` -#[cfg(not(target_os = "redox"))] -macro_rules! offset_of { - ($ty:ty, $field:ident) => {{ - // Safe because we don't actually read from the dereferenced pointer - #[allow(unused_unsafe)] // for when the macro is used in an unsafe block - unsafe { - &(*(ptr::null() as *const $ty)).$field as *const _ as usize - } - }} -} diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 1f7f4ec68e..71b2c973c5 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -1,6 +1,7 @@ use super::sa_family_t; use crate::{Error, Result, NixPath}; use crate::errno::Errno; +use memoffset::offset_of; use std::{fmt, mem, net, ptr, slice}; use std::ffi::OsStr; use std::hash::{Hash, Hasher}; diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 2725e57c43..c04af50f73 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -5,8 +5,11 @@ use cfg_if::cfg_if; use crate::{Error, Result, errno::Errno}; use libc::{self, c_void, c_int, iovec, socklen_t, size_t, CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, CMSG_LEN}; +use memoffset::offset_of; use std::{mem, ptr, slice}; use std::os::unix::io::RawFd; +#[cfg(all(target_os = "linux"))] +use crate::sys::time::TimeSpec; use crate::sys::time::TimeVal; use crate::sys::uio::IoVec; @@ -554,6 +557,11 @@ pub enum ControlMessageOwned { /// # } /// ``` ScmTimestamp(TimeVal), + /// Nanoseconds resolution timestamp + /// + /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) + #[cfg(all(target_os = "linux"))] + ScmTimestampns(TimeSpec), #[cfg(any( target_os = "android", target_os = "ios", @@ -645,6 +653,11 @@ impl ControlMessageOwned { let tv: libc::timeval = ptr::read_unaligned(p as *const _); ControlMessageOwned::ScmTimestamp(TimeVal::from(tv)) }, + #[cfg(all(target_os = "linux"))] + (libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => { + let ts: libc::timespec = ptr::read_unaligned(p as *const _); + ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts)) + } #[cfg(any( target_os = "android", target_os = "freebsd", @@ -1101,23 +1114,22 @@ pub fn sendmmsg<'a, I, C>( let mut output = Vec::::with_capacity(reserve_items); - let mut cmsgs_buffer = vec![0u8; 0]; + let mut cmsgs_buffers = Vec::>::with_capacity(reserve_items); for d in iter { - let cmsgs_start = cmsgs_buffer.len(); - let cmsgs_required_capacity: usize = d.cmsgs.as_ref().iter().map(|c| c.space()).sum(); - let cmsgs_buffer_need_capacity = cmsgs_start + cmsgs_required_capacity; - cmsgs_buffer.resize(cmsgs_buffer_need_capacity, 0); + let capacity: usize = d.cmsgs.as_ref().iter().map(|c| c.space()).sum(); + let mut cmsgs_buffer = vec![0u8; capacity]; output.push(libc::mmsghdr { msg_hdr: pack_mhdr_to_send( - &mut cmsgs_buffer[cmsgs_start..], + &mut cmsgs_buffer, &d.iov, &d.cmsgs, d.addr.as_ref() ), msg_len: 0, }); + cmsgs_buffers.push(cmsgs_buffer); }; let ret = unsafe { libc::sendmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _) }; diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index fd9a710c51..ff55cb0b9b 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -238,6 +238,8 @@ cfg_if! { } sockopt_impl!(Both, IpMulticastTtl, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8); sockopt_impl!(Both, IpMulticastLoop, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool); +[cfg(any(target_os = "linux", target_os = "android"))] +sockopt_impl!(Both, IpMulticastAll, libc::IPPROTO_IP, libc::IP_MULTICAST_ALL, bool); sockopt_impl!(Both, ReceiveTimeout, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal); sockopt_impl!(Both, SendTimeout, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal); sockopt_impl!(Both, Broadcast, libc::SOL_SOCKET, libc::SO_BROADCAST, bool); @@ -272,6 +274,8 @@ sockopt_impl!(Both, BindToDevice, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsStr #[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!(GetOnly, OriginalDst, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in); sockopt_impl!(Both, ReceiveTimestamp, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool); +#[cfg(all(target_os = "linux"))] +sockopt_impl!(Both, ReceiveTimestampns, libc::SOL_SOCKET, libc::SO_TIMESTAMPNS, bool); #[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!(Both, IpTransparent, libc::SOL_IP, libc::IP_TRANSPARENT, bool); #[cfg(target_os = "openbsd")] diff --git a/src/unistd.rs b/src/unistd.rs index f93c21924c..d3afeac633 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -2641,10 +2641,10 @@ impl User { libc::size_t, *mut *mut libc::passwd) -> libc::c_int { - let buflimit = 16384; + let buflimit = 1048576; let bufsize = match sysconf(SysconfVar::GETPW_R_SIZE_MAX) { Ok(Some(n)) => n as usize, - Ok(None) | Err(_) => buflimit as usize, + Ok(None) | Err(_) => 16384, }; let mut cbuf = Vec::with_capacity(bufsize); @@ -2762,10 +2762,10 @@ impl Group { libc::size_t, *mut *mut libc::group) -> libc::c_int { - let buflimit = 16384; + let buflimit = 1048576; let bufsize = match sysconf(SysconfVar::GETGR_R_SIZE_MAX) { Ok(Some(n)) => n as usize, - Ok(None) | Err(_) => buflimit as usize, + Ok(None) | Err(_) => 16384, }; let mut cbuf = Vec::with_capacity(bufsize); diff --git a/test/sys/mod.rs b/test/sys/mod.rs index 14b03784a0..4f5316ffa9 100644 --- a/test/sys/mod.rs +++ b/test/sys/mod.rs @@ -41,5 +41,5 @@ mod test_pthread; target_os = "netbsd", target_os = "openbsd"))] mod test_ptrace; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(target_os = "linux")] mod test_timerfd; diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 2b89a45336..32318ef0cb 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -757,6 +757,7 @@ pub fn test_af_alg_aead() { target_os = "netbsd"))] #[test] pub fn test_sendmsg_ipv4packetinfo() { + use cfg_if::cfg_if; use nix::sys::uio::IoVec; use nix::sys::socket::{socket, sendmsg, bind, AddressFamily, SockType, SockFlag, SockAddr, @@ -778,11 +779,21 @@ pub fn test_sendmsg_ipv4packetinfo() { let iov = [IoVec::from_slice(&slice)]; if let InetAddr::V4(sin) = inet_addr { - let pi = libc::in_pktinfo { - ipi_ifindex: 0, /* Unspecified interface */ - ipi_addr: libc::in_addr { s_addr: 0 }, - ipi_spec_dst: sin.sin_addr, - }; + cfg_if! { + if #[cfg(target_os = "netbsd")] { + drop(sin); + let pi = libc::in_pktinfo { + ipi_ifindex: 0, /* Unspecified interface */ + ipi_addr: libc::in_addr { s_addr: 0 }, + }; + } else { + let pi = libc::in_pktinfo { + ipi_ifindex: 0, /* Unspecified interface */ + ipi_addr: libc::in_addr { s_addr: 0 }, + ipi_spec_dst: sin.sin_addr, + }; + } + } let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)]; @@ -1472,13 +1483,13 @@ pub fn test_recv_ipv6pktinfo() { Some(ControlMessageOwned::Ipv6PacketInfo(pktinfo)) => { let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex"); assert_eq!( - pktinfo.ipi6_ifindex, + pktinfo.ipi6_ifindex as libc::c_uint, i, "unexpected ifindex (expected {}, got {})", i, pktinfo.ipi6_ifindex ); - } + }, _ => (), } assert!(cmsgs.next().is_none(), "unexpected additional control msg"); @@ -1535,3 +1546,111 @@ pub fn test_vsock() { close(s1).unwrap(); thr.join().unwrap(); } + +// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack of QEMU +// support is suspected. +#[cfg_attr(not(any(target_arch = "x86_64")), ignore)] +#[cfg(all(target_os = "linux"))] +#[test] +fn test_recvmsg_timestampns() { + use nix::sys::socket::*; + use nix::sys::uio::IoVec; + use nix::sys::time::*; + use std::time::*; + + // Set up + let message = "Ohayō!".as_bytes(); + let in_socket = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None).unwrap(); + setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); + let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0); + bind(in_socket, &SockAddr::new_inet(localhost)).unwrap(); + let address = getsockname(in_socket).unwrap(); + // Get initial time + let time0 = SystemTime::now(); + // Send the message + let iov = [IoVec::from_slice(message)]; + let flags = MsgFlags::empty(); + let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); + assert_eq!(message.len(), l); + // Receive the message + let mut buffer = vec![0u8; message.len()]; + let mut cmsgspace = nix::cmsg_space!(TimeSpec); + let iov = [IoVec::from_mut_slice(&mut buffer)]; + let r = recvmsg(in_socket, &iov, Some(&mut cmsgspace), flags).unwrap(); + let rtime = match r.cmsgs().next() { + Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, + Some(_) => panic!("Unexpected control message"), + None => panic!("No control message") + }; + // Check the final time + let time1 = SystemTime::now(); + // the packet's received timestamp should lie in-between the two system + // times, unless the system clock was adjusted in the meantime. + let rduration = Duration::new(rtime.tv_sec() as u64, + rtime.tv_nsec() as u32); + assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); + assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); + // Close socket + nix::unistd::close(in_socket).unwrap(); +} + +// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack of QEMU +// support is suspected. +#[cfg_attr(not(any(target_arch = "x86_64")), ignore)] +#[cfg(all(target_os = "linux"))] +#[test] +fn test_recvmmsg_timestampns() { + use nix::sys::socket::*; + use nix::sys::uio::IoVec; + use nix::sys::time::*; + use std::time::*; + + // Set up + let message = "Ohayō!".as_bytes(); + let in_socket = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None).unwrap(); + setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); + let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0); + bind(in_socket, &SockAddr::new_inet(localhost)).unwrap(); + let address = getsockname(in_socket).unwrap(); + // Get initial time + let time0 = SystemTime::now(); + // Send the message + let iov = [IoVec::from_slice(message)]; + let flags = MsgFlags::empty(); + let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); + assert_eq!(message.len(), l); + // Receive the message + let mut buffer = vec![0u8; message.len()]; + let mut cmsgspace = nix::cmsg_space!(TimeSpec); + let iov = [IoVec::from_mut_slice(&mut buffer)]; + let mut data = vec![ + RecvMmsgData { + iov, + cmsg_buffer: Some(&mut cmsgspace), + }, + ]; + let r = recvmmsg(in_socket, &mut data, flags, None).unwrap(); + let rtime = match r[0].cmsgs().next() { + Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, + Some(_) => panic!("Unexpected control message"), + None => panic!("No control message") + }; + // Check the final time + let time1 = SystemTime::now(); + // the packet's received timestamp should lie in-between the two system + // times, unless the system clock was adjusted in the meantime. + let rduration = Duration::new(rtime.tv_sec() as u64, + rtime.tv_nsec() as u32); + assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); + assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); + // Close socket + nix::unistd::close(in_socket).unwrap(); +} diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index 5d1bafebe1..48d46626b6 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -81,19 +81,18 @@ fn test_readlink() { #[cfg(any(target_os = "linux", target_os = "android"))] mod linux_android { - use std::fs::File; use std::io::prelude::*; - use std::io::{BufRead, BufReader, SeekFrom}; + use std::io::SeekFrom; use std::os::unix::prelude::*; - use libc::loff_t; use nix::fcntl::*; - use nix::sys::stat::fstat; use nix::sys::uio::IoVec; use nix::unistd::{close, pipe, read, write}; - use tempfile::{tempfile, NamedTempFile}; + use tempfile::tempfile; + #[cfg(any(target_os = "linux"))] + use tempfile::NamedTempFile; use crate::*; @@ -206,6 +205,7 @@ mod linux_android { close(wr).unwrap(); } + #[cfg(any(target_os = "linux"))] #[test] fn test_fallocate() { let tmp = NamedTempFile::new().unwrap(); @@ -224,17 +224,11 @@ mod linux_android { // they run under QEMU. #[test] - #[cfg(not(any(target_arch = "aarch64", - target_arch = "arm", - target_arch = "armv7", - target_arch = "x86", - target_arch = "mips", - target_arch = "mips64", - target_arch = "mips64el", - target_arch = "powerpc64", - target_arch = "powerpc64le", - target_env = "musl")))] + #[cfg(all(target_os = "linux", not(target_env = "musl")))] fn test_ofd_write_lock() { + use nix::sys::stat::fstat; + use std::mem; + let tmp = NamedTempFile::new().unwrap(); let fd = tmp.as_raw_fd(); @@ -247,13 +241,14 @@ mod linux_android { } let inode = fstat(fd).expect("fstat failed").st_ino as usize; - let mut flock = libc::flock { - l_type: libc::F_WRLCK as libc::c_short, - l_whence: libc::SEEK_SET as libc::c_short, - l_start: 0, - l_len: 0, - l_pid: 0, + let mut flock: libc::flock = unsafe { + mem::zeroed() // required for Linux/mips }; + flock.l_type = libc::F_WRLCK as libc::c_short; + flock.l_whence = libc::SEEK_SET as libc::c_short; + flock.l_start = 0; + flock.l_len = 0; + flock.l_pid = 0; fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write lock failed"); assert_eq!( Some(("OFDLCK".to_string(), "WRITE".to_string())), @@ -266,17 +261,11 @@ mod linux_android { } #[test] - #[cfg(not(any(target_arch = "aarch64", - target_arch = "arm", - target_arch = "armv7", - target_arch = "x86", - target_arch = "mips", - target_arch = "mips64", - target_arch = "mips64el", - target_arch = "powerpc64", - target_arch = "powerpc64le", - target_env = "musl")))] + #[cfg(all(target_os = "linux", not(target_env = "musl")))] fn test_ofd_read_lock() { + use nix::sys::stat::fstat; + use std::mem; + let tmp = NamedTempFile::new().unwrap(); let fd = tmp.as_raw_fd(); @@ -289,13 +278,14 @@ mod linux_android { } let inode = fstat(fd).expect("fstat failed").st_ino as usize; - let mut flock = libc::flock { - l_type: libc::F_RDLCK as libc::c_short, - l_whence: libc::SEEK_SET as libc::c_short, - l_start: 0, - l_len: 0, - l_pid: 0, + let mut flock: libc::flock = unsafe { + mem::zeroed() // required for Linux/mips }; + flock.l_type = libc::F_RDLCK as libc::c_short; + flock.l_whence = libc::SEEK_SET as libc::c_short; + flock.l_start = 0; + flock.l_len = 0; + flock.l_pid = 0; fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read lock failed"); assert_eq!( Some(("OFDLCK".to_string(), "READ".to_string())), @@ -307,7 +297,13 @@ mod linux_android { assert_eq!(None, lock_info(inode)); } + #[cfg(all(target_os = "linux", not(target_env = "musl")))] fn lock_info(inode: usize) -> Option<(String, String)> { + use std::{ + fs::File, + io::BufReader + }; + let file = File::open("/proc/locks").expect("open /proc/locks failed"); let buf = BufReader::new(file); diff --git a/test/test_stat.rs b/test/test_stat.rs index 0b94666856..98112d6146 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -10,7 +10,9 @@ use std::time::{Duration, UNIX_EPOCH}; use std::path::Path; #[cfg(not(any(target_os = "netbsd", target_os = "redox")))] -use libc::{S_IFMT, S_IFLNK, mode_t}; +use libc::{S_IFMT, S_IFLNK}; +#[cfg(not(target_os = "redox"))] +use libc::mode_t; #[cfg(not(target_os = "redox"))] use nix::{fcntl, Error}; @@ -69,6 +71,8 @@ fn assert_stat_results(stat_result: Result) { } #[cfg(not(any(target_os = "netbsd", target_os = "redox")))] +// (Android's st_blocks is ulonglong which is always non-negative.) +#[cfg_attr(target_os = "android", allow(unused_comparisons))] fn assert_lstat_results(stat_result: Result) { let stats = stat_result.expect("stat call failed"); assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent @@ -86,7 +90,6 @@ fn assert_lstat_results(stat_result: Result) { // st_blocks depends on whether the machine's file system uses fast // or slow symlinks, so just make sure it's not negative - // (Android's st_blocks is ulonglong which is always non-negative.) assert!(stats.st_blocks >= 0); } @@ -159,14 +162,14 @@ fn test_fchmod() { fchmod(file.as_raw_fd(), mode1).unwrap(); let file_stat1 = stat(&filename).unwrap(); - assert_eq!(file_stat1.st_mode & 0o7777, mode1.bits()); + assert_eq!(file_stat1.st_mode as mode_t & 0o7777, mode1.bits()); let mut mode2 = Mode::empty(); mode2.insert(Mode::S_IROTH); fchmod(file.as_raw_fd(), mode2).unwrap(); let file_stat2 = stat(&filename).unwrap(); - assert_eq!(file_stat2.st_mode & 0o7777, mode2.bits()); + assert_eq!(file_stat2.st_mode as mode_t & 0o7777, mode2.bits()); } #[test] @@ -186,7 +189,7 @@ fn test_fchmodat() { fchmodat(Some(dirfd), filename, mode1, FchmodatFlags::FollowSymlink).unwrap(); let file_stat1 = stat(&fullpath).unwrap(); - assert_eq!(file_stat1.st_mode & 0o7777, mode1.bits()); + assert_eq!(file_stat1.st_mode as mode_t & 0o7777, mode1.bits()); chdir(tempdir.path()).unwrap(); @@ -195,7 +198,7 @@ fn test_fchmodat() { fchmodat(None, filename, mode2, FchmodatFlags::FollowSymlink).unwrap(); let file_stat2 = stat(&fullpath).unwrap(); - assert_eq!(file_stat2.st_mode & 0o7777, mode2.bits()); + assert_eq!(file_stat2.st_mode as mode_t & 0o7777, mode2.bits()); } /// Asserts that the atime and mtime in a file's metadata match expected values. diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 9f71016802..4acfff3792 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -23,7 +23,7 @@ use std::os::unix::prelude::*; #[cfg(not(target_os = "redox"))] use std::path::Path; use tempfile::{tempdir, tempfile}; -use libc::{_exit, off_t}; +use libc::{_exit, mode_t, off_t}; use crate::*; @@ -102,7 +102,7 @@ fn test_mkfifo() { mkfifo(&mkfifo_fifo, Mode::S_IRUSR).unwrap(); let stats = stat::stat(&mkfifo_fifo).unwrap(); - let typ = stat::SFlag::from_bits_truncate(stats.st_mode); + let typ = stat::SFlag::from_bits_truncate(stats.st_mode as mode_t); assert!(typ == SFlag::S_IFIFO); } @@ -629,10 +629,10 @@ fn test_sysconf_unsupported() { #[test] fn test_pipe() { let (fd0, fd1) = pipe().unwrap(); - let m0 = stat::SFlag::from_bits_truncate(stat::fstat(fd0).unwrap().st_mode); + let m0 = stat::SFlag::from_bits_truncate(stat::fstat(fd0).unwrap().st_mode as mode_t); // S_IFIFO means it's a pipe assert_eq!(m0, SFlag::S_IFIFO); - let m1 = stat::SFlag::from_bits_truncate(stat::fstat(fd1).unwrap().st_mode); + let m1 = stat::SFlag::from_bits_truncate(stat::fstat(fd1).unwrap().st_mode as mode_t); assert_eq!(m1, SFlag::S_IFIFO); } @@ -926,7 +926,9 @@ fn test_linkat_follow_symlink() { let newfilestat = stat::stat(&newfilepath).unwrap(); // Check the file type of the new link - assert!((stat::SFlag::from_bits_truncate(newfilestat.st_mode) & SFlag::S_IFMT) == SFlag::S_IFREG); + assert_eq!((stat::SFlag::from_bits_truncate(newfilestat.st_mode as mode_t) & SFlag::S_IFMT), + SFlag::S_IFREG + ); // Check the number of hard links to the original file assert_eq!(newfilestat.st_nlink, 2);