Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FreeBSD RESOLVE_BENEATH support and more #541

Merged
merged 4 commits into from
Mar 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ targets = [
"i686-unknown-linux-gnu",
"x86_64-apple-darwin",
"x86_64-pc-windows-msvc",
"x86_64-unknown-freebsd",
"x86_64-unknown-openbsd",
"x86_64-unknown-netbsd",
"x86_64-unknown-dragonfly",
"x86_64-unknown-illumos",
"x86_64-unknown-redox",
"x86_64-unknown-haiku",
"wasm32-unknown-emscripten",
"wasm32-wasi",
]

[features]
Expand Down
29 changes: 26 additions & 3 deletions src/backend/libc/fs/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -638,18 +638,41 @@ unsafe fn utimensat_old(
target_os = "redox",
target_os = "wasi",
)))]
pub(crate) fn chmodat(dirfd: BorrowedFd<'_>, path: &CStr, mode: Mode) -> io::Result<()> {
unsafe { ret(c::fchmodat(borrowed_fd(dirfd), c_str(path), mode.bits(), 0)) }
pub(crate) fn chmodat(
dirfd: BorrowedFd<'_>,
path: &CStr,
mode: Mode,
flags: AtFlags,
) -> io::Result<()> {
unsafe {
ret(c::fchmodat(
borrowed_fd(dirfd),
c_str(path),
mode.bits() as c::mode_t,
flags.bits(),
))
}
}

#[cfg(any(target_os = "android", target_os = "linux"))]
pub(crate) fn chmodat(dirfd: BorrowedFd<'_>, path: &CStr, mode: Mode) -> io::Result<()> {
pub(crate) fn chmodat(
dirfd: BorrowedFd<'_>,
path: &CStr,
mode: Mode,
flags: AtFlags,
) -> io::Result<()> {
// Linux's `fchmodat` does not have a flags argument.
//
// Use `c::syscall` rather than `c::fchmodat` because some libc
// implementations, such as musl, add extra logic to `fchmod` to emulate
// support for `O_PATH`, which uses `/proc` outside our control and
// interferes with our own use of `O_PATH`.
if flags == AtFlags::SYMLINK_NOFOLLOW {
return Err(io::Errno::OPNOTSUPP);
}
if !flags.is_empty() {
return Err(io::Errno::INVAL);
}
unsafe {
// Pass `mode` as a `c_uint` even if `mode_t` is narrower, since
// `libc_openat` is declared as a variadic function and narrower
Expand Down
28 changes: 15 additions & 13 deletions src/backend/libc/fs/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,16 @@ bitflags! {
/// `AT_EMPTY_PATH`
#[cfg(any(
target_os = "android",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
))]
const EMPTY_PATH = c::AT_EMPTY_PATH;

/// `AT_RESOLVE_BENEATH`
#[cfg(target_os = "freebsd")]
const RESOLVE_BENEATH = c::AT_RESOLVE_BENEATH;

/// `AT_EACCESS`
#[cfg(not(any(target_os = "emscripten", target_os = "android")))]
const EACCESS = c::AT_EACCESS;
Expand Down Expand Up @@ -175,7 +180,7 @@ bitflags! {
const DIRECTORY = c::O_DIRECTORY;

/// `O_DSYNC`
#[cfg(not(any(freebsdlike, target_os = "redox")))]
#[cfg(not(any(target_os = "dragonfly", target_os = "redox")))]
const DSYNC = c::O_DSYNC;

/// `O_EXCL`
Expand Down Expand Up @@ -228,6 +233,7 @@ bitflags! {
#[cfg(any(
target_os = "android",
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_os = "redox",
Expand Down Expand Up @@ -264,6 +270,14 @@ bitflags! {
target_os = "netbsd",
))]
const DIRECT = c::O_DIRECT;

/// `O_RESOLVE_BENEATH`
#[cfg(target_os = "freebsd")]
const RESOLVE_BENEATH = c::O_RESOLVE_BENEATH;

/// `O_EMPTY_PATH`
#[cfg(target_os = "freebsd")]
const EMPTY_PATH = c::O_EMPTY_PATH;
}
}

Expand Down Expand Up @@ -499,40 +513,28 @@ bitflags! {
const HUGETLB = c::MFD_HUGETLB;

/// `MFD_HUGE_64KB`
#[cfg(any(target_os = "android", target_os = "linux"))]
const HUGE_64KB = c::MFD_HUGE_64KB;
/// `MFD_HUGE_512JB`
#[cfg(any(target_os = "android", target_os = "linux"))]
const HUGE_512KB = c::MFD_HUGE_512KB;
/// `MFD_HUGE_1MB`
#[cfg(any(target_os = "android", target_os = "linux"))]
const HUGE_1MB = c::MFD_HUGE_1MB;
/// `MFD_HUGE_2MB`
#[cfg(any(target_os = "android", target_os = "linux"))]
const HUGE_2MB = c::MFD_HUGE_2MB;
/// `MFD_HUGE_8MB`
#[cfg(any(target_os = "android", target_os = "linux"))]
const HUGE_8MB = c::MFD_HUGE_8MB;
/// `MFD_HUGE_16MB`
#[cfg(any(target_os = "android", target_os = "linux"))]
const HUGE_16MB = c::MFD_HUGE_16MB;
/// `MFD_HUGE_32MB`
#[cfg(any(target_os = "android", target_os = "linux"))]
const HUGE_32MB = c::MFD_HUGE_32MB;
/// `MFD_HUGE_256MB`
#[cfg(any(target_os = "android", target_os = "linux"))]
const HUGE_256MB = c::MFD_HUGE_256MB;
/// `MFD_HUGE_512MB`
#[cfg(any(target_os = "android", target_os = "linux"))]
const HUGE_512MB = c::MFD_HUGE_512MB;
/// `MFD_HUGE_1GB`
#[cfg(any(target_os = "android", target_os = "linux"))]
const HUGE_1GB = c::MFD_HUGE_1GB;
/// `MFD_HUGE_2GB`
#[cfg(any(target_os = "android", target_os = "linux"))]
const HUGE_2GB = c::MFD_HUGE_2GB;
/// `MFD_HUGE_16GB`
#[cfg(any(target_os = "android", target_os = "linux"))]
const HUGE_16GB = c::MFD_HUGE_16GB;
}
}
Expand Down
8 changes: 6 additions & 2 deletions src/backend/libc/time/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ pub enum ClockId {
/// `CLOCK_MONOTONIC`
Monotonic = c::CLOCK_MONOTONIC,

/// `CLOCK_UPTIME`
#[cfg(any(freebsdlike))]
Uptime = c::CLOCK_UPTIME,

/// `CLOCK_PROCESS_CPUTIME_ID`
#[cfg(not(any(netbsdlike, solarish, target_os = "redox")))]
ProcessCPUTime = c::CLOCK_PROCESS_CPUTIME_ID,
Expand All @@ -135,11 +139,11 @@ pub enum ClockId {
ThreadCPUTime = c::CLOCK_THREAD_CPUTIME_ID,

/// `CLOCK_REALTIME_COARSE`
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
RealtimeCoarse = c::CLOCK_REALTIME_COARSE,

/// `CLOCK_MONOTONIC_COARSE`
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
MonotonicCoarse = c::CLOCK_MONOTONIC_COARSE,

/// `CLOCK_MONOTONIC_RAW`
Expand Down
13 changes: 12 additions & 1 deletion src/backend/linux_raw/fs/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,18 @@ pub(crate) fn chmod(filename: &CStr, mode: Mode) -> io::Result<()> {
}

#[inline]
pub(crate) fn chmodat(dirfd: BorrowedFd<'_>, filename: &CStr, mode: Mode) -> io::Result<()> {
pub(crate) fn chmodat(
dirfd: BorrowedFd<'_>,
filename: &CStr,
mode: Mode,
flags: AtFlags,
) -> io::Result<()> {
if flags == AtFlags::SYMLINK_NOFOLLOW {
return Err(io::Errno::OPNOTSUPP);
}
if !flags.is_empty() {
return Err(io::Errno::INVAL);
}
unsafe { ret(syscall_readonly!(__NR_fchmodat, dirfd, filename, mode)) }
}

Expand Down
31 changes: 25 additions & 6 deletions src/fs/at.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,11 +303,7 @@ pub fn utimensat<P: path::Arg, Fd: AsFd>(

/// `fchmodat(dirfd, path, mode, 0)`—Sets file or directory permissions.
///
/// The flags argument is fixed to 0, so `AT_SYMLINK_NOFOLLOW` is not
/// supported. <details>Platform support for this flag varies widely.</details>
///
/// This implementation does not support `O_PATH` file descriptors, even on
/// platforms where the host libc emulates it.
/// See `fchmodat_with` for a version that does take flags.
///
/// # References
/// - [POSIX]
Expand All @@ -319,7 +315,30 @@ pub fn utimensat<P: path::Arg, Fd: AsFd>(
#[inline]
#[doc(alias = "fchmodat")]
pub fn chmodat<P: path::Arg, Fd: AsFd>(dirfd: Fd, path: P, mode: Mode) -> io::Result<()> {
path.into_with_c_str(|path| backend::fs::syscalls::chmodat(dirfd.as_fd(), path, mode))
chmodat_with(dirfd, path, mode, AtFlags::empty())
}

/// `fchmodat(dirfd, path, mode, flags)`—Sets file or directory permissions.
///
/// Platform support for flags varies widely, for example on Linux `AT_SYMLINK_NOFOLLOW`
/// is not implemented and therefore `io::Errno::OPNOTSUPP` will be returned.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html
/// [Linux]: https://man7.org/linux/man-pages/man2/fchmodat.2.html
#[cfg(not(target_os = "wasi"))]
#[inline]
#[doc(alias = "fchmodat_with")]
pub fn chmodat_with<P: path::Arg, Fd: AsFd>(
dirfd: Fd,
path: P,
mode: Mode,
flags: AtFlags,
) -> io::Result<()> {
path.into_with_c_str(|path| backend::fs::syscalls::chmodat(dirfd.as_fd(), path, mode, flags))
}

/// `fclonefileat(src, dst_dir, dst, flags)`—Efficiently copies between files.
Expand Down
28 changes: 24 additions & 4 deletions src/io/kqueue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ impl Event {
let (ident, filter, fflags) = match filter {
EventFilter::Read(fd) => (fd.as_raw_fd() as uintptr_t, c::EVFILT_READ, 0),
EventFilter::Write(fd) => (fd.as_raw_fd() as _, c::EVFILT_WRITE, 0),
#[cfg(target_os = "freebsd")]
EventFilter::Empty(fd) => (fd.as_raw_fd() as _, c::EVFILT_EMPTY, 0),
EventFilter::Vnode { vnode, flags } => {
(vnode.as_raw_fd() as _, c::EVFILT_VNODE, flags.bits())
}
Expand All @@ -37,8 +39,8 @@ impl Event {
c::EVFILT_PROC,
flags.bits(),
),
#[cfg(any(apple, target_os = "freebsd"))]
EventFilter::Timer(timer) => {
#[cfg(any(apple, target_os = "freebsd", target_os = "netbsd"))]
let (data, fflags) = match timer {
Some(timer) => {
if timer.subsec_millis() == 0 {
Expand All @@ -51,6 +53,11 @@ impl Event {
}
None => (uintptr_t::MAX, c::NOTE_SECONDS),
};
#[cfg(any(target_os = "dragonfly", target_os = "openbsd"))]
let (data, fflags) = match timer {
Some(timer) => (timer.as_millis() as _, 0),
None => (uintptr_t::MAX, 0),
};

(data, c::EVFILT_TIMER, fflags)
}
Expand Down Expand Up @@ -98,6 +105,8 @@ impl Event {
match self.inner.filter as _ {
c::EVFILT_READ => EventFilter::Read(self.inner.ident as _),
c::EVFILT_WRITE => EventFilter::Write(self.inner.ident as _),
#[cfg(target_os = "freebsd")]
c::EVFILT_EMPTY => EventFilter::Empty(self.inner.ident as _),
c::EVFILT_VNODE => EventFilter::Vnode {
vnode: self.inner.ident as _,
flags: VnodeEvents::from_bits_truncate(self.inner.fflags),
Expand All @@ -107,9 +116,9 @@ impl Event {
pid: unsafe { crate::process::Pid::from_raw(self.inner.ident as _) }.unwrap(),
flags: ProcessEvents::from_bits_truncate(self.inner.fflags),
},
#[cfg(any(apple, target_os = "freebsd"))]
c::EVFILT_TIMER => EventFilter::Timer({
let (data, fflags) = (self.inner.data, self.inner.fflags);
#[cfg(any(apple, target_os = "freebsd", target_os = "netbsd"))]
match fflags as _ {
c::NOTE_SECONDS => Some(Duration::from_secs(data as _)),
c::NOTE_USECONDS => Some(Duration::from_micros(data as _)),
Expand All @@ -119,6 +128,8 @@ impl Event {
None
}
}
#[cfg(any(target_os = "dragonfly", target_os = "openbsd"))]
Some(Duration::from_millis(data as _))
}),
#[cfg(any(apple, freebsdlike))]
c::EVFILT_USER => EventFilter::User {
Expand All @@ -145,6 +156,10 @@ pub enum EventFilter {
/// A write filter.
Write(RawFd),

/// An empty filter.
#[cfg(target_os = "freebsd")]
Empty(RawFd),

/// A VNode filter.
Vnode {
/// The file descriptor we looked for events in.
Expand All @@ -165,7 +180,6 @@ pub enum EventFilter {
},

/// A timer filter.
#[cfg(any(apple, target_os = "freebsd"))]
Timer(Option<Duration>),

/// A user filter.
Expand Down Expand Up @@ -241,6 +255,9 @@ bitflags::bitflags! {

/// Access to the file was revoked.
const REVOKE = c::NOTE_REVOKE;

/// The link count of the file has changed.
const LINK = c::NOTE_LINK;
}
}

Expand All @@ -257,8 +274,11 @@ bitflags::bitflags! {
/// The process executed a new process.
const EXEC = c::NOTE_EXEC;

/// TODO
/// Follow the process through fork() calls (write only).
const TRACK = c::NOTE_TRACK;

/// An error has occurred with following the process.
const TRACKERR = c::NOTE_TRACKERR;
}
}

Expand Down