Skip to content

Commit 873bac5

Browse files
authored
Add a rustix::fs::ABS constant. (#1189)
Add a `rustix::fs::ABS` constant, which corresponds to the undocumented but commonly used convention of using `-EBADF` as the file descriptor in `openat` and similar calls. This makes them fail if the path is not absolute. Fixes #1187.
1 parent 2c01c69 commit 873bac5

11 files changed

Lines changed: 145 additions & 56 deletions

File tree

src/backend/libc/fs/syscalls.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -595,14 +595,9 @@ pub(crate) fn stat(path: &CStr) -> io::Result<Stat> {
595595
)
596596
))]
597597
{
598-
match crate::fs::statx(
599-
crate::fs::CWD,
600-
path,
601-
AtFlags::empty(),
602-
StatxFlags::BASIC_STATS,
603-
) {
598+
match crate::fs::statx(CWD, path, AtFlags::empty(), StatxFlags::BASIC_STATS) {
604599
Ok(x) => statx_to_stat(x),
605-
Err(io::Errno::NOSYS) => statat_old(crate::fs::CWD, path, AtFlags::empty()),
600+
Err(io::Errno::NOSYS) => statat_old(CWD, path, AtFlags::empty()),
606601
Err(err) => Err(err),
607602
}
608603
}
@@ -636,13 +631,13 @@ pub(crate) fn lstat(path: &CStr) -> io::Result<Stat> {
636631
))]
637632
{
638633
match crate::fs::statx(
639-
crate::fs::CWD,
634+
CWD,
640635
path,
641636
AtFlags::SYMLINK_NOFOLLOW,
642637
StatxFlags::BASIC_STATS,
643638
) {
644639
Ok(x) => statx_to_stat(x),
645-
Err(io::Errno::NOSYS) => statat_old(crate::fs::CWD, path, AtFlags::SYMLINK_NOFOLLOW),
640+
Err(io::Errno::NOSYS) => statat_old(CWD, path, AtFlags::SYMLINK_NOFOLLOW),
646641
Err(err) => Err(err),
647642
}
648643
}

src/backend/linux_raw/c.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
pub(crate) type size_t = usize;
1010
pub(crate) use linux_raw_sys::ctypes::*;
11-
pub(crate) use linux_raw_sys::errno::EINVAL;
11+
pub(crate) use linux_raw_sys::errno::{EBADF, EINVAL};
1212
pub(crate) use linux_raw_sys::general::{__kernel_fd_set as fd_set, __FD_SETSIZE as FD_SETSIZE};
1313
pub(crate) use linux_raw_sys::ioctl::{FIONBIO, FIONREAD};
1414
// Import the kernel's `uid_t` and `gid_t` if they're 32-bit.

src/backend/linux_raw/conv.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ impl<'a, Num: ArgNumber> From<BorrowedFd<'a>> for ArgReg<'a, Num> {
162162
pub(super) unsafe fn raw_fd<'a, Num: ArgNumber>(fd: RawFd) -> ArgReg<'a, Num> {
163163
// Use `no_fd` when passing `-1` is intended.
164164
#[cfg(feature = "fs")]
165-
debug_assert!(fd == crate::fs::CWD.as_raw_fd() || fd >= 0);
165+
debug_assert!(fd == crate::fs::CWD.as_raw_fd() || fd == crate::fs::ABS.as_raw_fd() || fd >= 0);
166166

167167
// Don't pass the `io_uring_register_files_skip` sentry value this way.
168168
#[cfg(feature = "io_uring")]

src/fs/at.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
//! POSIX-style `*at` functions.
22
//!
33
//! The `dirfd` argument to these functions may be a file descriptor for a
4-
//! directory, or the special value [`CWD`].
4+
//! directory, the special value [`CWD`], or the special value [`ABS`].
55
//!
6-
//! [`cwd`]: crate::fs::CWD
6+
//! [`CWD`]: crate::fs::CWD
7+
//! [`ABS`]: crate::fs::ABS
78
89
use crate::fd::OwnedFd;
910
use crate::ffi::CStr;

src/fs/cwd.rs

Lines changed: 0 additions & 29 deletions
This file was deleted.

src/fs/mod.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ mod at;
66
mod constants;
77
#[cfg(linux_kernel)]
88
mod copy_file_range;
9-
#[cfg(not(any(target_os = "espidf", target_os = "redox")))]
10-
#[cfg(not(target_os = "haiku"))]
11-
// Haiku needs <https://git.haiku-os.org/haiku/commit/?id=b8caef69155fbe87def579305622b9718d7779dc>
12-
mod cwd;
139
#[cfg(all(feature = "alloc", not(any(target_os = "espidf", target_os = "redox"))))]
1410
mod dir;
1511
#[cfg(not(any(
@@ -54,6 +50,8 @@ mod raw_dir;
5450
mod seek_from;
5551
#[cfg(target_os = "linux")]
5652
mod sendfile;
53+
#[cfg(not(any(target_os = "espidf", target_os = "redox")))]
54+
mod special;
5755
#[cfg(linux_kernel)]
5856
mod statx;
5957
#[cfg(not(any(
@@ -72,10 +70,6 @@ pub use at::*;
7270
pub use constants::*;
7371
#[cfg(linux_kernel)]
7472
pub use copy_file_range::copy_file_range;
75-
#[cfg(not(any(target_os = "espidf", target_os = "redox")))]
76-
#[cfg(not(target_os = "haiku"))]
77-
// Haiku needs <https://git.haiku-os.org/haiku/commit/?id=b8caef69155fbe87def579305622b9718d7779dc>
78-
pub use cwd::*;
7973
#[cfg(all(feature = "alloc", not(any(target_os = "espidf", target_os = "redox"))))]
8074
pub use dir::{Dir, DirEntry};
8175
#[cfg(not(any(
@@ -118,6 +112,8 @@ pub use raw_dir::{RawDir, RawDirEntry};
118112
pub use seek_from::SeekFrom;
119113
#[cfg(target_os = "linux")]
120114
pub use sendfile::sendfile;
115+
#[cfg(not(any(target_os = "espidf", target_os = "redox")))]
116+
pub use special::*;
121117
#[cfg(linux_kernel)]
122118
pub use statx::statx;
123119
#[cfg(not(any(

src/fs/special.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//! The `CWD` and `ABS` constants, representing the current working directory
2+
//! and absolute-only paths, respectively.
3+
//!
4+
//! # Safety
5+
//!
6+
//! This file uses `AT_FDCWD`, which is a raw file descriptor, but which is
7+
//! always valid, and `-EBADF`, which is an undocumented by commonly used
8+
//! convention of passing a value which will always fail if the accompanying
9+
//! path isn't absolute.
10+
11+
#![allow(unsafe_code)]
12+
13+
use crate::backend;
14+
use backend::c;
15+
use backend::fd::{BorrowedFd, RawFd};
16+
17+
/// `AT_FDCWD`—A handle representing the current working directory.
18+
///
19+
/// This is a file descriptor which refers to the process current directory
20+
/// which can be used as the directory argument in `*at` functions such as
21+
/// [`openat`].
22+
///
23+
/// # References
24+
/// - [POSIX]
25+
///
26+
/// [`openat`]: crate::fs::openat
27+
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/fcntl.h.html
28+
// SAFETY: `AT_FDCWD` is a reserved value that is never dynamically
29+
// allocated, so it'll remain valid for the duration of `'static`.
30+
#[doc(alias = "AT_FDCWD")]
31+
pub const CWD: BorrowedFd<'static> =
32+
unsafe { BorrowedFd::<'static>::borrow_raw(c::AT_FDCWD as RawFd) };
33+
34+
/// `-EBADF`—A handle that requires paths to be absolute.
35+
///
36+
/// This is a file descriptor which refers to no directory, which can be used
37+
/// as the directory argument in `*at` functions such as [`openat`], which
38+
/// causes them to fail with [`BADF`] if the accompanying path is not absolute.
39+
///
40+
/// This corresponds to the undocumented by commonly used convention of
41+
/// passing `-EBADF` as the `dirfd` argument, which is ignored if the path
42+
/// is absolute, and evokes an `EBADF` error otherwise.
43+
///
44+
/// [`openat`]: crate::fs::openat
45+
/// [`BADF`]: crate::io::Errno::BADF
46+
// SAFETY: This `-EBADF` convention is commonly used, such as in lxc, so OS's
47+
// aren't going to break it.
48+
pub const ABS: BorrowedFd<'static> =
49+
unsafe { BorrowedFd::<'static>::borrow_raw(c::EBADF.wrapping_neg() as RawFd) };
50+
51+
#[cfg(test)]
52+
mod tests {
53+
use super::*;
54+
use crate::fd::AsRawFd;
55+
56+
#[test]
57+
fn test_cwd() {
58+
assert!(CWD.as_raw_fd() != -1);
59+
#[cfg(linux_kernel)]
60+
#[cfg(feature = "io_uring")]
61+
assert!(CWD.as_raw_fd() != linux_raw_sys::io_uring::IORING_REGISTER_FILES_SKIP);
62+
}
63+
64+
#[test]
65+
fn test_abs() {
66+
assert!(ABS.as_raw_fd() < 0);
67+
assert!(ABS.as_raw_fd() != -1);
68+
assert!(ABS.as_raw_fd() != c::AT_FDCWD);
69+
#[cfg(linux_kernel)]
70+
#[cfg(feature = "io_uring")]
71+
assert!(ABS.as_raw_fd() != linux_raw_sys::io_uring::IORING_REGISTER_FILES_SKIP);
72+
}
73+
}

src/process/chdir.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub fn fchdir<Fd: AsFd>(fd: Fd) -> io::Result<()> {
4040
backend::process::syscalls::fchdir(fd.as_fd())
4141
}
4242

43-
/// `getCWD`—Return the current working directory.
43+
/// `getcwd`—Return the current working directory.
4444
///
4545
/// If `reuse` already has available capacity, reuse it if possible.
4646
///

tests/fs/cwd.rs

Lines changed: 0 additions & 4 deletions
This file was deleted.

tests/fs/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#![cfg_attr(core_c_str, feature(core_c_str))]
66

77
mod chmodat;
8-
mod cwd;
98
#[cfg(not(target_os = "redox"))]
109
mod dir;
1110
mod fcntl;
@@ -42,6 +41,7 @@ mod renameat;
4241
#[cfg(any(linux_kernel, target_os = "freebsd"))]
4342
mod seals;
4443
mod seek;
44+
mod special;
4545
#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))]
4646
mod statfs;
4747
#[cfg(linux_kernel)]

0 commit comments

Comments
 (0)