From 358adafa279ff3e6898ed49f4a2140144f121e9c Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 24 Jul 2021 14:43:02 -0600 Subject: Mark most C-derived enums as non_exhaustive Since libc may add new variants at any time, Nix's consumers should not use exhaustive match patterns. Fixes #1182 --- CHANGELOG.md | 4 ++++ src/errno.rs | 8 ++++++++ src/fcntl.rs | 4 ++++ src/sys/aio.rs | 2 ++ src/sys/epoll.rs | 1 + src/sys/event.rs | 1 + src/sys/mman.rs | 1 + src/sys/ptrace/bsd.rs | 1 + src/sys/ptrace/linux.rs | 2 ++ src/sys/quota.rs | 2 ++ src/sys/reboot.rs | 1 + src/sys/signal.rs | 2 ++ src/sys/socket/addr.rs | 2 ++ src/sys/socket/mod.rs | 4 ++++ src/sys/termios.rs | 5 +++++ src/sys/timerfd.rs | 1 + src/unistd.rs | 2 ++ 17 files changed, 43 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c4bcaf2..b7b10f84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ This project adheres to [Semantic Versioning](https://semver.org/). - `FdSet::{contains, highest, fds}` no longer require a mutable reference. (#[1464](https://github.com/nix-rust/nix/pull/1464)) +- Most enums that come from C, for example `Errno`, are now marked as + `#[non_exhaustive]`. + (#[1474](https://github.com/nix-rust/nix/pull/1474)) + ### Fixed - Added more errno definitions for better backwards compatibility with diff --git a/src/errno.rs b/src/errno.rs index 9c2dfe46..abfb80fe 100644 --- a/src/errno.rs +++ b/src/errno.rs @@ -768,6 +768,7 @@ fn desc(errno: Errno) -> &'static str { mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] + #[non_exhaustive] pub enum Errno { UnknownErrno = 0, EPERM = libc::EPERM, @@ -1073,6 +1074,7 @@ mod consts { mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] + #[non_exhaustive] pub enum Errno { UnknownErrno = 0, EPERM = libc::EPERM, @@ -1324,6 +1326,7 @@ mod consts { mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] + #[non_exhaustive] pub enum Errno { UnknownErrno = 0, EPERM = libc::EPERM, @@ -1562,6 +1565,7 @@ mod consts { mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] + #[non_exhaustive] pub enum Errno { UnknownErrno = 0, EPERM = libc::EPERM, @@ -1796,6 +1800,7 @@ mod consts { mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] + #[non_exhaustive] pub enum Errno { UnknownErrno = 0, EPERM = libc::EPERM, @@ -2019,6 +2024,7 @@ mod consts { mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] + #[non_exhaustive] pub enum Errno { UnknownErrno = 0, EPERM = libc::EPERM, @@ -2244,6 +2250,7 @@ mod consts { mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] + #[non_exhaustive] pub enum Errno { UnknownErrno = 0, EPERM = libc::EPERM, @@ -2441,6 +2448,7 @@ mod consts { mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] + #[non_exhaustive] pub enum Errno { UnknownErrno = 0, EPERM = libc::EPERM, diff --git a/src/fcntl.rs b/src/fcntl.rs index f8f1372a..0a50e748 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -374,6 +374,7 @@ libc_bitflags!( #[cfg(not(target_os = "redox"))] #[derive(Debug, Eq, Hash, PartialEq)] +#[non_exhaustive] pub enum FcntlArg<'a> { F_DUPFD(RawFd), F_DUPFD_CLOEXEC(RawFd), @@ -405,6 +406,7 @@ pub enum FcntlArg<'a> { #[cfg(target_os = "redox")] #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] +#[non_exhaustive] pub enum FcntlArg { F_DUPFD(RawFd), F_DUPFD_CLOEXEC(RawFd), @@ -454,6 +456,7 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result { } #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[non_exhaustive] pub enum FlockArg { LockShared, LockExclusive, @@ -649,6 +652,7 @@ mod posix_fadvise { libc_enum! { #[repr(i32)] + #[non_exhaustive] pub enum PosixFadviseAdvice { POSIX_FADV_NORMAL, POSIX_FADV_SEQUENTIAL, diff --git a/src/sys/aio.rs b/src/sys/aio.rs index b63affb8..71a2184d 100644 --- a/src/sys/aio.rs +++ b/src/sys/aio.rs @@ -39,6 +39,7 @@ libc_enum! { /// Mode for `AioCb::fsync`. Controls whether only data or both data and /// metadata are synced. #[repr(i32)] + #[non_exhaustive] pub enum AioFsyncMode { /// do it like `fsync` O_SYNC, @@ -57,6 +58,7 @@ libc_enum! { /// given `aiocb` should be used for a read operation, a write operation, or /// ignored. Has no effect for any other aio functions. #[repr(i32)] + #[non_exhaustive] pub enum LioOpcode { LIO_NOP, LIO_WRITE, diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index b73af13e..9f68d5ce 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -29,6 +29,7 @@ libc_bitflags!( #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(i32)] +#[non_exhaustive] pub enum EpollOp { EpollCtlAdd = libc::EPOLL_CTL_ADD, EpollCtlDel = libc::EPOLL_CTL_DEL, diff --git a/src/sys/event.rs b/src/sys/event.rs index 8050af31..1f4c1b41 100644 --- a/src/sys/event.rs +++ b/src/sys/event.rs @@ -36,6 +36,7 @@ type type_of_event_filter = i16; libc_enum! { #[cfg_attr(target_os = "netbsd", repr(u32))] #[cfg_attr(not(target_os = "netbsd"), repr(i16))] + #[non_exhaustive] pub enum EventFilter { EVFILT_AIO, /// Returns whenever there is no remaining data in the write buffer diff --git a/src/sys/mman.rs b/src/sys/mman.rs index 58edf086..a8d6d7c9 100644 --- a/src/sys/mman.rs +++ b/src/sys/mman.rs @@ -155,6 +155,7 @@ libc_enum!{ /// /// Used by [`madvise`](./fn.madvise.html). #[repr(i32)] + #[non_exhaustive] pub enum MmapAdvise { /// No further special treatment. This is the default. MADV_NORMAL, diff --git a/src/sys/ptrace/bsd.rs b/src/sys/ptrace/bsd.rs index 141dfbc4..a62881ef 100644 --- a/src/sys/ptrace/bsd.rs +++ b/src/sys/ptrace/bsd.rs @@ -24,6 +24,7 @@ cfg_if! { libc_enum! { #[repr(i32)] /// Ptrace Request enum defining the action to be taken. + #[non_exhaustive] pub enum Request { PT_TRACE_ME, PT_READ_I, diff --git a/src/sys/ptrace/linux.rs b/src/sys/ptrace/linux.rs index 4ac43936..74a23e03 100644 --- a/src/sys/ptrace/linux.rs +++ b/src/sys/ptrace/linux.rs @@ -33,6 +33,7 @@ libc_enum!{ #[cfg_attr(not(any(target_env = "musl", target_os = "android")), repr(u32))] #[cfg_attr(any(target_env = "musl", target_os = "android"), repr(i32))] /// Ptrace Request enum defining the action to be taken. + #[non_exhaustive] pub enum Request { PTRACE_TRACEME, PTRACE_PEEKTEXT, @@ -123,6 +124,7 @@ libc_enum!{ /// Using the ptrace options the tracer can configure the tracee to stop /// at certain events. This enum is used to define those events as defined /// in `man ptrace`. + #[non_exhaustive] pub enum Event { /// Event that stops before a return from fork or clone. PTRACE_EVENT_FORK, diff --git a/src/sys/quota.rs b/src/sys/quota.rs index 19330132..6e34e38d 100644 --- a/src/sys/quota.rs +++ b/src/sys/quota.rs @@ -42,6 +42,7 @@ libc_enum!{ libc_enum!{ /// The scope of the quota. #[repr(i32)] + #[non_exhaustive] pub enum QuotaType { /// Specify a user quota USRQUOTA, @@ -53,6 +54,7 @@ libc_enum!{ libc_enum!{ /// The type of quota format to use. #[repr(i32)] + #[non_exhaustive] pub enum QuotaFmt { /// Use the original quota format. QFMT_VFS_OLD, diff --git a/src/sys/reboot.rs b/src/sys/reboot.rs index 5b376824..be5067a9 100644 --- a/src/sys/reboot.rs +++ b/src/sys/reboot.rs @@ -12,6 +12,7 @@ libc_enum! { /// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for /// enabling/disabling Ctrl-Alt-Delete. #[repr(i32)] + #[non_exhaustive] pub enum RebootMode { RB_HALT_SYSTEM, RB_KEXEC, diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 273b3521..b1d938c3 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -23,6 +23,7 @@ libc_enum!{ // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately // this is not (yet) possible. #[repr(i32)] + #[non_exhaustive] pub enum Signal { SIGHUP, SIGINT, @@ -396,6 +397,7 @@ libc_bitflags!{ libc_enum! { #[repr(i32)] + #[non_exhaustive] pub enum SigmaskHow { SIG_BLOCK, SIG_UNBLOCK, diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index d4860562..bd031cf6 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -32,6 +32,7 @@ pub use self::vsock::VsockAddr; /// These constants specify the protocol family to be used /// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) #[repr(i32)] +#[non_exhaustive] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub enum AddressFamily { /// Local communication (see [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html)) @@ -641,6 +642,7 @@ impl Hash for UnixAddr { /// Represents a socket address #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[non_exhaustive] pub enum SockAddr { Inet(InetAddr), Unix(UnixAddr), diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index da5573c4..32904d01 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -70,6 +70,7 @@ pub use libc::{c_uint, CMSG_SPACE}; /// when creating a socket with [`socket()`](fn.socket.html) #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[repr(i32)] +#[non_exhaustive] pub enum SockType { /// Provides sequenced, reliable, two-way, connection- /// based byte streams. An out-of-band data transmission @@ -94,6 +95,7 @@ pub enum SockType { /// to specify the protocol to use. #[repr(i32)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[non_exhaustive] pub enum SockProtocol { /// TCP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html)) Tcp = libc::IPPROTO_TCP, @@ -490,6 +492,7 @@ impl<'a> Iterator for CmsgIterator<'a> { // // See https://github.com/nix-rust/nix/issues/999 #[derive(Clone, Debug, Eq, PartialEq)] +#[non_exhaustive] pub enum ControlMessageOwned { /// Received version of /// [`ControlMessage::ScmRights`][#enum.ControlMessage.html#variant.ScmRights] @@ -739,6 +742,7 @@ impl ControlMessageOwned { /// /// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html) #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[non_exhaustive] pub enum ControlMessage<'a> { /// A message of type `SCM_RIGHTS`, containing an array of file /// descriptors passed between processes. diff --git a/src/sys/termios.rs b/src/sys/termios.rs index 9abae9d0..b29d3b98 100644 --- a/src/sys/termios.rs +++ b/src/sys/termios.rs @@ -256,6 +256,7 @@ libc_enum!{ /// B0 is special and will disable the port. #[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))] #[cfg_attr(not(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64")), repr(u32))] + #[non_exhaustive] pub enum BaudRate { B0, B50, @@ -472,6 +473,7 @@ libc_enum! { /// /// Used as an argument to `tcsetattr()` #[repr(i32)] + #[non_exhaustive] pub enum SetArg { /// The change will occur immediately TCSANOW, @@ -487,6 +489,7 @@ libc_enum! { /// /// Used as an argument to `tcflush()`. #[repr(i32)] + #[non_exhaustive] pub enum FlushArg { /// Flush data that was received but not read TCIFLUSH, @@ -502,6 +505,7 @@ libc_enum! { /// /// Used as an argument to `tcflow()`. #[repr(i32)] + #[non_exhaustive] pub enum FlowArg { /// Suspend transmission TCOOFF, @@ -518,6 +522,7 @@ libc_enum! { libc_enum! { /// Indices into the `termios.c_cc` array for special characters. #[repr(usize)] + #[non_exhaustive] pub enum SpecialCharacterIndices { VDISCARD, #[cfg(any(target_os = "dragonfly", diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs index 44915be1..030e5976 100644 --- a/src/sys/timerfd.rs +++ b/src/sys/timerfd.rs @@ -58,6 +58,7 @@ libc_enum! { /// The type of the clock used to mark the progress of the timer. For more /// details on each kind of clock, please refer to [timerfd_create(2)](https://man7.org/linux/man-pages/man2/timerfd_create.2.html). #[repr(i32)] + #[non_exhaustive] pub enum ClockId { CLOCK_REALTIME, CLOCK_MONOTONIC, diff --git a/src/unistd.rs b/src/unistd.rs index 268c9994..9d764fd2 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -1806,6 +1806,7 @@ pub fn mkstemp(template: &P) -> Result<(RawFd, PathBuf)> { /// - [unistd.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html) #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(i32)] +#[non_exhaustive] pub enum PathconfVar { #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "netbsd", target_os = "openbsd", target_os = "redox"))] @@ -1985,6 +1986,7 @@ pub fn pathconf(path: &P, var: PathconfVar) -> Result Date: Sat, 24 Jul 2021 16:47:26 -0600 Subject: Constify many functions Constify most functions that can be constified. The exceptions are mostly accessors for structs that have no const constructor. --- CHANGELOG.md | 3 +++ src/errno.rs | 6 +++--- src/features.rs | 4 ++-- src/mount/bsd.rs | 2 +- src/mqueue.rs | 2 +- src/poll.rs | 2 +- src/sched.rs | 2 +- src/sys/signal.rs | 2 +- src/sys/socket/addr.rs | 36 ++++++++++++++++++------------------ src/sys/socket/mod.rs | 2 +- src/sys/stat.rs | 6 +++--- src/sys/time.rs | 8 ++++---- src/sys/timerfd.rs | 2 +- src/time.rs | 4 ++-- 14 files changed, 42 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03d2ef1a..1e3fda57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). - `FdSet::{contains, highest, fds}` no longer require a mutable reference. (#[1464](https://github.com/nix-rust/nix/pull/1464)) +- Many more functions, mostly contructors, are now `const`. + (#[1476](https://github.com/nix-rust/nix/pull/1476)) + ### Fixed - Added more errno definitions for better backwards compatibility with diff --git a/src/errno.rs b/src/errno.rs index 9c2dfe46..9980c47d 100644 --- a/src/errno.rs +++ b/src/errno.rs @@ -63,7 +63,7 @@ impl Errno { since = "0.22.0", note = "It's a no-op now; just delete it." )] - pub fn as_errno(self) -> Option { + pub const fn as_errno(self) -> Option { Some(self) } @@ -81,7 +81,7 @@ impl Errno { since = "0.22.0", note = "Use Errno::EINVAL instead" )] - pub fn invalid_argument() -> Error { + pub const fn invalid_argument() -> Error { Errno::EINVAL } @@ -122,7 +122,7 @@ impl Errno { )] #[allow(non_snake_case)] #[inline] - pub fn Sys(errno: Errno) -> Error { + pub const fn Sys(errno: Errno) -> Error { errno } } diff --git a/src/features.rs b/src/features.rs index bcda45d4..38eb3ea0 100644 --- a/src/features.rs +++ b/src/features.rs @@ -97,7 +97,7 @@ mod os { #[cfg(any(target_os = "illumos"))] mod os { /// Check if the OS supports atomic close-on-exec for sockets - pub fn socket_atomic_cloexec() -> bool { + pub const fn socket_atomic_cloexec() -> bool { true } } @@ -109,7 +109,7 @@ mod os { target_os = "solaris"))] mod os { /// Check if the OS supports atomic close-on-exec for sockets - pub fn socket_atomic_cloexec() -> bool { + pub const fn socket_atomic_cloexec() -> bool { false } } diff --git a/src/mount/bsd.rs b/src/mount/bsd.rs index 01449081..f0a9443a 100644 --- a/src/mount/bsd.rs +++ b/src/mount/bsd.rs @@ -111,7 +111,7 @@ impl NmountError { } /// Returns the inner [`Error`] - pub fn error(&self) -> Error { + pub const fn error(&self) -> Error { self.errno } diff --git a/src/mqueue.rs b/src/mqueue.rs index 3e494801..8598eaf2 100644 --- a/src/mqueue.rs +++ b/src/mqueue.rs @@ -59,7 +59,7 @@ impl MqAttr { } } - pub fn flags(&self) -> mq_attr_member_t { + pub const fn flags(&self) -> mq_attr_member_t { self.mq_attr.mq_flags } } diff --git a/src/poll.rs b/src/poll.rs index 0c3f208a..e814337a 100644 --- a/src/poll.rs +++ b/src/poll.rs @@ -25,7 +25,7 @@ pub struct PollFd { impl PollFd { /// Creates a new `PollFd` specifying the events of interest /// for a given file descriptor. - pub fn new(fd: RawFd, events: PollFlags) -> PollFd { + pub const fn new(fd: RawFd, events: PollFlags) -> PollFd { PollFd { pollfd: libc::pollfd { fd, diff --git a/src/sched.rs b/src/sched.rs index bf51bc12..575bf24b 100644 --- a/src/sched.rs +++ b/src/sched.rs @@ -97,7 +97,7 @@ mod sched_linux_like { } /// Return the maximum number of CPU in CpuSet - pub fn count() -> usize { + pub const fn count() -> usize { 8 * mem::size_of::() } } diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 273b3521..e7b9e88a 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -356,7 +356,7 @@ impl Iterator for SignalIterator { } impl Signal { - pub fn iterator() -> SignalIterator { + pub const fn iterator() -> SignalIterator { SignalIterator{next: 0} } } diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index d4860562..d8bb064c 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -372,7 +372,7 @@ impl IpAddr { /// Create a new IpAddr that contains an IPv4 address. /// /// The result will represent the IP address a.b.c.d - pub fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr { + pub const fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr { IpAddr::V4(Ipv4Addr::new(a, b, c, d)) } @@ -381,7 +381,7 @@ impl IpAddr { /// The result will represent the IP address a:b:c:d:e:f #[allow(clippy::many_single_char_names)] #[allow(clippy::too_many_arguments)] - pub fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr { + pub const fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr { IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)) } @@ -420,11 +420,11 @@ pub struct Ipv4Addr(pub libc::in_addr); impl Ipv4Addr { #[allow(clippy::identity_op)] // More readable this way - pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { - let ip = ((u32::from(a) << 24) | - (u32::from(b) << 16) | - (u32::from(c) << 8) | - (u32::from(d) << 0)).to_be(); + pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { + let ip = (((a as u32) << 24) | + ((b as u32) << 16) | + ((c as u32) << 8) | + ((d as u32) << 0)).to_be(); Ipv4Addr(libc::in_addr { s_addr: ip }) } @@ -436,16 +436,16 @@ impl Ipv4Addr { Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3]) } - pub fn any() -> Ipv4Addr { + pub const fn any() -> Ipv4Addr { Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY }) } - pub fn octets(self) -> [u8; 4] { + pub const fn octets(self) -> [u8; 4] { let bits = u32::from_be(self.0.s_addr); [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8] } - pub fn to_std(self) -> net::Ipv4Addr { + pub const fn to_std(self) -> net::Ipv4Addr { let bits = self.octets(); net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3]) } @@ -486,7 +486,7 @@ macro_rules! to_u16_array { impl Ipv6Addr { #[allow(clippy::many_single_char_names)] #[allow(clippy::too_many_arguments)] - pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { + pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { Ipv6Addr(libc::in6_addr{s6_addr: to_u8_array!(a,b,c,d,e,f,g,h)}) } @@ -496,11 +496,11 @@ impl Ipv6Addr { } /// Return the eight 16-bit segments that make up this address - pub fn segments(&self) -> [u16; 8] { + pub const fn segments(&self) -> [u16; 8] { to_u16_array!(self, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) } - pub fn to_std(&self) -> net::Ipv6Addr { + pub const fn to_std(&self) -> net::Ipv6Addr { let s = self.segments(); net::Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]) } @@ -913,11 +913,11 @@ pub mod netlink { NetlinkAddr(addr) } - pub fn pid(&self) -> u32 { + pub const fn pid(&self) -> u32 { self.0.nl_pid } - pub fn groups(&self) -> u32 { + pub const fn groups(&self) -> u32 { self.0.nl_groups } } @@ -1020,7 +1020,7 @@ pub mod sys_control { pub struct SysControlAddr(pub libc::sockaddr_ctl); impl SysControlAddr { - pub fn new(id: u32, unit: u32) -> SysControlAddr { + pub const fn new(id: u32, unit: u32) -> SysControlAddr { let addr = libc::sockaddr_ctl { sc_len: mem::size_of::() as c_uchar, sc_family: AddressFamily::System as c_uchar, @@ -1047,11 +1047,11 @@ pub mod sys_control { Ok(SysControlAddr::new(info.ctl_id, unit)) } - pub fn id(&self) -> u32 { + pub const fn id(&self) -> u32 { self.0.sc_id } - pub fn unit(&self) -> u32 { + pub const fn unit(&self) -> u32 { self.0.sc_unit } } diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index da5573c4..33bdbb62 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -384,7 +384,7 @@ pub struct Ipv6MembershipRequest(libc::ipv6_mreq); impl Ipv6MembershipRequest { /// Instantiate a new `Ipv6MembershipRequest` - pub fn new(group: Ipv6Addr) -> Self { + pub const fn new(group: Ipv6Addr) -> Self { Ipv6MembershipRequest(libc::ipv6_mreq { ipv6mr_multiaddr: group.0, ipv6mr_interface: 0, diff --git a/src/sys/stat.rs b/src/sys/stat.rs index 15451e78..ba212611 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -52,19 +52,19 @@ pub fn mknod(path: &P, kind: SFlag, perm: Mode, dev: dev_t) } #[cfg(target_os = "linux")] -pub fn major(dev: dev_t) -> u64 { +pub const fn major(dev: dev_t) -> u64 { ((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff) } #[cfg(target_os = "linux")] -pub fn minor(dev: dev_t) -> u64 { +pub const fn minor(dev: dev_t) -> u64 { ((dev >> 12) & 0xffff_ff00) | ((dev ) & 0x0000_00ff) } #[cfg(target_os = "linux")] -pub fn makedev(major: u64, minor: u64) -> dev_t { +pub const fn makedev(major: u64, minor: u64) -> dev_t { ((major & 0xffff_f000) << 32) | ((major & 0x0000_0fff) << 8) | ((minor & 0xffff_ff00) << 12) | diff --git a/src/sys/time.rs b/src/sys/time.rs index c786500a..ac424718 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -187,11 +187,11 @@ impl TimeSpec { } #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - pub fn tv_sec(&self) -> time_t { + pub const fn tv_sec(&self) -> time_t { self.0.tv_sec } - pub fn tv_nsec(&self) -> timespec_tv_nsec_t { + pub const fn tv_nsec(&self) -> timespec_tv_nsec_t { self.0.tv_nsec } @@ -404,11 +404,11 @@ impl TimeVal { } #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - pub fn tv_sec(&self) -> time_t { + pub const fn tv_sec(&self) -> time_t { self.0.tv_sec } - pub fn tv_usec(&self) -> suseconds_t { + pub const fn tv_usec(&self) -> suseconds_t { self.0.tv_usec } } diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs index 44915be1..3e1a1558 100644 --- a/src/sys/timerfd.rs +++ b/src/sys/timerfd.rs @@ -87,7 +87,7 @@ bitflags! { struct TimerSpec(libc::itimerspec); impl TimerSpec { - pub fn none() -> Self { + pub const fn none() -> Self { Self(libc::itimerspec { it_interval: libc::timespec { tv_sec: 0, diff --git a/src/time.rs b/src/time.rs index 45dd26e7..1731e60e 100644 --- a/src/time.rs +++ b/src/time.rs @@ -20,7 +20,7 @@ pub struct ClockId(clockid_t); impl ClockId { /// Creates `ClockId` from raw `clockid_t` - pub fn from_raw(clk_id: clockid_t) -> Self { + pub const fn from_raw(clk_id: clockid_t) -> Self { ClockId(clk_id) } @@ -61,7 +61,7 @@ impl ClockId { } /// Gets the raw `clockid_t` wrapped by `self` - pub fn as_raw(self) -> clockid_t { + pub const fn as_raw(self) -> clockid_t { self.0 } -- cgit v1.2.3 From 6e2158bc7126510890351d67400d53de9fa9629e Mon Sep 17 00:00:00 2001 From: Luca BRUNO Date: Thu, 22 Jul 2021 07:49:59 +0000 Subject: sys/stat: add a safe wrapper for mknodat(2) This introduces a new `mknodat` helper. Ref: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mknod.html --- CHANGELOG.md | 2 ++ src/sys/stat.rs | 25 +++++++++++++++++++++---- test/test_stat.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97268ef2..dce18009 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1471](https://github.com/nix-rust/nix/pull/1471)) - Added `pthread_kill`. (#[1472](https://github.com/nix-rust/nix/pull/1472)) +- Added `mknodat`. + (#[1473](https://github.com/nix-rust/nix/pull/1473)) ### Changed diff --git a/src/sys/stat.rs b/src/sys/stat.rs index 15451e78..c797576e 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -9,6 +9,7 @@ use std::os::unix::io::RawFd; use crate::sys::time::{TimeSpec, TimeVal}; libc_bitflags!( + /// "File type" flags for `mknod` and related functions. pub struct SFlag: mode_t { S_IFIFO; S_IFCHR; @@ -22,6 +23,7 @@ libc_bitflags!( ); libc_bitflags! { + /// "File mode / permissions" flags. pub struct Mode: mode_t { S_IRWXU; S_IRUSR; @@ -41,11 +43,26 @@ libc_bitflags! { } } +/// Create a special or ordinary file, by pathname. pub fn mknod(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev) - } + let res = path.with_nix_path(|cstr| unsafe { + libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev) + })?; + + Errno::result(res).map(drop) +} + +/// Create a special or ordinary file, relative to a given directory. +#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))] +pub fn mknodat( + dirfd: RawFd, + path: &P, + kind: SFlag, + perm: Mode, + dev: dev_t, +) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::mknodat(dirfd, cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev) })?; Errno::result(res).map(drop) diff --git a/test/test_stat.rs b/test/test_stat.rs index 424371fa..42c536a8 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -306,3 +306,45 @@ fn test_mkdirat_fail() { let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err(); assert_eq!(result, Errno::ENOTDIR); } + +#[test] +#[cfg(not(any(target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "redox")))] +fn test_mknod_family() { + use fcntl::{AtFlags, OFlag}; + use nix::dir::Dir; + use stat::{fstatat, lstat, mknod, mknodat, SFlag}; + + let file_name = "test_file"; + { + let tempdir = tempfile::tempdir().unwrap(); + let target = tempdir.path().join(file_name); + mknod(&target, SFlag::S_IFREG, Mode::S_IRWXU, 0).unwrap(); + let mode = lstat(&target).unwrap().st_mode as mode_t; + assert!(mode & libc::S_IFREG == libc::S_IFREG); + assert!(mode & libc::S_IRWXU == libc::S_IRWXU); + } + { + let tempdir = tempfile::tempdir().unwrap(); + let target_dir = Dir::open(tempdir.path(), OFlag::O_DIRECTORY, Mode::S_IRWXU).unwrap(); + mknodat( + target_dir.as_raw_fd(), + file_name, + SFlag::S_IFREG, + Mode::S_IRWXU, + 0, + ) + .unwrap(); + let mode = fstatat( + target_dir.as_raw_fd(), + file_name, + AtFlags::AT_SYMLINK_NOFOLLOW, + ) + .unwrap() + .st_mode as mode_t; + assert!(mode & libc::S_IFREG == libc::S_IFREG); + assert!(mode & libc::S_IRWXU == libc::S_IRWXU); + } +} -- cgit v1.2.3