summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml2
-rw-r--r--.travis.yml50
-rw-r--r--CHANGELOG.md13
-rw-r--r--Cargo.toml4
-rw-r--r--README.md5
-rw-r--r--src/dir.rs41
-rw-r--r--src/fcntl.rs78
-rw-r--r--src/ifaddrs.rs2
-rw-r--r--src/lib.rs4
-rw-r--r--src/mqueue.rs13
-rw-r--r--src/poll.rs20
-rw-r--r--src/pty.rs5
-rw-r--r--src/sched.rs231
-rw-r--r--src/sys/aio.rs10
-rw-r--r--src/sys/epoll.rs3
-rw-r--r--src/sys/event.rs3
-rw-r--r--src/sys/mod.rs9
-rw-r--r--src/sys/quota.rs3
-rw-r--r--src/sys/select.rs3
-rw-r--r--src/sys/sendfile.rs2
-rw-r--r--src/sys/signal.rs38
-rw-r--r--src/sys/socket/addr.rs384
-rw-r--r--src/sys/socket/mod.rs75
-rw-r--r--src/sys/socket/sockopt.rs6
-rw-r--r--src/sys/stat.rs8
-rw-r--r--src/sys/statfs.rs548
-rw-r--r--src/sys/statvfs.rs3
-rw-r--r--src/sys/sysinfo.rs3
-rw-r--r--src/sys/termios.rs3
-rw-r--r--src/sys/time.rs42
-rw-r--r--src/sys/uio.rs5
-rw-r--r--src/sys/utsname.rs3
-rw-r--r--src/sys/wait.rs2
-rw-r--r--src/ucontext.rs3
-rw-r--r--test/sys/test_socket.rs66
-rw-r--r--test/test_fcntl.rs41
-rw-r--r--test/test_mq.rs18
-rw-r--r--test/test_poll.rs20
-rw-r--r--test/test_stat.rs42
39 files changed, 1031 insertions, 780 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 00d0095c..eca3d347 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -14,7 +14,7 @@ task:
setup_script:
- pkg install -y curl
- curl https://sh.rustup.rs -sSf --output rustup.sh
- - sh rustup.sh -y --default-toolchain 1.24.1
+ - sh rustup.sh -y --default-toolchain 1.25.0
- $HOME/.cargo/bin/rustup target add i686-unknown-freebsd
amd64_test_script:
- . $HOME/.cargo/env
diff --git a/.travis.yml b/.travis.yml
index 7b0270de..a667201a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,71 +18,71 @@ matrix:
# week. Additionally they're moved to the front of the line to get them in
# the Travis OS X build queue first.
- env: TARGET="aarch64-apple-ios;armv7-apple-ios;armv7s-apple-ios;i386-apple-ios;x86_64-apple-ios" DISABLE_TESTS=1
- rust: 1.24.1
+ rust: 1.25.0
os: osx
# Mac builds
# These are also moved to be first because they wait in a long queue with
# Travis
- env: TARGET=i686-apple-darwin
- rust: 1.24.1
+ rust: 1.25.0
os: osx
- env: TARGET=x86_64-apple-darwin
- rust: 1.24.1
+ rust: 1.25.0
os: osx
# Android
- env: TARGET=aarch64-linux-android DISABLE_TESTS=1
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=arm-linux-androideabi DISABLE_TESTS=1
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=armv7-linux-androideabi DISABLE_TESTS=1
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=i686-linux-android DISABLE_TESTS=1
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=x86_64-linux-android DISABLE_TESTS=1
- rust: 1.24.1
+ rust: 1.25.0
# Linux
- env: TARGET=aarch64-unknown-linux-gnu
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=arm-unknown-linux-gnueabi
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=arm-unknown-linux-musleabi DISABLE_TESTS=1
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=armv7-unknown-linux-gnueabihf
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=i686-unknown-linux-gnu
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=i686-unknown-linux-musl
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=mips-unknown-linux-gnu
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=mips64-unknown-linux-gnuabi64
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=mips64el-unknown-linux-gnuabi64
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=mipsel-unknown-linux-gnu
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=powerpc-unknown-linux-gnu DISABLE_TESTS=1
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=powerpc64-unknown-linux-gnu
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=powerpc64le-unknown-linux-gnu
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=s390x-unknown-linux-gnu DISABLE_TESTS=1
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=x86_64-unknown-linux-gnu
- rust: 1.24.1
+ rust: 1.25.0
- env: TARGET=x86_64-unknown-linux-musl
- rust: 1.24.1
+ rust: 1.25.0
# *BSD
# FreeBSD i686 and x86_64 use Cirrus instead of Travis
# - env: TARGET=i686-unknown-freebsd DISABLE_TESTS=1
# - env: TARGET=x86_64-unknown-freebsd DISABLE_TESTS=1
- env: TARGET=x86_64-unknown-netbsd DISABLE_TESTS=1
- rust: 1.24.1
+ rust: 1.25.0
# Make sure stable is always working too
- env: TARGET=x86_64-unknown-linux-gnu
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3420681b..b3d7089e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,12 +7,25 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Added
- Added `MSG_WAITALL` to `MsgFlags` in `sys::socket`.
([#1079](https://github.com/nix-rust/nix/pull/1079))
+- Implemented `Clone`, `Copy`, `Debug`, `Eq`, `Hash`, and `PartialEq` for most
+ types that support them. ([#1035](https://github.com/nix-rust/nix/pull/1035))
+- Added `copy_file_range` wrapper
+ ([#1069](https://github.com/nix-rust/nix/pull/1069))
+- Add `mkdirat`.
+ ([#1084](https://github.com/nix-rust/nix/pull/1084))
### Changed
- Support for `ifaddrs` now present when building for Android.
([#1077](https://github.com/nix-rust/nix/pull/1077))
+- Minimum supported Rust version is now 1.25.0
+ ([#1035](https://github.com/nix-rust/nix/pull/1035))
+- Now functions `statfs()` and `fstatfs()` return result with `Statfs` wrapper
+ ([#928](https://github.com/nix-rust/nix/pull/928))
### Fixed
+- Enabled `sched_yield` for all nix hosts.
+ ([#1090](https://github.com/nix-rust/nix/pull/1090))
+
### Removed
## [0.14.1] - 2019-06-06
diff --git a/Cargo.toml b/Cargo.toml
index 9421cd70..b1af4605 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,7 +16,7 @@ exclude = [
]
[dependencies]
-libc = { git = "https://github.com/rust-lang/libc" }
+libc = { git = "https://github.com/rust-lang/libc", features = [ "extra_traits" ] }
bitflags = "1.0"
cfg-if = "0.1.2"
void = "1.0.2"
@@ -28,7 +28,7 @@ cc = "1"
bytes = "0.4.8"
lazy_static = "1.2"
rand = ">= 0.6, < 0.7"
-tempfile = "3.0.5"
+tempfile = ">= 3.0.5, < 3.0.9"
[target.'cfg(any(target_os = "android", target_os = "linux"))'.dev-dependencies]
caps = "0.3.1"
diff --git a/README.md b/README.md
index 23a20532..41ee98a5 100644
--- a/README.md
+++ b/README.md
@@ -44,8 +44,7 @@ limitations. Support for platforms is split into three tiers:
*do not* block the inclusion of new code. Testing may be run, but
failures in tests don't block the inclusion of new code.
-The following targets are all supported by nix on Rust 1.24.1 or newer (unless
-otherwise noted):
+The following targets are supported by `nix`:
Tier 1:
* aarch64-unknown-linux-gnu
@@ -84,6 +83,8 @@ Tier 2:
## Usage
+`nix` requires Rust 1.25.0 or newer.
+
To use `nix`, first add this to your `Cargo.toml`:
```toml
diff --git a/src/dir.rs b/src/dir.rs
index 814e9e0c..1820b533 100644
--- a/src/dir.rs
+++ b/src/dir.rs
@@ -3,7 +3,7 @@ use errno::Errno;
use fcntl::{self, OFlag};
use libc;
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
-use std::{ffi, fmt, ptr};
+use std::{ffi, ptr};
use sys;
#[cfg(target_os = "linux")]
@@ -25,9 +25,9 @@ use libc::{dirent, readdir_r};
/// * returns entries for `.` (current directory) and `..` (parent directory).
/// * returns entries' names as a `CStr` (no allocation or conversion beyond whatever libc
/// does).
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Dir(
- // This could be ptr::NonNull once nix requires Rust 1.25.
- *mut libc::DIR
+ ptr::NonNull<libc::DIR>
);
impl Dir {
@@ -59,7 +59,8 @@ impl Dir {
unsafe { libc::close(fd) };
return Err(e);
};
- Ok(Dir(d))
+ // Always guaranteed to be non-null by the previous check
+ Ok(Dir(ptr::NonNull::new(d).unwrap()))
}
/// Returns an iterator of `Result<Entry>` which rewinds when finished.
@@ -78,25 +79,17 @@ unsafe impl Send for Dir {}
impl AsRawFd for Dir {
fn as_raw_fd(&self) -> RawFd {
- unsafe { libc::dirfd(self.0) }
- }
-}
-
-impl fmt::Debug for Dir {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("Dir")
- .field("fd", &self.as_raw_fd())
- .finish()
+ unsafe { libc::dirfd(self.0.as_ptr()) }
}
}
impl Drop for Dir {
fn drop(&mut self) {
- unsafe { libc::closedir(self.0) };
+ unsafe { libc::closedir(self.0.as_ptr()) };
}
}
-#[derive(Debug)]
+#[derive(Debug, Eq, Hash, PartialEq)]
pub struct Iter<'d>(&'d mut Dir);
impl<'d> Iterator for Iter<'d> {
@@ -111,7 +104,7 @@ impl<'d> Iterator for Iter<'d> {
// Probably fine here too then.
let mut ent: Entry = Entry(::std::mem::uninitialized());
let mut result = ptr::null_mut();
- if let Err(e) = Errno::result(readdir_r((self.0).0, &mut ent.0, &mut result)) {
+ if let Err(e) = Errno::result(readdir_r((self.0).0.as_ptr(), &mut ent.0, &mut result)) {
return Some(Err(e));
}
if result == ptr::null_mut() {
@@ -125,17 +118,17 @@ impl<'d> Iterator for Iter<'d> {
impl<'d> Drop for Iter<'d> {
fn drop(&mut self) {
- unsafe { libc::rewinddir((self.0).0) }
+ unsafe { libc::rewinddir((self.0).0.as_ptr()) }
}
}
/// A directory entry, similar to `std::fs::DirEntry`.
///
/// Note that unlike the std version, this may represent the `.` or `..` entries.
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct Entry(dirent);
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum Type {
Fifo,
CharacterDevice,
@@ -198,13 +191,3 @@ impl Entry {
}
}
}
-
-impl fmt::Debug for Entry {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("Entry")
- .field("ino", &self.ino())
- .field("file_name", &self.file_name())
- .field("file_type", &self.file_type())
- .finish()
- }
-}
diff --git a/src/fcntl.rs b/src/fcntl.rs
index 40f4cf94..3d932a53 100644
--- a/src/fcntl.rs
+++ b/src/fcntl.rs
@@ -8,6 +8,8 @@ use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
#[cfg(any(target_os = "android", target_os = "linux"))]
+use std::ptr; // For splice and copy_file_range
+#[cfg(any(target_os = "android", target_os = "linux"))]
use sys::uio::IoVec; // For vmsplice
libc_bitflags!{
@@ -214,7 +216,7 @@ libc_bitflags!(
}
);
-#[allow(missing_debug_implementations)]
+#[derive(Debug, Eq, Hash, PartialEq)]
pub enum FcntlArg<'a> {
F_DUPFD(RawFd),
F_DUPFD_CLOEXEC(RawFd),
@@ -277,8 +279,7 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> {
Errno::result(res)
}
-#[derive(Clone, Copy)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum FlockArg {
LockShared,
LockExclusive,
@@ -326,15 +327,70 @@ libc_bitflags! {
}
}
+/// Copy a range of data from one file to another
+///
+/// The `copy_file_range` system call performs an in-kernel copy between
+/// file descriptors `fd_in` and `fd_out` without the additional cost of
+/// transferring data from the kernel to user space and then back into the
+/// kernel. It copies up to `len` bytes of data from file descriptor `fd_in` to
+/// file descriptor `fd_out`, overwriting any data that exists within the
+/// requested range of the target file.
+///
+/// If the `off_in` and/or `off_out` arguments are used, the values
+/// will be mutated to reflect the new position within the file after
+/// copying. If they are not used, the relevant filedescriptors will be seeked
+/// to the new position.
+///
+/// On successful completion the number of bytes actually copied will be
+/// returned.
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub fn copy_file_range(
+ fd_in: RawFd,
+ off_in: Option<&mut libc::loff_t>,
+ fd_out: RawFd,
+ off_out: Option<&mut libc::loff_t>,
+ len: usize,
+) -> Result<usize> {
+ let off_in = off_in
+ .map(|offset| offset as *mut libc::loff_t)
+ .unwrap_or(ptr::null_mut());
+ let off_out = off_out
+ .map(|offset| offset as *mut libc::loff_t)
+ .unwrap_or(ptr::null_mut());
+
+ let ret = unsafe {
+ libc::syscall(
+ libc::SYS_copy_file_range,
+ fd_in,
+ off_in,
+ fd_out,
+ off_out,
+ len,
+ 0,
+ )
+ };
+ Errno::result(ret).map(|r| r as usize)
+}
+
#[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn splice(fd_in: RawFd, off_in: Option<&mut libc::loff_t>,
- fd_out: RawFd, off_out: Option<&mut libc::loff_t>,
- len: usize, flags: SpliceFFlags) -> Result<usize> {
- use std::ptr;
- let off_in = off_in.map(|offset| offset as *mut _).unwrap_or(ptr::null_mut());
- let off_out = off_out.map(|offset| offset as *mut _).unwrap_or(ptr::null_mut());
-
- let ret = unsafe { libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits()) };
+pub fn splice(
+ fd_in: RawFd,
+ off_in: Option<&mut libc::loff_t>,
+ fd_out: RawFd,
+ off_out: Option<&mut libc::loff_t>,
+ len: usize,
+ flags: SpliceFFlags,
+) -> Result<usize> {
+ let off_in = off_in
+ .map(|offset| offset as *mut libc::loff_t)
+ .unwrap_or(ptr::null_mut());
+ let off_out = off_out
+ .map(|offset| offset as *mut libc::loff_t)
+ .unwrap_or(ptr::null_mut());
+
+ let ret = unsafe {
+ libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits())
+ };
Errno::result(ret).map(|r| r as usize)
}
diff --git a/src/ifaddrs.rs b/src/ifaddrs.rs
index c9790773..12b59bcc 100644
--- a/src/ifaddrs.rs
+++ b/src/ifaddrs.rs
@@ -15,7 +15,7 @@ use sys::socket::SockAddr;
use net::if_::*;
/// Describes a single address for an interface as returned by `getifaddrs`.
-#[derive(Clone, Eq, Hash, PartialEq, Debug)]
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct InterfaceAddress {
/// Name of the network interface
pub interface_name: String,
diff --git a/src/lib.rs b/src/lib.rs
index 7ef91f4e..22577cfe 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -62,8 +62,6 @@ pub mod net;
pub mod poll;
#[deny(missing_docs)]
pub mod pty;
-#[cfg(any(target_os = "android",
- target_os = "linux"))]
pub mod sched;
pub mod sys;
// This can be implemented for other platforms as soon as libc
@@ -98,7 +96,7 @@ pub type Result<T> = result::Result<T, Error>;
/// error has a corresponding errno (usually the one from the
/// underlying OS) to which it can be mapped in addition to
/// implementing other common traits.
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Error {
Sys(Errno),
InvalidPath,
diff --git a/src/mqueue.rs b/src/mqueue.rs
index 87be6532..b958b71c 100644
--- a/src/mqueue.rs
+++ b/src/mqueue.rs
@@ -29,22 +29,11 @@ libc_bitflags!{
}
#[repr(C)]
-#[derive(Clone, Copy)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MqAttr {
mq_attr: libc::mq_attr,
}
-impl PartialEq<MqAttr> for MqAttr {
- fn eq(&self, other: &MqAttr) -> bool {
- let self_attr = self.mq_attr;
- let other_attr = other.mq_attr;
- self_attr.mq_flags == other_attr.mq_flags && self_attr.mq_maxmsg == other_attr.mq_maxmsg &&
- self_attr.mq_msgsize == other_attr.mq_msgsize &&
- self_attr.mq_curmsgs == other_attr.mq_curmsgs
- }
-}
-
impl MqAttr {
pub fn new(mq_flags: c_long,
mq_maxmsg: c_long,
diff --git a/src/poll.rs b/src/poll.rs
index 160b5bc6..c603611e 100644
--- a/src/poll.rs
+++ b/src/poll.rs
@@ -4,7 +4,6 @@ use sys::time::TimeSpec;
#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
use sys::signal::SigSet;
use std::os::unix::io::RawFd;
-use std::fmt;
use libc;
use Result;
@@ -19,7 +18,7 @@ use errno::Errno;
/// After a call to `poll` or `ppoll`, the events that occured can be
/// retrieved by calling [`revents()`](#method.revents) on the `PollFd`.
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct PollFd {
pollfd: libc::pollfd,
}
@@ -43,23 +42,6 @@ impl PollFd {
}
}
-impl fmt::Debug for PollFd {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let pfd = self.pollfd;
- let mut ds = f.debug_struct("PollFd");
- ds.field("fd", &pfd.fd);
- match PollFlags::from_bits(pfd.events) {
- None => ds.field("events", &pfd.events),
- Some(ef) => ds.field("events", &ef),
- };
- match PollFlags::from_bits(pfd.revents) {
- None => ds.field("revents", &pfd.revents),
- Some(ef) => ds.field("revents", &ef),
- };
- ds.finish()
- }
-}
-
libc_bitflags! {
/// These flags define the different events that can be monitored by `poll` and `ppoll`
pub struct PollFlags: libc::c_short {
diff --git a/src/pty.rs b/src/pty.rs
index 41bd51b6..db012d81 100644
--- a/src/pty.rs
+++ b/src/pty.rs
@@ -18,8 +18,7 @@ use errno::Errno;
///
/// This is returned by `openpty`. Note that this type does *not* implement `Drop`, so the user
/// must manually close the file descriptors.
-#[derive(Clone, Copy)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct OpenptyResult {
/// The master port in a virtual pty pair
pub master: RawFd,
@@ -45,7 +44,7 @@ pub struct ForkptyResult {
/// While this datatype is a thin wrapper around `RawFd`, it enforces that the available PTY
/// functions are given the correct file descriptor. Additionally this type implements `Drop`,
/// so that when it's consumed or goes out of scope, it's automatically cleaned-up.
-#[derive(Debug)]
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct PtyMaster(RawFd);
impl AsRawFd for PtyMaster {
diff --git a/src/sched.rs b/src/sched.rs
index d381cbb5..064fc29d 100644
--- a/src/sched.rs
+++ b/src/sched.rs
@@ -1,132 +1,147 @@
-use std::mem;
-use std::os::unix::io::RawFd;
-use std::option::Option;
-use libc::{self, c_int, c_void};
-use {Error, Result};
-use errno::Errno;
-use ::unistd::Pid;
-
-// For some functions taking with a parameter of type CloneFlags,
-// only a subset of these flags have an effect.
-libc_bitflags!{
- pub struct CloneFlags: c_int {
- CLONE_VM;
- CLONE_FS;
- CLONE_FILES;
- CLONE_SIGHAND;
- CLONE_PTRACE;
- CLONE_VFORK;
- CLONE_PARENT;
- CLONE_THREAD;
- CLONE_NEWNS;
- CLONE_SYSVSEM;
- CLONE_SETTLS;
- CLONE_PARENT_SETTID;
- CLONE_CHILD_CLEARTID;
- CLONE_DETACHED;
- CLONE_UNTRACED;
- CLONE_CHILD_SETTID;
- CLONE_NEWCGROUP;
- CLONE_NEWUTS;
- CLONE_NEWIPC;
- CLONE_NEWUSER;
- CLONE_NEWPID;
- CLONE_NEWNET;
- CLONE_IO;
+use libc;
+use {Errno, Result};
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub use self::sched_linux_like::*;
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+mod sched_linux_like {
+ use errno::Errno;
+ use libc::{self, c_int, c_void};
+ use std::mem;
+ use std::option::Option;
+ use std::os::unix::io::RawFd;
+ use unistd::Pid;
+ use {Error, Result};
+
+ // For some functions taking with a parameter of type CloneFlags,
+ // only a subset of these flags have an effect.
+ libc_bitflags! {
+ pub struct CloneFlags: c_int {
+ CLONE_VM;
+ CLONE_FS;
+ CLONE_FILES;
+ CLONE_SIGHAND;
+ CLONE_PTRACE;
+ CLONE_VFORK;
+ CLONE_PARENT;
+ CLONE_THREAD;
+ CLONE_NEWNS;
+ CLONE_SYSVSEM;
+ CLONE_SETTLS;
+ CLONE_PARENT_SETTID;
+ CLONE_CHILD_CLEARTID;
+ CLONE_DETACHED;
+ CLONE_UNTRACED;
+ CLONE_CHILD_SETTID;
+ CLONE_NEWCGROUP;
+ CLONE_NEWUTS;
+ CLONE_NEWIPC;
+ CLONE_NEWUSER;
+ CLONE_NEWPID;
+ CLONE_NEWNET;
+ CLONE_IO;
+ }
}
-}
-pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;
-
-#[repr(C)]
-#[derive(Clone, Copy)]
-#[allow(missing_debug_implementations)]
-pub struct CpuSet {
- cpu_set: libc::cpu_set_t,
-}
+ pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;
-impl CpuSet {
- pub fn new() -> CpuSet {
- CpuSet { cpu_set: unsafe { mem::zeroed() } }
+ #[repr(C)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ pub struct CpuSet {
+ cpu_set: libc::cpu_set_t,
}
- pub fn is_set(&self, field: usize) -> Result<bool> {
- if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
- Err(Error::Sys(Errno::EINVAL))
- } else {
- Ok(unsafe { libc::CPU_ISSET(field, &self.cpu_set) })
+ impl CpuSet {
+ pub fn new() -> CpuSet {
+ CpuSet {
+ cpu_set: unsafe { mem::zeroed() },
+ }
}
- }
- pub fn set(&mut self, field: usize) -> Result<()> {
- if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
- Err(Error::Sys(Errno::EINVAL))
- } else {
- Ok(unsafe { libc::CPU_SET(field, &mut self.cpu_set) })
+ pub fn is_set(&self, field: usize) -> Result<bool> {
+ if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
+ Err(Error::Sys(Errno::EINVAL))
+ } else {
+ Ok(unsafe { libc::CPU_ISSET(field, &self.cpu_set) })
+ }
}
- }
- pub fn unset(&mut self, field: usize) -> Result<()> {
- if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
- Err(Error::Sys(Errno::EINVAL))
- } else {
- Ok(unsafe { libc::CPU_CLR(field, &mut self.cpu_set) })
+ pub fn set(&mut self, field: usize) -> Result<()> {
+ if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
+ Err(Error::Sys(Errno::EINVAL))
+ } else {
+ Ok(unsafe { libc::CPU_SET(field, &mut self.cpu_set) })
+ }
}
- }
-}
-pub fn sched_setaffinity(pid: Pid, cpuset: &CpuSet) -> Result<()> {
- let res = unsafe {
- libc::sched_setaffinity(pid.into(),
- mem::size_of::<CpuSet>() as libc::size_t,
- &cpuset.cpu_set)
- };
+ pub fn unset(&mut self, field: usize) -> Result<()> {
+ if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
+ Err(Error::Sys(Errno::EINVAL))
+ } else {
+ Ok(unsafe { libc::CPU_CLR(field, &mut self.cpu_set) })
+ }
+ }
+ }
- Errno::result(res).map(drop)
-}
+ pub fn sched_setaffinity(pid: Pid, cpuset: &CpuSet) -> Result<()> {
+ let res = unsafe {
+ libc::sched_setaffinity(
+ pid.into(),
+ mem::size_of::<CpuSet>() as libc::size_t,
+ &cpuset.cpu_set,
+ )
+ };
-/// Explicitly yield the processor to other threads.
-///
-/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_yield.html)
-pub fn sched_yield() -> Result<()> {
- let res = unsafe {
- libc::sched_yield()
- };
+ Errno::result(res).map(drop)
+ }
- Errno::result(res).map(drop)
-}
+ pub fn clone(
+ mut cb: CloneCb,
+ stack: &mut [u8],
+ flags: CloneFlags,
+ signal: Option<c_int>,
+ ) -> Result<Pid> {
+ extern "C" fn callback(data: *mut CloneCb) -> c_int {
+ let cb: &mut CloneCb = unsafe { &mut *data };
+ (*cb)() as c_int
+ }
-pub fn clone(mut cb: CloneCb,
- stack: &mut [u8],
- flags: CloneFlags,
- signal: Option<c_int>)
- -> Result<Pid> {
- extern "C" fn callback(data: *mut CloneCb) -> c_int {
- let cb: &mut CloneCb = unsafe { &mut *data };
- (*cb)() as c_int
+ let res = unsafe {
+ let combined = flags.bits() | signal.unwrap_or(0);
+ let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
+ let ptr_aligned = ptr.offset((ptr as usize % 16) as isize * -1);
+ libc::clone(
+ mem::transmute(
+ callback as extern "C" fn(*mut Box<::std::ops::FnMut() -> isize>) -> i32,
+ ),
+ ptr_aligned as *mut c_void,
+ combined,
+ &mut cb as *mut _ as *mut c_void,
+ )
+ };
+
+ Errno::result(res).map(Pid::from_raw)
}
- let res = unsafe {
- let combined = flags.bits() | signal.unwrap_or(0);
- let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
- let ptr_aligned = ptr.offset((ptr as usize % 16) as isize * -1);
- libc::clone(mem::transmute(callback as extern "C" fn(*mut Box<::std::ops::FnMut() -> isize>) -> i32),
- ptr_aligned as *mut c_void,
- combined,
- &mut cb as *mut _ as *mut c_void)
- };
-
- Errno::result(res).map(Pid::from_raw)
-}
+ pub fn unshare(flags: CloneFlags) -> Result<()> {
+ let res = unsafe { libc::unshare(flags.bits()) };
+
+ Errno::result(res).map(drop)
+ }
-pub fn unshare(flags: CloneFlags) -> Result<()> {
- let res = unsafe { libc::unshare(flags.bits()) };
+ pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
+ let res = unsafe { libc::setns(fd, nstype.bits()) };
- Errno::result(res).map(drop)
+ Errno::result(res).map(drop)
+ }
}
-pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
- let res = unsafe { libc::setns(fd, nstype.bits()) };
+/// Explicitly yield the processor to other threads.
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_yield.html)
+pub fn sched_yield() -> Result<()> {
+ let res = unsafe { libc::sched_yield() };
Errno::result(res).map(drop)
}
diff --git a/src/sys/aio.rs b/src/sys/aio.rs
index c54c2e31..40fa4e15 100644
--- a/src/sys/aio.rs
+++ b/src/sys/aio.rs
@@ -80,7 +80,7 @@ libc_enum! {
/// Return values for [`AioCb::cancel`](struct.AioCb.html#method.cancel) and
/// [`aio_cancel_all`](fn.aio_cancel_all.html)
#[repr(i32)]
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum AioCancelStat {
/// All outstanding requests were canceled
AioCanceled = libc::AIO_CANCELED,
@@ -1021,13 +1021,7 @@ pub fn aio_suspend(list: &[&AioCb], timeout: Option<TimeSpec>) -> Result<()> {
impl<'a> Debug for AioCb<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("AioCb")
- .field("aio_fildes", &self.aiocb.aio_fildes)
- .field("aio_offset", &self.aiocb.aio_offset)
- .field("aio_buf", &self.aiocb.aio_buf)
- .field("aio_nbytes", &self.aiocb.aio_nbytes)
- .field("aio_lio_opcode", &self.aiocb.aio_lio_opcode)
- .field("aio_reqprio", &self.aiocb.aio_reqprio)
- .field("aio_sigevent", &SigEvent::from(&self.aiocb.aio_sigevent))
+ .field("aiocb", &self.aiocb)
.field("mutable", &self.mutable)
.field("in_progress", &self.in_progress)
.finish()
diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs
index 3ed1dd72..fef6f4e3 100644
--- a/src/sys/epoll.rs
+++ b/src/sys/epoll.rs
@@ -42,8 +42,7 @@ libc_bitflags!{
}
}
-#[allow(missing_debug_implementations)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(C)]
pub struct EpollEvent {
event: libc::epoll_event,
diff --git a/src/sys/event.rs b/src/sys/event.rs
index f1eaa0d1..8cd7372f 100644
--- a/src/sys/event.rs
+++ b/src/sys/event.rs
@@ -12,9 +12,8 @@ use std::ptr;
use std::mem;
// Redefine kevent in terms of programmer-friendly enums and bitfields.
-#[derive(Clone, Copy)]
#[repr(C)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct KEvent {
kevent: libc::kevent,
}
diff --git a/src/sys/mod.rs b/src/sys/mod.rs
index 88c7251d..d3c2f92b 100644
--- a/src/sys/mod.rs
+++ b/src/sys/mod.rs
@@ -71,7 +71,14 @@ pub mod socket;
pub mod stat;
-#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
+#[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+))]
pub mod statfs;
pub mod statvfs;
diff --git a/src/sys/quota.rs b/src/sys/quota.rs
index 14c04629..8946fca2 100644
--- a/src/sys/quota.rs
+++ b/src/sys/quota.rs
@@ -96,8 +96,7 @@ libc_bitflags!(
/// Wrapper type for `if_dqblk`
// FIXME: Change to repr(transparent)
#[repr(C)]
-#[derive(Clone, Copy)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Dqblk(libc::dqblk);
impl Default for Dqblk {
diff --git a/src/sys/select.rs b/src/sys/select.rs
index 95b6b148..1b518e29 100644
--- a/src/sys/select.rs
+++ b/src/sys/select.rs
@@ -11,8 +11,7 @@ pub use libc::FD_SETSIZE;
// FIXME: Change to repr(transparent) once it's stable
#[repr(C)]
-#[derive(Clone, Copy)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct FdSet(libc::fd_set);
impl FdSet {
diff --git a/src/sys/sendfile.rs b/src/sys/sendfile.rs
index 1190518d..a47d8962 100644
--- a/src/sys/sendfile.rs
+++ b/src/sys/sendfile.rs
@@ -38,7 +38,7 @@ cfg_if! {
target_os = "macos"))] {
use sys::uio::IoVec;
- #[allow(missing_debug_implementations)]
+ #[derive(Clone, Debug, Eq, Hash, PartialEq)]
struct SendfileHeaderTrailer<'a>(
libc::sf_hdtr,
Option<Vec<IoVec<&'a [u8]>>>,
diff --git a/src/sys/signal.rs b/src/sys/signal.rs
index a49b273f..1013a77f 100644
--- a/src/sys/signal.rs
+++ b/src/sys/signal.rs
@@ -265,8 +265,7 @@ const SIGNALS: [Signal; 31] = [
pub const NSIG: libc::c_int = 32;
-#[derive(Clone, Copy)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SignalIterator {
next: usize,
}
@@ -328,8 +327,7 @@ libc_enum! {
}
}
-#[derive(Clone, Copy)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SigSet {
sigset: libc::sigset_t
}
@@ -427,7 +425,7 @@ impl AsRef<libc::sigset_t> for SigSet {
/// A signal handler.
#[allow(unknown_lints)]
-#[derive(Debug, Clone, Copy, PartialEq)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SigHandler {
/// Default signal handling.
SigDfl,
@@ -441,8 +439,7 @@ pub enum SigHandler {
}
/// Action to take on receipt of a signal. Corresponds to `sigaction`.
-#[derive(Clone, Copy)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SigAction {
sigaction: libc::sigaction
}
@@ -683,7 +680,7 @@ pub type type_of_thread_id = libc::pid_t;
// sigval is actually a union of a int and a void*. But it's never really used
// as a pointer, because neither libc nor the kernel ever dereference it. nix
// therefore presents it as an intptr_t, which is how kevent uses it.
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SigevNotify {
/// No notification will be delivered
SigevNone,
@@ -710,7 +707,6 @@ mod sigevent {
use libc;
use std::mem;
use std::ptr;
- use std::fmt::{self, Debug};
use super::SigevNotify;
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
use super::type_of_thread_id;
@@ -718,7 +714,7 @@ mod sigevent {
/// Used to request asynchronous notification of the completion of certain
/// events, such as POSIX AIO and timers.
#[repr(C)]
- #[derive(Clone, Copy)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SigEvent {
sigevent: libc::sigevent
}
@@ -788,28 +784,6 @@ mod sigevent {
}
}
- impl Debug for SigEvent {
- #[cfg(any(target_os = "freebsd", target_os = "linux"))]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- fmt.debug_struct("SigEvent")
- .field("sigev_notify", &self.sigevent.sigev_notify)
- .field("sigev_signo", &self.sigevent.sigev_signo)
- .field("sigev_value", &self.sigevent.sigev_value.sival_ptr)
- .field("sigev_notify_thread_id",
- &self.sigevent.sigev_notify_thread_id)
- .finish()
- }
-
- #[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- fmt.debug_struct("SigEvent")
- .field("sigev_notify", &self.sigevent.sigev_notify)
- .field("sigev_signo", &self.sigevent.sigev_signo)
- .field("sigev_value", &self.sigevent.sigev_value.sival_ptr)
- .finish()
- }
- }
-
impl<'a> From<&'a libc::sigevent> for SigEvent {
fn from(sigevent: &libc::sigevent) -> Self {
SigEvent{ sigevent: *sigevent }
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs
index fc24bd79..e6c5f8ae 100644
--- a/src/sys/socket/addr.rs
+++ b/src/sys/socket/addr.rs
@@ -2,8 +2,9 @@ use super::sa_family_t;
use {Error, Result, NixPath};
use errno::Errno;
use libc;
-use std::{fmt, hash, mem, net, ptr, slice};
+use std::{fmt, mem, net, ptr, slice};
use std::ffi::OsStr;
+use std::hash::{Hash, Hasher};
use std::path::Path;
use std::os::unix::ffi::OsStrExt;
#[cfg(any(target_os = "android", target_os = "linux"))]
@@ -245,7 +246,7 @@ impl AddressFamily {
}
}
-#[derive(Copy)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum InetAddr {
V4(libc::sockaddr_in),
V6(libc::sockaddr_in6),
@@ -331,52 +332,6 @@ impl InetAddr {
}
}
-impl PartialEq for InetAddr {
- fn eq(&self, other: &InetAddr) -> bool {
- match (*self, *other) {
- (InetAddr::V4(ref a), InetAddr::V4(ref b)) => {
- a.sin_port == b.sin_port &&
- a.sin_addr.s_addr == b.sin_addr.s_addr
- }
- (InetAddr::V6(ref a), InetAddr::V6(ref b)) => {
- a.sin6_port == b.sin6_port &&
- a.sin6_addr.s6_addr == b.sin6_addr.s6_addr &&
- a.sin6_flowinfo == b.sin6_flowinfo &&
- a.sin6_scope_id == b.sin6_scope_id
- }
- _ => false,
- }
- }
-}
-
-impl Eq for InetAddr {
-}
-
-impl hash::Hash for InetAddr {
- fn hash<H: hash::Hasher>(&self, s: &mut H) {
- match *self {
- InetAddr::V4(ref a) => {
- ( a.sin_family,
- a.sin_port,
- a.sin_addr.s_addr ).hash(s)
- }
- InetAddr::V6(ref a) => {
- ( a.sin6_family,
- a.sin6_port,
- &a.sin6_addr.s6_addr,
- a.sin6_flowinfo,
- a.sin6_scope_id ).hash(s)
- }
- }
- }
-}
-
-impl Clone for InetAddr {
- fn clone(&self) -> InetAddr {
- *self
- }
-}
-
impl fmt::Display for InetAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
@@ -386,18 +341,12 @@ impl fmt::Display for InetAddr {
}
}
-impl fmt::Debug for InetAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(self, f)
- }
-}
-
/*
*
* ===== IpAddr =====
*
*/
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum IpAddr {
V4(Ipv4Addr),
V6(Ipv6Addr),
@@ -442,19 +391,13 @@ impl fmt::Display for IpAddr {
}
}
-impl fmt::Debug for IpAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(self, f)
- }
-}
-
/*
*
* ===== Ipv4Addr =====
*
*/
-#[derive(Copy)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Ipv4Addr(pub libc::in_addr);
impl Ipv4Addr {
@@ -487,28 +430,6 @@ impl Ipv4Addr {
}
}
-impl PartialEq for Ipv4Addr {
- fn eq(&self, other: &Ipv4Addr) -> bool {
- self.0.s_addr == other.0.s_addr
- }
-}
-
-impl Eq for Ipv4Addr {
-}
-
-impl hash::Hash for Ipv4Addr {
- fn hash<H: hash::Hasher>(&self, s: &mut H) {
- let saddr = self.0.s_addr;
- saddr.hash(s)
- }
-}
-
-impl Clone for Ipv4Addr {
- fn clone(&self) -> Ipv4Addr {
- *self
- }
-}
-
impl fmt::Display for Ipv4Addr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let octets = self.octets();
@@ -516,19 +437,13 @@ impl fmt::Display for Ipv4Addr {
}
}
-impl fmt::Debug for Ipv4Addr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(self, f)
- }
-}
-
/*
*
* ===== Ipv6Addr =====
*
*/
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Ipv6Addr(pub libc::in6_addr);
// Note that IPv6 addresses are stored in big endian order on all architectures.
@@ -576,18 +491,6 @@ impl fmt::Display for Ipv6Addr {
}
}
-impl fmt::Debug for Ipv6Addr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(self, f)
- }
-}
-
-/*
- *
- * ===== UnixAddr =====
- *
- */
-
/// A wrapper around `sockaddr_un`.
///
/// This also tracks the length of `sun_path` address (excluding
@@ -596,7 +499,7 @@ impl fmt::Debug for Ipv6Addr {
/// does not require that `sun_len` include the terminating null even for normal
/// sockets. Note that the actual sockaddr length is greater by
/// `offset_of!(libc::sockaddr_un, sun_path)`
-#[derive(Copy)]
+#[derive(Clone, Copy, Debug)]
pub struct UnixAddr(pub libc::sockaddr_un, pub usize);
impl UnixAddr {
@@ -648,7 +551,7 @@ impl UnixAddr {
ret.sun_path.as_mut_ptr().offset(1) as *mut u8,
path.len());
- Ok(UnixAddr(ret, path.len() + 1))
+ Ok(UnixAddr(ret, ret.sun_path.len()))
}
}
@@ -688,27 +591,6 @@ impl UnixAddr {
}
}
-impl PartialEq for UnixAddr {
- fn eq(&self, other: &UnixAddr) -> bool {
- self.sun_path() == other.sun_path()
- }
-}
-
-impl Eq for UnixAddr {
-}
-
-impl hash::Hash for UnixAddr {
- fn hash<H: hash::Hasher>(&self, s: &mut H) {
- ( self.0.sun_family, self.sun_path() ).hash(s)
- }
-}
-
-impl Clone for UnixAddr {
- fn clone(&self) -> UnixAddr {
- *self
- }
-}
-
impl fmt::Display for UnixAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.1 == 0 {
@@ -722,20 +604,22 @@ impl fmt::Display for UnixAddr {
}
}
-impl fmt::Debug for UnixAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(self, f)
+impl PartialEq for UnixAddr {
+ fn eq(&self, other: &UnixAddr) -> bool {
+ self.sun_path() == other.sun_path()
}
}
-/*
- *
- * ===== Sock addr =====
- *
- */
+impl Eq for UnixAddr {}
+
+impl Hash for UnixAddr {
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ ( self.0.sun_family, self.sun_path() ).hash(s)
+ }
+}
/// Represents a socket address
-#[derive(Copy, Debug)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SockAddr {
Inet(InetAddr),
Unix(UnixAddr),
@@ -883,68 +767,6 @@ impl SockAddr {
}
}
-impl PartialEq for SockAddr {
- fn eq(&self, other: &SockAddr) -> bool {
- match (*self, *other) {
- (SockAddr::Inet(ref a), SockAddr::Inet(ref b)) => {
- a == b
- }
- (SockAddr::Unix(ref a), SockAddr::Unix(ref b)) => {
- a == b
- }
- #[cfg(any(target_os = "android", target_os = "linux"))]
- (SockAddr::Netlink(ref a), SockAddr::Netlink(ref b)) => {
- a == b
- }
- #[cfg(any(target_os = "android",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "ios",
- target_os = "linux",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "openbsd"))]
- (SockAddr::Link(ref a), SockAddr::Link(ref b)) => {
- a == b
- }
- _ => false,
- }
- }
-}
-
-impl Eq for SockAddr {
-}
-
-impl hash::Hash for SockAddr {
- fn hash<H: hash::Hasher>(&self, s: &mut H) {
- match *self {
- SockAddr::Inet(ref a) => a.hash(s),
- SockAddr::Unix(ref a) => a.hash(s),
- #[cfg(any(target_os = "android", target_os = "linux"))]
- SockAddr::Netlink(ref a) => a.hash(s),
- #[cfg(any(target_os = "android", target_os = "linux"))]
- SockAddr::Alg(ref a) => a.hash(s),
- #[cfg(any(target_os = "ios", target_os = "macos"))]
- SockAddr::SysControl(ref a) => a.hash(s),
- #[cfg(any(target_os = "android",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "ios",
- target_os = "linux",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "openbsd"))]
- SockAddr::Link(ref ether_addr) => ether_addr.hash(s)
- }
- }
-}
-
-impl Clone for SockAddr {
- fn clone(&self) -> SockAddr {
- *self
- }
-}
-
impl fmt::Display for SockAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
@@ -974,30 +796,10 @@ pub mod netlink {
use ::sys::socket::addr::AddressFamily;
use libc::{sa_family_t, sockaddr_nl};
use std::{fmt, mem};
- use std::hash::{Hash, Hasher};
- #[derive(Copy, Clone)]
+ #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct NetlinkAddr(pub sockaddr_nl);
- // , PartialEq, Eq, Debug, Hash
- impl PartialEq for NetlinkAddr {
- fn eq(&self, other: &Self) -> bool {
- let (inner, other) = (self.0, other.0);
- (inner.nl_family, inner.nl_pid, inner.nl_groups) ==
- (other.nl_family, other.nl_pid, other.nl_groups)
- }
- }
-
- impl Eq for NetlinkAddr {}
-
- impl Hash for NetlinkAddr {
- fn hash<H: Hasher>(&self, s: &mut H) {
- let inner = self.0;
- (inner.nl_family, inner.nl_pid, inner.nl_groups).hash(s);
- }
- }
-
-
impl NetlinkAddr {
pub fn new(pid: u32, groups: u32) -> NetlinkAddr {
let mut addr: sockaddr_nl = unsafe { mem::zeroed() };
@@ -1022,12 +824,6 @@ pub mod netlink {
write!(f, "pid: {} groups: {}", self.pid(), self.groups())
}
}
-
- impl fmt::Debug for NetlinkAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(self, f)
- }
- }
}
#[cfg(any(target_os = "android", target_os = "linux"))]
@@ -1098,11 +894,13 @@ pub mod sys_control {
use ::sys::socket::addr::AddressFamily;
use libc::{self, c_uchar};
use std::{fmt, mem};
- use std::hash::{Hash, Hasher};
use std::os::unix::io::RawFd;
use {Errno, Error, Result};
+ // FIXME: Move type into `libc`
#[repr(C)]
+ #[derive(Clone, Copy)]
+ #[allow(missing_debug_implementations)]
pub struct ctl_ioc_info {
pub ctl_id: u32,
pub ctl_name: [c_uchar; MAX_KCTL_NAME],
@@ -1114,28 +912,10 @@ pub mod sys_control {
ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info);
- #[derive(Copy, Clone)]
#[repr(C)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SysControlAddr(pub libc::sockaddr_ctl);
- impl PartialEq for SysControlAddr {
- fn eq(&self, other: &Self) -> bool {
- let (inner, other) = (self.0, other.0);
- (inner.sc_id, inner.sc_unit) ==
- (other.sc_id, other.sc_unit)
- }
- }
-
- impl Eq for SysControlAddr {}
-
- impl Hash for SysControlAddr {
- fn hash<H: Hasher>(&self, s: &mut H) {
- let inner = self.0;
- (inner.sc_id, inner.sc_unit).hash(s);
- }
- }
-
-
impl SysControlAddr {
pub fn new(id: u32, unit: u32) -> SysControlAddr {
let addr = libc::sockaddr_ctl {
@@ -1178,27 +958,15 @@ pub mod sys_control {
fmt::Debug::fmt(self, f)
}
}
-
- impl fmt::Debug for SysControlAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("SysControlAddr")
- .field("sc_len", &self.0.sc_len)
- .field("sc_family", &self.0.sc_family)
- .field("ss_sysaddr", &self.0.ss_sysaddr)
- .field("sc_id", &self.0.sc_id)
- .field("sc_unit", &self.0.sc_unit)
- .finish()
- }
- }
}
#[cfg(any(target_os = "android", target_os = "linux"))]
mod datalink {
- use super::{libc, hash, fmt, AddressFamily};
+ use super::{libc, fmt, AddressFamily};
/// Hardware Address
- #[derive(Clone, Copy)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct LinkAddr(pub libc::sockaddr_ll);
impl LinkAddr {
@@ -1246,26 +1014,6 @@ mod datalink {
}
}
- impl Eq for LinkAddr {}
-
- impl PartialEq for LinkAddr {
- fn eq(&self, other: &Self) -> bool {
- let (a, b) = (self.0, other.0);
- (a.sll_family, a.sll_protocol, a.sll_ifindex, a.sll_hatype,
- a.sll_pkttype, a.sll_halen, a.sll_addr) ==
- (b.sll_family, b.sll_protocol, b.sll_ifindex, b.sll_hatype,
- b.sll_pkttype, b.sll_halen, b.sll_addr)
- }
- }
-
- impl hash::Hash for LinkAddr {
- fn hash<H: hash::Hasher>(&self, s: &mut H) {
- let a = self.0;
- (a.sll_family, a.sll_protocol, a.sll_ifindex, a.sll_hatype,
- a.sll_pkttype, a.sll_halen, a.sll_addr).hash(s);
- }
- }
-
impl fmt::Display for LinkAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let addr = self.addr();
@@ -1278,12 +1026,6 @@ mod datalink {
addr[5])
}
}
-
- impl fmt::Debug for LinkAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(self, f)
- }
- }
}
#[cfg(any(target_os = "dragonfly",
@@ -1293,10 +1035,10 @@ mod datalink {
target_os = "netbsd",
target_os = "openbsd"))]
mod datalink {
- use super::{libc, hash, fmt, AddressFamily};
+ use super::{libc, fmt, AddressFamily};
/// Hardware Address
- #[derive(Clone, Copy)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct LinkAddr(pub libc::sockaddr_dl);
impl LinkAddr {
@@ -1368,52 +1110,6 @@ mod datalink {
}
}
- impl Eq for LinkAddr {}
-
- impl PartialEq for LinkAddr {
- #[cfg(any(target_os = "freebsd",
- target_os = "ios",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "openbsd"))]
- fn eq(&self, other: &Self) -> bool {
- let (a, b) = (self.0, other.0);
- (a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
- a.sdl_nlen, a.sdl_alen, a.sdl_slen, &a.sdl_data[..]) ==
- (b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type,
- b.sdl_nlen, b.sdl_alen, b.sdl_slen, &b.sdl_data[..])
- }
-
- #[cfg(target_os = "dragonfly")]
- fn eq(&self, other: &Self) -> bool {
- let (a, b) = (self.0, other.0);
- (a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type, a.sdl_nlen,
- a.sdl_alen, a.sdl_slen, a.sdl_data, a.sdl_rcf, a.sdl_route) ==
- (b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type, b.sdl_nlen,
- b.sdl_alen, b.sdl_slen, b.sdl_data, b.sdl_rcf, b.sdl_route)
- }
- }
-
- impl hash::Hash for LinkAddr {
- #[cfg(any(target_os = "freebsd",
- target_os = "ios",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "openbsd"))]
- fn hash<H: hash::Hasher>(&self, s: &mut H) {
- let a = self.0;
- (a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
- a.sdl_nlen, a.sdl_alen, a.sdl_slen, &a.sdl_data[..]).hash(s);
- }
-
- #[cfg(target_os = "dragonfly")]
- fn hash<H: hash::Hasher>(&self, s: &mut H) {
- let a = self.0;
- (a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type, a.sdl_nlen,
- a.sdl_alen, a.sdl_slen, a.sdl_data, a.sdl_rcf, a.sdl_route).hash(s);
- }
- }
-
impl fmt::Display for LinkAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let addr = self.addr();
@@ -1426,19 +1122,15 @@ mod datalink {
addr[5])
}
}
-
- impl fmt::Debug for LinkAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(self, f)
- }
- }
}
#[cfg(test)]
mod tests {
- #[cfg(any(target_os = "dragonfly",
+ #[cfg(any(target_os = "android",
+ target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
+ target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
@@ -1484,4 +1176,18 @@ mod tests {
_ => { unreachable!() }
};
}
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[test]
+ fn test_abstract_sun_path() {
+ let name = String::from("nix\0abstract\0test");
+ let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
+
+ let sun_path1 = addr.sun_path();
+ let sun_path2 = [0u8, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+ assert_eq!(sun_path1.len(), sun_path2.len());
+ for i in 0..sun_path1.len() {
+ assert_eq!(sun_path1[i], sun_path2[i]);
+ }
+ }
}
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
index a8631f24..0e27216f 100644
--- a/src/sys/socket/mod.rs
+++ b/src/sys/socket/mod.rs
@@ -5,7 +5,7 @@ use {Error, Result};
use errno::Errno;
use libc::{self, c_void, c_int, iovec, socklen_t, size_t,
CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, CMSG_LEN};
-use std::{fmt, mem, ptr, slice};
+use std::{mem, ptr, slice};
use std::os::unix::io::RawFd;
use sys::time::TimeVal;
use sys::uio::IoVec;
@@ -189,7 +189,7 @@ cfg_if! {
///
/// This struct is used with the `SO_PEERCRED` ancillary message for UNIX sockets.
#[repr(C)]
- #[derive(Clone, Copy)]
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct UnixCredentials(libc::ucred);
impl UnixCredentials {
@@ -209,13 +209,6 @@ cfg_if! {
}
}
- impl PartialEq for UnixCredentials {
- fn eq(&self, other: &Self) -> bool {
- self.0.pid == other.0.pid && self.0.uid == other.0.uid && self.0.gid == other.0.gid
- }
- }
- impl Eq for UnixCredentials {}
-
impl From<libc::ucred> for UnixCredentials {
fn from(cred: libc::ucred) -> Self {
UnixCredentials(cred)
@@ -227,16 +220,6 @@ cfg_if! {
self.0
}
}
-
- impl fmt::Debug for UnixCredentials {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("UnixCredentials")
- .field("pid", &self.0.pid)
- .field("uid", &self.0.uid)
- .field("gid", &self.0.gid)
- .finish()
- }
- }
}
}
@@ -244,7 +227,7 @@ cfg_if! {
///
/// This is a wrapper type around `ip_mreq`.
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct IpMembershipRequest(libc::ip_mreq);
impl IpMembershipRequest {
@@ -259,32 +242,11 @@ impl IpMembershipRequest {
}
}
-impl PartialEq for IpMembershipRequest {
- fn eq(&self, other: &Self) -> bool {
- self.0.imr_multiaddr.s_addr == other.0.imr_multiaddr.s_addr
- && self.0.imr_interface.s_addr == other.0.imr_interface.s_addr
- }
-}
-impl Eq for IpMembershipRequest {}
-
-impl fmt::Debug for IpMembershipRequest {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let mref = &self.0.imr_multiaddr;
- let maddr = mref.s_addr;
- let iref = &self.0.imr_interface;
- let ifaddr = iref.s_addr;
- f.debug_struct("IpMembershipRequest")
- .field("imr_multiaddr", &maddr)
- .field("imr_interface", &ifaddr)
- .finish()
- }
-}
-
/// Request for ipv6 multicast socket operations
///
/// This is a wrapper type around `ipv6_mreq`.
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Ipv6MembershipRequest(libc::ipv6_mreq);
impl Ipv6MembershipRequest {
@@ -297,23 +259,6 @@ impl Ipv6MembershipRequest {
}
}
-impl PartialEq for Ipv6MembershipRequest {
- fn eq(&self, other: &Self) -> bool {
- self.0.ipv6mr_multiaddr.s6_addr == other.0.ipv6mr_multiaddr.s6_addr &&
- self.0.ipv6mr_interface == other.0.ipv6mr_interface
- }
-}
-impl Eq for Ipv6MembershipRequest {}
-
-impl fmt::Debug for Ipv6MembershipRequest {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("Ipv6MembershipRequest")
- .field("ipv6mr_multiaddr", &self.0.ipv6mr_multiaddr.s6_addr)
- .field("ipv6mr_interface", &self.0.ipv6mr_interface)
- .finish()
- }
-}
-
cfg_if! {
// Darwin and DragonFly BSD always align struct cmsghdr to 32-bit only.
if #[cfg(any(target_os = "dragonfly", target_os = "ios", target_os = "macos"))] {
@@ -386,7 +331,7 @@ macro_rules! cmsg_space {
/// let cmsg: CmsgSpace<([RawFd; 3], CmsgSpace<[RawFd; 2]>)> = CmsgSpace::new();
/// ```
#[repr(C)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct CmsgSpace<T> {
_hdr: cmsghdr,
_pad: [align_of_cmsg_data; 0],
@@ -419,7 +364,7 @@ impl CmsgBuffer for Vec<u8> {
}
}
-#[allow(missing_debug_implementations)] // msghdr isn't Debug
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RecvMsg<'a> {
pub bytes: usize,
cmsghdr: Option<&'a cmsghdr>,
@@ -439,7 +384,7 @@ impl<'a> RecvMsg<'a> {
}
}
-#[allow(missing_debug_implementations)] // msghdr isn't Debug
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct CmsgIterator<'a> {
/// Control message buffer to decode from. Must adhere to cmsg alignment.
cmsghdr: Option<&'a cmsghdr>,
@@ -478,7 +423,7 @@ impl<'a> Iterator for CmsgIterator<'a> {
// alignment issues.
//
// See https://github.com/nix-rust/nix/issues/999
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ControlMessageOwned {
/// Received version of
/// [`ControlMessage::ScmRights`][#enum.ControlMessage.html#variant.ScmRights]
@@ -679,7 +624,7 @@ impl ControlMessageOwned {
/// exhaustively pattern-match it.
///
/// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html)
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ControlMessage<'a> {
/// A message of type `SCM_RIGHTS`, containing an array of file
/// descriptors passed between processes.
@@ -742,7 +687,7 @@ pub enum ControlMessage<'a> {
// An opaque structure used to prevent cmsghdr from being a public type
#[doc(hidden)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct UnknownCmsg(cmsghdr, Vec<u8>);
impl<'a> ControlMessage<'a> {
diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs
index 5f19e5f3..a9960100 100644
--- a/src/sys/socket/sockopt.rs
+++ b/src/sys/socket/sockopt.rs
@@ -173,7 +173,7 @@ macro_rules! sockopt_impl {
};
(GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
- #[derive(Copy, Clone, Debug)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct $name;
getsockopt_impl!($name, $level, $flag, $ty, $getter);
@@ -184,14 +184,14 @@ macro_rules! sockopt_impl {
};
(SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
- #[derive(Copy, Clone, Debug)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct $name;
setsockopt_impl!($name, $level, $flag, $ty, $setter);
};
(Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
- #[derive(Copy, Clone, Debug)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct $name;
setsockopt_impl!($name, $level, $flag, $ty, $setter);
diff --git a/src/sys/stat.rs b/src/sys/stat.rs
index 1e0936ed..66c8c9dd 100644
--- a/src/sys/stat.rs
+++ b/src/sys/stat.rs
@@ -284,3 +284,11 @@ pub fn utimensat<P: ?Sized + NixPath>(
Errno::result(res).map(drop)
}
+
+pub fn mkdirat<P: ?Sized + NixPath>(fd: RawFd, path: &P, mode: Mode) -> Result<()> {
+ let res = path.with_nix_path(|cstr| {
+ unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) }
+ })?;
+
+ Errno::result(res).map(drop)
+}
diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs
index e7ffae5e..d4596bf3 100644
--- a/src/sys/statfs.rs
+++ b/src/sys/statfs.rs
@@ -1,20 +1,548 @@
-use {Result, NixPath};
-use errno::Errno;
+use std::fmt::{self, Debug};
+use std::mem;
use std::os::unix::io::AsRawFd;
+#[cfg(not(any(target_os = "linux", target_os = "android")))]
+use std::ffi::CStr;
+
use libc;
-pub fn statfs<P: ?Sized + NixPath>(path: &P, stat: &mut libc::statfs) -> Result<()> {
- unsafe {
- Errno::clear();
- let res = path.with_nix_path(|path| libc::statfs(path.as_ptr(), stat))?;
+use {NixPath, Result};
+use errno::Errno;
+
+#[cfg(target_os = "android")]
+pub type fsid_t = libc::__fsid_t;
+#[cfg(not(target_os = "android"))]
+pub type fsid_t = libc::fsid_t;
+
+#[derive(Clone, Copy)]
+pub struct Statfs(libc::statfs);
+
+#[cfg(target_os = "freebsd")]
+#[derive(Eq, Copy, Clone, PartialEq, Debug)]
+pub struct FsType(u32);
+#[cfg(target_os = "android")]
+#[derive(Eq, Copy, Clone, PartialEq, Debug)]
+pub struct FsType(libc::c_ulong);
+#[cfg(all(target_os = "linux", target_arch = "s390x"))]
+#[derive(Eq, Copy, Clone, PartialEq, Debug)]
+pub struct FsType(u32);
+#[cfg(all(target_os = "linux", target_env = "musl"))]
+#[derive(Eq, Copy, Clone, PartialEq, Debug)]
+pub struct FsType(libc::c_ulong);
+#[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
+#[derive(Eq, Copy, Clone, PartialEq, Debug)]
+pub struct FsType(libc::c_long);
+
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const ADFS_SUPER_MAGIC: FsType = FsType(libc::ADFS_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const AFFS_SUPER_MAGIC: FsType = FsType(libc::AFFS_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const CODA_SUPER_MAGIC: FsType = FsType(libc::CODA_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const EXT2_SUPER_MAGIC: FsType = FsType(libc::EXT2_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const HPFS_SUPER_MAGIC: FsType = FsType(libc::HPFS_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const ISOFS_SUPER_MAGIC: FsType = FsType(libc::ISOFS_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const JFFS2_SUPER_MAGIC: FsType = FsType(libc::JFFS2_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const MINIX2_SUPER_MAGIC: FsType = FsType(libc::MINIX2_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const MSDOS_SUPER_MAGIC: FsType = FsType(libc::MSDOS_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const OPENPROM_SUPER_MAGIC: FsType = FsType(libc::OPENPROM_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const PROC_SUPER_MAGIC: FsType = FsType(libc::PROC_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const QNX4_SUPER_MAGIC: FsType = FsType(libc::QNX4_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const REISERFS_SUPER_MAGIC: FsType = FsType(libc::REISERFS_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC);
+#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
+pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC);
+
+impl Statfs {
+ /// Magic code defining system type
+ #[cfg(not(any(
+ target_os = "openbsd",
+ target_os = "ios",
+ target_os = "macos"
+ )))]
+ pub fn filesystem_type(&self) -> FsType {
+ FsType(self.0.f_type)
+ }
+
+ /// Magic code defining system type
+ #[cfg(not(any(target_os = "linux", target_os = "android")))]
+ pub fn filesystem_type_name(&self) -> &str {
+ let c_str = unsafe { CStr::from_ptr(self.0.f_fstypename.as_ptr()) };
+ c_str.to_str().unwrap()
+ }
+
+ /// Optimal transfer block size
+ #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))]
+ pub fn optimal_transfer_size(&self) -> i32 {
+ self.0.f_iosize
+ }
+
+ /// Optimal transfer block size
+ #[cfg(all(target_os = "linux", target_arch = "s390x"))]
+ pub fn optimal_transfer_size(&self) -> u32 {
+ self.0.f_bsize
+ }
+
+ /// Optimal transfer block size
+ #[cfg(all(target_os = "linux", target_env = "musl"))]
+ pub fn optimal_transfer_size(&self) -> libc::c_ulong {
+ self.0.f_bsize
+ }
+
+ /// Optimal transfer block size
+ #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
+ pub fn optimal_transfer_size(&self) -> libc::c_long {
+ self.0.f_bsize
+ }
+
+ /// Optimal transfer block size
+ #[cfg(target_os = "android")]
+ pub fn optimal_transfer_size(&self) -> libc::c_ulong {
+ self.0.f_bsize
+ }
+
+ /// Optimal transfer block size
+ #[cfg(target_os = "dragonfly")]
+ pub fn optimal_transfer_size(&self) -> libc::c_long {
+ self.0.f_iosize
+ }
+
+ /// Optimal transfer block size
+ #[cfg(target_os = "freebsd")]
+ pub fn optimal_transfer_size(&self) -> u64 {
+ self.0.f_iosize
+ }
+
+ /// Size of a block
+ #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))]
+ pub fn block_size(&self) -> u32 {
+ self.0.f_bsize
+ }
+
+ /// Size of a block
+ // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
+ #[cfg(all(target_os = "linux", target_arch = "s390x"))]
+ pub fn block_size(&self) -> u32 {
+ self.0.f_bsize
+ }
+
+ /// Size of a block
+ // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
+ #[cfg(all(target_os = "linux", target_env = "musl"))]
+ pub fn block_size(&self) -> libc::c_ulong {
+ self.0.f_bsize
+ }
+
+ /// Size of a block
+ // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
+ #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
+ pub fn block_size(&self) -> libc::c_long {
+ self.0.f_bsize
+ }
+
+ /// Size of a block
+ #[cfg(target_os = "freebsd")]
+ pub fn block_size(&self) -> u64 {
+ self.0.f_bsize
+ }
+
+ /// Size of a block
+ #[cfg(target_os = "android")]
+ pub fn block_size(&self) -> libc::c_ulong {
+ self.0.f_bsize
+ }
+
+ /// Size of a block
+ #[cfg(target_os = "dragonfly")]
+ pub fn block_size(&self) -> libc::c_long {
+ self.0.f_bsize
+ }
+
+ /// Maximum length of filenames
+ #[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
+ pub fn maximum_name_length(&self) -> u32 {
+ self.0.f_namemax
+ }
+
+ /// Maximum length of filenames
+ #[cfg(all(target_os = "linux", target_arch = "s390x"))]
+ pub fn maximum_name_length(&self) -> u32 {
+ self.0.f_namelen
+ }
+
+ /// Maximum length of filenames
+ #[cfg(all(target_os = "linux", target_env = "musl"))]
+ pub fn maximum_name_length(&self) -> libc::c_ulong {
+ self.0.f_namelen
+ }
+
+ /// Maximum length of filenames
+ #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
+ pub fn maximum_name_length(&self) -> libc::c_long {
+ self.0.f_namelen
+ }
+
+ /// Maximum length of filenames
+ #[cfg(target_os = "android")]
+ pub fn maximum_name_length(&self) -> libc::c_ulong {
+ self.0.f_namelen
+ }
+
+ /// Total data blocks in filesystem
+ #[cfg(any(
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ ))]
+ pub fn blocks(&self) -> u64 {
+ self.0.f_blocks
+ }
+
+ /// Total data blocks in filesystem
+ #[cfg(target_os = "dragonfly")]
+ pub fn blocks(&self) -> libc::c_long {
+ self.0.f_blocks
+ }
+
+ /// Total data blocks in filesystem
+ #[cfg(all(target_os = "linux", target_env = "musl"))]
+ pub fn blocks(&self) -> u64 {
+ self.0.f_blocks
+ }
+
+ /// Total data blocks in filesystem
+ #[cfg(not(any(
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "dragonfly",
+ all(target_os = "linux", target_env = "musl")
+ )))]
+ pub fn blocks(&self) -> libc::c_ulong {
+ self.0.f_blocks
+ }
+
+ /// Free blocks in filesystem
+ #[cfg(any(
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ ))]
+ pub fn blocks_free(&self) -> u64 {
+ self.0.f_bfree
+ }
+
+ /// Free blocks in filesystem
+ #[cfg(target_os = "dragonfly")]
+ pub fn blocks_free(&self) -> libc::c_long {
+ self.0.f_bfree
+ }
- Errno::result(res).map(drop)
+ /// Free blocks in filesystem
+ #[cfg(all(target_os = "linux", target_env = "musl"))]
+ pub fn blocks_free(&self) -> u64 {
+ self.0.f_bfree
+ }
+
+ /// Free blocks in filesystem
+ #[cfg(not(any(
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "dragonfly",
+ all(target_os = "linux", target_env = "musl")
+ )))]
+ pub fn blocks_free(&self) -> libc::c_ulong {
+ self.0.f_bfree
+ }
+
+ /// Free blocks available to unprivileged user
+ #[cfg(any(target_os = "ios", target_os = "macos", target_os = "android"))]
+ pub fn blocks_available(&self) -> u64 {
+ self.0.f_bavail
+ }
+
+ /// Free blocks available to unprivileged user
+ #[cfg(target_os = "dragonfly")]
+ pub fn blocks_available(&self) -> libc::c_long {
+ self.0.f_bavail
+ }
+
+ /// Free blocks available to unprivileged user
+ #[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
+ pub fn blocks_available(&self) -> i64 {
+ self.0.f_bavail
+ }
+
+ /// Free blocks available to unprivileged user
+ #[cfg(all(target_os = "linux", target_env = "musl"))]
+ pub fn blocks_available(&self) -> u64 {
+ self.0.f_bavail
+ }
+
+ /// Free blocks available to unprivileged user
+ #[cfg(not(any(
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "dragonfly",
+ all(target_os = "linux", target_env = "musl")
+ )))]
+ pub fn blocks_available(&self) -> libc::c_ulong {
+ self.0.f_bavail
+ }
+
+ /// Total file nodes in filesystem
+ #[cfg(any(
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ ))]
+ pub fn files(&self) -> u64 {
+ self.0.f_files
+ }
+
+ /// Total file nodes in filesystem
+ #[cfg(target_os = "dragonfly")]
+ pub fn files(&self) -> libc::c_long {
+ self.0.f_files
+ }
+
+ /// Total file nodes in filesystem
+ #[cfg(all(target_os = "linux", target_env = "musl"))]
+ pub fn files(&self) -> u64 {
+ self.0.f_files
+ }
+
+ /// Total file nodes in filesystem
+ #[cfg(not(any(
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "dragonfly",
+ all(target_os = "linux", target_env = "musl")
+ )))]
+ pub fn files(&self) -> libc::c_ulong {
+ self.0.f_files
+ }
+
+ /// Free file nodes in filesystem
+ #[cfg(any(target_os = "ios", target_os = "macos", target_os = "android"))]
+ pub fn files_free(&self) -> u64 {
+ self.0.f_ffree
+ }
+
+ /// Free file nodes in filesystem
+ #[cfg(target_os = "dragonfly")]
+ pub fn files_free(&self) -> libc::c_long {
+ self.0.f_ffree
+ }
+
+ /// Free file nodes in filesystem
+ #[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
+ pub fn files_free(&self) -> i64 {
+ self.0.f_ffree
+ }
+
+ /// Free file nodes in filesystem
+ #[cfg(all(target_os = "linux", target_env = "musl"))]
+ pub fn files_free(&self) -> u64 {
+ self.0.f_ffree
+ }
+
+ /// Free file nodes in filesystem
+ #[cfg(not(any(
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "dragonfly",
+ all(target_os = "linux", target_env = "musl")
+ )))]
+ pub fn files_free(&self) -> libc::c_ulong {
+ self.0.f_ffree
+ }
+
+ /// Filesystem ID
+ pub fn filesystem_id(&self) -> fsid_t {
+ self.0.f_fsid
+ }
+}
+
+impl Debug for Statfs {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Statfs")
+ .field("optimal_transfer_size", &self.optimal_transfer_size())
+ .field("block_size", &self.block_size())
+ .field("blocks", &self.blocks())
+ .field("blocks_free", &self.blocks_free())
+ .field("blocks_available", &self.blocks_available())
+ .field("files", &self.files())
+ .field("files_free", &self.files_free())
+ .field("filesystem_id", &self.filesystem_id())
+ .finish()
+ }
+}
+
+pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> {
+ unsafe {
+ let mut stat: Statfs = mem::uninitialized();
+ let res = path.with_nix_path(|path| libc::statfs(path.as_ptr(), &mut stat.0))?;
+ Errno::result(res).map(|_| stat)
}
}
-pub fn fstatfs<T: AsRawFd>(fd: &T, stat: &mut libc::statfs) -> Result<()> {
+pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> {
unsafe {
- Errno::clear();
- Errno::result(libc::fstatfs(fd.as_raw_fd(), stat)).map(drop)
+ let mut stat: Statfs = mem::uninitialized();
+ Errno::result(libc::fstatfs(fd.as_raw_fd(), &mut stat.0)).map(|_| stat)
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use std::fs::File;
+
+ use sys::statfs::*;
+ use sys::statvfs::*;
+ use std::path::Path;
+
+ #[test]
+ fn statfs_call() {
+ check_statfs("/tmp");
+ check_statfs("/dev");
+ check_statfs("/run");
+ check_statfs("/");
+ }
+
+ #[test]
+ fn fstatfs_call() {
+ check_fstatfs("/tmp");
+ check_fstatfs("/dev");
+ check_fstatfs("/run");
+ check_fstatfs("/");
+ }
+
+ fn check_fstatfs(path: &str) {
+ if !Path::new(path).exists() {
+ return;
+ }
+ let vfs = statvfs(path.as_bytes()).unwrap();
+ let file = File::open(path).unwrap();
+ let fs = fstatfs(&file).unwrap();
+ assert_fs_equals(fs, vfs);
+ }
+
+ fn check_statfs(path: &str) {
+ if !Path::new(path).exists() {
+ return;
+ }
+ let vfs = statvfs(path.as_bytes()).unwrap();
+ let fs = statfs(path.as_bytes()).unwrap();
+ assert_fs_equals(fs, vfs);
+ }
+
+ fn assert_fs_equals(fs: Statfs, vfs: Statvfs) {
+ assert_eq!(fs.files() as u64, vfs.files() as u64);
+ assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
+ assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
+ }
+
+ // This test is ignored because files_free/blocks_free can change after statvfs call and before
+ // statfs call.
+ #[test]
+ #[ignore]
+ fn statfs_call_strict() {
+ check_statfs_strict("/tmp");
+ check_statfs_strict("/dev");
+ check_statfs_strict("/run");
+ check_statfs_strict("/");
+ }
+
+ // This test is ignored because files_free/blocks_free can change after statvfs call and before
+ // fstatfs call.
+ #[test]
+ #[ignore]
+ fn fstatfs_call_strict() {
+ check_fstatfs_strict("/tmp");
+ check_fstatfs_strict("/dev");
+ check_fstatfs_strict("/run");
+ check_fstatfs_strict("/");
+ }
+
+ fn check_fstatfs_strict(path: &str) {
+ if !Path::new(path).exists() {
+ return;
+ }
+ let vfs = statvfs(path.as_bytes());
+ let file = File::open(path).unwrap();
+ let fs = fstatfs(&file);
+ assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
+ }
+
+ fn check_statfs_strict(path: &str) {
+ if !Path::new(path).exists() {
+ return;
+ }
+ let vfs = statvfs(path.as_bytes());
+ let fs = statfs(path.as_bytes());
+ assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
+ }
+
+ fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) {
+ assert_eq!(fs.files_free() as u64, vfs.files_free() as u64);
+ assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64);
+ assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64);
+ assert_eq!(fs.files() as u64, vfs.files() as u64);
+ assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
+ assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
}
}
diff --git a/src/sys/statvfs.rs b/src/sys/statvfs.rs
index de69ae51..e5980369 100644
--- a/src/sys/statvfs.rs
+++ b/src/sys/statvfs.rs
@@ -57,8 +57,7 @@ libc_bitflags!(
/// For more information see the [`statvfs(3)` man pages](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_statvfs.h.html).
// FIXME: Replace with repr(transparent)
#[repr(C)]
-#[derive(Clone, Copy)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Statvfs(libc::statvfs);
impl Statvfs {
diff --git a/src/sys/sysinfo.rs b/src/sys/sysinfo.rs
index 98ef7bd5..4c8e3898 100644
--- a/src/sys/sysinfo.rs
+++ b/src/sys/sysinfo.rs
@@ -6,8 +6,7 @@ use Result;
use errno::Errno;
/// System info structure returned by `sysinfo`.
-#[derive(Copy, Clone)]
-#[allow(missing_debug_implementations)] // libc::sysinfo doesn't impl Debug
+#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct SysInfo(libc::sysinfo);
impl SysInfo {
diff --git a/src/sys/termios.rs b/src/sys/termios.rs
index d8815baa..c7cdf10b 100644
--- a/src/sys/termios.rs
+++ b/src/sys/termios.rs
@@ -176,8 +176,7 @@ use ::unistd::Pid;
/// This is a wrapper around the `libc::termios` struct that provides a safe interface for the
/// standard fields. The only safe way to obtain an instance of this struct is to extract it from
/// an open port using `tcgetattr()`.
-#[derive(Clone)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Termios {
inner: RefCell<libc::termios>,
/// Input mode flags (see `termios.c_iflag` documentation)
diff --git a/src/sys/time.rs b/src/sys/time.rs
index 4bd3b780..3ad57543 100644
--- a/src/sys/time.rs
+++ b/src/sys/time.rs
@@ -45,7 +45,7 @@ pub trait TimeValLike: Sized {
}
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct TimeSpec(timespec);
const NANOS_PER_SEC: i64 = 1_000_000_000;
@@ -67,25 +67,6 @@ impl AsRef<timespec> for TimeSpec {
}
}
-impl fmt::Debug for TimeSpec {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- fmt.debug_struct("TimeSpec")
- .field("tv_sec", &self.tv_sec())
- .field("tv_nsec", &self.tv_nsec())
- .finish()
- }
-}
-
-impl PartialEq for TimeSpec {
- // The implementation of cmp is simplified by assuming that the struct is
- // normalized. That is, tv_nsec must always be within [0, 1_000_000_000)
- fn eq(&self, other: &TimeSpec) -> bool {
- self.tv_sec() == other.tv_sec() && self.tv_nsec() == other.tv_nsec()
- }
-}
-
-impl Eq for TimeSpec {}
-
impl Ord for TimeSpec {
// The implementation of cmp is simplified by assuming that the struct is
// normalized. That is, tv_nsec must always be within [0, 1_000_000_000)
@@ -259,7 +240,7 @@ impl fmt::Display for TimeSpec {
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct TimeVal(timeval);
const MICROS_PER_SEC: i64 = 1_000_000;
@@ -278,25 +259,6 @@ impl AsRef<timeval> for TimeVal {
}
}
-impl fmt::Debug for TimeVal {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- fmt.debug_struct("TimeVal")
- .field("tv_sec", &self.tv_sec())
- .field("tv_usec", &self.tv_usec())
- .finish()
- }
-}
-
-impl PartialEq for TimeVal {
- // The implementation of cmp is simplified by assuming that the struct is
- // normalized. That is, tv_usec must always be within [0, 1_000_000)
- fn eq(&self, other: &TimeVal) -> bool {
- self.tv_sec() == other.tv_sec() && self.tv_usec() == other.tv_usec()
- }
-}
-
-impl Eq for TimeVal {}
-
impl Ord for TimeVal {
// The implementation of cmp is simplified by assuming that the struct is
// normalized. That is, tv_usec must always be within [0, 1_000_000)
diff --git a/src/sys/uio.rs b/src/sys/uio.rs
index 45860be5..d089084e 100644
--- a/src/sys/uio.rs
+++ b/src/sys/uio.rs
@@ -88,8 +88,7 @@ pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize>{
/// and [`process_vm_writev`](fn.process_vm_writev.html).
#[cfg(target_os = "linux")]
#[repr(C)]
-#[derive(Clone, Copy)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct RemoteIoVec {
/// The starting address of this slice (`iov_base`).
pub base: usize,
@@ -160,7 +159,7 @@ pub fn process_vm_readv(pid: ::unistd::Pid, local_iov: &[IoVec<&mut [u8]>], remo
}
#[repr(C)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct IoVec<T>(libc::iovec, PhantomData<T>);
impl<T> IoVec<T> {
diff --git a/src/sys/utsname.rs b/src/sys/utsname.rs
index e33d0739..ab09c7d2 100644
--- a/src/sys/utsname.rs
+++ b/src/sys/utsname.rs
@@ -4,8 +4,7 @@ use std::ffi::CStr;
use std::str::from_utf8_unchecked;
#[repr(C)]
-#[derive(Clone, Copy)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct UtsName(libc::utsname);
impl UtsName {
diff --git a/src/sys/wait.rs b/src/sys/wait.rs
index 3f99757d..c54f7ec5 100644
--- a/src/sys/wait.rs
+++ b/src/sys/wait.rs
@@ -55,7 +55,7 @@ libc_bitflags!(
/// Note that there are two Linux-specific enum variants, `PtraceEvent`
/// and `PtraceSyscall`. Portable code should avoid exhaustively
/// matching on `WaitStatus`.
-#[derive(Eq, PartialEq, Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum WaitStatus {
/// The process exited normally (as with `exit()` or returning from
/// `main`) with the given exit code. This case matches the C macro
diff --git a/src/ucontext.rs b/src/ucontext.rs
index c94464d5..5e10e7d1 100644
--- a/src/ucontext.rs
+++ b/src/ucontext.rs
@@ -6,8 +6,7 @@ use errno::Errno;
use std::mem;
use sys::signal::SigSet;
-#[derive(Clone, Copy)]
-#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct UContext {
context: libc::ucontext_t,
}
diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs
index 9cbf0257..12afc84c 100644
--- a/test/sys/test_socket.rs
+++ b/test/sys/test_socket.rs
@@ -1,9 +1,11 @@
use nix::sys::socket::{InetAddr, UnixAddr, getsockname};
-use std::slice;
+use std::collections::hash_map::DefaultHasher;
+use std::hash::{Hash, Hasher};
use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV6};
+use std::os::unix::io::RawFd;
use std::path::Path;
+use std::slice;
use std::str::FromStr;
-use std::os::unix::io::RawFd;
use libc::c_char;
use tempfile;
@@ -66,26 +68,70 @@ pub fn test_path_to_sock_addr() {
assert_eq!(addr.path(), Some(actual));
}
+fn calculate_hash<T: Hash>(t: &T) -> u64 {
+ let mut s = DefaultHasher::new();
+ t.hash(&mut s);
+ s.finish()
+}
+
+#[test]
+pub fn test_addr_equality_path() {
+ let path = "/foo/bar";
+ let actual = Path::new(path);
+ let addr1 = UnixAddr::new(actual).unwrap();
+ let mut addr2 = addr1.clone();
+
+ addr2.0.sun_path[10] = 127;
+
+ assert_eq!(addr1, addr2);
+ assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+pub fn test_abstract_sun_path_too_long() {
+ let name = String::from("nix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0testttttnix\0abstract\0test\0make\0sure\0this\0is\0long\0enough");
+ let addr = UnixAddr::new_abstract(name.as_bytes());
+ assert!(addr.is_err());
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+pub fn test_addr_equality_abstract() {
+ let name = String::from("nix\0abstract\0test");
+ let addr1 = UnixAddr::new_abstract(name.as_bytes()).unwrap();
+ let mut addr2 = addr1.clone();
+
+ assert_eq!(addr1, addr2);
+ assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
+
+ addr2.0.sun_path[18] = 127;
+ assert_ne!(addr1, addr2);
+ assert_ne!(calculate_hash(&addr1), calculate_hash(&addr2));
+}
+
// Test getting/setting abstract addresses (without unix socket creation)
#[cfg(target_os = "linux")]
#[test]
pub fn test_abstract_uds_addr() {
let empty = String::new();
let addr = UnixAddr::new_abstract(empty.as_bytes()).unwrap();
- assert_eq!(addr.as_abstract(), Some(empty.as_bytes()));
+ let sun_path = [0u8; 107];
+ assert_eq!(addr.as_abstract(), Some(&sun_path[..]));
let name = String::from("nix\0abstract\0test");
let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
- assert_eq!(addr.as_abstract(), Some(name.as_bytes()));
+ let sun_path = [
+ 110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ];
+ assert_eq!(addr.as_abstract(), Some(&sun_path[..]));
assert_eq!(addr.path(), None);
// Internally, name is null-prefixed (abstract namespace)
- let internal: &[u8] = unsafe {
- slice::from_raw_parts(addr.0.sun_path.as_ptr() as *const u8, addr.1)
- };
- let mut abstract_name = name.clone();
- abstract_name.insert(0, '\0');
- assert_eq!(internal, abstract_name.as_bytes());
+ assert_eq!(addr.0.sun_path[0], 0);
}
#[test]
diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs
index bcc523bf..8d02f147 100644
--- a/test/test_fcntl.rs
+++ b/test/test_fcntl.rs
@@ -48,16 +48,55 @@ fn test_readlink() {
#[cfg(any(target_os = "linux", target_os = "android"))]
mod linux_android {
use std::io::prelude::*;
+ use std::io::SeekFrom;
use std::os::unix::prelude::*;
use libc::loff_t;
- use nix::fcntl::{SpliceFFlags, FallocateFlags, fallocate, splice, tee, vmsplice};
+ use nix::fcntl::*;
use nix::sys::uio::IoVec;
use nix::unistd::{close, pipe, read, write};
use tempfile::{tempfile, NamedTempFile};
+ /// This test creates a temporary file containing the contents
+ /// 'foobarbaz' and uses the `copy_file_range` call to transfer
+ /// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The
+ /// resulting file is read and should contain the contents `bar`.
+ /// The from_offset should be updated by the call to reflect
+ /// the 3 bytes read (6).
+ ///
+ /// FIXME: This test is disabled for linux based builds, because Travis
+ /// Linux version is too old for `copy_file_range`.
+ #[test]
+ #[ignore]
+ fn test_copy_file_range() {
+ const CONTENTS: &[u8] = b"foobarbaz";
+
+ let mut tmp1 = tempfile().unwrap();
+ let mut tmp2 = tempfile().unwrap();
+
+ tmp1.write_all(CONTENTS).unwrap();
+ tmp1.flush().unwrap();
+
+ let mut from_offset: i64 = 3;
+ copy_file_range(
+ tmp1.as_raw_fd(),
+ Some(&mut from_offset),
+ tmp2.as_raw_fd(),
+ None,
+ 3,
+ )
+ .unwrap();
+
+ let mut res: String = String::new();
+ tmp2.seek(SeekFrom::Start(0)).unwrap();
+ tmp2.read_to_string(&mut res).unwrap();
+
+ assert_eq!(res, String::from("bar"));
+ assert_eq!(from_offset, 6);
+ }
+
#[test]
fn test_splice() {
const CONTENTS: &[u8] = b"abcdef123456";
diff --git a/test/test_mq.rs b/test/test_mq.rs
index 41ab358b..caac4fc2 100644
--- a/test/test_mq.rs
+++ b/test/test_mq.rs
@@ -55,8 +55,8 @@ fn test_mq_getattr() {
};
let mqd = r.unwrap();
- let read_attr = mq_getattr(mqd);
- assert!(read_attr.unwrap() == initial_attr);
+ let read_attr = mq_getattr(mqd).unwrap();
+ assert_eq!(read_attr, initial_attr);
mq_close(mqd).unwrap();
}
@@ -79,21 +79,21 @@ fn test_mq_setattr() {
let mqd = r.unwrap();
let new_attr = MqAttr::new(0, 20, MSG_SIZE * 2, 100);
- let old_attr = mq_setattr(mqd, &new_attr);
- assert!(old_attr.unwrap() == initial_attr);
+ let old_attr = mq_setattr(mqd, &new_attr).unwrap();
+ assert_eq!(old_attr, initial_attr);
- let new_attr_get = mq_getattr(mqd);
+ let new_attr_get = mq_getattr(mqd).unwrap();
// The following tests make sense. No changes here because according to the Linux man page only
// O_NONBLOCK can be set (see tests below)
- assert!(new_attr_get.unwrap() != new_attr);
+ assert_ne!(new_attr_get, new_attr);
let new_attr_non_blocking = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as c_long, 10, MSG_SIZE, 0);
mq_setattr(mqd, &new_attr_non_blocking).unwrap();
- let new_attr_get = mq_getattr(mqd);
+ let new_attr_get = mq_getattr(mqd).unwrap();
// now the O_NONBLOCK flag has been set
- assert!(new_attr_get.unwrap() != initial_attr);
- assert!(new_attr_get.unwrap() == new_attr_non_blocking);
+ assert_ne!(new_attr_get, initial_attr);
+ assert_eq!(new_attr_get, new_attr_non_blocking);
mq_close(mqd).unwrap();
}
diff --git a/test/test_poll.rs b/test/test_poll.rs
index 6cac3b77..aef40e47 100644
--- a/test/test_poll.rs
+++ b/test/test_poll.rs
@@ -1,5 +1,5 @@
use nix::poll::{PollFlags, poll, PollFd};
-use nix::unistd::{write, pipe, close};
+use nix::unistd::{write, pipe};
#[test]
fn test_poll() {
@@ -19,24 +19,6 @@ fn test_poll() {
assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
}
-#[test]
-fn test_poll_debug() {
- assert_eq!(format!("{:?}", PollFd::new(0, PollFlags::empty())),
- "PollFd { fd: 0, events: (empty), revents: (empty) }");
- assert_eq!(format!("{:?}", PollFd::new(1, PollFlags::POLLIN)),
- "PollFd { fd: 1, events: POLLIN, revents: (empty) }");
-
- // Testing revents requires doing some I/O
- let (r, w) = pipe().unwrap();
- let mut fds = [PollFd::new(r, PollFlags::POLLIN)];
- write(w, b" ").unwrap();
- close(w).unwrap();
- poll(&mut fds, -1).unwrap();
- assert_eq!(format!("{:?}", fds[0]),
- format!("PollFd {{ fd: {}, events: POLLIN, revents: POLLIN | POLLHUP }}", r));
- close(r).unwrap();
-}
-
// ppoll(2) is the same as poll except for how it handles timeouts and signals.
// Repeating the test for poll(2) should be sufficient to check that our
// bindings are correct.
diff --git a/test/test_stat.rs b/test/test_stat.rs
index b9da7fc3..1173455f 100644
--- a/test/test_stat.rs
+++ b/test/test_stat.rs
@@ -1,13 +1,15 @@
use std::fs::{self, File};
-use std::os::unix::fs::symlink;
+use std::os::unix::fs::{symlink, PermissionsExt};
use std::os::unix::prelude::AsRawFd;
use std::time::{Duration, UNIX_EPOCH};
+use std::path::Path;
#[cfg(not(any(target_os = "netbsd")))]
-use libc::{S_IFMT, S_IFLNK};
+use libc::{S_IFMT, S_IFLNK, mode_t};
-use nix::fcntl;
-use nix::sys::stat::{self, fchmod, fchmodat, futimens, stat, utimes, utimensat};
+use nix::{fcntl, Error};
+use nix::errno::{Errno};
+use nix::sys::stat::{self, fchmod, fchmodat, futimens, stat, utimes, utimensat, mkdirat};
#[cfg(any(target_os = "linux",
target_os = "haiku",
target_os = "ios",
@@ -260,3 +262,35 @@ fn test_utimensat() {
UtimensatFlags::FollowSymlink).unwrap();
assert_times_eq(500, 800, &fs::metadata(&fullpath).unwrap());
}
+
+#[test]
+fn test_mkdirat_success_path() {
+ let tempdir = tempfile::tempdir().unwrap();
+ let filename = "example_subdir";
+ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
+ assert!((mkdirat(dirfd, filename, Mode::S_IRWXU)).is_ok());
+ assert!(Path::exists(&tempdir.path().join(filename)));
+}
+
+#[test]
+fn test_mkdirat_success_mode() {
+ let expected_bits = stat::SFlag::S_IFDIR.bits() | stat::Mode::S_IRWXU.bits();
+ let tempdir = tempfile::tempdir().unwrap();
+ let filename = "example_subdir";
+ let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
+ assert!((mkdirat(dirfd, filename, Mode::S_IRWXU)).is_ok());
+ let permissions = fs::metadata(tempdir.path().join(filename)).unwrap().permissions();
+ let mode = permissions.mode();
+ assert_eq!(mode as mode_t, expected_bits)
+}
+
+#[test]
+fn test_mkdirat_fail() {
+ let tempdir = tempfile::tempdir().unwrap();
+ let not_dir_filename= "example_not_dir";
+ let filename = "example_subdir_dir";
+ let dirfd = fcntl::open(&tempdir.path().join(not_dir_filename), fcntl::OFlag::O_CREAT,
+ stat::Mode::empty()).unwrap();
+ let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err();
+ assert_eq!(result, Error::Sys(Errno::ENOTDIR));
+}