Skip to content

Commit 465c70b

Browse files
authored
Fix tests on FreeBSD (#341)
* Disable tests that fail on FreeBSD. Disable tests that are failing on FreeBSD. The "ambient" versions of these tests are also failing, so this appears to be platform-specific behavior rather than cap-std's behavior. * Don't install `curl`; just use the default one. * Check for opening `..` in the FreeBSD `RESOLVE_BENEATH` check. Change the `RESOLVE_BENEATH` check to check for the behavior of opening `..` on FreeBSD. * Add a freebsd-14-0-snap entry to the Cirrus CI config. FreeBSD 14 supports the RESOLVE_BENEATH semantics where `..` is a capability error even when the base fd is the root directory.
1 parent 5e32356 commit 465c70b

File tree

9 files changed

+72
-47
lines changed

9 files changed

+72
-47
lines changed

.cirrus.yml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
# Implementation derived from `.cirrus.yml` in Rust's libc bindings
22
# at revision 7f4774e76bd5cb9ccb7140d71ef9be9c16009cdf.
33

4+
task:
5+
name: stable x86_64-unknown-freebsd-14-snap
6+
freebsd_instance:
7+
image_family: freebsd-14-0-snap
8+
setup_script:
9+
- curl https://sh.rustup.rs -sSf --output rustup.sh
10+
- sh rustup.sh --default-toolchain stable -y --profile=minimal
11+
- . $HOME/.cargo/env
12+
- rustup default stable
13+
test_script:
14+
- . $HOME/.cargo/env
15+
- cargo test --features=fs_utf8 --workspace
16+
417
task:
518
name: stable x86_64-unknown-freebsd-13
619
freebsd_instance:
720
image_family: freebsd-13-2
821
setup_script:
9-
- pkg install -y curl
1022
- curl https://sh.rustup.rs -sSf --output rustup.sh
1123
- sh rustup.sh --default-toolchain stable -y --profile=minimal
1224
- . $HOME/.cargo/env
@@ -20,7 +32,6 @@ task:
2032
freebsd_instance:
2133
image_family: freebsd-12-4
2234
setup_script:
23-
- pkg install -y curl
2435
- curl https://sh.rustup.rs -sSf --output rustup.sh
2536
- sh rustup.sh --default-toolchain stable -y --profile=minimal
2637
- . $HOME/.cargo/env
Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,40 @@
1-
use rustix::fs::{statat, AtFlags};
2-
use std::fs;
1+
use rustix::cstr;
2+
use rustix::fs::{openat, statat, AtFlags, Mode, OFlags, CWD};
3+
use rustix::io::Errno;
34
use std::sync::atomic::{AtomicBool, Ordering::Relaxed};
45

56
static WORKING: AtomicBool = AtomicBool::new(false);
67
static CHECKED: AtomicBool = AtomicBool::new(false);
78

89
#[inline]
9-
pub(crate) fn beneath_supported(start: &fs::File) -> bool {
10+
pub(crate) fn beneath_supported() -> bool {
1011
if WORKING.load(Relaxed) {
1112
return true;
1213
}
1314
if CHECKED.load(Relaxed) {
1415
return false;
1516
}
16-
// Unknown O_ flags get ignored but AT_ flags have strict checks, so we use that.
17-
if let Err(rustix::io::Errno::INVAL) =
18-
statat(start, "", AtFlags::EMPTY_PATH | AtFlags::RESOLVE_BENEATH)
19-
{
20-
CHECKED.store(true, Relaxed);
21-
false
22-
} else {
23-
WORKING.store(true, Relaxed);
24-
true
17+
check_beneath_supported()
18+
}
19+
20+
#[cold]
21+
fn check_beneath_supported() -> bool {
22+
// `RESOLVE_BENEATH` was introduced in FreeBSD 13, but opening `..` within
23+
// the root directory re-opened the root directory. In FreeBSD 14, it fails
24+
// as cap-std expects.
25+
if let Ok(root) = openat(
26+
CWD,
27+
cstr!("/"),
28+
OFlags::RDONLY | OFlags::CLOEXEC,
29+
Mode::empty(),
30+
) {
31+
// Unknown O_ flags get ignored but AT_ flags have strict checks, so we use that.
32+
if let Err(Errno::NOTCAPABLE) = statat(root, cstr!(".."), AtFlags::RESOLVE_BENEATH) {
33+
WORKING.store(true, Relaxed);
34+
return true;
35+
}
2536
}
37+
38+
CHECKED.store(true, Relaxed);
39+
false
2640
}

cap-primitives/src/rustix/freebsd/fs/open_impl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub(crate) fn open_impl(
1010
path: &Path,
1111
options: &OpenOptions,
1212
) -> io::Result<fs::File> {
13-
if !super::beneath_supported(start) {
13+
if !super::beneath_supported() {
1414
return manually::open(start, path, options);
1515
}
1616

cap-primitives/src/rustix/freebsd/fs/remove_dir_impl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::path::Path;
44
use std::{fs, io};
55

66
pub(crate) fn remove_dir_impl(start: &fs::File, path: &Path) -> io::Result<()> {
7-
if !super::beneath_supported(start) {
7+
if !super::beneath_supported() {
88
return via_parent::remove_dir(start, path);
99
}
1010

cap-primitives/src/rustix/freebsd/fs/remove_file_impl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::path::Path;
44
use std::{fs, io};
55

66
pub(crate) fn remove_file_impl(start: &fs::File, path: &Path) -> io::Result<()> {
7-
if !super::beneath_supported(start) {
7+
if !super::beneath_supported() {
88
return via_parent::remove_file(start, path);
99
}
1010

cap-primitives/src/rustix/freebsd/fs/set_permissions_impl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub(crate) fn set_permissions_impl(
99
path: &Path,
1010
perm: Permissions,
1111
) -> io::Result<()> {
12-
if !super::beneath_supported(start) {
12+
if !super::beneath_supported() {
1313
return super::super::super::fs::set_permissions_manually(start, path, perm);
1414
}
1515

cap-primitives/src/rustix/freebsd/fs/set_times_impl.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub(crate) fn set_times_impl(
99
atime: Option<SystemTimeSpec>,
1010
mtime: Option<SystemTimeSpec>,
1111
) -> io::Result<()> {
12-
if !super::beneath_supported(start) {
12+
if !super::beneath_supported() {
1313
return super::super::super::fs::set_times_manually(start, path, atime, mtime);
1414
}
1515

@@ -27,7 +27,7 @@ pub(crate) fn set_times_nofollow_impl(
2727
atime: Option<SystemTimeSpec>,
2828
mtime: Option<SystemTimeSpec>,
2929
) -> io::Result<()> {
30-
if !super::beneath_supported(start) {
30+
if !super::beneath_supported() {
3131
return via_parent::set_times_nofollow(start, path, atime, mtime);
3232
}
3333

cap-primitives/src/rustix/freebsd/fs/stat_impl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub(crate) fn stat_impl(
88
path: &Path,
99
follow: FollowSymlinks,
1010
) -> io::Result<Metadata> {
11-
if !super::beneath_supported(start) {
11+
if !super::beneath_supported() {
1212
return manually::stat(start, path, follow);
1313
}
1414

tests/fs_additional.rs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -454,16 +454,18 @@ fn check_dot_access() {
454454
check!(tmpdir.metadata("dir/"));
455455
check!(tmpdir.metadata("dir//"));
456456

457-
assert!(tmpdir.metadata("dir/.").is_err());
458-
assert!(tmpdir.metadata("dir/./").is_err());
459-
assert!(tmpdir.metadata("dir/.//").is_err());
460-
assert!(tmpdir.metadata("dir/./.").is_err());
461-
assert!(tmpdir.metadata("dir/.//.").is_err());
462-
assert!(tmpdir.metadata("dir/..").is_err());
463-
assert!(tmpdir.metadata("dir/../").is_err());
464-
assert!(tmpdir.metadata("dir/..//").is_err());
465-
assert!(tmpdir.metadata("dir/../.").is_err());
466-
assert!(tmpdir.metadata("dir/..//.").is_err());
457+
if !cfg!(target_os = "freebsd") {
458+
assert!(tmpdir.metadata("dir/.").is_err());
459+
assert!(tmpdir.metadata("dir/./").is_err());
460+
assert!(tmpdir.metadata("dir/.//").is_err());
461+
assert!(tmpdir.metadata("dir/./.").is_err());
462+
assert!(tmpdir.metadata("dir/.//.").is_err());
463+
assert!(tmpdir.metadata("dir/..").is_err());
464+
assert!(tmpdir.metadata("dir/../").is_err());
465+
assert!(tmpdir.metadata("dir/..//").is_err());
466+
assert!(tmpdir.metadata("dir/../.").is_err());
467+
assert!(tmpdir.metadata("dir/..//.").is_err());
468+
}
467469
}
468470

469471
/// This test is the same as `check_dot_access` but uses `std::fs`'
@@ -486,16 +488,18 @@ fn check_dot_access_ambient() {
486488
check!(fs::metadata(dir.path().join("dir/")));
487489
check!(fs::metadata(dir.path().join("dir//")));
488490

489-
assert!(fs::metadata(dir.path().join("dir/.")).is_err());
490-
assert!(fs::metadata(dir.path().join("dir/./")).is_err());
491-
assert!(fs::metadata(dir.path().join("dir/.//")).is_err());
492-
assert!(fs::metadata(dir.path().join("dir/./.")).is_err());
493-
assert!(fs::metadata(dir.path().join("dir/.//.")).is_err());
494-
assert!(fs::metadata(dir.path().join("dir/..")).is_err());
495-
assert!(fs::metadata(dir.path().join("dir/../")).is_err());
496-
assert!(fs::metadata(dir.path().join("dir/..//")).is_err());
497-
assert!(fs::metadata(dir.path().join("dir/../.")).is_err());
498-
assert!(fs::metadata(dir.path().join("dir/..//.")).is_err());
491+
if !cfg!(target_os = "freebsd") {
492+
assert!(fs::metadata(dir.path().join("dir/.")).is_err());
493+
assert!(fs::metadata(dir.path().join("dir/./")).is_err());
494+
assert!(fs::metadata(dir.path().join("dir/.//")).is_err());
495+
assert!(fs::metadata(dir.path().join("dir/./.")).is_err());
496+
assert!(fs::metadata(dir.path().join("dir/.//.")).is_err());
497+
assert!(fs::metadata(dir.path().join("dir/..")).is_err());
498+
assert!(fs::metadata(dir.path().join("dir/../")).is_err());
499+
assert!(fs::metadata(dir.path().join("dir/..//")).is_err());
500+
assert!(fs::metadata(dir.path().join("dir/../.")).is_err());
501+
assert!(fs::metadata(dir.path().join("dir/..//.")).is_err());
502+
}
499503
}
500504

501505
// Windows allows one to open "file/." and "file/.." and similar, however it
@@ -650,19 +654,16 @@ fn dir_unsearchable_unreadable() {
650654
options.mode(0o000);
651655
check!(tmpdir.create_dir_with("dir", &options));
652656

653-
// Platforms with `O_PATH` can open a directory with no permissions. And
654-
// somehow FreeBSD can too; see `dir_unsearchable_unreadable_ambient`
655-
// below confirming this.
657+
// Platforms with `O_PATH` can open a directory with no permissions.
656658
if cfg!(any(
657659
target_os = "android",
658-
target_os = "freebsd",
659660
target_os = "linux",
660661
target_os = "redox",
661662
)) {
662663
let dir = check!(tmpdir.open_dir("dir"));
663664
assert!(dir.entries().is_err());
664665
assert!(dir.open_dir(".").is_err());
665-
} else {
666+
} else if !cfg!(target_os = "freebsd") {
666667
assert!(tmpdir.open_dir("dir").is_err());
667668
}
668669
}
@@ -684,7 +685,6 @@ fn dir_unsearchable_unreadable_ambient() {
684685
if cfg!(any(
685686
target_os = "android",
686687
target_os = "linux",
687-
target_os = "freebsd",
688688
target_os = "redox",
689689
)) {
690690
assert!(std::fs::File::open(dir.path().join("dir")).is_err());

0 commit comments

Comments
 (0)