summaryrefslogtreecommitdiffstats
path: root/vendor/rustix/tests/fs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/rustix/tests/fs')
-rw-r--r--vendor/rustix/tests/fs/cwd.rs3
-rw-r--r--vendor/rustix/tests/fs/dir.rs37
-rw-r--r--vendor/rustix/tests/fs/fcntl.rs17
-rw-r--r--vendor/rustix/tests/fs/file.rs83
-rw-r--r--vendor/rustix/tests/fs/flock.rs34
-rw-r--r--vendor/rustix/tests/fs/futimens.rs42
-rw-r--r--vendor/rustix/tests/fs/invalid_offset.rs182
-rw-r--r--vendor/rustix/tests/fs/long_paths.rs28
-rw-r--r--vendor/rustix/tests/fs/main.rs47
-rw-r--r--vendor/rustix/tests/fs/makedev.rs10
-rw-r--r--vendor/rustix/tests/fs/mkdirat.rs33
-rw-r--r--vendor/rustix/tests/fs/mknodat.rs27
-rw-r--r--vendor/rustix/tests/fs/openat.rs33
-rw-r--r--vendor/rustix/tests/fs/openat2.rs184
-rw-r--r--vendor/rustix/tests/fs/readdir.rs68
-rw-r--r--vendor/rustix/tests/fs/renameat.rs104
-rw-r--r--vendor/rustix/tests/fs/statfs.rs49
-rw-r--r--vendor/rustix/tests/fs/utimensat.rs127
-rw-r--r--vendor/rustix/tests/fs/y2038.rs146
19 files changed, 1254 insertions, 0 deletions
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, &times).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", &times, 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", &times, 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", &times, 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", &timestamps, 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, &timestamps) {
+ 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
+ );
+}