From d1d381e2984ee3103f164c8045f40b13e2e6db8c Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 12 Apr 2023 09:57:53 -0700 Subject: [PATCH] add a wasi-test to show a dir_fd always gets ERRNO_BADF on appropriate fd_ operations (#6197) * add a wasi-test to show a dir_fd always gets ERRNO_BADF on appropriate fd_ operations. This is a conformance test for the current behavior of preview 1 in wasi-common. It is debatable whether this is the right errno, I think for most of these ERRNO_ISDIR would be more descriptive, but this is the behavior we have. * Add comments to all the fd op failures explaining closest linux/posix behavior --- .../wasi-tests/src/bin/dir_fd_op_failures.rs | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 crates/test-programs/wasi-tests/src/bin/dir_fd_op_failures.rs diff --git a/crates/test-programs/wasi-tests/src/bin/dir_fd_op_failures.rs b/crates/test-programs/wasi-tests/src/bin/dir_fd_op_failures.rs new file mode 100644 index 0000000000..35c0f28273 --- /dev/null +++ b/crates/test-programs/wasi-tests/src/bin/dir_fd_op_failures.rs @@ -0,0 +1,99 @@ +use std::{env, process}; +use wasi_tests::open_scratch_directory; + +unsafe fn test_fd_dir_ops(dir_fd: wasi::Fd) { + let stat = wasi::fd_filestat_get(dir_fd).expect("failed to fdstat"); + assert_eq!(stat.filetype, wasi::FILETYPE_DIRECTORY); + + let mut read_buf = vec![0; 128].into_boxed_slice(); + let iovec = wasi::Iovec { + buf: read_buf.as_mut_ptr(), + buf_len: read_buf.len(), + }; + let r = wasi::fd_read(dir_fd, &[iovec]); + // On posix, this fails with ERRNO_ISDIR: + assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_read error"); + + let r = wasi::fd_pread(dir_fd, &[iovec], 0); + // On posix, this fails with ERRNO_ISDIR + assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_pread error"); + + let write_buf = vec![0; 128].into_boxed_slice(); + let ciovec = wasi::Ciovec { + buf: write_buf.as_ptr(), + buf_len: write_buf.len(), + }; + let r = wasi::fd_write(dir_fd, &[ciovec]); + // Same behavior as specified by POSIX: + assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_write error"); + + let r = wasi::fd_pwrite(dir_fd, &[ciovec], 0); + // Same behavior as specified by POSIX: + assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_pwrite error"); + + // Divergence from posix: lseek(dirfd) will return 0 + let r = wasi::fd_seek(dir_fd, 0, wasi::WHENCE_CUR); + assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_seek WHENCE_CUR error"); + let r = wasi::fd_seek(dir_fd, 0, wasi::WHENCE_SET); + assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_seek WHENCE_SET error"); + let r = wasi::fd_seek(dir_fd, 0, wasi::WHENCE_END); + assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_seek WHENCE_END error"); + + // Tell isnt in posix, its basically lseek with WHENCE_CUR above + let r = wasi::fd_tell(dir_fd); + assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_tell error"); + + // posix_fadvise(dirfd, 0, 0, POSIX_FADV_DONTNEED) will return 0 on linux. + // not available on mac os. + let r = wasi::fd_advise(dir_fd, 0, 0, wasi::ADVICE_DONTNEED); + assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_advise error"); + + // fallocate(dirfd, FALLOC_FL_ZERO_RANGE, 0, 1) will fail with errno EBADF on linux. + // not available on mac os. + let r = wasi::fd_allocate(dir_fd, 0, 0); + assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_allocate error"); + + // fdatasync(dirfd) will return 0 on linux. + // not available on mac os. + let r = wasi::fd_datasync(dir_fd); + assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_datasync error"); + + // fsync(dirfd) will return 0 on linux. + // not available on mac os. + let r = wasi::fd_sync(dir_fd); + assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_sync error"); + + // fcntl(dirfd, F_SETFL, O_NONBLOCK) will return 0 on linux. + // not available on mac os. + let r = wasi::fd_fdstat_set_flags(dir_fd, wasi::FDFLAGS_NONBLOCK); + assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_fdstat_set_flags error"); + + // ftruncate(dirfd, 1) will fail with errno EINVAL on posix. + // here, we fail with EBADF instead: + let r = wasi::fd_filestat_set_size(dir_fd, 0); + assert_eq!(r, Err(wasi::ERRNO_BADF), "fd_filestat_set_size error"); +} + +fn main() { + let mut args = env::args(); + let prog = args.next().unwrap(); + let arg = if let Some(arg) = args.next() { + arg + } else { + eprintln!("usage: {} ", prog); + process::exit(1); + }; + + // Open scratch directory + let dir_fd = match open_scratch_directory(&arg) { + Ok(dir_fd) => dir_fd, + Err(err) => { + eprintln!("{}", err); + process::exit(1) + } + }; + + unsafe { + test_fd_dir_ops(dir_fd); + } +}