Skip to content
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
13 changes: 4 additions & 9 deletions src/backend/libc/fs/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -596,14 +596,9 @@ pub(crate) fn stat(path: &CStr) -> io::Result<Stat> {
)
))]
{
match crate::fs::statx(
crate::fs::CWD,
path,
AtFlags::empty(),
StatxFlags::BASIC_STATS,
) {
match crate::fs::statx(CWD, path, AtFlags::empty(), StatxFlags::BASIC_STATS) {
Ok(x) => statx_to_stat(x),
Err(io::Errno::NOSYS) => statat_old(crate::fs::CWD, path, AtFlags::empty()),
Err(io::Errno::NOSYS) => statat_old(CWD, path, AtFlags::empty()),
Err(err) => Err(err),
}
}
Expand Down Expand Up @@ -637,13 +632,13 @@ pub(crate) fn lstat(path: &CStr) -> io::Result<Stat> {
))]
{
match crate::fs::statx(
crate::fs::CWD,
CWD,
path,
AtFlags::SYMLINK_NOFOLLOW,
StatxFlags::BASIC_STATS,
) {
Ok(x) => statx_to_stat(x),
Err(io::Errno::NOSYS) => statat_old(crate::fs::CWD, path, AtFlags::SYMLINK_NOFOLLOW),
Err(io::Errno::NOSYS) => statat_old(CWD, path, AtFlags::SYMLINK_NOFOLLOW),
Err(err) => Err(err),
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/backend/linux_raw/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

pub(crate) type size_t = usize;
pub(crate) use linux_raw_sys::ctypes::*;
pub(crate) use linux_raw_sys::errno::EINVAL;
pub(crate) use linux_raw_sys::errno::{EBADF, EINVAL};
pub(crate) use linux_raw_sys::general::{__kernel_fd_set as fd_set, __FD_SETSIZE as FD_SETSIZE};
pub(crate) use linux_raw_sys::ioctl::{FIONBIO, FIONREAD};
// Import the kernel's `uid_t` and `gid_t` if they're 32-bit.
Expand Down
2 changes: 1 addition & 1 deletion src/backend/linux_raw/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ impl<'a, Num: ArgNumber> From<BorrowedFd<'a>> for ArgReg<'a, Num> {
pub(super) unsafe fn raw_fd<'a, Num: ArgNumber>(fd: RawFd) -> ArgReg<'a, Num> {
// Use `no_fd` when passing `-1` is intended.
#[cfg(feature = "fs")]
debug_assert!(fd == crate::fs::CWD.as_raw_fd() || fd >= 0);
debug_assert!(fd == crate::fs::CWD.as_raw_fd() || fd == crate::fs::ABS.as_raw_fd() || fd >= 0);

// Don't pass the `io_uring_register_files_skip` sentry value this way.
#[cfg(feature = "io_uring")]
Expand Down
5 changes: 3 additions & 2 deletions src/fs/at.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
//! POSIX-style `*at` functions.
//!
//! The `dirfd` argument to these functions may be a file descriptor for a
//! directory, or the special value [`CWD`].
//! directory, the special value [`CWD`], or the special value [`ABS`].
//!
//! [`cwd`]: crate::fs::CWD
//! [`CWD`]: crate::fs::CWD
//! [`ABS`]: crate::fs::ABS

use crate::fd::OwnedFd;
use crate::ffi::CStr;
Expand Down
29 changes: 0 additions & 29 deletions src/fs/cwd.rs

This file was deleted.

12 changes: 4 additions & 8 deletions src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ mod at;
mod constants;
#[cfg(linux_kernel)]
mod copy_file_range;
#[cfg(not(any(target_os = "espidf", target_os = "redox")))]
#[cfg(not(target_os = "haiku"))]
// Haiku needs <https://git.haiku-os.org/haiku/commit/?id=b8caef69155fbe87def579305622b9718d7779dc>
mod cwd;
#[cfg(all(feature = "alloc", not(any(target_os = "espidf", target_os = "redox"))))]
mod dir;
#[cfg(not(any(
Expand Down Expand Up @@ -54,6 +50,8 @@ mod raw_dir;
mod seek_from;
#[cfg(target_os = "linux")]
mod sendfile;
#[cfg(not(any(target_os = "espidf", target_os = "redox")))]
mod special;
#[cfg(linux_kernel)]
mod statx;
#[cfg(not(any(
Expand All @@ -72,10 +70,6 @@ pub use at::*;
pub use constants::*;
#[cfg(linux_kernel)]
pub use copy_file_range::copy_file_range;
#[cfg(not(any(target_os = "espidf", target_os = "redox")))]
#[cfg(not(target_os = "haiku"))]
// Haiku needs <https://git.haiku-os.org/haiku/commit/?id=b8caef69155fbe87def579305622b9718d7779dc>
pub use cwd::*;
#[cfg(all(feature = "alloc", not(any(target_os = "espidf", target_os = "redox"))))]
pub use dir::{Dir, DirEntry};
#[cfg(not(any(
Expand Down Expand Up @@ -118,6 +112,8 @@ pub use raw_dir::{RawDir, RawDirEntry};
pub use seek_from::SeekFrom;
#[cfg(target_os = "linux")]
pub use sendfile::sendfile;
#[cfg(not(any(target_os = "espidf", target_os = "redox")))]
pub use special::*;
#[cfg(linux_kernel)]
pub use statx::statx;
#[cfg(not(any(
Expand Down
73 changes: 73 additions & 0 deletions src/fs/special.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//! The `CWD` and `ABS` constants, representing the current working directory
//! and absolute-only paths, respectively.
//!
//! # Safety
//!
//! This file uses `AT_FDCWD`, which is a raw file descriptor, but which is
//! always valid, and `-EBADF`, which is an undocumented by commonly used
//! convention of passing a value which will always fail if the accompanying
//! path isn't absolute.

#![allow(unsafe_code)]

use crate::backend;
use backend::c;
use backend::fd::{BorrowedFd, RawFd};

/// `AT_FDCWD`—A handle representing the current working directory.
///
/// This is a file descriptor which refers to the process current directory
/// which can be used as the directory argument in `*at` functions such as
/// [`openat`].
///
/// # References
/// - [POSIX]
///
/// [`openat`]: crate::fs::openat
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/fcntl.h.html
// SAFETY: `AT_FDCWD` is a reserved value that is never dynamically
// allocated, so it'll remain valid for the duration of `'static`.
#[doc(alias = "AT_FDCWD")]
pub const CWD: BorrowedFd<'static> =
unsafe { BorrowedFd::<'static>::borrow_raw(c::AT_FDCWD as RawFd) };

/// `-EBADF`—A handle that requires paths to be absolute.
///
/// This is a file descriptor which refers to no directory, which can be used
/// as the directory argument in `*at` functions such as [`openat`], which
/// causes them to fail with [`BADF`] if the accompanying path is not absolute.
///
/// This corresponds to the undocumented by commonly used convention of
/// passing `-EBADF` as the `dirfd` argument, which is ignored if the path
/// is absolute, and evokes an `EBADF` error otherwise.
///
/// [`openat`]: crate::fs::openat
/// [`BADF`]: crate::io::Errno::BADF
// SAFETY: This `-EBADF` convention is commonly used, such as in lxc, so OS's
// aren't going to break it.
pub const ABS: BorrowedFd<'static> =
unsafe { BorrowedFd::<'static>::borrow_raw(c::EBADF.wrapping_neg() as RawFd) };

#[cfg(test)]
mod tests {
use super::*;
use crate::fd::AsRawFd;

#[test]
fn test_cwd() {
assert!(CWD.as_raw_fd() != -1);
#[cfg(linux_kernel)]
#[cfg(feature = "io_uring")]
assert!(CWD.as_raw_fd() != linux_raw_sys::io_uring::IORING_REGISTER_FILES_SKIP);
}

#[test]
fn test_abs() {
assert!(ABS.as_raw_fd() < 0);
assert!(ABS.as_raw_fd() != -1);
assert!(ABS.as_raw_fd() != c::AT_FDCWD);
#[cfg(linux_kernel)]
#[cfg(feature = "io_uring")]
assert!(ABS.as_raw_fd() != linux_raw_sys::io_uring::IORING_REGISTER_FILES_SKIP);
}
}
2 changes: 1 addition & 1 deletion src/process/chdir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub fn fchdir<Fd: AsFd>(fd: Fd) -> io::Result<()> {
backend::process::syscalls::fchdir(fd.as_fd())
}

/// `getCWD`—Return the current working directory.
/// `getcwd`—Return the current working directory.
///
/// If `reuse` already has available capacity, reuse it if possible.
///
Expand Down
4 changes: 0 additions & 4 deletions tests/fs/cwd.rs

This file was deleted.

2 changes: 1 addition & 1 deletion tests/fs/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#![cfg_attr(core_c_str, feature(core_c_str))]

mod chmodat;
mod cwd;
#[cfg(not(target_os = "redox"))]
mod dir;
mod fcntl;
Expand Down Expand Up @@ -42,6 +41,7 @@ mod renameat;
#[cfg(any(linux_kernel, target_os = "freebsd"))]
mod seals;
mod seek;
mod special;
#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))]
mod statfs;
#[cfg(linux_kernel)]
Expand Down
57 changes: 57 additions & 0 deletions tests/fs/special.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#[cfg(not(target_os = "wasi"))]
#[test]
fn test_special_fds() {
use rustix::fs::{fstat, open, openat, Mode, OFlags, Stat, ABS, CWD};
use rustix::process::getcwd;
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
use std::path::PathBuf;

let cwd_path = getcwd(Vec::new()).unwrap().into_bytes();
let cwd_path = OsStr::from_bytes(&cwd_path).to_owned();
let cwd_path = PathBuf::from(cwd_path);

// Open the same file several ways using special constants and make sure
// we get the same file.

// Use plain `open`.
let a = open("Cargo.toml", OFlags::RDONLY, Mode::empty()).unwrap();

// Use `CWD` with a relative path.
let b = openat(CWD, "Cargo.toml", OFlags::RDONLY, Mode::empty()).unwrap();

// Use `CWD` with an absolute path.
let c = openat(
CWD,
cwd_path.join("Cargo.toml"),
OFlags::RDONLY,
Mode::empty(),
)
.unwrap();

// Use `ABS` with an absolute path.
let d = openat(
ABS,
cwd_path.join("Cargo.toml"),
OFlags::RDONLY,
Mode::empty(),
)
.unwrap();

// Test that opening a relative path with `ABS` fails.
let err = openat(ABS, "Cargo.toml", OFlags::RDONLY, Mode::empty()).unwrap_err();
assert_eq!(err, rustix::io::Errno::BADF);

let a_stat = fstat(a).unwrap();
let b_stat = fstat(b).unwrap();
let c_stat = fstat(c).unwrap();
let d_stat = fstat(d).unwrap();

assert!(same(&a_stat, &b_stat));
assert!(same(&b_stat, &c_stat));
assert!(same(&c_stat, &d_stat));

fn same(a: &Stat, b: &Stat) -> bool {
a.st_ino == b.st_ino && a.st_dev == b.st_dev
}
}