diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /vendor/rustix/tests | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/rustix/tests')
75 files changed, 4937 insertions, 0 deletions
diff --git a/vendor/rustix/tests/backends.rs b/vendor/rustix/tests/backends.rs new file mode 100644 index 000000000..4b88bd11c --- /dev/null +++ b/vendor/rustix/tests/backends.rs @@ -0,0 +1,109 @@ +use std::process::Command; + +#[test] +fn test_backends() { + // Pick an arbitrary platform where linux_raw is enabled by default and + // ensure that the use-default crate uses it. + #[cfg(all(target_os = "linux", target_arch = "aarch64"))] + { + assert!( + !has_dependency("test-crates/use-default", &[], &[], &["RUSTFLAGS"], "libc"), + "use-default depends on libc" + ); + assert!( + has_dependency( + "test-crates/use-default", + &[], + &[], + &["RUSTFLAGS"], + "linux-raw-sys" + ), + "use-default does not depend on linux-raw-sys" + ); + } + + #[cfg(windows)] + let libc_dep = "windows-sys"; + #[cfg(unix)] + let libc_dep = "libc"; + + // Test the use-libc crate, which enables the "use-libc" cargo feature. + assert!( + has_dependency("test-crates/use-libc", &[], &[], &["RUSTFLAGS"], libc_dep), + "use-libc doesn't depend on {}", + libc_dep + ); + + // Test the use-default crate with `--cfg=rustix_use_libc`. + assert!( + has_dependency( + "test-crates/use-default", + &[], + &[("RUSTFLAGS", "--cfg=rustix_use_libc")], + &[], + libc_dep + ), + "use-default with --cfg=rustix_use_libc does not depend on {}", + libc_dep + ); + assert!( + !has_dependency( + "test-crates/use-default", + &[], + &[("RUSTFLAGS", "--cfg=rustix_use_libc")], + &[], + "linux-raw-sys" + ), + "use-default with --cfg=rustix_use_libc depends on linux-raw-sys" + ); + + // Test the use-default crate with `--features=rustix/use-libc`. + assert!( + has_dependency( + "test-crates/use-default", + &["--features=rustix/use-libc"], + &[], + &[], + libc_dep + ), + "use-default with --features=rustix/use-libc does not depend on {}", + libc_dep + ); +} + +/// Test whether the crate at directory `dir` has a dependency on `dependency`, +/// setting the environment variables `envs` and unsetting the environment +/// variables `remove_envs` when running `cargo`. +fn has_dependency( + dir: &str, + args: &[&str], + envs: &[(&str, &str)], + remove_envs: &[&str], + dependency: &str, +) -> bool { + let mut command = Command::new("cargo"); + + command + .arg("tree") + .arg("--quiet") + .arg("--edges=normal") + .arg(&format!("--invert={}", dependency)) + .current_dir(dir); + + command.args(args); + for (key, value) in envs { + command.env(key, value); + } + for key in remove_envs { + command.env_remove(key); + } + + let child = command.output().unwrap(); + + // `cargo tree --invert=foo` can fail in two different ways: it exits with + // a non-zero status if the dependency is not present in the Cargo.toml + // configuration, and it exists with a zero status and prints nothing if + // the dependency is present but optional and not enabled. So we check for + // both here. + child.status.success() && !child.stdout.is_empty() +} diff --git a/vendor/rustix/tests/fs/cwd.rs b/vendor/rustix/tests/fs/cwd.rs new file mode 100644 index 000000000..749c84f24 --- /dev/null +++ b/vendor/rustix/tests/fs/cwd.rs @@ -0,0 +1,3 @@ +/// Make sure we can use `cwd` in const contexts. +#[allow(dead_code)] +const CWD: rustix::fd::BorrowedFd<'static> = rustix::fs::cwd(); diff --git a/vendor/rustix/tests/fs/dir.rs b/vendor/rustix/tests/fs/dir.rs new file mode 100644 index 000000000..f5120be96 --- /dev/null +++ b/vendor/rustix/tests/fs/dir.rs @@ -0,0 +1,37 @@ +#[test] +fn test_dir() { + let t = rustix::fs::openat( + rustix::fs::cwd(), + rustix::cstr!("."), + rustix::fs::OFlags::RDONLY | rustix::fs::OFlags::CLOEXEC, + rustix::fs::Mode::empty(), + ) + .unwrap(); + + let dir = rustix::fs::Dir::read_from(&t).unwrap(); + + let _file = rustix::fs::openat( + &t, + rustix::cstr!("Cargo.toml"), + rustix::fs::OFlags::RDONLY | rustix::fs::OFlags::CLOEXEC, + rustix::fs::Mode::empty(), + ) + .unwrap(); + + let mut saw_dot = false; + let mut saw_dotdot = false; + let mut saw_cargo_toml = false; + for entry in dir { + let entry = entry.unwrap(); + if entry.file_name() == rustix::cstr!(".") { + saw_dot = true; + } else if entry.file_name() == rustix::cstr!("..") { + saw_dotdot = true; + } else if entry.file_name() == rustix::cstr!("Cargo.toml") { + saw_cargo_toml = true; + } + } + assert!(saw_dot); + assert!(saw_dotdot); + assert!(saw_cargo_toml); +} diff --git a/vendor/rustix/tests/fs/fcntl.rs b/vendor/rustix/tests/fs/fcntl.rs new file mode 100644 index 000000000..1f8b78387 --- /dev/null +++ b/vendor/rustix/tests/fs/fcntl.rs @@ -0,0 +1,17 @@ +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[test] +fn test_fcntl_dupfd_cloexec() { + use rustix::fd::AsFd; + use std::os::unix::io::AsRawFd; + + let file = rustix::fs::openat( + rustix::fs::cwd(), + "Cargo.toml", + rustix::fs::OFlags::RDONLY, + rustix::fs::Mode::empty(), + ) + .unwrap(); + + let new = rustix::fs::fcntl_dupfd_cloexec(&file, 700).unwrap(); + assert_eq!(new.as_fd().as_raw_fd(), 700); +} diff --git a/vendor/rustix/tests/fs/file.rs b/vendor/rustix/tests/fs/file.rs new file mode 100644 index 000000000..5c09f640d --- /dev/null +++ b/vendor/rustix/tests/fs/file.rs @@ -0,0 +1,83 @@ +#[cfg(not(target_os = "redox"))] +#[test] +fn test_file() { + #[cfg(not(target_os = "illumos"))] + rustix::fs::accessat( + rustix::fs::cwd(), + "Cargo.toml", + rustix::fs::Access::READ_OK, + rustix::fs::AtFlags::empty(), + ) + .unwrap(); + + assert_eq!( + rustix::fs::openat( + rustix::fs::cwd(), + "Cagro.motl", + rustix::fs::OFlags::RDONLY, + rustix::fs::Mode::empty(), + ) + .unwrap_err(), + rustix::io::Errno::NOENT + ); + + let file = rustix::fs::openat( + rustix::fs::cwd(), + "Cargo.toml", + rustix::fs::OFlags::RDONLY, + rustix::fs::Mode::empty(), + ) + .unwrap(); + + assert_eq!( + rustix::fs::openat( + &file, + "Cargo.toml", + rustix::fs::OFlags::RDONLY, + rustix::fs::Mode::empty(), + ) + .unwrap_err(), + rustix::io::Errno::NOTDIR + ); + + #[cfg(not(any( + target_os = "dragonfly", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + )))] + rustix::fs::fadvise(&file, 0, 10, rustix::fs::Advice::Normal).unwrap(); + + assert_eq!( + rustix::fs::fcntl_getfd(&file).unwrap(), + rustix::fs::FdFlags::empty() + ); + assert_eq!( + rustix::fs::fcntl_getfl(&file).unwrap(), + rustix::fs::OFlags::empty() + ); + + let stat = rustix::fs::fstat(&file).unwrap(); + assert!(stat.st_size > 0); + assert!(stat.st_blocks > 0); + + #[cfg(not(any( + target_os = "illumos", + target_os = "netbsd", + target_os = "redox", + target_os = "wasi", + )))] + // not implemented in libc for netbsd yet + { + let statfs = rustix::fs::fstatfs(&file).unwrap(); + assert!(statfs.f_blocks > 0); + } + + #[cfg(feature = "net")] + assert_eq!(rustix::io::is_read_write(&file).unwrap(), (true, false)); + + assert_ne!(rustix::io::ioctl_fionread(&file).unwrap(), 0); +} diff --git a/vendor/rustix/tests/fs/flock.rs b/vendor/rustix/tests/fs/flock.rs new file mode 100644 index 000000000..1b7df6ffd --- /dev/null +++ b/vendor/rustix/tests/fs/flock.rs @@ -0,0 +1,34 @@ +#[cfg(not(target_os = "redox"))] +#[test] +fn test_flock() { + use rustix::fs::{cwd, flock, openat, FlockOperation, Mode, OFlags}; + + let f = openat(cwd(), "Cargo.toml", OFlags::RDONLY, Mode::empty()).unwrap(); + flock(&f, FlockOperation::LockExclusive).unwrap(); + flock(&f, FlockOperation::Unlock).unwrap(); + let g = openat(cwd(), "Cargo.toml", OFlags::RDONLY, Mode::empty()).unwrap(); + flock(&g, FlockOperation::LockExclusive).unwrap(); + flock(&g, FlockOperation::Unlock).unwrap(); + drop(f); + drop(g); + + let f = openat(cwd(), "Cargo.toml", OFlags::RDONLY, Mode::empty()).unwrap(); + flock(&f, FlockOperation::LockShared).unwrap(); + let g = openat(cwd(), "Cargo.toml", OFlags::RDONLY, Mode::empty()).unwrap(); + flock(&g, FlockOperation::LockShared).unwrap(); + flock(&f, FlockOperation::Unlock).unwrap(); + flock(&g, FlockOperation::Unlock).unwrap(); + drop(f); + drop(g); + + let f = openat(cwd(), "Cargo.toml", OFlags::RDONLY, Mode::empty()).unwrap(); + flock(&f, FlockOperation::LockShared).unwrap(); + flock(&f, FlockOperation::LockExclusive).unwrap(); + flock(&f, FlockOperation::Unlock).unwrap(); + let g = openat(cwd(), "Cargo.toml", OFlags::RDONLY, Mode::empty()).unwrap(); + flock(&g, FlockOperation::LockShared).unwrap(); + flock(&g, FlockOperation::LockExclusive).unwrap(); + flock(&g, FlockOperation::Unlock).unwrap(); + drop(f); + drop(g); +} diff --git a/vendor/rustix/tests/fs/futimens.rs b/vendor/rustix/tests/fs/futimens.rs new file mode 100644 index 000000000..81f8b8a27 --- /dev/null +++ b/vendor/rustix/tests/fs/futimens.rs @@ -0,0 +1,42 @@ +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[test] +fn test_futimens() { + use rustix::fs::{cwd, fstat, futimens, openat, Mode, OFlags, Timespec, Timestamps}; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + + let foo = openat( + &dir, + "foo", + OFlags::CREATE | OFlags::WRONLY | OFlags::CLOEXEC, + Mode::empty(), + ) + .unwrap(); + + let times = Timestamps { + last_access: Timespec { + tv_sec: 44000, + tv_nsec: 45000, + }, + last_modification: Timespec { + tv_sec: 46000, + tv_nsec: 47000, + }, + }; + futimens(&foo, ×).unwrap(); + + let after = fstat(&foo).unwrap(); + + assert_eq!(times.last_modification.tv_sec as u64, after.st_mtime as u64); + #[cfg(not(target_os = "netbsd"))] + assert_eq!( + times.last_modification.tv_nsec as u64, + after.st_mtime_nsec as u64 + ); + #[cfg(target_os = "netbsd")] + assert_eq!( + times.last_modification.tv_nsec as u64, + after.st_mtimensec as u64 + ); +} diff --git a/vendor/rustix/tests/fs/invalid_offset.rs b/vendor/rustix/tests/fs/invalid_offset.rs new file mode 100644 index 000000000..995e302a1 --- /dev/null +++ b/vendor/rustix/tests/fs/invalid_offset.rs @@ -0,0 +1,182 @@ +//! Tests for extreme `u64` file offsets. +//! +//! POSIX-ish interfaces tend to use signed integers for file offsets, while +//! Rust APIs tend to use `u64`. Test that extreme `u64` values in APIs that +//! take file offsets are properly diagnosed. +//! +//! These tests are disabled on ios/macos since those platforms kill the +//! process with `SIGXFSZ` instead of returning an error. + +#![cfg(not(any(target_os = "redox", target_os = "wasi")))] + +use rustix::io::SeekFrom; + +#[test] +fn invalid_offset_seek() { + use rustix::fs::{cwd, openat, seek, Mode, OFlags}; + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + let file = openat( + &dir, + "foo", + OFlags::WRONLY | OFlags::TRUNC | OFlags::CREATE, + Mode::RUSR | Mode::WUSR, + ) + .unwrap(); + + seek(&file, SeekFrom::Start(u64::MAX)).unwrap_err(); + seek(&file, SeekFrom::Start(i64::MAX as u64 + 1)).unwrap_err(); + seek(&file, SeekFrom::End(-1)).unwrap_err(); + seek(&file, SeekFrom::End(i64::MIN)).unwrap_err(); + seek(&file, SeekFrom::Current(-1)).unwrap_err(); + seek(&file, SeekFrom::Current(i64::MIN)).unwrap_err(); +} + +#[cfg(not(any( + target_os = "dragonfly", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", +)))] +#[test] +fn invalid_offset_fallocate() { + use rustix::fs::{cwd, fallocate, openat, FallocateFlags, Mode, OFlags}; + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + let file = openat( + &dir, + "foo", + OFlags::WRONLY | OFlags::TRUNC | OFlags::CREATE, + Mode::RUSR | Mode::WUSR, + ) + .unwrap(); + + fallocate(&file, FallocateFlags::empty(), u64::MAX, 1).unwrap_err(); + fallocate(&file, FallocateFlags::empty(), i64::MAX as u64 + 1, 1).unwrap_err(); + fallocate(&file, FallocateFlags::empty(), 0, u64::MAX).unwrap_err(); + fallocate(&file, FallocateFlags::empty(), 0, i64::MAX as u64 + 1).unwrap_err(); +} + +#[cfg(not(any( + target_os = "dragonfly", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", +)))] +#[test] +fn invalid_offset_fadvise() { + use rustix::fs::{cwd, fadvise, openat, Advice, Mode, OFlags}; + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + let file = openat( + &dir, + "foo", + OFlags::WRONLY | OFlags::TRUNC | OFlags::CREATE, + Mode::RUSR | Mode::WUSR, + ) + .unwrap(); + + // `fadvise` never fails on invalid offsets. + fadvise(&file, i64::MAX as u64, i64::MAX as u64, Advice::Normal).unwrap(); + fadvise(&file, u64::MAX, 0, Advice::Normal).unwrap(); + fadvise(&file, i64::MAX as u64, 1, Advice::Normal).unwrap(); + fadvise(&file, 1, i64::MAX as u64, Advice::Normal).unwrap(); + fadvise(&file, i64::MAX as u64 + 1, 0, Advice::Normal).unwrap(); + fadvise(&file, u64::MAX, i64::MAX as u64, Advice::Normal).unwrap(); + + // `fadvise` fails on invalid lengths. + fadvise(&file, u64::MAX, u64::MAX, Advice::Normal).unwrap_err(); + fadvise(&file, i64::MAX as u64, u64::MAX, Advice::Normal).unwrap_err(); + fadvise(&file, 0, u64::MAX, Advice::Normal).unwrap_err(); + fadvise(&file, u64::MAX, i64::MAX as u64 + 1, Advice::Normal).unwrap_err(); + fadvise(&file, i64::MAX as u64 + 1, u64::MAX, Advice::Normal).unwrap_err(); + fadvise(&file, i64::MAX as u64, i64::MAX as u64 + 1, Advice::Normal).unwrap_err(); + fadvise(&file, 0, i64::MAX as u64 + 1, Advice::Normal).unwrap_err(); +} + +#[test] +fn invalid_offset_pread() { + use rustix::fs::{cwd, openat, Mode, OFlags}; + use rustix::io::pread; + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + let file = openat( + &dir, + "foo", + OFlags::RDWR | OFlags::TRUNC | OFlags::CREATE, + Mode::RUSR | Mode::WUSR, + ) + .unwrap(); + + let mut buf = [0_u8; 1]; + pread(&file, &mut buf, u64::MAX).unwrap_err(); + pread(&file, &mut buf, i64::MAX as u64 + 1).unwrap_err(); +} + +#[cfg(not(any(target_os = "ios", target_os = "macos")))] +#[test] +fn invalid_offset_pwrite() { + use rustix::fs::{cwd, openat, Mode, OFlags}; + use rustix::io::pwrite; + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + let file = openat( + &dir, + "foo", + OFlags::WRONLY | OFlags::TRUNC | OFlags::CREATE, + Mode::RUSR | Mode::WUSR, + ) + .unwrap(); + + let buf = [0_u8; 1]; + pwrite(&file, &buf, u64::MAX).unwrap_err(); + pwrite(&file, &buf, i64::MAX as u64 + 1).unwrap_err(); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn invalid_offset_copy_file_range() { + use rustix::fs::{copy_file_range, cwd, openat, Mode, OFlags}; + use rustix::io::write; + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + let foo = openat( + &dir, + "foo", + OFlags::RDWR | OFlags::TRUNC | OFlags::CREATE, + Mode::RUSR | Mode::WUSR, + ) + .unwrap(); + let bar = openat( + &dir, + "bar", + OFlags::WRONLY | OFlags::TRUNC | OFlags::CREATE, + Mode::RUSR | Mode::WUSR, + ) + .unwrap(); + write(&foo, b"a").unwrap(); + + let mut off_in = u64::MAX; + let mut off_out = 0; + copy_file_range(&foo, Some(&mut off_in), &bar, Some(&mut off_out), 1).unwrap_err(); + + let mut off_in = i64::MAX as u64 + 1; + let mut off_out = 0; + copy_file_range(&foo, Some(&mut off_in), &bar, Some(&mut off_out), 1).unwrap_err(); + + let mut off_in = 0; + let mut off_out = u64::MAX; + copy_file_range(&foo, Some(&mut off_in), &bar, Some(&mut off_out), 1).unwrap_err(); + + let mut off_in = 0; + let mut off_out = i64::MAX as u64; + copy_file_range(&foo, Some(&mut off_in), &bar, Some(&mut off_out), 1).unwrap_err(); + + let mut off_in = 0; + let mut off_out = i64::MAX as u64 + 1; + copy_file_range(&foo, Some(&mut off_in), &bar, Some(&mut off_out), 1).unwrap_err(); +} diff --git a/vendor/rustix/tests/fs/long_paths.rs b/vendor/rustix/tests/fs/long_paths.rs new file mode 100644 index 000000000..dbc2fa6ea --- /dev/null +++ b/vendor/rustix/tests/fs/long_paths.rs @@ -0,0 +1,28 @@ +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[test] +fn test_long_paths() { + use rustix::fs::{cwd, mkdirat, openat, Mode, OFlags}; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + + #[cfg(libc)] + const PATH_MAX: usize = libc::PATH_MAX as usize; + #[cfg(linux_raw)] + const PATH_MAX: usize = linux_raw_sys::general::PATH_MAX as usize; + + mkdirat(&dir, "a", Mode::RUSR | Mode::XUSR | Mode::WUSR).unwrap(); + + let mut long_path = String::new(); + for _ in 0..PATH_MAX / 5 { + long_path.push_str("a/../"); + } + + let mut too_long_path = String::new(); + for _ in 0..PATH_MAX / 4 { + too_long_path.push_str("a/../"); + } + + let _ = openat(&dir, &long_path, OFlags::RDONLY, Mode::empty()).unwrap(); + let _ = openat(&dir, &too_long_path, OFlags::RDONLY, Mode::empty()).unwrap_err(); +} diff --git a/vendor/rustix/tests/fs/main.rs b/vendor/rustix/tests/fs/main.rs new file mode 100644 index 000000000..23928a6ba --- /dev/null +++ b/vendor/rustix/tests/fs/main.rs @@ -0,0 +1,47 @@ +//! Tests for [`rustix::fs`]. + +#![cfg(feature = "fs")] +#![cfg(not(windows))] +#![cfg_attr(target_os = "wasi", feature(wasi_ext))] +#![cfg_attr(io_lifetimes_use_std, feature(io_safety))] +#![cfg_attr(core_c_str, feature(core_c_str))] + +mod cwd; +mod dir; +mod fcntl; +mod file; +#[cfg(not(target_os = "wasi"))] +mod flock; +mod futimens; +mod invalid_offset; +mod long_paths; +#[cfg(not(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "wasi", +)))] +mod makedev; +mod mkdirat; +mod mknodat; +#[cfg(any(target_os = "android", target_os = "linux"))] +mod openat; +#[cfg(any(target_os = "android", target_os = "linux"))] +mod openat2; +mod readdir; +mod renameat; +#[cfg(not(any( + target_os = "illumos", + target_os = "netbsd", + target_os = "redox", + target_os = "wasi", +)))] +// not implemented in libc for netbsd yet +mod statfs; +mod utimensat; +mod y2038; diff --git a/vendor/rustix/tests/fs/makedev.rs b/vendor/rustix/tests/fs/makedev.rs new file mode 100644 index 000000000..79b5199e8 --- /dev/null +++ b/vendor/rustix/tests/fs/makedev.rs @@ -0,0 +1,10 @@ +use rustix::fs::{major, makedev, minor}; + +#[test] +fn makedev_roundtrip() { + let maj = 0x2324_2526; + let min = 0x6564_6361; + let dev = makedev(maj, min); + assert_eq!(maj, major(dev)); + assert_eq!(min, minor(dev)); +} diff --git a/vendor/rustix/tests/fs/mkdirat.rs b/vendor/rustix/tests/fs/mkdirat.rs new file mode 100644 index 000000000..884588037 --- /dev/null +++ b/vendor/rustix/tests/fs/mkdirat.rs @@ -0,0 +1,33 @@ +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[test] +fn test_mkdirat() { + use rustix::fs::{cwd, mkdirat, openat, statat, unlinkat, AtFlags, FileType, Mode, OFlags}; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + + mkdirat(&dir, "foo", Mode::RWXU).unwrap(); + let stat = statat(&dir, "foo", AtFlags::empty()).unwrap(); + assert_eq!(FileType::from_raw_mode(stat.st_mode), FileType::Directory); + unlinkat(&dir, "foo", AtFlags::REMOVEDIR).unwrap(); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_mkdirat_with_o_path() { + use rustix::fs::{cwd, mkdirat, openat, statat, unlinkat, AtFlags, FileType, Mode, OFlags}; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat( + cwd(), + tmp.path(), + OFlags::RDONLY | OFlags::PATH, + Mode::empty(), + ) + .unwrap(); + + mkdirat(&dir, "foo", Mode::RWXU).unwrap(); + let stat = statat(&dir, "foo", AtFlags::empty()).unwrap(); + assert_eq!(FileType::from_raw_mode(stat.st_mode), FileType::Directory); + unlinkat(&dir, "foo", AtFlags::REMOVEDIR).unwrap(); +} diff --git a/vendor/rustix/tests/fs/mknodat.rs b/vendor/rustix/tests/fs/mknodat.rs new file mode 100644 index 000000000..fa1c84f69 --- /dev/null +++ b/vendor/rustix/tests/fs/mknodat.rs @@ -0,0 +1,27 @@ +#[cfg(not(any( + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "wasi", +)))] +#[test] +fn test_mknodat() { + use rustix::fs::{cwd, mknodat, openat, statat, unlinkat, AtFlags, FileType, Mode, OFlags}; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + + // Create a regular file. Not supported on FreeBSD or OpenBSD. + #[cfg(not(any(target_os = "freebsd", target_os = "openbsd")))] + { + mknodat(&dir, "foo", FileType::RegularFile, Mode::empty(), 0).unwrap(); + let stat = statat(&dir, "foo", AtFlags::empty()).unwrap(); + assert_eq!(FileType::from_raw_mode(stat.st_mode), FileType::RegularFile); + unlinkat(&dir, "foo", AtFlags::empty()).unwrap(); + } + + mknodat(&dir, "foo", FileType::Fifo, Mode::empty(), 0).unwrap(); + let stat = statat(&dir, "foo", AtFlags::empty()).unwrap(); + assert_eq!(FileType::from_raw_mode(stat.st_mode), FileType::Fifo); + unlinkat(&dir, "foo", AtFlags::empty()).unwrap(); +} diff --git a/vendor/rustix/tests/fs/openat.rs b/vendor/rustix/tests/fs/openat.rs new file mode 100644 index 000000000..564574dc1 --- /dev/null +++ b/vendor/rustix/tests/fs/openat.rs @@ -0,0 +1,33 @@ +use std::fs::File; + +use io_lifetimes::{FromFd, IntoFd}; +use rustix::fs::{cwd, openat, Mode, OFlags}; +use std::io::Write; + +#[test] +fn test_openat_tmpfile() { + let tmp = tempfile::tempdir().unwrap(); + let dir = openat( + cwd(), + tmp.path(), + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ) + .unwrap(); + let f = match openat( + &dir, + ".", + OFlags::WRONLY | OFlags::CLOEXEC | OFlags::TMPFILE, + Mode::from_bits_truncate(0o644), + ) { + Ok(f) => Ok(Some(File::from_fd(f.into_fd()))), + // TODO: Factor out the `Err`, once we no longer support Rust 1.48. + Err(rustix::io::Errno::OPNOTSUPP) + | Err(rustix::io::Errno::ISDIR) + | Err(rustix::io::Errno::NOENT) => Ok(None), + Err(e) => Err(e), + }; + if let Some(mut f) = f.unwrap() { + write!(f, "hello world").unwrap(); + } +} diff --git a/vendor/rustix/tests/fs/openat2.rs b/vendor/rustix/tests/fs/openat2.rs new file mode 100644 index 000000000..0b1d86fe2 --- /dev/null +++ b/vendor/rustix/tests/fs/openat2.rs @@ -0,0 +1,184 @@ +use rustix::fd::AsFd; +use rustix::fs::{cwd, mkdirat, openat, openat2, symlinkat, Mode, OFlags, ResolveFlags}; +use rustix::io::OwnedFd; +use rustix::{io, path}; +use std::os::unix::io::AsRawFd; + +/// Like `openat2`, but keep retrying until it fails or succeeds. +fn openat2_more<Fd: AsFd, P: path::Arg>( + dirfd: Fd, + path: P, + oflags: OFlags, + mode: Mode, + resolve: ResolveFlags, +) -> io::Result<OwnedFd> { + let path = path.as_cow_c_str().unwrap().into_owned(); + loop { + match openat2(dirfd.as_fd(), &path, oflags, mode, resolve) { + Ok(file) => return Ok(file), + Err(io::Errno::AGAIN) => continue, + Err(err) => return Err(err), + } + } +} + +#[test] +fn test_openat2() { + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + + // Detect whether `openat2` is available. + match openat2( + &dir, + ".", + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ResolveFlags::empty(), + ) { + Ok(_file) => (), + Err(io::Errno::NOSYS) => return, + Err(_err) => return, + } + + // Create a file. + let _ = openat2_more( + &dir, + "test.txt", + OFlags::WRONLY | OFlags::CREATE | OFlags::TRUNC | OFlags::CLOEXEC, + Mode::RUSR, + ResolveFlags::empty(), + ) + .unwrap(); + + // Test `NO_SYMLINKS`. + symlinkat("test.txt", &dir, "symlink.txt").unwrap(); + let _ = openat2_more( + &dir, + "symlink.txt", + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ResolveFlags::empty(), + ) + .unwrap(); + let _ = openat2_more( + &dir, + "symlink.txt", + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ResolveFlags::NO_MAGICLINKS, + ) + .unwrap(); + let _ = openat2_more( + &dir, + "symlink.txt", + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ResolveFlags::NO_SYMLINKS, + ) + .unwrap_err(); + + // Test `NO_MAGICLINKS`. + let test = openat2_more( + &dir, + "test.txt", + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ResolveFlags::empty(), + ) + .unwrap(); + let _ = openat2_more( + &dir, + &format!("/proc/self/fd/{}", test.as_fd().as_raw_fd()), + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ResolveFlags::empty(), + ) + .unwrap(); + let _ = openat2_more( + &dir, + &format!("/proc/self/fd/{}", test.as_fd().as_raw_fd()), + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ResolveFlags::NO_SYMLINKS, + ) + .unwrap_err(); + let _ = openat2_more( + &dir, + &format!("/proc/self/fd/{}", test.as_fd().as_raw_fd()), + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ResolveFlags::NO_MAGICLINKS, + ) + .unwrap_err(); + + // Test `NO_XDEV`. + let root = openat2_more( + &dir, + "/", + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ResolveFlags::empty(), + ) + .unwrap(); + let _ = openat2_more( + &root, + "proc", + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ResolveFlags::empty(), + ) + .unwrap(); + let _ = openat2_more( + &root, + "proc", + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ResolveFlags::NO_XDEV, + ) + .unwrap_err(); + + // Test `BENEATH`. + let _ = openat2_more( + &dir, + "..", + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ResolveFlags::empty(), + ) + .unwrap(); + let _ = openat2_more( + &dir, + "..", + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ResolveFlags::BENEATH, + ) + .unwrap_err(); + + // Test `IN_ROOT`. + let _ = openat2_more( + &dir, + "/proc", + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ResolveFlags::empty(), + ) + .unwrap(); + let _ = openat2_more( + &dir, + "/proc", + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ResolveFlags::IN_ROOT, + ) + .unwrap_err(); + mkdirat(&dir, "proc", Mode::RUSR | Mode::XUSR).unwrap(); + let _ = openat2_more( + &dir, + "/proc", + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ResolveFlags::IN_ROOT, + ) + .unwrap(); +} diff --git a/vendor/rustix/tests/fs/readdir.rs b/vendor/rustix/tests/fs/readdir.rs new file mode 100644 index 000000000..8925660a9 --- /dev/null +++ b/vendor/rustix/tests/fs/readdir.rs @@ -0,0 +1,68 @@ +#![cfg(not(target_os = "redox"))] + +use rustix::fs::{Dir, DirEntry}; +use std::collections::HashMap; + +#[test] +fn dir_entries() { + let tmpdir = tempfile::tempdir().expect("construct tempdir"); + let dirfd = std::fs::File::open(tmpdir.path()).expect("open tempdir as file"); + let mut dir = Dir::read_from(dirfd).expect("construct Dir from dirfd"); + + let entries = read_entries(&mut dir); + assert_eq!(entries.len(), 0, "no files in directory"); + + let _f1 = std::fs::File::create(tmpdir.path().join("file1")).expect("create file1"); + + let entries = read_entries(&mut dir); + assert!( + entries.get("file1").is_some(), + "directory contains `file1`: {:?}", + entries + ); + assert_eq!(entries.len(), 1); + + let _f2 = std::fs::File::create(tmpdir.path().join("file2")).expect("create file1"); + let entries = read_entries(&mut dir); + assert!( + entries.get("file1").is_some(), + "directory contains `file1`: {:?}", + entries + ); + assert!( + entries.get("file2").is_some(), + "directory contains `file2`: {:?}", + entries + ); + assert_eq!(entries.len(), 2); +} + +fn read_entries(dir: &mut Dir) -> HashMap<String, DirEntry> { + dir.rewind(); + let mut out = HashMap::new(); + loop { + match dir.read() { + Some(e) => { + let e = e.expect("non-error entry"); + let name = e.file_name().to_str().expect("utf8 filename").to_owned(); + if name != "." && name != ".." { + out.insert(name, e); + } + } + None => break, + } + } + out +} + +#[test] +fn dir_from_openat() { + let dirfd = rustix::fs::openat( + rustix::fs::cwd(), + ".", + rustix::fs::OFlags::RDONLY, + rustix::fs::Mode::empty(), + ) + .expect("open cwd as file"); + let _dir = Dir::read_from(dirfd).expect("construct Dir from dirfd"); +} diff --git a/vendor/rustix/tests/fs/renameat.rs b/vendor/rustix/tests/fs/renameat.rs new file mode 100644 index 000000000..2eea2e77a --- /dev/null +++ b/vendor/rustix/tests/fs/renameat.rs @@ -0,0 +1,104 @@ +#[cfg(any(target_os = "android", target_os = "linux"))] +use rustix::fs::Stat; + +#[cfg(any(target_os = "android", target_os = "linux"))] +fn same(a: &Stat, b: &Stat) -> bool { + a.st_ino == b.st_ino && a.st_dev == b.st_dev +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_renameat() { + use rustix::fs::{cwd, openat, renameat, statat, AtFlags, Mode, OFlags}; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat( + cwd(), + tmp.path(), + OFlags::RDONLY | OFlags::PATH, + Mode::empty(), + ) + .unwrap(); + + let _ = openat(&dir, "foo", OFlags::CREATE | OFlags::WRONLY, Mode::empty()).unwrap(); + let before = statat(&dir, "foo", AtFlags::empty()).unwrap(); + renameat(&dir, "foo", &dir, "bar").unwrap(); + let renamed = statat(&dir, "bar", AtFlags::empty()).unwrap(); + assert!(same(&before, &renamed)); +} + +/// Like `test_renameat` but the file already exists, so `renameat` +/// overwrites it. +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_renameat_overwrite() { + use rustix::fs::{cwd, openat, renameat, statat, AtFlags, Mode, OFlags}; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat( + cwd(), + tmp.path(), + OFlags::RDONLY | OFlags::PATH, + Mode::empty(), + ) + .unwrap(); + + let _ = openat(&dir, "foo", OFlags::CREATE | OFlags::WRONLY, Mode::empty()).unwrap(); + let _ = openat(&dir, "bar", OFlags::CREATE | OFlags::WRONLY, Mode::empty()).unwrap(); + let before = statat(&dir, "foo", AtFlags::empty()).unwrap(); + renameat(&dir, "foo", &dir, "bar").unwrap(); + let renamed = statat(&dir, "bar", AtFlags::empty()).unwrap(); + assert!(same(&before, &renamed)); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_renameat_with() { + use rustix::fs::{cwd, openat, renameat_with, statat, AtFlags, Mode, OFlags, RenameFlags}; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat( + cwd(), + tmp.path(), + OFlags::RDONLY | OFlags::PATH, + Mode::empty(), + ) + .unwrap(); + + let _ = openat(&dir, "foo", OFlags::CREATE | OFlags::WRONLY, Mode::empty()).unwrap(); + let before = statat(&dir, "foo", AtFlags::empty()).unwrap(); + + match renameat_with(&dir, "foo", &dir, "red", RenameFlags::empty()) { + Ok(()) => (), + Err(e) if e == rustix::io::Errno::NOSYS => return, + Err(e) => unreachable!("unexpected error from renameat_with: {:?}", e), + } + + let renamed = statat(&dir, "red", AtFlags::empty()).unwrap(); + assert!(same(&before, &renamed)); + + let _ = openat( + &dir, + "green", + OFlags::CREATE | OFlags::WRONLY, + Mode::empty(), + ) + .unwrap(); + + #[cfg(all(target_os = "linux", target_env = "gnu"))] + { + let green = statat(&dir, "green", AtFlags::empty()).unwrap(); + + renameat_with(&dir, "red", &dir, "green", RenameFlags::NOREPLACE).unwrap_err(); + let renamed = statat(&dir, "red", AtFlags::empty()).unwrap(); + assert!(same(&before, &renamed)); + let orig = statat(&dir, "green", AtFlags::empty()).unwrap(); + assert!(same(&green, &orig)); + + renameat_with(&dir, "red", &dir, "green", RenameFlags::EXCHANGE).unwrap(); + let renamed = statat(&dir, "red", AtFlags::empty()).unwrap(); + assert!(same(&green, &renamed)); + let orig = statat(&dir, "green", AtFlags::empty()).unwrap(); + assert!(same(&before, &orig)); + } +} diff --git a/vendor/rustix/tests/fs/statfs.rs b/vendor/rustix/tests/fs/statfs.rs new file mode 100644 index 000000000..f8bf2e350 --- /dev/null +++ b/vendor/rustix/tests/fs/statfs.rs @@ -0,0 +1,49 @@ +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_statfs_abi() { + use rustix::fs::{FsWord, StatFs, NFS_SUPER_MAGIC, PROC_SUPER_MAGIC}; + + // Ensure these all have consistent types. + let t: StatFs = unsafe { std::mem::zeroed() }; + let _s: FsWord = t.f_type; + let _u: FsWord = PROC_SUPER_MAGIC; + let _v: FsWord = NFS_SUPER_MAGIC; + + // Ensure that after all the platform-specific dancing we have to do, this + // constant comes out with the correct value. + #[cfg(all(libc, not(target_env = "musl")))] + { + assert_eq!( + i128::from(PROC_SUPER_MAGIC), + i128::from(libc::PROC_SUPER_MAGIC) + ); + assert_eq!( + i128::from(NFS_SUPER_MAGIC), + i128::from(libc::NFS_SUPER_MAGIC) + ); + } + + #[cfg(linux_raw)] + { + assert_eq!( + i128::from(PROC_SUPER_MAGIC), + i128::from(linux_raw_sys::general::PROC_SUPER_MAGIC) + ); + assert_eq!( + i128::from(NFS_SUPER_MAGIC), + i128::from(linux_raw_sys::general::NFS_SUPER_MAGIC) + ); + } + + assert_eq!(PROC_SUPER_MAGIC, 0x0000_9fa0); + assert_eq!(NFS_SUPER_MAGIC, 0x0000_6969); +} + +#[test] +fn test_statfs() { + let statfs = rustix::fs::statfs("Cargo.toml").unwrap(); + let f_blocks = statfs.f_blocks; + assert_ne!(f_blocks, 0); + // Previously we checked f_files != 0 here, but at least btrfs doesn't set + // that. +} diff --git a/vendor/rustix/tests/fs/utimensat.rs b/vendor/rustix/tests/fs/utimensat.rs new file mode 100644 index 000000000..f0fb7e27b --- /dev/null +++ b/vendor/rustix/tests/fs/utimensat.rs @@ -0,0 +1,127 @@ +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[test] +fn test_utimensat() { + use rustix::fs::{cwd, openat, statat, utimensat, AtFlags, Mode, OFlags, Timespec, Timestamps}; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat( + cwd(), + tmp.path(), + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ) + .unwrap(); + + let _ = openat( + &dir, + "foo", + OFlags::CREATE | OFlags::WRONLY | OFlags::CLOEXEC, + Mode::empty(), + ) + .unwrap(); + + let times = Timestamps { + last_access: Timespec { + tv_sec: 44000, + tv_nsec: 45000, + }, + last_modification: Timespec { + tv_sec: 46000, + tv_nsec: 47000, + }, + }; + utimensat(&dir, "foo", ×, AtFlags::empty()).unwrap(); + + let after = statat(&dir, "foo", AtFlags::empty()).unwrap(); + + assert_eq!(times.last_modification.tv_sec as u64, after.st_mtime as u64); + #[cfg(not(target_os = "netbsd"))] + assert_eq!( + times.last_modification.tv_nsec as u64, + after.st_mtime_nsec as u64 + ); + #[cfg(target_os = "netbsd")] + assert_eq!( + times.last_modification.tv_nsec as u64, + after.st_mtimensec as u64 + ); + assert!(times.last_access.tv_sec as u64 >= after.st_atime as u64); + #[cfg(not(target_os = "netbsd"))] + assert!( + times.last_access.tv_sec as u64 > after.st_atime as u64 + || times.last_access.tv_nsec as u64 >= after.st_atime_nsec as u64 + ); + #[cfg(target_os = "netbsd")] + assert!( + times.last_access.tv_sec as u64 > after.st_atime as u64 + || times.last_access.tv_nsec as u64 >= after.st_atimensec as u64 + ); +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[test] +fn test_utimensat_noent() { + use rustix::fs::{cwd, openat, utimensat, AtFlags, Mode, OFlags, Timespec, Timestamps}; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat( + cwd(), + tmp.path(), + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ) + .unwrap(); + + let times = Timestamps { + last_access: Timespec { + tv_sec: 44000, + tv_nsec: 45000, + }, + last_modification: Timespec { + tv_sec: 46000, + tv_nsec: 47000, + }, + }; + assert_eq!( + utimensat(&dir, "foo", ×, AtFlags::empty()).unwrap_err(), + rustix::io::Errno::NOENT + ); +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +#[test] +fn test_utimensat_notdir() { + use rustix::fs::{cwd, openat, utimensat, AtFlags, Mode, OFlags, Timespec, Timestamps}; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat( + cwd(), + tmp.path(), + OFlags::RDONLY | OFlags::CLOEXEC, + Mode::empty(), + ) + .unwrap(); + + let foo = openat( + &dir, + "foo", + OFlags::CREATE | OFlags::WRONLY | OFlags::CLOEXEC, + Mode::empty(), + ) + .unwrap(); + + let times = Timestamps { + last_access: Timespec { + tv_sec: 44000, + tv_nsec: 45000, + }, + last_modification: Timespec { + tv_sec: 46000, + tv_nsec: 47000, + }, + }; + assert_eq!( + utimensat(&foo, "bar", ×, AtFlags::empty()).unwrap_err(), + rustix::io::Errno::NOTDIR + ); +} diff --git a/vendor/rustix/tests/fs/y2038.rs b/vendor/rustix/tests/fs/y2038.rs new file mode 100644 index 000000000..4299d709b --- /dev/null +++ b/vendor/rustix/tests/fs/y2038.rs @@ -0,0 +1,146 @@ +/// Test that we can set a file timestamp to a date past the year 2038 with +/// `utimensat` and read it back again. +/// +/// See tests/time/y2038.rs for more information about y2038 testing. +#[cfg(not(all(target_env = "musl", target_pointer_width = "32")))] +#[cfg(not(all(target_os = "android", target_pointer_width = "32")))] +#[cfg(not(all(target_os = "emscripten", target_pointer_width = "32")))] +#[test] +fn test_y2038_with_utimensat() { + use rustix::fs::{ + cwd, fstat, openat, statat, utimensat, AtFlags, Mode, OFlags, Timespec, Timestamps, + }; + use std::convert::TryInto; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(&cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + + let m_sec = 1_u64 << 32; + let m_nsec = 17_u32; + let a_sec = m_sec + 1; + let a_nsec = m_nsec + 1; + + let timestamps = Timestamps { + last_modification: Timespec { + tv_sec: m_sec as _, + tv_nsec: m_nsec as _, + }, + last_access: Timespec { + tv_sec: a_sec as _, + tv_nsec: a_nsec as _, + }, + }; + let _ = openat(&dir, "foo", OFlags::CREATE | OFlags::WRONLY, Mode::RUSR).unwrap(); + + match utimensat(&dir, "foo", ×tamps, AtFlags::empty()) { + Ok(()) => (), + + // On 32-bit platforms, accept `EOVERFLOW`, meaning that y2038 support + // is not available in this version of the OS. + #[cfg(target_pointer_width = "32")] + Err(rustix::io::Errno::OVERFLOW) => return, + + Err(e) => panic!("unexpected error: {:?}", e), + } + + // Use `statat` to read back the timestamp. + let stat = statat(&dir, "foo", AtFlags::empty()).unwrap(); + + assert_eq!( + TryInto::<u64>::try_into(stat.st_mtime).unwrap() as u64, + m_sec + ); + assert_eq!(stat.st_mtime_nsec as u32, m_nsec); + assert!(TryInto::<u64>::try_into(stat.st_atime).unwrap() as u64 >= a_sec); + assert!( + TryInto::<u64>::try_into(stat.st_atime).unwrap() as u64 > a_sec + || stat.st_atime_nsec as u32 >= a_nsec + ); + + // Now test the same thing, but with `fstat`. + let file = openat(&dir, "foo", OFlags::RDONLY, Mode::empty()).unwrap(); + let stat = fstat(&file).unwrap(); + + assert_eq!( + TryInto::<u64>::try_into(stat.st_mtime).unwrap() as u64, + m_sec + ); + assert_eq!(stat.st_mtime_nsec as u32, m_nsec); + assert!(TryInto::<u64>::try_into(stat.st_atime).unwrap() as u64 >= a_sec); + assert!( + TryInto::<u64>::try_into(stat.st_atime).unwrap() as u64 > a_sec + || stat.st_atime_nsec as u32 >= a_nsec + ); +} + +/// Test that we can set a file timestamp to a date past the year 2038 with +/// `futimens` and read it back again. +/// +/// See tests/time/y2038.rs for more information about y2038 testing. +#[cfg(not(all(target_env = "musl", target_pointer_width = "32")))] +#[cfg(not(all(target_os = "android", target_pointer_width = "32")))] +#[cfg(not(all(target_os = "emscripten", target_pointer_width = "32")))] +#[test] +fn test_y2038_with_futimens() { + use rustix::fs::{ + cwd, fstat, futimens, openat, statat, AtFlags, Mode, OFlags, Timespec, Timestamps, + }; + use std::convert::TryInto; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(&cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + + let m_sec = 1_u64 << 32; + let m_nsec = 17_u32; + let a_sec = m_sec + 1; + let a_nsec = m_nsec + 1; + + let timestamps = Timestamps { + last_modification: Timespec { + tv_sec: m_sec as _, + tv_nsec: m_nsec as _, + }, + last_access: Timespec { + tv_sec: a_sec as _, + tv_nsec: a_nsec as _, + }, + }; + let file = openat(&dir, "foo", OFlags::CREATE | OFlags::WRONLY, Mode::RUSR).unwrap(); + + match futimens(&file, ×tamps) { + Ok(()) => (), + + // On 32-bit platforms, accept `EOVERFLOW`, meaning that y2038 support + // is not available in this version of the OS. + #[cfg(target_pointer_width = "32")] + Err(rustix::io::Errno::OVERFLOW) => return, + + Err(e) => panic!("unexpected error: {:?}", e), + } + + // Use `statat` to read back the timestamp. + let stat = statat(&dir, "foo", AtFlags::empty()).unwrap(); + + assert_eq!(TryInto::<u64>::try_into(stat.st_mtime).unwrap(), m_sec); + assert_eq!(stat.st_mtime_nsec as u32, m_nsec); + assert!(TryInto::<u64>::try_into(stat.st_atime).unwrap() >= a_sec); + assert!( + TryInto::<u64>::try_into(stat.st_atime).unwrap() > a_sec + || stat.st_atime_nsec as u32 >= a_nsec + ); + + // Now test the same thing, but with `fstat`. + let file = openat(&dir, "foo", OFlags::RDONLY, Mode::empty()).unwrap(); + let stat = fstat(&file).unwrap(); + + assert_eq!( + TryInto::<u64>::try_into(stat.st_mtime).unwrap() as u64, + m_sec + ); + assert_eq!(stat.st_mtime_nsec as u32, m_nsec); + assert!(TryInto::<u64>::try_into(stat.st_atime).unwrap() as u64 >= a_sec); + assert!( + TryInto::<u64>::try_into(stat.st_atime).unwrap() as u64 > a_sec + || stat.st_atime_nsec as u32 >= a_nsec + ); +} diff --git a/vendor/rustix/tests/io/dup2_to_replace_stdio.rs b/vendor/rustix/tests/io/dup2_to_replace_stdio.rs new file mode 100644 index 000000000..b07ec17f0 --- /dev/null +++ b/vendor/rustix/tests/io/dup2_to_replace_stdio.rs @@ -0,0 +1,18 @@ +#![cfg(not(target_os = "wasi"))] + +use std::env; +use std::process::Command; + +/// Use `dup2` to replace the stdin and stdout file descriptors. +#[test] +fn dup2_to_replace_stdio() { + // This test modifies the stdio file descriptors, so we run it in a + // separate process so that it doesn't interfere with the test harness. + assert!(Command::new(env::var("CARGO").unwrap()) + .arg("run") + .arg("--example") + .arg("dup2_to_replace_stdio") + .status() + .unwrap() + .success()); +} diff --git a/vendor/rustix/tests/io/epoll.rs b/vendor/rustix/tests/io/epoll.rs new file mode 100644 index 000000000..4cfe305fe --- /dev/null +++ b/vendor/rustix/tests/io/epoll.rs @@ -0,0 +1,103 @@ +#![cfg(any(target_os = "android", target_os = "linux"))] + +use rustix::fd::AsFd; +use rustix::io::epoll::{self, Epoll}; +use rustix::io::{ioctl_fionbio, read, write, OwnedFd}; +use rustix::net::{ + accept, bind_v4, connect_v4, getsockname, listen, socket, AddressFamily, Ipv4Addr, Protocol, + SocketAddrAny, SocketAddrV4, SocketType, +}; +use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use std::sync::{Arc, Condvar, Mutex}; +use std::thread; + +const BUFFER_SIZE: usize = 20; + +fn server(ready: Arc<(Mutex<u16>, Condvar)>) { + let listen_sock = socket(AddressFamily::INET, SocketType::STREAM, Protocol::default()).unwrap(); + bind_v4(&listen_sock, &SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0)).unwrap(); + listen(&listen_sock, 1).unwrap(); + + let who = match getsockname(&listen_sock).unwrap() { + SocketAddrAny::V4(addr) => addr, + _ => panic!(), + }; + + { + let (lock, cvar) = &*ready; + let mut port = lock.lock().unwrap(); + *port = who.port(); + cvar.notify_all(); + } + + let epoll = Epoll::new(epoll::CreateFlags::CLOEXEC, epoll::Owning::<OwnedFd>::new()).unwrap(); + + // Test into conversions. + let fd: OwnedFd = epoll.into(); + let epoll: Epoll<epoll::Owning<OwnedFd>> = fd.into(); + let fd: RawFd = epoll.into_raw_fd(); + let epoll = unsafe { Epoll::<epoll::Owning<OwnedFd>>::from_raw_fd(fd) }; + + let raw_listen_sock = listen_sock.as_fd().as_raw_fd(); + epoll.add(listen_sock, epoll::EventFlags::IN).unwrap(); + + let mut event_list = epoll::EventVec::with_capacity(4); + loop { + epoll.wait(&mut event_list, -1).unwrap(); + for (_event_flags, target) in &event_list { + if target.as_raw_fd() == raw_listen_sock { + let conn_sock = accept(&*target).unwrap(); + ioctl_fionbio(&conn_sock, true).unwrap(); + epoll + .add(conn_sock, epoll::EventFlags::OUT | epoll::EventFlags::ET) + .unwrap(); + } else { + write(&*target, b"hello\n").unwrap(); + let _ = epoll.del(target).unwrap(); + } + } + } +} + +fn client(ready: Arc<(Mutex<u16>, Condvar)>) { + let port = { + let (lock, cvar) = &*ready; + let mut port = lock.lock().unwrap(); + while *port == 0 { + port = cvar.wait(port).unwrap(); + } + *port + }; + + let addr = SocketAddrV4::new(Ipv4Addr::LOCALHOST, port); + let mut buffer = vec![0; BUFFER_SIZE]; + + for _ in 0..16 { + let data_socket = + socket(AddressFamily::INET, SocketType::STREAM, Protocol::default()).unwrap(); + connect_v4(&data_socket, &addr).unwrap(); + + let nread = read(&data_socket, &mut buffer).unwrap(); + assert_eq!(String::from_utf8_lossy(&buffer[..nread]), "hello\n"); + } +} + +#[test] +fn test_epoll() { + let ready = Arc::new((Mutex::new(0_u16), Condvar::new())); + let ready_clone = Arc::clone(&ready); + + let _server = thread::Builder::new() + .name("server".to_string()) + .spawn(move || { + server(ready); + }) + .unwrap(); + let client = thread::Builder::new() + .name("client".to_string()) + .spawn(move || { + client(ready_clone); + }) + .unwrap(); + client.join().unwrap(); +} diff --git a/vendor/rustix/tests/io/error.rs b/vendor/rustix/tests/io/error.rs new file mode 100644 index 000000000..128d3b59a --- /dev/null +++ b/vendor/rustix/tests/io/error.rs @@ -0,0 +1,14 @@ +#[test] +fn test_error() { + assert_eq!( + rustix::io::Errno::INVAL, + rustix::io::Errno::from_raw_os_error(rustix::io::Errno::INVAL.raw_os_error()) + ); + #[cfg(not(windows))] + assert_eq!(rustix::io::Errno::INVAL.raw_os_error(), libc::EINVAL); + #[cfg(windows)] + assert_eq!( + rustix::io::Errno::INVAL.raw_os_error(), + windows_sys::Win32::Networking::WinSock::WSAEINVAL + ); +} diff --git a/vendor/rustix/tests/io/eventfd.rs b/vendor/rustix/tests/io/eventfd.rs new file mode 100644 index 000000000..11bc8ae55 --- /dev/null +++ b/vendor/rustix/tests/io/eventfd.rs @@ -0,0 +1,24 @@ +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_eventfd() { + use rustix::io::{eventfd, read, write, EventfdFlags}; + use std::mem::size_of; + use std::thread; + + let efd = eventfd(0, EventfdFlags::CLOEXEC).unwrap(); + + let child = thread::spawn(move || { + for u in [1_u64, 3, 6, 11, 5000].iter() { + assert_eq!(write(&efd, &u.to_ne_bytes()).unwrap(), size_of::<u64>()); + } + efd + }); + + let efd = child.join().unwrap(); + + let mut bytes = [0_u8; size_of::<u64>()]; + let s = read(&efd, &mut bytes).unwrap(); + assert_eq!(s, bytes.len()); + let u = u64::from_ne_bytes(bytes); + assert_eq!(u, 5021); +} diff --git a/vendor/rustix/tests/io/from_into.rs b/vendor/rustix/tests/io/from_into.rs new file mode 100644 index 000000000..94d915993 --- /dev/null +++ b/vendor/rustix/tests/io/from_into.rs @@ -0,0 +1,28 @@ +#[cfg(feature = "fs")] +#[cfg(not(target_os = "redox"))] +#[test] +fn test_owned() { + use rustix::fd::AsFd; + #[cfg(unix)] + use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd}; + #[cfg(target_os = "wasi")] + use std::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd}; + + let file = rustix::fs::openat( + rustix::fs::cwd(), + "Cargo.toml", + rustix::fs::OFlags::RDONLY, + rustix::fs::Mode::empty(), + ) + .unwrap(); + + let raw = file.as_raw_fd(); + assert_eq!(raw, file.as_fd().as_raw_fd()); + + let inner = file.into_raw_fd(); + assert_eq!(raw, inner); + + let new = unsafe { rustix::io::OwnedFd::from_raw_fd(inner) }; + let mut buf = [0_u8; 4]; + let _ = rustix::io::read(&new, &mut buf).unwrap(); +} diff --git a/vendor/rustix/tests/io/ioctl.rs b/vendor/rustix/tests/io/ioctl.rs new file mode 100644 index 000000000..e260e4884 --- /dev/null +++ b/vendor/rustix/tests/io/ioctl.rs @@ -0,0 +1,14 @@ +// `is_read_write` is not yet implemented on Windows. And `ioctl_fionread` +// on Windows doesn't work on files. +#[cfg(not(windows))] +#[test] +fn test_ioctls() { + let file = std::fs::File::open("Cargo.toml").unwrap(); + + assert_eq!(rustix::io::is_read_write(&file).unwrap(), (true, false)); + + assert_eq!( + rustix::io::ioctl_fionread(&file).unwrap(), + file.metadata().unwrap().len() + ); +} diff --git a/vendor/rustix/tests/io/main.rs b/vendor/rustix/tests/io/main.rs new file mode 100644 index 000000000..bdd044809 --- /dev/null +++ b/vendor/rustix/tests/io/main.rs @@ -0,0 +1,31 @@ +//! Tests for [`rustix::io`]. + +#![cfg_attr(target_os = "wasi", feature(wasi_ext))] +#![cfg_attr(io_lifetimes_use_std, feature(io_safety))] + +#[cfg(not(feature = "rustc-dep-of-std"))] +#[cfg(not(windows))] +#[cfg(not(target_os = "wasi"))] +mod dup2_to_replace_stdio; +#[cfg(not(feature = "rustc-dep-of-std"))] // TODO +#[cfg(not(windows))] +#[cfg(feature = "net")] +#[cfg(not(target_os = "wasi"))] +mod epoll; +mod error; +#[cfg(not(windows))] +#[cfg(not(target_os = "wasi"))] +mod eventfd; +#[cfg(not(windows))] +mod from_into; +#[cfg(not(target_os = "redox"))] +mod ioctl; +mod poll; +#[cfg(all(feature = "procfs", any(target_os = "android", target_os = "linux")))] +mod procfs; +#[cfg(not(windows))] +#[cfg(not(target_os = "redox"))] // redox doesn't have cwd/openat +#[cfg(not(target_os = "wasi"))] // wasi support for S_IRUSR etc. submitted to libc in #2264 +mod read_write; +#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "android"))] +mod seals; diff --git a/vendor/rustix/tests/io/poll.rs b/vendor/rustix/tests/io/poll.rs new file mode 100644 index 000000000..ff2da695b --- /dev/null +++ b/vendor/rustix/tests/io/poll.rs @@ -0,0 +1,63 @@ +use rustix::fd::{AsFd, AsRawFd, FromRawFd, IntoRawFd, OwnedFd}; +#[cfg(not(windows))] +use rustix::io::{poll, retry_on_intr}; +use rustix::io::{PollFd, PollFlags}; + +#[cfg(not(windows))] +#[test] +fn test_poll() { + use rustix::io::{pipe, read, write}; + + // Create a pipe. + let (reader, writer) = pipe().unwrap(); + let mut poll_fds = [PollFd::new(&reader, PollFlags::IN)]; + assert_eq!(poll_fds[0].as_fd().as_raw_fd(), reader.as_fd().as_raw_fd()); + + // `poll` should say there's nothing ready to be read from the pipe. + let num = retry_on_intr(|| poll(&mut poll_fds, 0)).unwrap(); + assert_eq!(num, 0); + assert!(poll_fds[0].revents().is_empty()); + assert_eq!(poll_fds[0].as_fd().as_raw_fd(), reader.as_fd().as_raw_fd()); + + // Write a byte to the pipe. + assert_eq!(retry_on_intr(|| write(&writer, b"a")).unwrap(), 1); + + // `poll` should now say there's data to be read. + let num = retry_on_intr(|| poll(&mut poll_fds, -1)).unwrap(); + assert_eq!(num, 1); + assert_eq!(poll_fds[0].revents(), PollFlags::IN); + assert_eq!(poll_fds[0].as_fd().as_raw_fd(), reader.as_fd().as_raw_fd()); + + let mut temp = poll_fds[0].clone(); + assert_eq!(temp.revents(), PollFlags::IN); + temp.clear_revents(); + assert!(temp.revents().is_empty()); + + // Read the byte from the pipe. + let mut buf = [b'\0']; + assert_eq!(retry_on_intr(|| read(&reader, &mut buf)).unwrap(), 1); + assert_eq!(buf[0], b'a'); + assert_eq!(poll_fds[0].as_fd().as_raw_fd(), reader.as_fd().as_raw_fd()); + + // Poll should now say there's no more data to be read. + let num = retry_on_intr(|| poll(&mut poll_fds, 0)).unwrap(); + assert_eq!(num, 0); + assert!(poll_fds[0].revents().is_empty()); + assert_eq!(poll_fds[0].as_fd().as_raw_fd(), reader.as_fd().as_raw_fd()); +} + +#[test] +fn test_poll_fd_set_fd() { + // Make up some file descriptors so that we can test that set_fd works. + let a = unsafe { OwnedFd::from_raw_fd(777) }; + let mut poll_fd = PollFd::new(&a, PollFlags::empty()); + assert_eq!(poll_fd.as_fd().as_raw_fd(), 777); + + let b = unsafe { OwnedFd::from_raw_fd(888) }; + poll_fd.set_fd(&b); + assert_eq!(poll_fd.as_fd().as_raw_fd(), 888); + + // Don't attempt to close our made-up file descriptors. + let _ = a.into_raw_fd(); + let _ = b.into_raw_fd(); +} diff --git a/vendor/rustix/tests/io/procfs.rs b/vendor/rustix/tests/io/procfs.rs new file mode 100644 index 000000000..4c4256bd7 --- /dev/null +++ b/vendor/rustix/tests/io/procfs.rs @@ -0,0 +1,8 @@ +use io_lifetimes::raw::AsRawFilelike; + +#[test] +fn test_proc_self() { + // Verify that this API works at all + let fd = rustix::io::proc_self_fd().unwrap(); + assert_ne!(fd.as_raw_filelike(), 0); +} diff --git a/vendor/rustix/tests/io/read_write.rs b/vendor/rustix/tests/io/read_write.rs new file mode 100644 index 000000000..65186bf21 --- /dev/null +++ b/vendor/rustix/tests/io/read_write.rs @@ -0,0 +1,118 @@ +#[cfg(feature = "fs")] +use std::io::{IoSlice, IoSliceMut}; + +#[cfg(feature = "fs")] +#[test] +fn test_readwrite_pv() { + use rustix::fs::{cwd, openat, Mode, OFlags}; + use rustix::io::{preadv, pwritev}; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + let foo = openat( + &dir, + "foo", + OFlags::RDWR | OFlags::CREATE | OFlags::TRUNC, + Mode::RUSR | Mode::WUSR, + ) + .unwrap(); + + // For most targets, just call `pwritev`. + #[cfg(not(any(target_os = "ios", target_os = "macos")))] + { + pwritev(&foo, &[IoSlice::new(b"hello")], 200).unwrap(); + } + // macOS only has pwritev in newer versions; allow it to fail with `ENOSYS`. + #[cfg(any(target_os = "ios", target_os = "macos"))] + { + match pwritev(&foo, &[IoSlice::new(b"hello")], 200) { + Ok(_) => (), + Err(rustix::io::Errno::NOSYS) => return, + Err(err) => Err(err).unwrap(), + } + } + pwritev(&foo, &[IoSlice::new(b"world")], 300).unwrap(); + let mut buf = [0_u8; 5]; + preadv(&foo, &mut [IoSliceMut::new(&mut buf)], 200).unwrap(); + assert_eq!(&buf, b"hello"); + preadv(&foo, &mut [IoSliceMut::new(&mut buf)], 300).unwrap(); + assert_eq!(&buf, b"world"); +} + +#[cfg(feature = "fs")] +#[test] +fn test_readwrite_p() { + use rustix::fs::{cwd, openat, Mode, OFlags}; + use rustix::io::{pread, pwrite}; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + let foo = openat( + &dir, + "foo", + OFlags::RDWR | OFlags::CREATE | OFlags::TRUNC, + Mode::RUSR | Mode::WUSR, + ) + .unwrap(); + + pwrite(&foo, b"hello", 200).unwrap(); + pwrite(&foo, b"world", 300).unwrap(); + let mut buf = [0_u8; 5]; + pread(&foo, &mut buf, 200).unwrap(); + assert_eq!(&buf, b"hello"); + pread(&foo, &mut buf, 300).unwrap(); + assert_eq!(&buf, b"world"); +} + +#[cfg(feature = "fs")] +#[test] +fn test_readwrite_v() { + use rustix::fs::{cwd, openat, seek, Mode, OFlags}; + use rustix::io::{readv, writev, SeekFrom}; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + let foo = openat( + &dir, + "foo", + OFlags::RDWR | OFlags::CREATE | OFlags::TRUNC, + Mode::RUSR | Mode::WUSR, + ) + .unwrap(); + + writev(&foo, &[IoSlice::new(b"hello")]).unwrap(); + writev(&foo, &[IoSlice::new(b"world")]).unwrap(); + seek(&foo, SeekFrom::Start(0)).unwrap(); + let mut buf = [0_u8; 5]; + readv(&foo, &mut [IoSliceMut::new(&mut buf)]).unwrap(); + assert_eq!(&buf, b"hello"); + readv(&foo, &mut [IoSliceMut::new(&mut buf)]).unwrap(); + assert_eq!(&buf, b"world"); +} + +#[cfg(feature = "fs")] +#[test] +fn test_readwrite() { + use rustix::fs::{cwd, openat, seek, Mode, OFlags}; + use rustix::io::{read, write}; + use std::io::SeekFrom; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + let foo = openat( + &dir, + "foo", + OFlags::RDWR | OFlags::CREATE | OFlags::TRUNC, + Mode::RUSR | Mode::WUSR, + ) + .unwrap(); + + write(&foo, b"hello").unwrap(); + write(&foo, b"world").unwrap(); + seek(&foo, SeekFrom::Start(0)).unwrap(); + let mut buf = [0_u8; 5]; + read(&foo, &mut buf).unwrap(); + assert_eq!(&buf, b"hello"); + read(&foo, &mut buf).unwrap(); + assert_eq!(&buf, b"world"); +} diff --git a/vendor/rustix/tests/io/seals.rs b/vendor/rustix/tests/io/seals.rs new file mode 100644 index 000000000..ff971fa75 --- /dev/null +++ b/vendor/rustix/tests/io/seals.rs @@ -0,0 +1,41 @@ +#[cfg(feature = "fs")] +#[test] +fn test_seals() { + use rustix::fd::FromFd; + use rustix::fs::{ + fcntl_add_seals, fcntl_get_seals, ftruncate, memfd_create, MemfdFlags, SealFlags, + }; + use std::fs::File; + use std::io::Write; + + let fd = match memfd_create("test", MemfdFlags::CLOEXEC | MemfdFlags::ALLOW_SEALING) { + Ok(fd) => fd, + Err(rustix::io::Errno::NOSYS) => return, + Err(err) => Err(err).unwrap(), + }; + let mut file = File::from_fd(fd.into()); + + let old = fcntl_get_seals(&file).unwrap(); + assert_eq!(old, SealFlags::empty()); + + writeln!(&mut file, "Hello!").unwrap(); + + fcntl_add_seals(&file, SealFlags::GROW).unwrap(); + + let now = fcntl_get_seals(&file).unwrap(); + assert_eq!(now, SealFlags::GROW); + + // We sealed growing, so this should fail. + writeln!(&mut file, "World?").unwrap_err(); + + // We can still shrink for now. + ftruncate(&mut file, 1).unwrap(); + + fcntl_add_seals(&file, SealFlags::SHRINK).unwrap(); + + let now = fcntl_get_seals(&file).unwrap(); + assert_eq!(now, SealFlags::GROW | SealFlags::SHRINK); + + // We sealed shrinking, so this should fail. + ftruncate(&mut file, 0).unwrap_err(); +} diff --git a/vendor/rustix/tests/mm/main.rs b/vendor/rustix/tests/mm/main.rs new file mode 100644 index 000000000..ee746d900 --- /dev/null +++ b/vendor/rustix/tests/mm/main.rs @@ -0,0 +1,13 @@ +//! Tests for [`rustix::mm`]. + +#![cfg(feature = "mm")] +#![cfg_attr(target_os = "wasi", feature(wasi_ext))] +#![cfg_attr(io_lifetimes_use_std, feature(io_safety))] + +#[cfg(not(windows))] +#[cfg(not(target_os = "wasi"))] +mod mlock; +#[cfg(not(windows))] +mod mmap; +#[cfg(not(windows))] +mod prot; diff --git a/vendor/rustix/tests/mm/mlock.rs b/vendor/rustix/tests/mm/mlock.rs new file mode 100644 index 000000000..c4a1a83b5 --- /dev/null +++ b/vendor/rustix/tests/mm/mlock.rs @@ -0,0 +1,79 @@ +//! Tests for `mlock`. +//! +//! We can't easily test that it actually locks memory, but we can test that we +//! can call it and either get success or a reasonable error message. + +use std::ffi::c_void; + +#[test] +fn test_mlock() { + let mut buf = vec![0_u8; 4096]; + + unsafe { + match rustix::mm::mlock(buf.as_mut_ptr().cast::<c_void>(), buf.len()) { + Ok(()) => rustix::mm::munlock(buf.as_mut_ptr().cast::<c_void>(), buf.len()).unwrap(), + // Tests won't always have enough memory or permissions, and that's ok. + Err(rustix::io::Errno::PERM) | Err(rustix::io::Errno::NOMEM) => {} + // But they shouldn't fail otherwise. + Err(other) => Err(other).unwrap(), + } + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_mlock_with() { + let mut buf = vec![0_u8; 4096]; + + unsafe { + match rustix::mm::mlock_with( + buf.as_mut_ptr().cast::<c_void>(), + buf.len(), + rustix::mm::MlockFlags::empty(), + ) { + Ok(()) => rustix::mm::munlock(buf.as_mut_ptr().cast::<c_void>(), buf.len()).unwrap(), + // Tests won't always have enough memory or permissions, and that's ok. + Err(rustix::io::Errno::PERM) + | Err(rustix::io::Errno::NOMEM) + | Err(rustix::io::Errno::NOSYS) => {} + // But they shouldn't fail otherwise. + Err(other) => Err(other).unwrap(), + } + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_mlock_with_onfault() { + // With glibc, `mlock2` with `MLOCK_ONFAULT` returns `EINVAL` if the + // `mlock2` system call returns `ENOSYS`. That's not what we want + // here though, because `ENOSYS` just means the OS doesn't have + // `mlock2`, while `EINVAL` may indicate a bug in rustix. + // + // To work around this, we use `libc::syscall` to make a `mlock2` + // syscall directly to test for `ENOSYS`, before running the main + // test below. + unsafe { + if libc::syscall(libc::SYS_mlock2, 0, 0) == -1 && libc_errno::errno().0 == libc::ENOSYS { + return; + } + } + + let mut buf = vec![0_u8; 4096]; + + unsafe { + match rustix::mm::mlock_with( + buf.as_mut_ptr().cast::<c_void>(), + buf.len(), + rustix::mm::MlockFlags::ONFAULT, + ) { + Ok(()) => rustix::mm::munlock(buf.as_mut_ptr().cast::<c_void>(), buf.len()).unwrap(), + // Tests won't always have enough memory or permissions, and that's ok. + Err(rustix::io::Errno::PERM) + | Err(rustix::io::Errno::NOMEM) + | Err(rustix::io::Errno::NOSYS) => {} + // But they shouldn't fail otherwise. + Err(other) => Err(other).unwrap(), + } + } +} diff --git a/vendor/rustix/tests/mm/mmap.rs b/vendor/rustix/tests/mm/mmap.rs new file mode 100644 index 000000000..6b27287d7 --- /dev/null +++ b/vendor/rustix/tests/mm/mmap.rs @@ -0,0 +1,163 @@ +#![cfg(not(target_os = "wasi"))] + +#[cfg(feature = "fs")] +#[cfg(not(target_os = "redox"))] +#[test] +fn test_mmap() { + use rustix::fs::{cwd, openat, Mode, OFlags}; + use rustix::io::write; + use rustix::mm::{mmap, munmap, MapFlags, ProtFlags}; + use std::ptr::null_mut; + use std::slice; + + let tmp = tempfile::tempdir().unwrap(); + let dir = openat(cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); + + let file = openat( + &dir, + "foo", + OFlags::CREATE | OFlags::WRONLY | OFlags::TRUNC, + Mode::RUSR, + ) + .unwrap(); + write(&file, &[b'a'; 8192]).unwrap(); + drop(file); + + let file = openat(&dir, "foo", OFlags::RDONLY, Mode::empty()).unwrap(); + unsafe { + let addr = mmap( + null_mut(), + 8192, + ProtFlags::READ, + MapFlags::PRIVATE, + &file, + 0, + ) + .unwrap(); + let slice = slice::from_raw_parts(addr.cast::<u8>(), 8192); + assert_eq!(slice, &[b'a'; 8192]); + + munmap(addr, 8192).unwrap(); + } + + let file = openat(&dir, "foo", OFlags::RDONLY, Mode::empty()).unwrap(); + unsafe { + assert_eq!( + mmap( + null_mut(), + 8192, + ProtFlags::READ, + MapFlags::PRIVATE, + &file, + u64::MAX, + ) + .unwrap_err() + .raw_os_error(), + libc::EINVAL + ); + } +} + +#[test] +fn test_mmap_anonymous() { + use rustix::mm::{mmap_anonymous, munmap, MapFlags, ProtFlags}; + use std::ptr::null_mut; + use std::slice; + + unsafe { + let addr = mmap_anonymous(null_mut(), 8192, ProtFlags::READ, MapFlags::PRIVATE).unwrap(); + let slice = slice::from_raw_parts(addr.cast::<u8>(), 8192); + assert_eq!(slice, &[b'\0'; 8192]); + + munmap(addr, 8192).unwrap(); + } +} + +#[test] +fn test_mprotect() { + use rustix::mm::{mmap_anonymous, mprotect, munmap, MapFlags, MprotectFlags, ProtFlags}; + use std::ptr::null_mut; + use std::slice; + + unsafe { + let addr = mmap_anonymous(null_mut(), 8192, ProtFlags::READ, MapFlags::PRIVATE).unwrap(); + + mprotect(addr, 8192, MprotectFlags::empty()).unwrap(); + mprotect(addr, 8192, MprotectFlags::READ).unwrap(); + + let slice = slice::from_raw_parts(addr.cast::<u8>(), 8192); + assert_eq!(slice, &[b'\0'; 8192]); + + munmap(addr, 8192).unwrap(); + } +} + +#[test] +fn test_mlock() { + use rustix::mm::{mlock, mmap_anonymous, munlock, munmap, MapFlags, ProtFlags}; + #[cfg(any(target_os = "android", target_os = "linux"))] + use rustix::mm::{mlock_with, MlockFlags}; + use std::ptr::null_mut; + + unsafe { + let addr = mmap_anonymous(null_mut(), 8192, ProtFlags::READ, MapFlags::PRIVATE).unwrap(); + + mlock(addr, 8192).unwrap(); + munlock(addr, 8192).unwrap(); + + #[cfg(any(target_os = "android", target_os = "linux"))] + { + match mlock_with(addr, 8192, MlockFlags::empty()) { + Err(rustix::io::Errno::NOSYS) => (), + Err(err) => Err(err).unwrap(), + Ok(()) => munlock(addr, 8192).unwrap(), + } + + #[cfg(linux_raw)] // libc doesn't expose `MLOCK_UNFAULT` yet. + { + match mlock_with(addr, 8192, MlockFlags::ONFAULT) { + Err(rustix::io::Errno::NOSYS) => (), + Err(err) => Err(err).unwrap(), + Ok(()) => munlock(addr, 8192).unwrap(), + } + munlock(addr, 8192).unwrap(); + } + } + + munmap(addr, 8192).unwrap(); + } +} + +#[cfg(not(target_os = "redox"))] +#[test] +fn test_madvise() { + use rustix::mm::{madvise, mmap_anonymous, munmap, Advice, MapFlags, ProtFlags}; + use std::ptr::null_mut; + + unsafe { + let addr = mmap_anonymous(null_mut(), 8192, ProtFlags::READ, MapFlags::PRIVATE).unwrap(); + + madvise(addr, 8192, Advice::Normal).unwrap(); + madvise(addr, 8192, Advice::DontNeed).unwrap(); + + #[cfg(any(target_os = "android", target_os = "linux"))] + madvise(addr, 8192, Advice::LinuxDontNeed).unwrap(); + + munmap(addr, 8192).unwrap(); + } +} + +#[test] +fn test_msync() { + use rustix::mm::{mmap_anonymous, msync, munmap, MapFlags, MsyncFlags, ProtFlags}; + use std::ptr::null_mut; + + unsafe { + let addr = mmap_anonymous(null_mut(), 8192, ProtFlags::READ, MapFlags::PRIVATE).unwrap(); + + msync(addr, 8192, MsyncFlags::SYNC).unwrap(); + msync(addr, 8192, MsyncFlags::ASYNC).unwrap(); + + munmap(addr, 8192).unwrap(); + } +} diff --git a/vendor/rustix/tests/mm/prot.rs b/vendor/rustix/tests/mm/prot.rs new file mode 100644 index 000000000..6c86a8f2a --- /dev/null +++ b/vendor/rustix/tests/mm/prot.rs @@ -0,0 +1,4 @@ +#[test] +fn test_prot_flags() { + assert_eq!(libc::PROT_NONE, 0); +} diff --git a/vendor/rustix/tests/net/addr.rs b/vendor/rustix/tests/net/addr.rs new file mode 100644 index 000000000..124413132 --- /dev/null +++ b/vendor/rustix/tests/net/addr.rs @@ -0,0 +1,92 @@ +#[test] +fn encode_decode() { + #[cfg(unix)] + use rustix::net::SocketAddrUnix; + use rustix::net::{ + Ipv4Addr, Ipv6Addr, SocketAddrAny, SocketAddrStorage, SocketAddrV4, SocketAddrV6, + }; + + unsafe { + let orig = SocketAddrV4::new(Ipv4Addr::new(2, 3, 5, 6), 33); + let mut encoded = std::mem::MaybeUninit::<SocketAddrStorage>::uninit(); + let len = SocketAddrAny::V4(orig).write(encoded.as_mut_ptr()); + let decoded = SocketAddrAny::read(encoded.as_ptr(), len).unwrap(); + assert_eq!(decoded, SocketAddrAny::V4(orig)); + + let orig = SocketAddrV6::new(Ipv6Addr::new(2, 3, 5, 6, 8, 9, 11, 12), 33, 34, 36); + let mut encoded = std::mem::MaybeUninit::<SocketAddrStorage>::uninit(); + let len = SocketAddrAny::V6(orig).write(encoded.as_mut_ptr()); + let decoded = SocketAddrAny::read(encoded.as_ptr(), len).unwrap(); + assert_eq!(decoded, SocketAddrAny::V6(orig)); + + #[cfg(not(windows))] + { + let orig = SocketAddrUnix::new("/path/to/socket").unwrap(); + let mut encoded = std::mem::MaybeUninit::<SocketAddrStorage>::uninit(); + let len = SocketAddrAny::Unix(orig.clone()).write(encoded.as_mut_ptr()); + let decoded = SocketAddrAny::read(encoded.as_ptr(), len).unwrap(); + assert_eq!(decoded, SocketAddrAny::Unix(orig)); + } + } +} + +#[cfg(not(windows))] +#[test] +fn test_unix_addr() { + use rustix::cstr; + use rustix::net::SocketAddrUnix; + + assert_eq!( + SocketAddrUnix::new("/").unwrap().path().unwrap(), + cstr!("/") + ); + assert_eq!( + SocketAddrUnix::new("//").unwrap().path().unwrap(), + cstr!("//") + ); + assert_eq!( + SocketAddrUnix::new("/foo/bar").unwrap().path().unwrap(), + cstr!("/foo/bar") + ); + assert_eq!( + SocketAddrUnix::new("foo").unwrap().path().unwrap(), + cstr!("foo") + ); + SocketAddrUnix::new("/foo\0/bar").unwrap_err(); + assert!(SocketAddrUnix::new("").unwrap().path().is_none()); + + #[cfg(any(target_os = "android", target_os = "linux"))] + { + assert!(SocketAddrUnix::new("foo") + .unwrap() + .abstract_name() + .is_none()); + + assert_eq!( + SocketAddrUnix::new_abstract_name(b"test") + .unwrap() + .abstract_name() + .unwrap(), + b"test" + ); + assert_eq!( + SocketAddrUnix::new_abstract_name(b"") + .unwrap() + .abstract_name() + .unwrap(), + b"" + ); + assert_eq!( + SocketAddrUnix::new_abstract_name(b"this\0that") + .unwrap() + .abstract_name() + .unwrap(), + b"this\0that" + ); + SocketAddrUnix::new_abstract_name(&[b'a'; 500]).unwrap_err(); + assert!(SocketAddrUnix::new_abstract_name(b"test") + .unwrap() + .path() + .is_none()); + } +} diff --git a/vendor/rustix/tests/net/connect_bind_send.rs b/vendor/rustix/tests/net/connect_bind_send.rs new file mode 100644 index 000000000..84720975f --- /dev/null +++ b/vendor/rustix/tests/net/connect_bind_send.rs @@ -0,0 +1,487 @@ +use rustix::net::{ + AddressFamily, Ipv6Addr, Protocol, RecvFlags, SendFlags, SocketAddrAny, SocketAddrV4, + SocketAddrV6, SocketType, +}; +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + +/// Test `connect_any`. +#[test] +fn net_v4_connect_any() -> std::io::Result<()> { + let localhost = IpAddr::V4(Ipv4Addr::LOCALHOST); + let addr = SocketAddr::new(localhost, 0); + let listener = + rustix::net::socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?; + rustix::net::bind(&listener, &addr).expect("bind"); + rustix::net::listen(&listener, 1).expect("listen"); + + let local_addr = rustix::net::getsockname(&listener)?; + let sender = rustix::net::socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?; + rustix::net::connect_any(&sender, &local_addr).expect("connect"); + let request = b"Hello, World!!!"; + let n = rustix::net::send(&sender, request, SendFlags::empty()).expect("send"); + drop(sender); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + let accepted = rustix::net::accept(&listener).expect("accept"); + let mut response = [0_u8; 128]; + let n = rustix::net::recv(&accepted, &mut response, RecvFlags::empty()).expect("recv"); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + assert_eq!(request, &response[..n]); + + Ok(()) +} + +/// Similar, but with V6. +#[test] +fn net_v6_connect_any() -> std::io::Result<()> { + let localhost = IpAddr::V6(Ipv6Addr::LOCALHOST); + let addr = SocketAddr::new(localhost, 0); + let listener = rustix::net::socket( + AddressFamily::INET6, + SocketType::STREAM, + Protocol::default(), + )?; + rustix::net::bind(&listener, &addr).expect("bind"); + rustix::net::listen(&listener, 1).expect("listen"); + + let local_addr = rustix::net::getsockname(&listener)?; + let sender = rustix::net::socket( + AddressFamily::INET6, + SocketType::STREAM, + Protocol::default(), + )?; + rustix::net::connect_any(&sender, &local_addr).expect("connect"); + let request = b"Hello, World!!!"; + let n = rustix::net::send(&sender, request, SendFlags::empty()).expect("send"); + drop(sender); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + let accepted = rustix::net::accept(&listener).expect("accept"); + let mut response = [0_u8; 128]; + let n = rustix::net::recv(&accepted, &mut response, RecvFlags::empty()).expect("recv"); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + assert_eq!(request, &response[..n]); + + Ok(()) +} + +/// Test `connect` with a `SocketAddr`. +#[test] +fn net_v4_connect() -> std::io::Result<()> { + let localhost = IpAddr::V4(Ipv4Addr::LOCALHOST); + let addr = SocketAddr::new(localhost, 0); + let listener = + rustix::net::socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?; + rustix::net::bind(&listener, &addr).expect("bind"); + rustix::net::listen(&listener, 1).expect("listen"); + + let local_addr = rustix::net::getsockname(&listener)?; + let local_addr = match local_addr { + SocketAddrAny::V4(v4) => SocketAddr::V4(v4), + other => panic!("unexpected socket address {:?}", other), + }; + let sender = rustix::net::socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?; + rustix::net::connect(&sender, &local_addr).expect("connect"); + let request = b"Hello, World!!!"; + let n = rustix::net::send(&sender, request, SendFlags::empty()).expect("send"); + drop(sender); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + let accepted = rustix::net::accept(&listener).expect("accept"); + let mut response = [0_u8; 128]; + let n = rustix::net::recv(&accepted, &mut response, RecvFlags::empty()).expect("recv"); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + assert_eq!(request, &response[..n]); + + Ok(()) +} + +/// Similar, but use V6. +#[test] +fn net_v6_connect() -> std::io::Result<()> { + let localhost = IpAddr::V6(Ipv6Addr::LOCALHOST); + let addr = SocketAddr::new(localhost, 0); + let listener = rustix::net::socket( + AddressFamily::INET6, + SocketType::STREAM, + Protocol::default(), + )?; + rustix::net::bind(&listener, &addr).expect("bind"); + rustix::net::listen(&listener, 1).expect("listen"); + + let local_addr = rustix::net::getsockname(&listener)?; + let local_addr = match local_addr { + SocketAddrAny::V6(v6) => SocketAddr::V6(v6), + other => panic!("unexpected socket address {:?}", other), + }; + let sender = rustix::net::socket( + AddressFamily::INET6, + SocketType::STREAM, + Protocol::default(), + )?; + rustix::net::connect(&sender, &local_addr).expect("connect"); + let request = b"Hello, World!!!"; + let n = rustix::net::send(&sender, request, SendFlags::empty()).expect("send"); + drop(sender); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + let accepted = rustix::net::accept(&listener).expect("accept"); + let mut response = [0_u8; 128]; + let n = rustix::net::recv(&accepted, &mut response, RecvFlags::empty()).expect("recv"); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + assert_eq!(request, &response[..n]); + + Ok(()) +} + +/// Test `bind_any`. +#[test] +fn net_v4_bind_any() -> std::io::Result<()> { + let localhost = Ipv4Addr::LOCALHOST; + let addr = SocketAddrAny::V4(SocketAddrV4::new(localhost, 0)); + let listener = + rustix::net::socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?; + rustix::net::bind_any(&listener, &addr).expect("bind"); + rustix::net::listen(&listener, 1).expect("listen"); + + let local_addr = rustix::net::getsockname(&listener)?; + let sender = rustix::net::socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?; + rustix::net::connect_any(&sender, &local_addr).expect("connect"); + let request = b"Hello, World!!!"; + let n = rustix::net::send(&sender, request, SendFlags::empty()).expect("send"); + drop(sender); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + let accepted = rustix::net::accept(&listener).expect("accept"); + let mut response = [0_u8; 128]; + let n = rustix::net::recv(&accepted, &mut response, RecvFlags::empty()).expect("recv"); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + assert_eq!(request, &response[..n]); + + Ok(()) +} + +/// Similar, but use V6. +#[test] +fn net_v6_bind_any() -> std::io::Result<()> { + let localhost = Ipv6Addr::LOCALHOST; + let addr = SocketAddrAny::V6(SocketAddrV6::new(localhost, 0, 0, 0)); + let listener = rustix::net::socket( + AddressFamily::INET6, + SocketType::STREAM, + Protocol::default(), + )?; + rustix::net::bind_any(&listener, &addr).expect("bind"); + rustix::net::listen(&listener, 1).expect("listen"); + + let local_addr = rustix::net::getsockname(&listener)?; + let sender = rustix::net::socket( + AddressFamily::INET6, + SocketType::STREAM, + Protocol::default(), + )?; + rustix::net::connect_any(&sender, &local_addr).expect("connect"); + let request = b"Hello, World!!!"; + let n = rustix::net::send(&sender, request, SendFlags::empty()).expect("send"); + drop(sender); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + let accepted = rustix::net::accept(&listener).expect("accept"); + let mut response = [0_u8; 128]; + let n = rustix::net::recv(&accepted, &mut response, RecvFlags::empty()).expect("recv"); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + assert_eq!(request, &response[..n]); + + Ok(()) +} + +/// Test `sendto`. +#[test] +fn net_v4_sendto() -> std::io::Result<()> { + let localhost = IpAddr::V4(Ipv4Addr::LOCALHOST); + let addr = SocketAddr::new(localhost, 0); + let listener = + rustix::net::socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?; + rustix::net::bind(&listener, &addr).expect("bind"); + rustix::net::listen(&listener, 1).expect("listen"); + + let local_addr = rustix::net::getsockname(&listener)?; + let sender = rustix::net::socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?; + rustix::net::connect_any(&sender, &local_addr).expect("connect"); + let request = b"Hello, World!!!"; + let local_addr = match local_addr { + SocketAddrAny::V4(v4) => SocketAddr::V4(v4), + other => panic!("unexpected socket address {:?}", other), + }; + let n = rustix::net::sendto(&sender, request, SendFlags::empty(), &local_addr).expect("send"); + drop(sender); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + let accepted = rustix::net::accept(&listener).expect("accept"); + let mut response = [0_u8; 128]; + let (n, from) = + rustix::net::recvfrom(&accepted, &mut response, RecvFlags::empty()).expect("recv"); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + assert_eq!(request, &response[..n]); + assert!(from.is_none()); + + Ok(()) +} + +/// Similar, but with V6. +#[test] +fn net_v6_sendto() -> std::io::Result<()> { + let localhost = IpAddr::V6(Ipv6Addr::LOCALHOST); + let addr = SocketAddr::new(localhost, 0); + let listener = rustix::net::socket( + AddressFamily::INET6, + SocketType::STREAM, + Protocol::default(), + )?; + rustix::net::bind(&listener, &addr).expect("bind"); + rustix::net::listen(&listener, 1).expect("listen"); + + let local_addr = rustix::net::getsockname(&listener)?; + let sender = rustix::net::socket( + AddressFamily::INET6, + SocketType::STREAM, + Protocol::default(), + )?; + rustix::net::connect_any(&sender, &local_addr).expect("connect"); + let request = b"Hello, World!!!"; + let local_addr = match local_addr { + SocketAddrAny::V6(v6) => SocketAddr::V6(v6), + other => panic!("unexpected socket address {:?}", other), + }; + let n = rustix::net::sendto(&sender, request, SendFlags::empty(), &local_addr).expect("send"); + drop(sender); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + let accepted = rustix::net::accept(&listener).expect("accept"); + let mut response = [0_u8; 128]; + let (n, from) = + rustix::net::recvfrom(&accepted, &mut response, RecvFlags::empty()).expect("recv"); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + assert_eq!(request, &response[..n]); + assert!(from.is_none()); + + Ok(()) +} + +/// Test `sendto_any`. +#[test] +fn net_v4_sendto_any() -> std::io::Result<()> { + let localhost = IpAddr::V4(Ipv4Addr::LOCALHOST); + let addr = SocketAddr::new(localhost, 0); + let listener = + rustix::net::socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?; + rustix::net::bind(&listener, &addr).expect("bind"); + rustix::net::listen(&listener, 1).expect("listen"); + + let local_addr = rustix::net::getsockname(&listener)?; + let sender = rustix::net::socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?; + rustix::net::connect_any(&sender, &local_addr).expect("connect"); + let request = b"Hello, World!!!"; + let n = + rustix::net::sendto_any(&sender, request, SendFlags::empty(), &local_addr).expect("send"); + drop(sender); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + let accepted = rustix::net::accept(&listener).expect("accept"); + let mut response = [0_u8; 128]; + let (n, from) = + rustix::net::recvfrom(&accepted, &mut response, RecvFlags::empty()).expect("recv"); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + assert_eq!(request, &response[..n]); + assert!(from.is_none()); + + Ok(()) +} + +/// Test `sendto_any`. +#[test] +fn net_v6_sendto_any() -> std::io::Result<()> { + let localhost = IpAddr::V6(Ipv6Addr::LOCALHOST); + let addr = SocketAddr::new(localhost, 0); + let listener = rustix::net::socket( + AddressFamily::INET6, + SocketType::STREAM, + Protocol::default(), + )?; + rustix::net::bind(&listener, &addr).expect("bind"); + rustix::net::listen(&listener, 1).expect("listen"); + + let local_addr = rustix::net::getsockname(&listener)?; + let sender = rustix::net::socket( + AddressFamily::INET6, + SocketType::STREAM, + Protocol::default(), + )?; + rustix::net::connect_any(&sender, &local_addr).expect("connect"); + let request = b"Hello, World!!!"; + let n = + rustix::net::sendto_any(&sender, request, SendFlags::empty(), &local_addr).expect("send"); + drop(sender); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + let accepted = rustix::net::accept(&listener).expect("accept"); + let mut response = [0_u8; 128]; + let (n, from) = + rustix::net::recvfrom(&accepted, &mut response, RecvFlags::empty()).expect("recv"); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + assert_eq!(request, &response[..n]); + assert!(from.is_none()); + + Ok(()) +} + +/// Test `acceptfrom`. +#[test] +fn net_v4_acceptfrom() -> std::io::Result<()> { + let localhost = IpAddr::V4(Ipv4Addr::LOCALHOST); + let addr = SocketAddr::new(localhost, 0); + let listener = + rustix::net::socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?; + rustix::net::bind(&listener, &addr).expect("bind"); + rustix::net::listen(&listener, 1).expect("listen"); + + let local_addr = rustix::net::getsockname(&listener)?; + let sender = rustix::net::socket(AddressFamily::INET, SocketType::STREAM, Protocol::default())?; + rustix::net::connect_any(&sender, &local_addr).expect("connect"); + let request = b"Hello, World!!!"; + let n = rustix::net::send(&sender, request, SendFlags::empty()).expect("send"); + drop(sender); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + let (accepted, from) = rustix::net::acceptfrom(&listener).expect("accept"); + + assert_ne!(from.clone().unwrap(), local_addr); + + let from = match from.unwrap() { + SocketAddrAny::V4(v4) => v4, + other => panic!("unexpected socket address {:?}", other), + }; + let local_addr = match local_addr { + SocketAddrAny::V4(v4) => v4, + other => panic!("unexpected socket address {:?}", other), + }; + + assert_eq!(from.clone().ip(), local_addr.ip()); + assert_ne!(from.clone().port(), local_addr.port()); + + let mut response = [0_u8; 128]; + let n = rustix::net::recv(&accepted, &mut response, RecvFlags::empty()).expect("recv"); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + assert_eq!(request, &response[..n]); + + Ok(()) +} + +/// Similar, but with V6. +#[test] +fn net_v6_acceptfrom() -> std::io::Result<()> { + let localhost = IpAddr::V6(Ipv6Addr::LOCALHOST); + let addr = SocketAddr::new(localhost, 0); + let listener = rustix::net::socket( + AddressFamily::INET6, + SocketType::STREAM, + Protocol::default(), + )?; + rustix::net::bind(&listener, &addr).expect("bind"); + rustix::net::listen(&listener, 1).expect("listen"); + + let local_addr = rustix::net::getsockname(&listener)?; + let sender = rustix::net::socket( + AddressFamily::INET6, + SocketType::STREAM, + Protocol::default(), + )?; + rustix::net::connect_any(&sender, &local_addr).expect("connect"); + let request = b"Hello, World!!!"; + let n = rustix::net::send(&sender, request, SendFlags::empty()).expect("send"); + drop(sender); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + let (accepted, from) = rustix::net::acceptfrom(&listener).expect("accept"); + + assert_ne!(from.clone().unwrap(), local_addr); + + let from = match from.unwrap() { + SocketAddrAny::V6(v6) => v6, + other => panic!("unexpected socket address {:?}", other), + }; + let local_addr = match local_addr { + SocketAddrAny::V6(v6) => v6, + other => panic!("unexpected socket address {:?}", other), + }; + + assert_eq!(from.clone().ip(), local_addr.ip()); + assert_ne!(from.clone().port(), local_addr.port()); + + let mut response = [0_u8; 128]; + let n = rustix::net::recv(&accepted, &mut response, RecvFlags::empty()).expect("recv"); + + // Not strictly required, but it makes the test simpler. + assert_eq!(n, request.len()); + + assert_eq!(request, &response[..n]); + + Ok(()) +} diff --git a/vendor/rustix/tests/net/main.rs b/vendor/rustix/tests/net/main.rs new file mode 100644 index 000000000..0745282aa --- /dev/null +++ b/vendor/rustix/tests/net/main.rs @@ -0,0 +1,32 @@ +//! Tests for [`rustix::net`]. + +#![cfg(feature = "net")] +#![cfg_attr(target_os = "wasi", feature(wasi_ext))] +#![cfg(not(any(target_os = "redox", target_os = "wasi")))] +#![cfg_attr(io_lifetimes_use_std, feature(io_safety))] +#![cfg_attr(core_c_str, feature(core_c_str))] + +mod addr; +mod connect_bind_send; +mod poll; +mod sockopt; +#[cfg(unix)] +mod unix; +mod v4; +mod v6; + +/// Windows requires us to call a setup function before using any of the +/// socket APIs. +#[cfg(windows)] +#[ctor::ctor] +fn windows_startup() { + let _ = rustix::net::wsa_startup().unwrap(); +} + +/// Windows requires us to call a cleanup function after using any of the +/// socket APIs. +#[cfg(windows)] +#[ctor::dtor] +fn windows_shutdown() { + rustix::net::wsa_cleanup().unwrap(); +} diff --git a/vendor/rustix/tests/net/poll.rs b/vendor/rustix/tests/net/poll.rs new file mode 100644 index 000000000..7933983f2 --- /dev/null +++ b/vendor/rustix/tests/net/poll.rs @@ -0,0 +1,119 @@ +//! The same as v6.rs, but with `poll` calls. + +#![cfg(not(any(target_os = "redox", target_os = "wasi")))] + +use rustix::io::{poll, PollFd, PollFlags}; +use rustix::net::{ + accept, bind_v6, connect_v6, getsockname, listen, recv, send, socket, AddressFamily, Ipv6Addr, + Protocol, RecvFlags, SendFlags, SocketAddrAny, SocketAddrV6, SocketType, +}; +use std::sync::{Arc, Condvar, Mutex}; +use std::thread; + +const BUFFER_SIZE: usize = 20; + +fn server(ready: Arc<(Mutex<u16>, Condvar)>) { + let connection_socket = socket( + AddressFamily::INET6, + SocketType::STREAM, + Protocol::default(), + ) + .unwrap(); + + let name = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 0, 0, 0); + bind_v6(&connection_socket, &name).unwrap(); + + let who = match getsockname(&connection_socket).unwrap() { + SocketAddrAny::V6(addr) => addr, + _ => panic!(), + }; + + listen(&connection_socket, 1).unwrap(); + + { + let (lock, cvar) = &*ready; + let mut port = lock.lock().unwrap(); + *port = who.port(); + cvar.notify_all(); + } + + let mut buffer = vec![0; BUFFER_SIZE]; + let data_socket = accept(&connection_socket).unwrap(); + + let mut fds = [PollFd::new(&data_socket, PollFlags::IN)]; + assert_eq!(poll(&mut fds, -1).unwrap(), 1); + assert!(fds[0].revents().intersects(PollFlags::IN)); + assert!(!fds[0].revents().intersects(PollFlags::OUT)); + + let expected_nread = rustix::io::ioctl_fionread(&data_socket).unwrap(); + let nread = recv(&data_socket, &mut buffer, RecvFlags::empty()).unwrap(); + assert_eq!(String::from_utf8_lossy(&buffer[..nread]), "hello, world"); + assert_eq!(expected_nread, nread as u64); + + let mut fds = [PollFd::new(&data_socket, PollFlags::OUT)]; + assert_eq!(poll(&mut fds, -1).unwrap(), 1); + assert!(!fds[0].revents().intersects(PollFlags::IN)); + assert!(fds[0].revents().intersects(PollFlags::OUT)); + + send(&data_socket, b"goodnight, moon", SendFlags::empty()).unwrap(); +} + +fn client(ready: Arc<(Mutex<u16>, Condvar)>) { + let port = { + let (lock, cvar) = &*ready; + let mut port = lock.lock().unwrap(); + while *port == 0 { + port = cvar.wait(port).unwrap(); + } + *port + }; + + let addr = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), port, 0, 0); + let mut buffer = vec![0; BUFFER_SIZE]; + + let data_socket = socket( + AddressFamily::INET6, + SocketType::STREAM, + Protocol::default(), + ) + .unwrap(); + connect_v6(&data_socket, &addr).unwrap(); + + let mut fds = [PollFd::new(&data_socket, PollFlags::OUT)]; + assert_eq!(poll(&mut fds, -1).unwrap(), 1); + assert!(!fds[0].revents().intersects(PollFlags::IN)); + assert!(fds[0].revents().intersects(PollFlags::OUT)); + + send(&data_socket, b"hello, world", SendFlags::empty()).unwrap(); + + let mut fds = [PollFd::new(&data_socket, PollFlags::IN)]; + assert_eq!(poll(&mut fds, -1).unwrap(), 1); + assert!(fds[0].revents().intersects(PollFlags::IN)); + assert!(!fds[0].revents().intersects(PollFlags::OUT)); + + let expected_nread = rustix::io::ioctl_fionread(&data_socket).unwrap(); + let nread = recv(&data_socket, &mut buffer, RecvFlags::empty()).unwrap(); + assert_eq!(String::from_utf8_lossy(&buffer[..nread]), "goodnight, moon"); + assert_eq!(expected_nread, nread as u64); +} + +#[test] +fn test_poll() { + let ready = Arc::new((Mutex::new(0_u16), Condvar::new())); + let ready_clone = Arc::clone(&ready); + + let server = thread::Builder::new() + .name("server".to_string()) + .spawn(move || { + server(ready); + }) + .unwrap(); + let client = thread::Builder::new() + .name("client".to_string()) + .spawn(move || { + client(ready_clone); + }) + .unwrap(); + client.join().unwrap(); + server.join().unwrap(); +} diff --git a/vendor/rustix/tests/net/sockopt.rs b/vendor/rustix/tests/net/sockopt.rs new file mode 100644 index 000000000..8e4cf52e8 --- /dev/null +++ b/vendor/rustix/tests/net/sockopt.rs @@ -0,0 +1,158 @@ +#[test] +fn test_sockopts() { + use rustix::net::{AddressFamily, Protocol, SocketType}; + use std::time::Duration; + + let s = + rustix::net::socket(AddressFamily::INET, SocketType::STREAM, Protocol::default()).unwrap(); + + // On a new socket we shouldn't have a timeout yet. + assert!( + rustix::net::sockopt::get_socket_timeout(&s, rustix::net::sockopt::Timeout::Recv) + .unwrap() + .is_none() + ); + assert_eq!( + rustix::net::sockopt::get_socket_type(&s).unwrap(), + SocketType::STREAM + ); + #[cfg(not(windows))] + assert_eq!( + rustix::net::sockopt::get_socket_broadcast(&s).unwrap(), + false + ); + // On a new socket we shouldn't have a linger yet. + assert!(rustix::net::sockopt::get_socket_linger(&s) + .unwrap() + .is_none()); + #[cfg(any(target_os = "android", target_os = "linux"))] + assert_eq!( + rustix::net::sockopt::get_socket_passcred(&s).unwrap(), + false + ); + assert_ne!(rustix::net::sockopt::get_ip_ttl(&s).unwrap(), 0); + assert_ne!(rustix::net::sockopt::get_ip_ttl(&s).unwrap(), 77); + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + )))] + assert_eq!( + rustix::net::sockopt::get_ip_multicast_loop(&s).unwrap(), + true + ); + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + )))] + assert_eq!(rustix::net::sockopt::get_ip_multicast_ttl(&s).unwrap(), 1); + assert_eq!(rustix::net::sockopt::get_tcp_nodelay(&s).unwrap(), false); + + // Set a timeout. + rustix::net::sockopt::set_socket_timeout( + &s, + rustix::net::sockopt::Timeout::Recv, + Some(Duration::new(1, 1)), + ) + .unwrap(); + + // Check that we have a timeout of at least the time we set. + if cfg!(not(target_os = "freebsd")) { + assert!( + rustix::net::sockopt::get_socket_timeout(&s, rustix::net::sockopt::Timeout::Recv) + .unwrap() + .unwrap() + >= Duration::new(1, 1) + ); + } else { + // On FreeBSD <= 12, it appears the system rounds the timeout down. + assert!( + rustix::net::sockopt::get_socket_timeout(&s, rustix::net::sockopt::Timeout::Recv) + .unwrap() + .unwrap() + >= Duration::new(1, 0) + ); + } + + #[cfg(not(windows))] + { + // Set the broadcast flag; + rustix::net::sockopt::set_socket_broadcast(&s, true).unwrap(); + + // Check that the broadcast flag is set. This has no effect on stream + // sockets, and not all platforms even remember the value. + #[cfg(not(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + )))] + assert_eq!( + rustix::net::sockopt::get_socket_broadcast(&s).unwrap(), + true + ); + } + + // Set a linger. + rustix::net::sockopt::set_socket_linger(&s, Some(Duration::new(1, 1))).unwrap(); + + // Check that we have a linger of at least the time we set. + assert!( + dbg!(rustix::net::sockopt::get_socket_linger(&s) + .unwrap() + .unwrap()) + >= Duration::new(1, 1) + ); + + #[cfg(any(target_os = "android", target_os = "linux"))] + { + // Set the passcred flag; + rustix::net::sockopt::set_socket_passcred(&s, true).unwrap(); + + // Check that the passcred flag is set. + assert_eq!(rustix::net::sockopt::get_socket_passcred(&s).unwrap(), true); + } + + // Set the ip ttl. + rustix::net::sockopt::set_ip_ttl(&s, 77).unwrap(); + + // Check the ip ttl. + assert_eq!(rustix::net::sockopt::get_ip_ttl(&s).unwrap(), 77); + + #[cfg(not(any( + windows, + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + )))] + { + // Set the multicast loop flag; + rustix::net::sockopt::set_ip_multicast_loop(&s, false).unwrap(); + + // Check that the multicast loop flag is set. + assert_eq!( + rustix::net::sockopt::get_ip_multicast_loop(&s).unwrap(), + false + ); + } + + // Set the nodelay flag; + rustix::net::sockopt::set_tcp_nodelay(&s, true).unwrap(); + + // Check that the nodelay flag is set. + assert_eq!(rustix::net::sockopt::get_tcp_nodelay(&s).unwrap(), true); +} diff --git a/vendor/rustix/tests/net/unix.rs b/vendor/rustix/tests/net/unix.rs new file mode 100644 index 000000000..21a6542f8 --- /dev/null +++ b/vendor/rustix/tests/net/unix.rs @@ -0,0 +1,147 @@ +//! Test a simple Unix-domain socket server and client. +//! +//! The client sends lists of integers and the server sends back sums. + +// This test uses `AF_UNIX` with `SOCK_SEQPACKET` which is unsupported on macOS. +#![cfg(not(any( + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "wasi", +)))] +// This test uses `DecInt`. +#![cfg(feature = "itoa")] +#![cfg(feature = "fs")] + +use rustix::fs::{cwd, unlinkat, AtFlags}; +use rustix::io::{read, write}; +use rustix::net::{ + accept, bind_unix, connect_unix, listen, socket, AddressFamily, Protocol, SocketAddrUnix, + SocketType, +}; +use rustix::path::DecInt; +use std::path::Path; +use std::str::FromStr; +use std::sync::{Arc, Condvar, Mutex}; +use std::thread; + +const BUFFER_SIZE: usize = 20; + +fn server(ready: Arc<(Mutex<bool>, Condvar)>, path: &Path) { + let connection_socket = socket( + AddressFamily::UNIX, + SocketType::SEQPACKET, + Protocol::default(), + ) + .unwrap(); + + let name = SocketAddrUnix::new(path).unwrap(); + bind_unix(&connection_socket, &name).unwrap(); + listen(&connection_socket, 1).unwrap(); + + { + let (lock, cvar) = &*ready; + let mut started = lock.lock().unwrap(); + *started = true; + cvar.notify_all(); + } + + let mut buffer = vec![0; BUFFER_SIZE]; + 'exit: loop { + let data_socket = accept(&connection_socket).unwrap(); + let mut sum = 0; + loop { + let nread = read(&data_socket, &mut buffer).unwrap(); + + if &buffer[..nread] == b"exit" { + break 'exit; + } + if &buffer[..nread] == b"sum" { + break; + } + + sum += i32::from_str(&String::from_utf8_lossy(&buffer[..nread])).unwrap(); + } + + write(&data_socket, DecInt::new(sum).as_bytes()).unwrap(); + } + + unlinkat(cwd(), path, AtFlags::empty()).unwrap(); +} + +fn client(ready: Arc<(Mutex<bool>, Condvar)>, path: &Path, runs: &[(&[&str], i32)]) { + { + let (lock, cvar) = &*ready; + let mut started = lock.lock().unwrap(); + while !*started { + started = cvar.wait(started).unwrap(); + } + } + + let addr = SocketAddrUnix::new(path).unwrap(); + let mut buffer = vec![0; BUFFER_SIZE]; + + for (args, sum) in runs { + let data_socket = socket( + AddressFamily::UNIX, + SocketType::SEQPACKET, + Protocol::default(), + ) + .unwrap(); + connect_unix(&data_socket, &addr).unwrap(); + + for arg in *args { + write(&data_socket, arg.as_bytes()).unwrap(); + } + write(&data_socket, b"sum").unwrap(); + + let nread = read(&data_socket, &mut buffer).unwrap(); + assert_eq!( + i32::from_str(&String::from_utf8_lossy(&buffer[..nread])).unwrap(), + *sum + ); + } + + let data_socket = socket( + AddressFamily::UNIX, + SocketType::SEQPACKET, + Protocol::default(), + ) + .unwrap(); + connect_unix(&data_socket, &addr).unwrap(); + write(&data_socket, b"exit").unwrap(); +} + +#[test] +fn test_unix() { + let ready = Arc::new((Mutex::new(false), Condvar::new())); + let ready_clone = Arc::clone(&ready); + + let tmp = tempfile::tempdir().unwrap(); + let path = tmp.path().join("soccer"); + let send_path = path.to_owned(); + let server = thread::Builder::new() + .name("server".to_string()) + .spawn(move || { + server(ready, &send_path); + }) + .unwrap(); + let send_path = path.to_owned(); + let client = thread::Builder::new() + .name("client".to_string()) + .spawn(move || { + client( + ready_clone, + &send_path, + &[ + (&["1", "2"], 3), + (&["4", "77", "103"], 184), + (&["5", "78", "104"], 187), + (&[], 0), + ], + ); + }) + .unwrap(); + client.join().unwrap(); + server.join().unwrap(); +} diff --git a/vendor/rustix/tests/net/v4.rs b/vendor/rustix/tests/net/v4.rs new file mode 100644 index 000000000..0908057be --- /dev/null +++ b/vendor/rustix/tests/net/v4.rs @@ -0,0 +1,86 @@ +//! Test a simple IPv4 socket server and client. +//! +//! The client send a message and the server sends one back. + +#![cfg(not(any(target_os = "redox", target_os = "wasi")))] + +use rustix::net::{ + accept, bind_v4, connect_v4, getsockname, listen, recv, send, socket, AddressFamily, Ipv4Addr, + Protocol, RecvFlags, SendFlags, SocketAddrAny, SocketAddrV4, SocketType, +}; +use std::sync::{Arc, Condvar, Mutex}; +use std::thread; + +const BUFFER_SIZE: usize = 20; + +fn server(ready: Arc<(Mutex<u16>, Condvar)>) { + let connection_socket = + socket(AddressFamily::INET, SocketType::STREAM, Protocol::default()).unwrap(); + + let name = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 0); + bind_v4(&connection_socket, &name).unwrap(); + + let who = match getsockname(&connection_socket).unwrap() { + SocketAddrAny::V4(addr) => addr, + _ => panic!(), + }; + + listen(&connection_socket, 1).unwrap(); + + { + let (lock, cvar) = &*ready; + let mut port = lock.lock().unwrap(); + *port = who.port(); + cvar.notify_all(); + } + + let mut buffer = vec![0; BUFFER_SIZE]; + let data_socket = accept(&connection_socket).unwrap(); + let nread = recv(&data_socket, &mut buffer, RecvFlags::empty()).unwrap(); + assert_eq!(String::from_utf8_lossy(&buffer[..nread]), "hello, world"); + + send(&data_socket, b"goodnight, moon", SendFlags::empty()).unwrap(); +} + +fn client(ready: Arc<(Mutex<u16>, Condvar)>) { + let port = { + let (lock, cvar) = &*ready; + let mut port = lock.lock().unwrap(); + while *port == 0 { + port = cvar.wait(port).unwrap(); + } + *port + }; + + let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port); + let mut buffer = vec![0; BUFFER_SIZE]; + + let data_socket = socket(AddressFamily::INET, SocketType::STREAM, Protocol::default()).unwrap(); + connect_v4(&data_socket, &addr).unwrap(); + + send(&data_socket, b"hello, world", SendFlags::empty()).unwrap(); + + let nread = recv(&data_socket, &mut buffer, RecvFlags::empty()).unwrap(); + assert_eq!(String::from_utf8_lossy(&buffer[..nread]), "goodnight, moon"); +} + +#[test] +fn test_v4() { + let ready = Arc::new((Mutex::new(0_u16), Condvar::new())); + let ready_clone = Arc::clone(&ready); + + let server = thread::Builder::new() + .name("server".to_string()) + .spawn(move || { + server(ready); + }) + .unwrap(); + let client = thread::Builder::new() + .name("client".to_string()) + .spawn(move || { + client(ready_clone); + }) + .unwrap(); + client.join().unwrap(); + server.join().unwrap(); +} diff --git a/vendor/rustix/tests/net/v6.rs b/vendor/rustix/tests/net/v6.rs new file mode 100644 index 000000000..07205be89 --- /dev/null +++ b/vendor/rustix/tests/net/v6.rs @@ -0,0 +1,95 @@ +//! Test a simple IPv6 socket server and client. +//! +//! The client send a message and the server sends one back. + +#![cfg(not(any(target_os = "redox", target_os = "wasi")))] + +use rustix::net::{ + accept, bind_v6, connect_v6, getsockname, listen, recv, send, socket, AddressFamily, Ipv6Addr, + Protocol, RecvFlags, SendFlags, SocketAddrAny, SocketAddrV6, SocketType, +}; +use std::sync::{Arc, Condvar, Mutex}; +use std::thread; + +const BUFFER_SIZE: usize = 20; + +fn server(ready: Arc<(Mutex<u16>, Condvar)>) { + let connection_socket = socket( + AddressFamily::INET6, + SocketType::STREAM, + Protocol::default(), + ) + .unwrap(); + + let name = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 0, 0, 0); + bind_v6(&connection_socket, &name).unwrap(); + + let who = match getsockname(&connection_socket).unwrap() { + SocketAddrAny::V6(addr) => addr, + _ => panic!(), + }; + + listen(&connection_socket, 1).unwrap(); + + { + let (lock, cvar) = &*ready; + let mut port = lock.lock().unwrap(); + *port = who.port(); + cvar.notify_all(); + } + + let mut buffer = vec![0; BUFFER_SIZE]; + let data_socket = accept(&connection_socket).unwrap(); + let nread = recv(&data_socket, &mut buffer, RecvFlags::empty()).unwrap(); + assert_eq!(String::from_utf8_lossy(&buffer[..nread]), "hello, world"); + + send(&data_socket, b"goodnight, moon", SendFlags::empty()).unwrap(); +} + +fn client(ready: Arc<(Mutex<u16>, Condvar)>) { + let port = { + let (lock, cvar) = &*ready; + let mut port = lock.lock().unwrap(); + while *port == 0 { + port = cvar.wait(port).unwrap(); + } + *port + }; + + let addr = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), port, 0, 0); + let mut buffer = vec![0; BUFFER_SIZE]; + + let data_socket = socket( + AddressFamily::INET6, + SocketType::STREAM, + Protocol::default(), + ) + .unwrap(); + connect_v6(&data_socket, &addr).unwrap(); + + send(&data_socket, b"hello, world", SendFlags::empty()).unwrap(); + + let nread = recv(&data_socket, &mut buffer, RecvFlags::empty()).unwrap(); + assert_eq!(String::from_utf8_lossy(&buffer[..nread]), "goodnight, moon"); +} + +#[test] +fn test_v6() { + let ready = Arc::new((Mutex::new(0_u16), Condvar::new())); + let ready_clone = Arc::clone(&ready); + + let server = thread::Builder::new() + .name("server".to_string()) + .spawn(move || { + server(ready); + }) + .unwrap(); + let client = thread::Builder::new() + .name("client".to_string()) + .spawn(move || { + client(ready_clone); + }) + .unwrap(); + client.join().unwrap(); + server.join().unwrap(); +} diff --git a/vendor/rustix/tests/param/auxv.rs b/vendor/rustix/tests/param/auxv.rs new file mode 100644 index 000000000..90a088101 --- /dev/null +++ b/vendor/rustix/tests/param/auxv.rs @@ -0,0 +1,41 @@ +#[cfg(any( + all(target_os = "android", target_pointer_width = "64"), + target_os = "linux", +))] +use rustix::param::linux_hwcap; +use rustix::param::{clock_ticks_per_second, page_size}; + +#[test] +fn test_page_size() { + let size = page_size(); + assert_ne!(size, 0); + assert!(size.is_power_of_two()); + assert_eq!(size, page_size()); + assert_eq!(size, unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }); +} + +#[test] +fn test_clock_ticks_per_second() { + let size = clock_ticks_per_second(); + assert_ne!(size, 0); + assert_eq!(size, unsafe { libc::sysconf(libc::_SC_CLK_TCK) as u64 }); +} + +#[cfg(any( + all(target_os = "android", target_pointer_width = "64"), + target_os = "linux", +))] +#[test] +fn test_linux_hwcap() { + weak!(fn getauxval(libc::c_ulong) -> libc::c_ulong); + + if let Some(libc_getauxval) = getauxval.get() { + let (_hwcap, hwcap2) = linux_hwcap(); + + // GLIBC seems to return a different value than `LD_SHOW_AUXV=1` reports. + #[cfg(not(target_env = "gnu"))] + assert_eq!(_hwcap, unsafe { libc_getauxval(libc::AT_HWCAP) } as usize); + + assert_eq!(hwcap2, unsafe { libc_getauxval(libc::AT_HWCAP2) } as usize); + } +} diff --git a/vendor/rustix/tests/param/main.rs b/vendor/rustix/tests/param/main.rs new file mode 100644 index 000000000..e350a6f1f --- /dev/null +++ b/vendor/rustix/tests/param/main.rs @@ -0,0 +1,14 @@ +//! Tests for [`rustix::param`]. + +#![cfg(feature = "param")] +#![cfg(not(windows))] +#![cfg_attr(target_os = "wasi", feature(wasi_ext))] +#![cfg_attr(io_lifetimes_use_std, feature(io_safety))] +#![cfg_attr(core_c_str, feature(core_c_str))] + +#[cfg(not(target_os = "wasi"))] +#[macro_use] +mod weak; + +#[cfg(not(target_os = "wasi"))] +mod auxv; diff --git a/vendor/rustix/tests/param/weak.rs b/vendor/rustix/tests/param/weak.rs new file mode 100644 index 000000000..377a8a5a1 --- /dev/null +++ b/vendor/rustix/tests/param/weak.rs @@ -0,0 +1,201 @@ +// Implementation derived from `weak` in Rust's +// library/std/src/sys/unix/weak.rs at revision +// fd0cb0cdc21dd9c06025277d772108f8d42cb25f. + +//! Support for "weak linkage" to symbols on Unix +//! +//! Some I/O operations we do in libstd require newer versions of OSes but we +//! need to maintain binary compatibility with older releases for now. In order +//! to use the new functionality when available we use this module for +//! detection. +//! +//! One option to use here is weak linkage, but that is unfortunately only +//! really workable on Linux. Hence, use dlsym to get the symbol value at +//! runtime. This is also done for compatibility with older versions of glibc, +//! and to avoid creating dependencies on `GLIBC_PRIVATE` symbols. It assumes +//! that we've been dynamically linked to the library the symbol comes from, +//! but that is currently always the case for things like libpthread/libc. +//! +//! A long time ago this used weak linkage for the `__pthread_get_minstack` +//! symbol, but that caused Debian to detect an unnecessarily strict versioned +//! dependency on libc6 (#23628). + +// There are a variety of `#[cfg]`s controlling which targets are involved in +// each instance of `weak!` and `syscall!`. Rather than trying to unify all of +// that, we'll just allow that some unix targets don't use this module at all. +#![allow(dead_code, unused_macros)] +#![allow(clippy::doc_markdown)] + +use core::ffi::c_void; +use core::ptr::null_mut; +use core::sync::atomic::{self, AtomicPtr, Ordering}; +use core::{marker, mem}; +use rustix::ffi::CStr; + +const NULL: *mut c_void = null_mut(); +const INVALID: *mut c_void = 1 as *mut c_void; + +macro_rules! weak { + (fn $name:ident($($t:ty),*) -> $ret:ty) => ( + #[allow(non_upper_case_globals)] + static $name: $crate::weak::Weak<unsafe extern fn($($t),*) -> $ret> = + $crate::weak::Weak::new(concat!(stringify!($name), '\0')); + ) +} + +pub(crate) struct Weak<F> { + name: &'static str, + addr: AtomicPtr<c_void>, + _marker: marker::PhantomData<F>, +} + +impl<F> Weak<F> { + pub(crate) const fn new(name: &'static str) -> Self { + Self { + name, + addr: AtomicPtr::new(INVALID), + _marker: marker::PhantomData, + } + } + + pub(crate) fn get(&self) -> Option<F> { + assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>()); + unsafe { + // Relaxed is fine here because we fence before reading through the + // pointer (see the comment below). + match self.addr.load(Ordering::Relaxed) { + INVALID => self.initialize(), + NULL => None, + addr => { + let func = mem::transmute_copy::<*mut c_void, F>(&addr); + // The caller is presumably going to read through this value + // (by calling the function we've dlsymed). This means we'd + // need to have loaded it with at least C11's consume + // ordering in order to be guaranteed that the data we read + // from the pointer isn't from before the pointer was + // stored. Rust has no equivalent to memory_order_consume, + // so we use an acquire fence (sorry, ARM). + // + // Now, in practice this likely isn't needed even on CPUs + // where relaxed and consume mean different things. The + // symbols we're loading are probably present (or not) at + // init, and even if they aren't the runtime dynamic loader + // is extremely likely have sufficient barriers internally + // (possibly implicitly, for example the ones provided by + // invoking `mprotect`). + // + // That said, none of that's *guaranteed*, and so we fence. + atomic::fence(Ordering::Acquire); + Some(func) + } + } + } + } + + // Cold because it should only happen during first-time initialization. + #[cold] + unsafe fn initialize(&self) -> Option<F> { + let val = fetch(self.name); + // This synchronizes with the acquire fence in `get`. + self.addr.store(val, Ordering::Release); + + match val { + NULL => None, + addr => Some(mem::transmute_copy::<*mut c_void, F>(&addr)), + } + } +} + +unsafe fn fetch(name: &str) -> *mut c_void { + let name = match CStr::from_bytes_with_nul(name.as_bytes()) { + Ok(c_str) => c_str, + Err(..) => return null_mut(), + }; + libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) +} + +#[cfg(not(any(target_os = "android", target_os = "linux")))] +macro_rules! syscall { + (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( + unsafe fn $name($($arg_name: $t),*) -> $ret { + weak! { fn $name($($t),*) -> $ret } + + if let Some(fun) = $name.get() { + fun($($arg_name),*) + } else { + errno::set_errno(errno::Errno(libc::ENOSYS)); + -1 + } + } + ) +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +macro_rules! syscall { + (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( + unsafe fn $name($($arg_name:$t),*) -> $ret { + // This looks like a hack, but concat_idents only accepts idents + // (not paths). + use libc::*; + + trait AsSyscallArg { + type SyscallArgType; + fn as_syscall_arg(self) -> Self::SyscallArgType; + } + + // Pass pointer types as pointers, to preserve provenance. + impl<T> AsSyscallArg for *mut T { + type SyscallArgType = *mut T; + fn as_syscall_arg(self) -> Self::SyscallArgType { self } + } + impl<T> AsSyscallArg for *const T { + type SyscallArgType = *const T; + fn as_syscall_arg(self) -> Self::SyscallArgType { self } + } + + // Pass `BorrowedFd` values as the integer value. + impl AsSyscallArg for $crate::fd::BorrowedFd<'_> { + type SyscallArgType = c::c_long; + fn as_syscall_arg(self) -> Self::SyscallArgType { + $crate::fd::AsRawFd::as_raw_fd(&self) as _ + } + } + + // Coerce integer values into `c_long`. + impl AsSyscallArg for i32 { + type SyscallArgType = c::c_long; + fn as_syscall_arg(self) -> Self::SyscallArgType { self as _ } + } + impl AsSyscallArg for u32 { + type SyscallArgType = c::c_long; + fn as_syscall_arg(self) -> Self::SyscallArgType { self as _ } + } + impl AsSyscallArg for usize { + type SyscallArgType = c::c_long; + fn as_syscall_arg(self) -> Self::SyscallArgType { self as _ } + } + + syscall( + concat_idents!(SYS_, $name), + $($arg_name.as_syscall_arg()),* + ) as $ret + } + ) +} + +macro_rules! weakcall { + ($vis:vis fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( + $vis unsafe fn $name($($arg_name: $t),*) -> $ret { + weak! { fn $name($($t),*) -> $ret } + + // Use a weak symbol from libc when possible, allowing `LD_PRELOAD` + // interposition, but if it's not found just fail. + if let Some(fun) = $name.get() { + fun($($arg_name),*) + } else { + errno::set_errno(errno::Errno(libc::ENOSYS)); + -1 + } + } + ) +} diff --git a/vendor/rustix/tests/path/arg.rs b/vendor/rustix/tests/path/arg.rs new file mode 100644 index 000000000..0eb511be1 --- /dev/null +++ b/vendor/rustix/tests/path/arg.rs @@ -0,0 +1,167 @@ +use rustix::ffi::{CStr, CString}; +use rustix::io; +use rustix::path::Arg; +#[cfg(feature = "itoa")] +use rustix::path::DecInt; +use std::borrow::Cow; +use std::ffi::{OsStr, OsString}; +use std::path::{Component, Components, Iter, Path, PathBuf}; + +#[test] +fn test_arg() { + use rustix::cstr; + use std::borrow::Borrow; + + let t: &str = "hello"; + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: String = "hello".to_owned(); + assert_eq!("hello", Arg::as_str(&t).unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: &OsStr = OsStr::new("hello"); + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: OsString = OsString::from("hello".to_owned()); + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: &Path = Path::new("hello"); + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: PathBuf = PathBuf::from("hello".to_owned()); + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: &CStr = cstr!("hello"); + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: CString = cstr!("hello").to_owned(); + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!( + cstr!("hello"), + Borrow::borrow(&Arg::as_cow_c_str(&t).unwrap()) + ); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: Components = Path::new("hello").components(); + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: Component = Path::new("hello").components().next().unwrap(); + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: Iter = Path::new("hello").iter(); + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: Cow<'_, str> = Cow::Borrowed("hello"); + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: Cow<'_, str> = Cow::Owned("hello".to_owned()); + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: Cow<'_, OsStr> = Cow::Borrowed(OsStr::new("hello")); + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: Cow<'_, OsStr> = Cow::Owned(OsString::from("hello".to_owned())); + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: Cow<'_, CStr> = Cow::Borrowed(cstr!("hello")); + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: Cow<'_, CStr> = Cow::Owned(cstr!("hello").to_owned()); + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: &[u8] = b"hello"; + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + let t: Vec<u8> = b"hello".to_vec(); + assert_eq!("hello", t.as_str().unwrap()); + assert_eq!("hello".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("hello"), Borrow::borrow(&t.into_c_str().unwrap())); + + #[cfg(feature = "itoa")] + { + let t: DecInt = DecInt::new(43110); + assert_eq!("43110", t.as_str()); + assert_eq!("43110".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(cstr!("43110"), Borrow::borrow(&t.as_cow_c_str().unwrap())); + assert_eq!(cstr!("43110"), t.as_c_str()); + assert_eq!(cstr!("43110"), Borrow::borrow(&t.into_c_str().unwrap())); + } +} + +#[test] +fn test_invalid() { + use std::borrow::Borrow; + + let t: &[u8] = b"hello\xc0world"; + assert_eq!(t.as_str().unwrap_err(), io::Errno::INVAL); + assert_eq!("hello\u{fffd}world".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!( + b"hello\xc0world\0", + Borrow::<CStr>::borrow(&t.as_cow_c_str().unwrap()).to_bytes_with_nul() + ); + assert_eq!( + b"hello\xc0world\0", + Borrow::<CStr>::borrow(&t.into_c_str().unwrap()).to_bytes_with_nul() + ); +} + +#[test] +fn test_embedded_nul() { + let t: &[u8] = b"hello\0world"; + assert_eq!("hello\0world", t.as_str().unwrap()); + assert_eq!("hello\0world".to_owned(), Arg::to_string_lossy(&t)); + assert_eq!(t.as_cow_c_str().unwrap_err(), io::Errno::INVAL); + assert_eq!(t.into_c_str().unwrap_err(), io::Errno::INVAL); +} diff --git a/vendor/rustix/tests/path/dec_int.rs b/vendor/rustix/tests/path/dec_int.rs new file mode 100644 index 000000000..6ce1a5123 --- /dev/null +++ b/vendor/rustix/tests/path/dec_int.rs @@ -0,0 +1,20 @@ +use rustix::path::DecInt; + +#[test] +fn test_dec_int() { + assert_eq!(DecInt::new(0).as_ref().to_str().unwrap(), "0"); + assert_eq!(DecInt::new(-1).as_ref().to_str().unwrap(), "-1"); + assert_eq!(DecInt::new(789).as_ref().to_str().unwrap(), "789"); + assert_eq!( + DecInt::new(i64::MIN).as_ref().to_str().unwrap(), + i64::MIN.to_string() + ); + assert_eq!( + DecInt::new(i64::MAX).as_ref().to_str().unwrap(), + i64::MAX.to_string() + ); + assert_eq!( + DecInt::new(u64::MAX).as_ref().to_str().unwrap(), + u64::MAX.to_string() + ); +} diff --git a/vendor/rustix/tests/path/main.rs b/vendor/rustix/tests/path/main.rs new file mode 100644 index 000000000..3215c7e5e --- /dev/null +++ b/vendor/rustix/tests/path/main.rs @@ -0,0 +1,13 @@ +//! Tests for [`rustix::path`]. + +#![cfg(any(feature = "fs", feature = "net"))] +#![cfg(not(windows))] +#![cfg_attr(target_os = "wasi", feature(wasi_ext))] +#![cfg_attr(io_lifetimes_use_std, feature(io_safety))] +#![cfg_attr(core_c_str, feature(core_c_str))] +#![cfg_attr(alloc_c_string, feature(alloc_c_string))] + +#[cfg(not(feature = "rustc-dep-of-std"))] +mod arg; +#[cfg(feature = "itoa")] +mod dec_int; diff --git a/vendor/rustix/tests/process/cpu_set.rs b/vendor/rustix/tests/process/cpu_set.rs new file mode 100644 index 000000000..c4d9edf08 --- /dev/null +++ b/vendor/rustix/tests/process/cpu_set.rs @@ -0,0 +1,14 @@ +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_cpu_set() { + let set = rustix::process::sched_getaffinity(None).unwrap(); + + let mut count = 0; + for i in 0..rustix::process::CpuSet::MAX_CPU { + if set.is_set(i) { + count += 1; + } + } + + assert_eq!(count, set.count()); +} diff --git a/vendor/rustix/tests/process/id.rs b/vendor/rustix/tests/process/id.rs new file mode 100644 index 000000000..10095fa60 --- /dev/null +++ b/vendor/rustix/tests/process/id.rs @@ -0,0 +1,65 @@ +use rustix::process; + +#[test] +fn test_getuid() { + assert_eq!(process::getuid(), process::getuid()); + unsafe { + assert_eq!(process::getuid().as_raw(), libc::getuid()); + assert_eq!(process::getuid().is_root(), libc::getuid() == 0); + } +} + +#[test] +fn test_getgid() { + assert_eq!(process::getgid(), process::getgid()); + unsafe { + assert_eq!(process::getgid().as_raw(), libc::getgid()); + assert_eq!(process::getgid().is_root(), libc::getgid() == 0); + } +} + +#[test] +fn test_geteuid() { + assert_eq!(process::geteuid(), process::geteuid()); + unsafe { + assert_eq!(process::geteuid().as_raw(), libc::geteuid()); + assert_eq!(process::geteuid().is_root(), libc::geteuid() == 0); + } +} + +#[test] +fn test_getegid() { + assert_eq!(process::getegid(), process::getegid()); + unsafe { + assert_eq!(process::getegid().as_raw(), libc::getegid()); + assert_eq!(process::getegid().is_root(), libc::getegid() == 0); + } +} + +#[test] +fn test_getpid() { + assert_eq!(process::getpid(), process::getpid()); + unsafe { + assert_eq!( + process::getpid().as_raw_nonzero().get() as libc::pid_t, + libc::getpid() + ); + assert_eq!(process::getpid().is_init(), libc::getpid() == 1); + } +} + +#[test] +fn test_getppid() { + assert_eq!(process::getppid(), process::getppid()); + unsafe { + assert_eq!( + process::Pid::as_raw(process::getppid()) as libc::pid_t, + libc::getppid() + ); + if let Some(ppid) = process::getppid() { + assert_eq!(ppid.is_init(), libc::getppid() == 1); + } else { + assert_eq!(libc::getppid(), 0); + } + } +} diff --git a/vendor/rustix/tests/process/main.rs b/vendor/rustix/tests/process/main.rs new file mode 100644 index 000000000..90aa34c59 --- /dev/null +++ b/vendor/rustix/tests/process/main.rs @@ -0,0 +1,28 @@ +//! Tests for [`rustix::process`]. + +#![cfg(feature = "process")] +#![cfg(not(windows))] +#![cfg_attr(target_os = "wasi", feature(wasi_ext))] +#![cfg_attr(io_lifetimes_use_std, feature(io_safety))] +#![cfg_attr(core_c_str, feature(core_c_str))] + +#[cfg(not(target_os = "wasi"))] +#[macro_use] +mod weak; + +mod cpu_set; +#[cfg(not(target_os = "wasi"))] // WASI doesn't have get[gpu]id. +mod id; +#[cfg(any(target_os = "android", target_os = "linux"))] +mod membarrier; +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] // WASI doesn't have [gs]etpriority. +mod priority; +#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))] +mod rlimit; +mod sched_yield; +#[cfg(not(target_os = "wasi"))] // WASI doesn't have uname. +mod uname; +#[cfg(not(target_os = "wasi"))] // WASI doesn't have waitpid. +mod wait; +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +mod working_directory; diff --git a/vendor/rustix/tests/process/membarrier.rs b/vendor/rustix/tests/process/membarrier.rs new file mode 100644 index 000000000..ed9b00c1a --- /dev/null +++ b/vendor/rustix/tests/process/membarrier.rs @@ -0,0 +1,40 @@ +#[test] +fn test_membarrier() { + use rustix::process::{membarrier, membarrier_query, MembarrierCommand, MembarrierQuery}; + + let query: MembarrierQuery = membarrier_query(); + + // Supported registration commands should succeed. + for cmd in [ + MembarrierCommand::RegisterGlobalExpedited, + MembarrierCommand::RegisterPrivateExpedited, + MembarrierCommand::RegisterPrivateExpeditedSyncCore, + MembarrierCommand::RegisterPrivateExpeditedRseq, + ] + .iter() + .copied() + { + if query.contains_command(cmd) { + membarrier(cmd).unwrap(); + } + } + + // All supported commands should now succeed, and all unsupported + // commands should fail. + for cmd in [ + MembarrierCommand::Global, + MembarrierCommand::GlobalExpedited, + MembarrierCommand::PrivateExpedited, + MembarrierCommand::PrivateExpeditedSyncCore, + MembarrierCommand::PrivateExpeditedRseq, + ] + .iter() + .copied() + { + if query.contains_command(cmd) { + membarrier(cmd).unwrap(); + } else { + membarrier(cmd).unwrap_err(); + } + } +} diff --git a/vendor/rustix/tests/process/priority.rs b/vendor/rustix/tests/process/priority.rs new file mode 100644 index 000000000..7feb1467a --- /dev/null +++ b/vendor/rustix/tests/process/priority.rs @@ -0,0 +1,83 @@ +use rustix::process::nice; +#[cfg(not(target_os = "redox"))] +use rustix::process::{getpriority_process, setpriority_process}; + +#[cfg(not(target_os = "freebsd"))] // FreeBSD's nice(3) doesn't return the old value. +#[test] +fn test_priorities() { + let old = nice(0).unwrap(); + + #[cfg(not(target_os = "redox"))] + { + let get_prio = getpriority_process(None).unwrap(); + assert_eq!(get_prio, old); + } + + // Lower the priority by one. + let new = nice(1).unwrap(); + + // If the test wasn't running with the lowest priority initially, test that + // we were able to lower the priority. + if old < 19 { + assert_eq!(old + 1, new); + } + + let get = nice(0).unwrap(); + assert_eq!(new, get); + + #[cfg(not(target_os = "redox"))] + { + let get_prio = getpriority_process(None).unwrap(); + assert_eq!(get_prio, new); + + setpriority_process(None, get + 1).unwrap(); + let now = getpriority_process(None).unwrap(); + + // If the test wasn't running with the lowest priority initially, test + // that we were able to lower the priority. + if get < 19 { + assert_eq!(get + 1, now); + } + setpriority_process(None, get + 10000).unwrap(); + let now = getpriority_process(None).unwrap(); + // Linux's max is 19; Darwin's max is 20. + assert!(now >= 19 && now <= 20); + // Darwin appears to return `EPERM` on an out of range `nice`. + if let Ok(again) = nice(1) { + assert_eq!(now, again); + } + } +} + +/// FreeBSD's `nice` doesn't return the new nice value, so use a specialized +/// test. +#[cfg(target_os = "freebsd")] +#[test] +fn test_priorities() { + let start = getpriority_process(None).unwrap(); + + let _ = nice(0).unwrap(); + + let now = getpriority_process(None).unwrap(); + assert_eq!(start, now); + + let _ = nice(1).unwrap(); + + let now = getpriority_process(None).unwrap(); + assert_eq!(start + 1, now); + + setpriority_process(None, start + 2).unwrap(); + + let now = getpriority_process(None).unwrap(); + assert_eq!(start + 2, now); + + setpriority_process(None, 10000).unwrap(); + + let now = getpriority_process(None).unwrap(); + assert_eq!(now, 20); + + let _ = nice(1).unwrap(); + + let now = getpriority_process(None).unwrap(); + assert_eq!(now, 20); +} diff --git a/vendor/rustix/tests/process/proc.rs b/vendor/rustix/tests/process/proc.rs new file mode 100644 index 000000000..e85d85883 --- /dev/null +++ b/vendor/rustix/tests/process/proc.rs @@ -0,0 +1,5 @@ +#[test] +fn test_proc_funcs() { + let _maps = rustix::io::proc_self_maps().unwrap(); + let _pagemap = rustix::io::proc_self_pagemap().unwrap(); +} diff --git a/vendor/rustix/tests/process/rlimit.rs b/vendor/rustix/tests/process/rlimit.rs new file mode 100644 index 000000000..b01f9204c --- /dev/null +++ b/vendor/rustix/tests/process/rlimit.rs @@ -0,0 +1,51 @@ +use rustix::process::{Resource, Rlimit}; + +#[test] +fn test_getrlimit() { + let lim = rustix::process::getrlimit(Resource::Stack); + assert_ne!(lim.current, Some(0)); + assert_ne!(lim.maximum, Some(0)); +} + +#[test] +fn test_setrlimit() { + let old = rustix::process::getrlimit(Resource::Core); + let new = Rlimit { + current: Some(0), + maximum: Some(4096), + }; + assert_ne!(old, new); + rustix::process::setrlimit(Resource::Core, new.clone()).unwrap(); + + let lim = rustix::process::getrlimit(Resource::Core); + assert_eq!(lim, new); + + #[cfg(any(target_os = "android", target_os = "linux"))] + { + let new = Rlimit { + current: Some(0), + maximum: Some(0), + }; + + let first = rustix::process::getrlimit(Resource::Core); + + let old = match rustix::process::prlimit(None, Resource::Core, new.clone()) { + Ok(rlimit) => rlimit, + Err(rustix::io::Errno::NOSYS) => return, + Err(e) => Err(e).unwrap(), + }; + + assert_eq!(first, old); + + let other = Rlimit { + current: Some(0), + maximum: Some(0), + }; + + let again = + rustix::process::prlimit(Some(rustix::process::getpid()), Resource::Core, other) + .unwrap(); + + assert_eq!(again, new); + } +} diff --git a/vendor/rustix/tests/process/sched_yield.rs b/vendor/rustix/tests/process/sched_yield.rs new file mode 100644 index 000000000..eacf17d5e --- /dev/null +++ b/vendor/rustix/tests/process/sched_yield.rs @@ -0,0 +1,7 @@ +use rustix::process::sched_yield; + +#[test] +fn test_sched_yield() { + // Just make sure we can call it. + sched_yield(); +} diff --git a/vendor/rustix/tests/process/uname.rs b/vendor/rustix/tests/process/uname.rs new file mode 100644 index 000000000..bc944c49e --- /dev/null +++ b/vendor/rustix/tests/process/uname.rs @@ -0,0 +1,13 @@ +#[test] +fn test_uname() { + let name: rustix::process::Uname = rustix::process::uname(); + + assert!(!name.sysname().to_bytes().is_empty()); + assert!(!name.nodename().to_bytes().is_empty()); + assert!(!name.release().to_bytes().is_empty()); + assert!(!name.version().to_bytes().is_empty()); + assert!(!name.machine().to_bytes().is_empty()); + + #[cfg(any(target_os = "android", target_os = "linux"))] + assert!(!name.domainname().to_bytes().is_empty()); +} diff --git a/vendor/rustix/tests/process/wait.rs b/vendor/rustix/tests/process/wait.rs new file mode 100644 index 000000000..a1f25a631 --- /dev/null +++ b/vendor/rustix/tests/process/wait.rs @@ -0,0 +1,25 @@ +use libc::{kill, SIGSTOP}; +use rustix::process; +use serial_test::serial; +use std::process::{Command, Stdio}; + +// These tests must execute serially to prevent race condition, where +// `test_wait` waits for the child process spawned in `test_waitpid`, causing +// the tests to get stuck. + +#[test] +#[serial] +fn test_waitpid() { + let child = Command::new("yes") + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .expect("failed to execute child"); + unsafe { kill(child.id() as _, SIGSTOP) }; + + let pid = unsafe { process::Pid::from_raw(child.id() as _) }; + let status = process::waitpid(pid, process::WaitOptions::UNTRACED) + .expect("failed to wait") + .unwrap(); + assert!(status.stopped()); +} diff --git a/vendor/rustix/tests/process/weak.rs b/vendor/rustix/tests/process/weak.rs new file mode 100644 index 000000000..d4f00f999 --- /dev/null +++ b/vendor/rustix/tests/process/weak.rs @@ -0,0 +1,201 @@ +// Implementation derived from `weak` in Rust's +// library/std/src/sys/unix/weak.rs at revision +// fd0cb0cdc21dd9c06025277d772108f8d42cb25f. + +//! Support for "weak linkage" to symbols on Unix +//! +//! Some I/O operations we do in libstd require newer versions of OSes but we +//! need to maintain binary compatibility with older releases for now. In order +//! to use the new functionality when available we use this module for +//! detection. +//! +//! One option to use here is weak linkage, but that is unfortunately only +//! really workable on Linux. Hence, use dlsym to get the symbol value at +//! runtime. This is also done for compatibility with older versions of glibc, +//! and to avoid creating dependencies on `GLIBC_PRIVATE` symbols. It assumes +//! that we've been dynamically linked to the library the symbol comes from, +//! but that is currently always the case for things like libpthread/libc. +//! +//! A long time ago this used weak linkage for the `__pthread_get_minstack` +//! symbol, but that caused Debian to detect an unnecessarily strict versioned +//! dependency on libc6 (#23628). + +// There are a variety of `#[cfg]`s controlling which targets are involved in +// each instance of `weak!` and `syscall!`. Rather than trying to unify all of +// that, we'll just allow that some unix targets don't use this module at all. +#![allow(dead_code, unused_macros)] +#![allow(clippy::doc_markdown)] + +use core::ffi::c_void; +use core::ptr::null_mut; +use core::sync::atomic::{self, AtomicPtr, Ordering}; +use core::{marker, mem}; +use rustix::ffi::CStr; + +const NULL: *mut c_void = null_mut(); +const INVALID: *mut c_void = 1 as *mut c_void; + +macro_rules! weak { + (fn $name:ident($($t:ty),*) -> $ret:ty) => ( + #[allow(non_upper_case_globals)] + static $name: $crate::weak::Weak<unsafe extern fn($($t),*) -> $ret> = + $crate::weak::Weak::new(concat!(stringify!($name), '\0')); + ) +} + +pub(crate) struct Weak<F> { + name: &'static str, + addr: AtomicPtr<c_void>, + _marker: marker::PhantomData<F>, +} + +impl<F> Weak<F> { + pub(crate) const fn new(name: &'static str) -> Self { + Self { + name, + addr: AtomicPtr::new(INVALID), + _marker: marker::PhantomData, + } + } + + pub(crate) fn get(&self) -> Option<F> { + assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>()); + unsafe { + // Relaxed is fine here because we fence before reading through the + // pointer (see the comment below). + match self.addr.load(Ordering::Relaxed) { + INVALID => self.initialize(), + NULL => None, + addr => { + let func = mem::transmute_copy::<*mut c_void, F>(&addr); + // The caller is presumably going to read through this value + // (by calling the function we've dlsymed). This means we'd + // need to have loaded it with at least C11's consume + // ordering in order to be guaranteed that the data we read + // from the pointer isn't from before the pointer was + // stored. Rust has no equivalent to memory_order_consume, + // so we use an acquire fence (sorry, ARM). + // + // Now, in practice this likely isn't needed even on CPUs + // where relaxed and consume mean different things. The + // symbols we're loading are probably present (or not) at + // init, and even if they aren't the runtime dynamic loader + // is extremely likely have sufficient barriers internally + // (possibly implicitly, for example the ones provided by + // invoking `mprotect`). + // + // That said, none of that's *guaranteed*, and so we fence. + atomic::fence(Ordering::Acquire); + Some(func) + } + } + } + } + + // Cold because it should only happen during first-time initialization. + #[cold] + unsafe fn initialize(&self) -> Option<F> { + let val = fetch(self.name); + // This synchronizes with the acquire fence in `get`. + self.addr.store(val, Ordering::Release); + + match val { + NULL => None, + addr => Some(mem::transmute_copy::<*mut c_void, F>(&addr)), + } + } +} + +unsafe fn fetch(name: &str) -> *mut c_void { + let name = match CStr::from_bytes_with_nul(name.as_bytes()) { + Ok(c_str) => c_str, + Err(..) => return null_mut(), + }; + libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr().cast()) +} + +#[cfg(not(any(target_os = "android", target_os = "linux")))] +macro_rules! syscall { + (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( + unsafe fn $name($($arg_name: $t),*) -> $ret { + weak! { fn $name($($t),*) -> $ret } + + if let Some(fun) = $name.get() { + fun($($arg_name),*) + } else { + errno::set_errno(errno::Errno(libc::ENOSYS)); + -1 + } + } + ) +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +macro_rules! syscall { + (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( + unsafe fn $name($($arg_name:$t),*) -> $ret { + // This looks like a hack, but concat_idents only accepts idents + // (not paths). + use libc::*; + + trait AsSyscallArg { + type SyscallArgType; + fn as_syscall_arg(self) -> Self::SyscallArgType; + } + + // Pass pointer types as pointers, to preserve provenance. + impl<T> AsSyscallArg for *mut T { + type SyscallArgType = *mut T; + fn as_syscall_arg(self) -> Self::SyscallArgType { self } + } + impl<T> AsSyscallArg for *const T { + type SyscallArgType = *const T; + fn as_syscall_arg(self) -> Self::SyscallArgType { self } + } + + // Pass `BorrowedFd` values as the integer value. + impl AsSyscallArg for $crate::fd::BorrowedFd<'_> { + type SyscallArgType = c::c_long; + fn as_syscall_arg(self) -> Self::SyscallArgType { + $crate::fd::AsRawFd::as_raw_fd(&self) as _ + } + } + + // Coerce integer values into `c_long`. + impl AsSyscallArg for i32 { + type SyscallArgType = c::c_long; + fn as_syscall_arg(self) -> Self::SyscallArgType { self as _ } + } + impl AsSyscallArg for u32 { + type SyscallArgType = c::c_long; + fn as_syscall_arg(self) -> Self::SyscallArgType { self as _ } + } + impl AsSyscallArg for usize { + type SyscallArgType = c::c_long; + fn as_syscall_arg(self) -> Self::SyscallArgType { self as _ } + } + + syscall( + concat_idents!(SYS_, $name), + $($arg_name.as_syscall_arg()),* + ) as $ret + } + ) +} + +macro_rules! weakcall { + ($vis:vis fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( + $vis unsafe fn $name($($arg_name: $t),*) -> $ret { + weak! { fn $name($($t),*) -> $ret } + + // Use a weak symbol from libc when possible, allowing `LD_PRELOAD` + // interposition, but if it's not found just fail. + if let Some(fun) = $name.get() { + fun($($arg_name),*) + } else { + errno::set_errno(errno::Errno(libc::ENOSYS)); + -1 + } + } + ) +} diff --git a/vendor/rustix/tests/process/working_directory.rs b/vendor/rustix/tests/process/working_directory.rs new file mode 100644 index 000000000..1c3262bb9 --- /dev/null +++ b/vendor/rustix/tests/process/working_directory.rs @@ -0,0 +1,43 @@ +#![cfg(feature = "fs")] + +#[cfg(not(target_os = "macos"))] +use rustix::fs::{Mode, OFlags}; +use tempfile::{tempdir, TempDir}; + +#[allow(unused)] +fn tmpdir() -> TempDir { + tempdir().expect("expected to be able to create a temporary directory") +} + +/// Disable this test on macos because GHA has a weird system folder structure +/// that makes this test fail. +#[cfg(not(target_os = "macos"))] +#[test] +fn test_changing_working_directory() { + let tmpdir = tmpdir(); + + let orig_cwd = rustix::process::getcwd(Vec::new()).expect("get the cwd"); + let orig_fd_cwd = rustix::fs::openat(rustix::fs::cwd(), ".", OFlags::RDONLY, Mode::empty()) + .expect("get a fd for the current directory"); + + rustix::process::chdir(tmpdir.path()).expect("changing dir to the tmp"); + let ch1_cwd = rustix::process::getcwd(Vec::new()).expect("get the cwd"); + + assert_ne!(orig_cwd, ch1_cwd, "The cwd hasn't changed!"); + assert_eq!( + ch1_cwd.to_string_lossy(), + tmpdir.path().to_string_lossy(), + "The cwd is not the same as the tmpdir" + ); + + #[cfg(not(target_os = "fuchsia"))] + rustix::process::fchdir(orig_fd_cwd).expect("changing dir to the original"); + #[cfg(target_os = "fushcia")] + rustix::process::chdir(orig_cwd).expect("changing dir to the original"); + let ch2_cwd = rustix::process::getcwd(ch1_cwd).expect("get the cwd"); + + assert_eq!( + orig_cwd, ch2_cwd, + "The cwd wasn't changed back to the its original position" + ); +} diff --git a/vendor/rustix/tests/rand/getrandom.rs b/vendor/rustix/tests/rand/getrandom.rs new file mode 100644 index 000000000..ac316e447 --- /dev/null +++ b/vendor/rustix/tests/rand/getrandom.rs @@ -0,0 +1,7 @@ +use rustix::rand::{getrandom, GetRandomFlags}; + +#[test] +fn test_getrandom() { + let mut buf = [0_u8; 256]; + let _ = getrandom(&mut buf, GetRandomFlags::empty()); +} diff --git a/vendor/rustix/tests/rand/main.rs b/vendor/rustix/tests/rand/main.rs new file mode 100644 index 000000000..9dac8027f --- /dev/null +++ b/vendor/rustix/tests/rand/main.rs @@ -0,0 +1,9 @@ +//! Tests for [`rustix::rand`]. + +#![cfg(feature = "rand")] +#![cfg(not(windows))] +#![cfg_attr(target_os = "wasi", feature(wasi_ext))] +#![cfg_attr(io_lifetimes_use_std, feature(io_safety))] + +#[cfg(any(linux_raw, all(libc, target_os = "linux")))] +mod getrandom; diff --git a/vendor/rustix/tests/termios/isatty.rs b/vendor/rustix/tests/termios/isatty.rs new file mode 100644 index 000000000..5e6fae73d --- /dev/null +++ b/vendor/rustix/tests/termios/isatty.rs @@ -0,0 +1,69 @@ +use rustix::fd::AsRawFd; +use rustix::termios::{isatty, tcgetwinsize}; +use tempfile::{tempdir, TempDir}; + +#[allow(unused)] +fn tmpdir() -> TempDir { + tempdir().expect("expected to be able to create a temporary directory") +} + +#[test] +fn std_file_is_not_terminal() { + let tmpdir = tempfile::tempdir().unwrap(); + assert!(!isatty( + &std::fs::File::create(tmpdir.path().join("file")).unwrap() + )); + assert!(!isatty( + &std::fs::File::open(tmpdir.path().join("file")).unwrap() + )); +} + +#[test] +fn stdout_stderr_terminals() { + // This test is flaky under qemu. + if std::env::vars().any(|var| var.0.starts_with("CARGO_TARGET_") && var.0.ends_with("_RUNNER")) + { + return; + } + + // Compare `isatty` against `libc::isatty`. + assert_eq!(isatty(&std::io::stdout()), unsafe { + libc::isatty(std::io::stdout().as_raw_fd()) != 0 + }); + assert_eq!(isatty(&std::io::stderr()), unsafe { + libc::isatty(std::io::stderr().as_raw_fd()) != 0 + }); + + // Compare `isatty` against `tcgetwinsize`. + assert_eq!( + isatty(&std::io::stdout()), + tcgetwinsize(&std::io::stdout()).is_ok() + ); + assert_eq!( + isatty(&std::io::stderr()), + tcgetwinsize(&std::io::stderr()).is_ok() + ); +} + +#[test] +fn stdio_descriptors() { + #[cfg(unix)] + use std::os::unix::io::AsRawFd; + #[cfg(target_os = "wasi")] + use std::os::wasi::io::AsRawFd; + + unsafe { + assert_eq!( + rustix::io::stdin().as_raw_fd(), + std::io::stdin().as_raw_fd() + ); + assert_eq!( + rustix::io::stdout().as_raw_fd(), + std::io::stdout().as_raw_fd() + ); + assert_eq!( + rustix::io::stderr().as_raw_fd(), + std::io::stderr().as_raw_fd() + ); + } +} diff --git a/vendor/rustix/tests/termios/main.rs b/vendor/rustix/tests/termios/main.rs new file mode 100644 index 000000000..d9ad9338b --- /dev/null +++ b/vendor/rustix/tests/termios/main.rs @@ -0,0 +1,10 @@ +//! Tests for [`rustix::termios`]. + +#![cfg_attr(target_os = "wasi", feature(wasi_ext))] +#![cfg_attr(io_lifetimes_use_std, feature(io_safety))] +#![cfg(feature = "termios")] + +#[cfg(not(windows))] +mod isatty; +#[cfg(not(windows))] +mod ttyname; diff --git a/vendor/rustix/tests/termios/ttyname.rs b/vendor/rustix/tests/termios/ttyname.rs new file mode 100644 index 000000000..636178c31 --- /dev/null +++ b/vendor/rustix/tests/termios/ttyname.rs @@ -0,0 +1,24 @@ +use rustix::io; +use rustix::termios::{isatty, ttyname}; +use std::fs::File; + +#[test] +fn test_ttyname_ok() { + let file = File::open("/dev/stdin").unwrap(); + if isatty(&file) { + assert!(ttyname(&file, Vec::new()) + .unwrap() + .into_string() + .unwrap() + .starts_with("/dev/")); + } +} + +#[test] +fn test_ttyname_not_tty() { + let file = File::open("Cargo.toml").unwrap(); + assert_eq!(ttyname(&file, Vec::new()).unwrap_err(), io::Errno::NOTTY); + + let file = File::open("/dev/null").unwrap(); + assert_eq!(ttyname(&file, Vec::new()).unwrap_err(), io::Errno::NOTTY); +} diff --git a/vendor/rustix/tests/thread/clocks.rs b/vendor/rustix/tests/thread/clocks.rs new file mode 100644 index 000000000..cf14df777 --- /dev/null +++ b/vendor/rustix/tests/thread/clocks.rs @@ -0,0 +1,212 @@ +#[cfg(not(any( + target_os = "emscripten", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd", + target_os = "redox", + target_os = "wasi", +)))] +use rustix::thread::{clock_nanosleep_absolute, clock_nanosleep_relative, ClockId}; +#[cfg(not(target_os = "redox"))] +use { + rustix::io, + rustix::thread::{nanosleep, NanosleepRelativeResult, Timespec}, +}; + +#[cfg(not(target_os = "redox"))] +#[test] +fn test_invalid_nanosleep() { + match nanosleep(&Timespec { + tv_sec: 0, + tv_nsec: 1_000_000_000, + }) { + NanosleepRelativeResult::Err(io::Errno::INVAL) => (), + otherwise => panic!("unexpected resut: {:?}", otherwise), + } + match nanosleep(&Timespec { + tv_sec: 0, + tv_nsec: !0, + }) { + NanosleepRelativeResult::Err(io::Errno::INVAL) => (), + otherwise => panic!("unexpected resut: {:?}", otherwise), + } + match nanosleep(&Timespec { + tv_sec: !0, + tv_nsec: 1_000_000_000, + }) { + NanosleepRelativeResult::Err(io::Errno::INVAL) => (), + otherwise => panic!("unexpected resut: {:?}", otherwise), + } + match nanosleep(&Timespec { + tv_sec: !0, + tv_nsec: !0, + }) { + NanosleepRelativeResult::Err(io::Errno::INVAL) => (), + otherwise => panic!("unexpected resut: {:?}", otherwise), + } +} + +#[cfg(not(any( + target_os = "emscripten", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd", + target_os = "redox", + target_os = "wasi", +)))] +#[test] +fn test_invalid_nanosleep_absolute() { + match clock_nanosleep_absolute( + ClockId::Monotonic, + &Timespec { + tv_sec: 0, + tv_nsec: 1000000000, + }, + ) { + Err(io::Errno::INVAL) => (), + otherwise => panic!("unexpected resut: {:?}", otherwise), + } + match clock_nanosleep_absolute( + ClockId::Monotonic, + &Timespec { + tv_sec: 0, + tv_nsec: !0, + }, + ) { + Err(io::Errno::INVAL) => (), + otherwise => panic!("unexpected resut: {:?}", otherwise), + } + match clock_nanosleep_absolute( + ClockId::Monotonic, + &Timespec { + tv_sec: !0, + tv_nsec: 1_000_000_000, + }, + ) { + Err(io::Errno::INVAL) => (), + otherwise => panic!("unexpected resut: {:?}", otherwise), + } + match clock_nanosleep_absolute( + ClockId::Monotonic, + &Timespec { + tv_sec: !0, + tv_nsec: !0, + }, + ) { + Err(io::Errno::INVAL) => (), + otherwise => panic!("unexpected resut: {:?}", otherwise), + } +} + +#[cfg(not(any( + target_os = "emscripten", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd", + target_os = "redox", + target_os = "wasi", +)))] +#[test] +fn test_invalid_nanosleep_relative() { + match clock_nanosleep_relative( + ClockId::Monotonic, + &Timespec { + tv_sec: 0, + tv_nsec: 1_000_000_000, + }, + ) { + NanosleepRelativeResult::Err(io::Errno::INVAL) => (), + otherwise => panic!("unexpected resut: {:?}", otherwise), + } + match clock_nanosleep_relative( + ClockId::Monotonic, + &Timespec { + tv_sec: 0, + tv_nsec: !0, + }, + ) { + NanosleepRelativeResult::Err(io::Errno::INVAL) => (), + otherwise => panic!("unexpected resut: {:?}", otherwise), + } + match clock_nanosleep_relative( + ClockId::Monotonic, + &Timespec { + tv_sec: !0, + tv_nsec: 1_000_000_000, + }, + ) { + NanosleepRelativeResult::Err(io::Errno::INVAL) => (), + otherwise => panic!("unexpected resut: {:?}", otherwise), + } + match clock_nanosleep_relative( + ClockId::Monotonic, + &Timespec { + tv_sec: !0, + tv_nsec: !0, + }, + ) { + NanosleepRelativeResult::Err(io::Errno::INVAL) => (), + otherwise => panic!("unexpected resut: {:?}", otherwise), + } +} + +#[cfg(not(target_os = "redox"))] +#[test] +fn test_zero_nanosleep() { + match nanosleep(&Timespec { + tv_sec: 0, + tv_nsec: 0, + }) { + NanosleepRelativeResult::Ok => (), + otherwise => panic!("unexpected resut: {:?}", otherwise), + } +} + +#[cfg(not(any( + target_os = "emscripten", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd", + target_os = "redox", + target_os = "wasi", +)))] +#[test] +fn test_zero_nanosleep_absolute() { + match clock_nanosleep_absolute( + ClockId::Monotonic, + &Timespec { + tv_sec: 0, + tv_nsec: 0, + }, + ) { + Ok(()) => (), + otherwise => panic!("unexpected resut: {:?}", otherwise), + } +} + +#[cfg(not(any( + target_os = "emscripten", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd", + target_os = "redox", + target_os = "wasi", +)))] +#[test] +fn test_zero_nanosleep_relative() { + match clock_nanosleep_relative( + ClockId::Monotonic, + &Timespec { + tv_sec: 0, + tv_nsec: 0, + }, + ) { + NanosleepRelativeResult::Ok => (), + otherwise => panic!("unexpected resut: {:?}", otherwise), + } +} diff --git a/vendor/rustix/tests/thread/id.rs b/vendor/rustix/tests/thread/id.rs new file mode 100644 index 000000000..7aa5abba5 --- /dev/null +++ b/vendor/rustix/tests/thread/id.rs @@ -0,0 +1,7 @@ +use rustix::thread; + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_gettid() { + assert_eq!(thread::gettid(), thread::gettid()); +} diff --git a/vendor/rustix/tests/thread/main.rs b/vendor/rustix/tests/thread/main.rs new file mode 100644 index 000000000..0fc9b42c4 --- /dev/null +++ b/vendor/rustix/tests/thread/main.rs @@ -0,0 +1,9 @@ +//! Tests for [`rustix::thread`]. + +#![cfg(feature = "thread")] +#![cfg(not(windows))] + +#[cfg(not(any(target_os = "redox")))] +mod clocks; +#[cfg(any(target_os = "android", target_os = "linux"))] +mod id; diff --git a/vendor/rustix/tests/time/dynamic_clocks.rs b/vendor/rustix/tests/time/dynamic_clocks.rs new file mode 100644 index 000000000..a7e1e6792 --- /dev/null +++ b/vendor/rustix/tests/time/dynamic_clocks.rs @@ -0,0 +1,22 @@ +#![cfg(not(any(target_os = "redox", target_os = "wasi")))] + +use rustix::fd::AsFd; +use rustix::time::{clock_gettime_dynamic, ClockId, DynamicClockId}; + +#[test] +fn test_known_clocks() { + clock_gettime_dynamic(DynamicClockId::Known(ClockId::Realtime)).unwrap(); + clock_gettime_dynamic(DynamicClockId::Known(ClockId::Monotonic)).unwrap(); +} + +#[test] +fn test_dynamic_clocks() { + let file = std::fs::File::open("Cargo.toml").unwrap(); + clock_gettime_dynamic(DynamicClockId::Dynamic(file.as_fd())).unwrap_err(); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_conditional_clocks() { + let _ = clock_gettime_dynamic(DynamicClockId::Tai); +} diff --git a/vendor/rustix/tests/time/main.rs b/vendor/rustix/tests/time/main.rs new file mode 100644 index 000000000..43283bca2 --- /dev/null +++ b/vendor/rustix/tests/time/main.rs @@ -0,0 +1,14 @@ +//! Tests for [`rustix::time`]. + +#![cfg(feature = "time")] +#![cfg(not(windows))] +#![cfg_attr(target_os = "wasi", feature(wasi_ext))] +#![cfg_attr(io_lifetimes_use_std, feature(io_safety))] + +mod dynamic_clocks; +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +mod monotonic; +#[cfg(any(target_os = "android", target_os = "linux"))] +mod timerfd; +mod timespec; +mod y2038; diff --git a/vendor/rustix/tests/time/monotonic.rs b/vendor/rustix/tests/time/monotonic.rs new file mode 100644 index 000000000..89470f2b4 --- /dev/null +++ b/vendor/rustix/tests/time/monotonic.rs @@ -0,0 +1,45 @@ +#[cfg(feature = "thread")] +use rustix::thread::nanosleep; +use rustix::time::{clock_gettime, ClockId, Timespec}; + +/// Attempt to test that the monotonic clock is monotonic. Time may or may not +/// advance, but it shouldn't regress. +#[test] +fn test_monotonic_clock() { + let a = clock_gettime(ClockId::Monotonic); + let b = clock_gettime(ClockId::Monotonic); + if b.tv_sec == a.tv_sec { + assert!(b.tv_nsec >= a.tv_nsec); + } else { + assert!(b.tv_sec > a.tv_sec); + } +} + +/// With the "thread" feature, we can sleep so that we're guaranteed that time +/// has advanced. +#[cfg(feature = "thread")] +#[test] +fn test_monotonic_clock_with_sleep_1s() { + let a = clock_gettime(ClockId::Monotonic); + let _rem = nanosleep(&Timespec { + tv_sec: 1, + tv_nsec: 0, + }); + let b = clock_gettime(ClockId::Monotonic); + assert!(b.tv_sec > a.tv_sec); +} + +/// With the "thread" feature, we can sleep so that we're guaranteed that time +/// has advanced. +#[cfg(feature = "thread")] +#[test] +fn test_monotonic_clock_with_sleep_1ms() { + let a = clock_gettime(ClockId::Monotonic); + let _rem = nanosleep(&Timespec { + tv_sec: 0, + tv_nsec: 1_000_000, + }); + let b = clock_gettime(ClockId::Monotonic); + assert!(b.tv_sec >= a.tv_sec); + assert!(b.tv_sec != a.tv_sec || b.tv_nsec > a.tv_nsec); +} diff --git a/vendor/rustix/tests/time/timerfd.rs b/vendor/rustix/tests/time/timerfd.rs new file mode 100644 index 000000000..6ad4dd72e --- /dev/null +++ b/vendor/rustix/tests/time/timerfd.rs @@ -0,0 +1,75 @@ +use rustix::time::{ + timerfd_create, timerfd_gettime, timerfd_settime, Itimerspec, TimerfdClockId, TimerfdFlags, + TimerfdTimerFlags, Timespec, +}; + +#[test] +fn test_timerfd() { + let fd = timerfd_create(TimerfdClockId::Monotonic, TimerfdFlags::CLOEXEC).unwrap(); + + let set = Itimerspec { + it_interval: Timespec { + tv_sec: 0, + tv_nsec: 0, + }, + it_value: Timespec { + tv_sec: 1, + tv_nsec: 2, + }, + }; + let _old: Itimerspec = timerfd_settime(&fd, TimerfdTimerFlags::ABSTIME, &set).unwrap(); + + // Wait for the timer to expire. + let mut buf = [0_u8; 8]; + assert_eq!(rustix::io::read(&fd, &mut buf), Ok(8)); + assert!(u64::from_ne_bytes(buf) >= 1); + + let new = timerfd_gettime(&fd).unwrap(); + + // The timer counts down. + assert_eq!(set.it_interval.tv_sec, new.it_interval.tv_sec); + assert_eq!(set.it_interval.tv_nsec, new.it_interval.tv_nsec); + assert!(new.it_value.tv_sec <= set.it_value.tv_sec); + assert!( + new.it_value.tv_nsec < set.it_value.tv_nsec || new.it_value.tv_sec < set.it_value.tv_sec + ); +} + +/// Similar, but set an interval for a repeated timer. Don't check that the +/// times are monotonic because that would race with the timer repeating. +#[test] +fn test_timerfd_with_interval() { + let fd = timerfd_create(TimerfdClockId::Monotonic, TimerfdFlags::CLOEXEC).unwrap(); + + let set = Itimerspec { + it_interval: Timespec { + tv_sec: 0, + tv_nsec: 6, + }, + it_value: Timespec { + tv_sec: 1, + tv_nsec: 7, + }, + }; + let _old: Itimerspec = timerfd_settime(&fd, TimerfdTimerFlags::ABSTIME, &set).unwrap(); + + // Wait for the timer to expire. + let mut buf = [0_u8; 8]; + assert_eq!(rustix::io::read(&fd, &mut buf), Ok(8)); + assert!(u64::from_ne_bytes(buf) >= 1); + + let new = timerfd_gettime(&fd).unwrap(); + + assert_eq!(set.it_interval.tv_sec, new.it_interval.tv_sec); + assert_eq!(set.it_interval.tv_nsec, new.it_interval.tv_nsec); + + // Wait for the timer to expire again. + let mut buf = [0_u8; 8]; + assert_eq!(rustix::io::read(&fd, &mut buf), Ok(8)); + assert!(u64::from_ne_bytes(buf) >= 1); + + let new = timerfd_gettime(&fd).unwrap(); + + assert_eq!(set.it_interval.tv_sec, new.it_interval.tv_sec); + assert_eq!(set.it_interval.tv_nsec, new.it_interval.tv_nsec); +} diff --git a/vendor/rustix/tests/time/timespec.rs b/vendor/rustix/tests/time/timespec.rs new file mode 100644 index 000000000..6d892dcfe --- /dev/null +++ b/vendor/rustix/tests/time/timespec.rs @@ -0,0 +1,26 @@ +#[test] +fn test_timespec_layout() { + #[cfg(not(target_os = "redox"))] + use rustix::fs::{UTIME_NOW, UTIME_OMIT}; + use rustix::time::{Nsecs, Secs, Timespec}; + + let tv_sec: Secs = 0; + let tv_nsec: Nsecs = 0; + let _ = Timespec { tv_sec, tv_nsec }; + + #[cfg(not(target_os = "redox"))] + let _ = Timespec { + tv_sec, + tv_nsec: UTIME_NOW, + }; + #[cfg(not(target_os = "redox"))] + let _ = Timespec { + tv_sec, + tv_nsec: UTIME_OMIT, + }; + let _ = Timespec { tv_sec, tv_nsec: 0 }; + let _ = Timespec { + tv_sec, + tv_nsec: 999_999_999, + }; +} diff --git a/vendor/rustix/tests/time/y2038.rs b/vendor/rustix/tests/time/y2038.rs new file mode 100644 index 000000000..45a073d19 --- /dev/null +++ b/vendor/rustix/tests/time/y2038.rs @@ -0,0 +1,77 @@ +/// Test that `Timespec` and `Secs` support a 64-bit number of seconds, +/// avoiding the y2038 bug. +/// +/// The Rust Musl target and libc crate are currently using Musl 1.1. It is +/// expected to update to Musl 1.2 at some point, at which point it'll gain a +/// 64-bit `time_t`. +/// +/// 32-bit Android is [not y2038 compatible]. In theory we could use +/// `libc::syscall` and call the new syscalls ourselves, however that doesn't +/// seem worth the effort on a platform that will likely never support add +/// such support itself. +/// +/// [not y2038 compatible]: https://android.googlesource.com/platform/bionic/+/refs/heads/master/docs/32-bit-abi.md#is-32_bit-on-lp32-y2038 +#[cfg(not(all(target_env = "musl", target_pointer_width = "32")))] +#[cfg(not(all(target_os = "android", target_pointer_width = "32")))] +#[cfg(not(all(target_os = "emscripten", target_pointer_width = "32")))] +#[test] +fn test_y2038() { + use rustix::time::{Secs, Timespec}; + + let tv_sec: i64 = 0; + let _ = Timespec { tv_sec, tv_nsec: 0 }; + let _: Secs = tv_sec; + + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + { + use rustix::time::Itimerspec; + + let _ = Itimerspec { + it_interval: Timespec { tv_sec, tv_nsec: 0 }, + it_value: Timespec { tv_sec, tv_nsec: 0 }, + }; + } +} + +#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] +#[test] +fn test_y2038_with_timerfd() { + use rustix::time::{ + timerfd_create, timerfd_gettime, timerfd_settime, Itimerspec, TimerfdClockId, TimerfdFlags, + TimerfdTimerFlags, Timespec, + }; + + let fd = timerfd_create(TimerfdClockId::Monotonic, TimerfdFlags::CLOEXEC).unwrap(); + + let set = Itimerspec { + it_interval: Timespec { + tv_sec: (1_u64 << 32) as _, + tv_nsec: 20, + }, + it_value: Timespec { + tv_sec: (1_u64 << 32) as _, + tv_nsec: 21, + }, + }; + let _old: Itimerspec = match timerfd_settime(&fd, TimerfdTimerFlags::ABSTIME, &set) { + Ok(i) => i, + + // On 32-bit and mips64 platforms, accept `EOVERFLOW`, meaning that + // y2038 support in `timerfd` APIs is not available on this platform + // or this version of the platform. + #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))] + Err(rustix::io::Errno::OVERFLOW) => return, + + Err(e) => panic!("unexpected error: {:?}", e), + }; + + let new = timerfd_gettime(&fd).unwrap(); + + // The timer counts down. + assert_eq!(set.it_interval.tv_sec, new.it_interval.tv_sec); + assert_eq!(set.it_interval.tv_nsec, new.it_interval.tv_nsec); + assert!(new.it_value.tv_sec <= set.it_value.tv_sec); + assert!( + new.it_value.tv_nsec < set.it_value.tv_nsec || new.it_value.tv_sec < set.it_value.tv_sec + ); +} |