Reorganize wasi-misc-tests. (#575)

* Reorganize wasi-misc-tests.

Move wasi-misc-tests out of wasi-common, to break a dependency cycle;
previously, wasmtime-* depended on wasi-common, but wasi-common
dev-dependended on wasmtime-*.

Now, wasi-common no longer dev-depends on wasmtime-*; instead, the
tests are in their own crate which depends on wasi-common and on
wasmtime-*.

Also, rename wasi-misc-tests to wasi-tests for simplicity.

This also removes the "wasm_tests" feature; it's replaced by the
"test-programs" feature.

* Update the CI script to use the new feature name.

* Update the CI script to use the new feature name in one more place.

* Change a `write!` to a `writeln!`.
This commit is contained in:
Dan Gohman
2019-11-15 08:03:43 -08:00
committed by GitHub
parent b0f558aa10
commit d4fd229e5e
49 changed files with 328 additions and 337 deletions

View File

@@ -0,0 +1,18 @@
use wasi::wasi_unstable;
fn test_big_random_buf() {
let mut buf = Vec::new();
buf.resize(1024, 0);
assert!(
wasi_unstable::random_get(&mut buf).is_ok(),
"calling get_random on a large buffer"
);
// Chances are pretty good that at least *one* byte will be non-zero in
// any meaningful random function producing 1024 u8 values.
assert!(buf.iter().any(|x| *x != 0), "random_get returned all zeros");
}
fn main() {
// Run the tests.
test_big_random_buf()
}

View File

@@ -0,0 +1,37 @@
use more_asserts::assert_le;
use wasi::wasi_unstable;
use wasi_tests::wasi_wrappers::wasi_clock_time_get;
unsafe fn test_clock_time_get() {
// Test that clock_time_get succeeds. Even in environments where it's not
// desirable to expose high-precision timers, it should still succeed.
// clock_res_get is where information about precision can be provided.
let mut time: wasi_unstable::Timestamp = 0;
let status = wasi_clock_time_get(wasi_unstable::CLOCK_MONOTONIC, 1, &mut time);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"clock_time_get with a precision of 1"
);
let status = wasi_clock_time_get(wasi_unstable::CLOCK_MONOTONIC, 0, &mut time);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"clock_time_get with a precision of 0"
);
let first_time = time;
let status = wasi_clock_time_get(wasi_unstable::CLOCK_MONOTONIC, 0, &mut time);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"clock_time_get with a precision of 0"
);
assert_le!(first_time, time, "CLOCK_MONOTONIC should be monotonic");
}
fn main() {
// Run the tests.
unsafe { test_clock_time_get() }
}

View File

@@ -0,0 +1,83 @@
use libc;
use more_asserts::assert_gt;
use std::{env, mem, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::wasi_wrappers::wasi_fd_fdstat_get;
unsafe fn test_close_preopen(dir_fd: wasi_unstable::Fd) {
let pre_fd: wasi_unstable::Fd = (libc::STDERR_FILENO + 1) as wasi_unstable::Fd;
assert_gt!(dir_fd, pre_fd, "dir_fd number");
// Try to close a preopened directory handle.
assert_eq!(
wasi_unstable::fd_close(pre_fd),
Err(wasi_unstable::ENOTSUP),
"closing a preopened file descriptor",
);
// Try to renumber over a preopened directory handle.
assert_eq!(
wasi_unstable::fd_renumber(dir_fd, pre_fd),
Err(wasi_unstable::ENOTSUP),
"renumbering over a preopened file descriptor",
);
// Ensure that dir_fd is still open.
let mut dir_fdstat: wasi_unstable::FdStat = mem::zeroed();
let mut status = wasi_fd_fdstat_get(dir_fd, &mut dir_fdstat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"calling fd_fdstat on the scratch directory"
);
assert_eq!(
dir_fdstat.fs_filetype,
wasi_unstable::FILETYPE_DIRECTORY,
"expected the scratch directory to be a directory",
);
// Try to renumber a preopened directory handle.
assert_eq!(
wasi_unstable::fd_renumber(pre_fd, dir_fd),
Err(wasi_unstable::ENOTSUP),
"renumbering over a preopened file descriptor",
);
// Ensure that dir_fd is still open.
status = wasi_fd_fdstat_get(dir_fd, &mut dir_fdstat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"calling fd_fdstat on the scratch directory"
);
assert_eq!(
dir_fdstat.fs_filetype,
wasi_unstable::FILETYPE_DIRECTORY,
"expected the scratch directory to be a directory",
);
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_close_preopen(dir_fd) }
}

View File

@@ -0,0 +1,62 @@
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::cleanup_file;
use wasi_tests::wasi_wrappers::{wasi_path_open, wasi_path_symlink};
unsafe fn test_dangling_symlink(dir_fd: wasi_unstable::Fd) {
// First create a dangling symlink.
assert!(
wasi_path_symlink("target", dir_fd, "symlink").is_ok(),
"creating a symlink"
);
// Try to open it as a directory with O_NOFOLLOW.
let mut file_fd: wasi_unstable::Fd = wasi_unstable::Fd::max_value() - 1;
let status = wasi_path_open(
dir_fd,
0,
"symlink",
wasi_unstable::O_DIRECTORY,
0,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ELOOP,
"opening a dangling symlink as a directory",
);
assert_eq!(
file_fd,
wasi_unstable::Fd::max_value(),
"failed open should set the file descriptor to -1",
);
// Clean up.
cleanup_file(dir_fd, "symlink");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_dangling_symlink(dir_fd) }
}

View File

@@ -0,0 +1,89 @@
use more_asserts::assert_gt;
use std::{env, mem, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_dir, close_fd, create_dir};
use wasi_tests::wasi_wrappers::{wasi_fd_fdstat_get, wasi_fd_seek, wasi_path_open};
unsafe fn test_directory_seek(dir_fd: wasi_unstable::Fd) {
// Create a directory in the scratch directory.
create_dir(dir_fd, "dir");
// Open the directory and attempt to request rights for seeking.
let mut fd: wasi_unstable::Fd = wasi_unstable::Fd::max_value() - 1;
let mut status = wasi_path_open(
dir_fd,
0,
"dir",
0,
wasi_unstable::RIGHT_FD_SEEK,
0,
0,
&mut fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a file"
);
assert_gt!(
fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
// Attempt to seek.
let mut newoffset = 1;
status = wasi_fd_seek(fd, 0, wasi_unstable::WHENCE_CUR, &mut newoffset);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ENOTCAPABLE,
"seek on a directory"
);
// Check if we obtained the right to seek.
let mut fdstat: wasi_unstable::FdStat = mem::zeroed();
status = wasi_fd_fdstat_get(fd, &mut fdstat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"calling fd_fdstat on a directory"
);
assert_eq!(
fdstat.fs_filetype,
wasi_unstable::FILETYPE_DIRECTORY,
"expected the scratch directory to be a directory",
);
assert_eq!(
(fdstat.fs_rights_base & wasi_unstable::RIGHT_FD_SEEK),
0,
"directory has the seek right",
);
// Clean up.
close_fd(fd);
cleanup_dir(dir_fd, "dir");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_directory_seek(dir_fd) }
}

View File

@@ -0,0 +1,98 @@
use libc;
use more_asserts::assert_gt;
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_file, close_fd};
use wasi_tests::wasi_wrappers::{wasi_fd_advise, wasi_fd_filestat_get, wasi_path_open};
unsafe fn test_fd_advise(dir_fd: wasi_unstable::Fd) {
// Create a file in the scratch directory.
let mut file_fd = wasi_unstable::Fd::max_value() - 1;
let status = wasi_path_open(
dir_fd,
0,
"file",
wasi_unstable::O_CREAT,
wasi_unstable::RIGHT_FD_READ | wasi_unstable::RIGHT_FD_WRITE,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a file"
);
assert_gt!(
file_fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
// Check file size
let mut stat = wasi_unstable::FileStat {
st_dev: 0,
st_ino: 0,
st_filetype: 0,
st_nlink: 0,
st_size: 0,
st_atim: 0,
st_mtim: 0,
st_ctim: 0,
};
let status = wasi_fd_filestat_get(file_fd, &mut stat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading file stats"
);
assert_eq!(stat.st_size, 0, "file size should be 0");
// Allocate some size
assert!(
wasi_unstable::fd_allocate(file_fd, 0, 100).is_ok(),
"allocating size"
);
let status = wasi_fd_filestat_get(file_fd, &mut stat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading file stats after initial allocation"
);
assert_eq!(stat.st_size, 100, "file size should be 100");
// Advise the kernel
let status = wasi_fd_advise(file_fd, 10, 50, wasi_unstable::ADVICE_NORMAL);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"advising the kernel"
);
close_fd(file_fd);
cleanup_file(dir_fd, "file");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_fd_advise(dir_fd) }
}

View File

@@ -0,0 +1,120 @@
use libc;
use more_asserts::assert_gt;
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_file, close_fd};
use wasi_tests::wasi_wrappers::{wasi_fd_filestat_get, wasi_path_open};
unsafe fn test_fd_filestat_set(dir_fd: wasi_unstable::Fd) {
// Create a file in the scratch directory.
let mut file_fd = wasi_unstable::Fd::max_value() - 1;
let status = wasi_path_open(
dir_fd,
0,
"file",
wasi_unstable::O_CREAT,
wasi_unstable::RIGHT_FD_READ | wasi_unstable::RIGHT_FD_WRITE,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a file"
);
assert_gt!(
file_fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
// Check file size
let mut stat = wasi_unstable::FileStat {
st_dev: 0,
st_ino: 0,
st_filetype: 0,
st_nlink: 0,
st_size: 0,
st_atim: 0,
st_mtim: 0,
st_ctim: 0,
};
let status = wasi_fd_filestat_get(file_fd, &mut stat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading file stats"
);
assert_eq!(stat.st_size, 0, "file size should be 0");
// Check fd_filestat_set_size
assert!(
wasi_unstable::fd_filestat_set_size(file_fd, 100).is_ok(),
"fd_filestat_set_size"
);
let status = wasi_fd_filestat_get(file_fd, &mut stat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading file stats after fd_filestat_set_size"
);
assert_eq!(stat.st_size, 100, "file size should be 100");
// Check fd_filestat_set_times
let old_atim = stat.st_atim;
let new_mtim = stat.st_mtim - 100;
assert!(
wasi_unstable::fd_filestat_set_times(
file_fd,
new_mtim,
new_mtim,
wasi_unstable::FILESTAT_SET_MTIM,
)
.is_ok(),
"fd_filestat_set_times"
);
let status = wasi_fd_filestat_get(file_fd, &mut stat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading file stats after fd_filestat_set_times"
);
assert_eq!(
stat.st_size, 100,
"file size should remain unchanged at 100"
);
assert_eq!(stat.st_mtim, new_mtim, "mtim should change");
assert_eq!(stat.st_atim, old_atim, "atim should not change");
// let status = wasi_fd_filestat_set_times(file_fd, new_mtim, new_mtim, wasi_unstable::FILESTAT_SET_MTIM | wasi_unstable::FILESTAT_SET_MTIM_NOW);
// assert_eq!(status, wasi_unstable::EINVAL, "ATIM & ATIM_NOW can't both be set");
close_fd(file_fd);
cleanup_file(dir_fd, "file");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_fd_filestat_set(dir_fd) }
}

View File

@@ -0,0 +1,189 @@
use libc;
use more_asserts::assert_gt;
use std::{cmp::min, env, mem, process, slice, str};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::wasi_wrappers::{wasi_fd_filestat_get, wasi_fd_readdir, wasi_path_open};
const BUF_LEN: usize = 256;
#[derive(Debug)]
struct DirEntry {
dirent: wasi_unstable::Dirent,
name: String,
}
// Manually reading the output from fd_readdir is tedious and repetitive,
// so encapsulate it into an iterator
struct ReadDir<'a> {
buf: &'a [u8],
}
impl<'a> ReadDir<'a> {
fn from_slice(buf: &'a [u8]) -> Self {
Self { buf }
}
}
impl<'a> Iterator for ReadDir<'a> {
type Item = DirEntry;
fn next(&mut self) -> Option<DirEntry> {
unsafe {
if self.buf.is_empty() {
return None;
}
// Read the data
let dirent_ptr = self.buf.as_ptr() as *const wasi_unstable::Dirent;
let dirent = *dirent_ptr;
let name_ptr = dirent_ptr.offset(1) as *const u8;
// NOTE Linux syscall returns a NULL-terminated name, but WASI doesn't
let namelen = dirent.d_namlen as usize;
let slice = slice::from_raw_parts(name_ptr, namelen);
let name = str::from_utf8(slice).expect("invalid utf8").to_owned();
// Update the internal state
let delta = mem::size_of_val(&dirent) + namelen;
self.buf = &self.buf[delta..];
DirEntry { dirent, name }.into()
}
}
}
unsafe fn exec_fd_readdir(
fd: wasi_unstable::Fd,
cookie: wasi_unstable::DirCookie,
) -> Vec<DirEntry> {
let mut buf: [u8; BUF_LEN] = [0; BUF_LEN];
let mut bufused = 0;
let status = wasi_fd_readdir(fd, &mut buf, BUF_LEN, cookie, &mut bufused);
assert_eq!(status, wasi_unstable::raw::__WASI_ESUCCESS, "fd_readdir");
let sl = slice::from_raw_parts(buf.as_ptr(), min(BUF_LEN, bufused));
let dirs: Vec<_> = ReadDir::from_slice(sl).collect();
dirs
}
unsafe fn test_fd_readdir(dir_fd: wasi_unstable::Fd) {
let mut stat: wasi_unstable::FileStat = mem::zeroed();
let status = wasi_fd_filestat_get(dir_fd, &mut stat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading scratch directory stats"
);
// Check the behavior in an empty directory
let mut dirs = exec_fd_readdir(dir_fd, wasi_unstable::DIRCOOKIE_START);
dirs.sort_by_key(|d| d.name.clone());
assert_eq!(dirs.len(), 2, "expected two entries in an empty directory");
let mut dirs = dirs.into_iter();
// the first entry should be `.`
let dir = dirs.next().expect("first entry is None");
assert_eq!(dir.name, ".", "first name");
assert_eq!(
dir.dirent.d_type,
wasi_unstable::FILETYPE_DIRECTORY,
"first type"
);
assert_eq!(dir.dirent.d_ino, stat.st_ino);
assert_eq!(dir.dirent.d_namlen, 1);
// the second entry should be `..`
let dir = dirs.next().expect("second entry is None");
assert_eq!(dir.name, "..", "second name");
assert_eq!(
dir.dirent.d_type,
wasi_unstable::FILETYPE_DIRECTORY,
"second type"
);
assert!(
dirs.next().is_none(),
"the directory should be seen as empty"
);
// Add a file and check the behavior
let mut file_fd = wasi_unstable::Fd::max_value() - 1;
let status = wasi_path_open(
dir_fd,
0,
"file",
wasi_unstable::O_CREAT,
wasi_unstable::RIGHT_FD_READ | wasi_unstable::RIGHT_FD_WRITE,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a file"
);
assert_gt!(
file_fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
let status = wasi_fd_filestat_get(file_fd, &mut stat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading file stats"
);
// Execute another readdir
let mut dirs = exec_fd_readdir(dir_fd, wasi_unstable::DIRCOOKIE_START);
assert_eq!(dirs.len(), 3, "expected three entries");
// Save the data about the last entry. We need to do it before sorting.
let lastfile_cookie = dirs[1].dirent.d_next;
let lastfile_name = dirs[2].name.clone();
dirs.sort_by_key(|d| d.name.clone());
let mut dirs = dirs.into_iter();
let dir = dirs.next().expect("first entry is None");
assert_eq!(dir.name, ".", "first name");
let dir = dirs.next().expect("second entry is None");
assert_eq!(dir.name, "..", "second name");
let dir = dirs.next().expect("third entry is None");
// check the file info
assert_eq!(dir.name, "file", "file name doesn't match");
assert_eq!(
dir.dirent.d_type,
wasi_unstable::FILETYPE_REGULAR_FILE,
"type for the real file"
);
assert_eq!(dir.dirent.d_ino, stat.st_ino);
// check if cookie works as expected
let dirs = exec_fd_readdir(dir_fd, lastfile_cookie);
assert_eq!(dirs.len(), 1, "expected one entry");
assert_eq!(dirs[0].name, lastfile_name, "name of the only entry");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_fd_readdir(dir_fd) }
}

View File

@@ -0,0 +1,124 @@
use more_asserts::assert_gt;
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_file, close_fd};
use wasi_tests::wasi_wrappers::{wasi_fd_filestat_get, wasi_path_open};
unsafe fn test_file_allocate(dir_fd: wasi_unstable::Fd) {
// Create a file in the scratch directory.
let mut file_fd = wasi_unstable::Fd::max_value() - 1;
let status = wasi_path_open(
dir_fd,
0,
"file",
wasi_unstable::O_CREAT,
wasi_unstable::RIGHT_FD_READ | wasi_unstable::RIGHT_FD_WRITE,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a file"
);
assert_gt!(
file_fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
// Check file size
let mut stat = wasi_unstable::FileStat {
st_dev: 0,
st_ino: 0,
st_filetype: 0,
st_nlink: 0,
st_size: 0,
st_atim: 0,
st_mtim: 0,
st_ctim: 0,
};
let status = wasi_fd_filestat_get(file_fd, &mut stat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading file stats"
);
assert_eq!(stat.st_size, 0, "file size should be 0");
// Allocate some size
assert!(
wasi_unstable::fd_allocate(file_fd, 0, 100).is_ok(),
"allocating size"
);
let status = wasi_fd_filestat_get(file_fd, &mut stat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading file stats after initial allocation"
);
assert_eq!(stat.st_size, 100, "file size should be 100");
// Allocate should not modify if less than current size
assert!(
wasi_unstable::fd_allocate(file_fd, 10, 10).is_ok(),
"allocating size less than current size"
);
let status = wasi_fd_filestat_get(file_fd, &mut stat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading file stats after additional allocation was not required"
);
assert_eq!(
stat.st_size, 100,
"file size should remain unchanged at 100"
);
// Allocate should modify if offset+len > current_len
assert!(
wasi_unstable::fd_allocate(file_fd, 90, 20).is_ok(),
"allocating size larger than current size"
);
let status = wasi_fd_filestat_get(file_fd, &mut stat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading file stats after additional allocation was required"
);
assert_eq!(
stat.st_size, 110,
"file size should increase from 100 to 110"
);
close_fd(file_fd);
cleanup_file(dir_fd, "file");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_file_allocate(dir_fd) }
}

View File

@@ -0,0 +1,131 @@
use libc;
use more_asserts::assert_gt;
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_file, close_fd};
use wasi_tests::wasi_wrappers::{wasi_fd_pread, wasi_fd_pwrite, wasi_path_open};
unsafe fn test_file_pread_pwrite(dir_fd: wasi_unstable::Fd) {
// Create a file in the scratch directory.
let mut file_fd = wasi_unstable::Fd::max_value() - 1;
let mut status = wasi_path_open(
dir_fd,
0,
"file",
wasi_unstable::O_CREAT,
wasi_unstable::RIGHT_FD_READ | wasi_unstable::RIGHT_FD_WRITE,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a file"
);
assert_gt!(
file_fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
let contents = &[0u8, 1, 2, 3];
let ciovec = wasi_unstable::CIoVec {
buf: contents.as_ptr() as *const libc::c_void,
buf_len: contents.len(),
};
let mut nwritten = 0;
status = wasi_fd_pwrite(file_fd, &mut [ciovec], 0, &mut nwritten);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"writing bytes at offset 0"
);
assert_eq!(nwritten, 4, "nwritten bytes check");
let contents = &mut [0u8; 4];
let iovec = wasi_unstable::IoVec {
buf: contents.as_mut_ptr() as *mut libc::c_void,
buf_len: contents.len(),
};
let mut nread = 0;
status = wasi_fd_pread(file_fd, &[iovec], 0, &mut nread);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading bytes at offset 0"
);
assert_eq!(nread, 4, "nread bytes check");
assert_eq!(contents, &[0u8, 1, 2, 3], "written bytes equal read bytes");
let contents = &mut [0u8; 4];
let iovec = wasi_unstable::IoVec {
buf: contents.as_mut_ptr() as *mut libc::c_void,
buf_len: contents.len(),
};
let mut nread = 0;
status = wasi_fd_pread(file_fd, &[iovec], 2, &mut nread);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading bytes at offset 2"
);
assert_eq!(nread, 2, "nread bytes check");
assert_eq!(contents, &[2u8, 3, 0, 0], "file cursor was overwritten");
let contents = &[1u8, 0];
let ciovec = wasi_unstable::CIoVec {
buf: contents.as_ptr() as *const libc::c_void,
buf_len: contents.len(),
};
let mut nwritten = 0;
status = wasi_fd_pwrite(file_fd, &mut [ciovec], 2, &mut nwritten);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"writing bytes at offset 2"
);
assert_eq!(nwritten, 2, "nwritten bytes check");
let contents = &mut [0u8; 4];
let iovec = wasi_unstable::IoVec {
buf: contents.as_mut_ptr() as *mut libc::c_void,
buf_len: contents.len(),
};
let mut nread = 0;
status = wasi_fd_pread(file_fd, &[iovec], 0, &mut nread);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading bytes at offset 0"
);
assert_eq!(nread, 4, "nread bytes check");
assert_eq!(contents, &[0u8, 1, 1, 0], "file cursor was overwritten");
close_fd(file_fd);
cleanup_file(dir_fd, "file");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_file_pread_pwrite(dir_fd) }
}

View File

@@ -0,0 +1,133 @@
use libc;
use more_asserts::assert_gt;
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_file, close_fd};
use wasi_tests::wasi_wrappers::{wasi_fd_seek, wasi_fd_tell, wasi_fd_write, wasi_path_open};
unsafe fn test_file_seek_tell(dir_fd: wasi_unstable::Fd) {
// Create a file in the scratch directory.
let mut file_fd = wasi_unstable::Fd::max_value() - 1;
let mut status = wasi_path_open(
dir_fd,
0,
"file",
wasi_unstable::O_CREAT,
wasi_unstable::RIGHT_FD_READ | wasi_unstable::RIGHT_FD_WRITE,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a file"
);
assert_gt!(
file_fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
// Check current offset
let mut offset: wasi_unstable::FileSize = 0;
status = wasi_fd_tell(file_fd, &mut offset);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"getting initial file offset"
);
assert_eq!(offset, 0, "current offset should be 0");
// Write to file
let buf = &[0u8; 100];
let iov = wasi_unstable::CIoVec {
buf: buf.as_ptr() as *const _,
buf_len: buf.len(),
};
let iovs = &[iov];
let mut nwritten = 0;
status = wasi_fd_write(file_fd, iovs, &mut nwritten);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"writing to a file"
);
assert_eq!(nwritten, 100, "should write 100 bytes to file");
// Check current offset
status = wasi_fd_tell(file_fd, &mut offset);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"getting file offset after writing"
);
assert_eq!(offset, 100, "offset after writing should be 100");
// Seek to middle of the file
let mut newoffset = 1;
status = wasi_fd_seek(file_fd, -50, wasi_unstable::WHENCE_CUR, &mut newoffset);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"seeking to the middle of a file"
);
assert_eq!(
newoffset, 50,
"offset after seeking to the middle should be at 50"
);
// Seek to the beginning of the file
status = wasi_fd_seek(file_fd, 0, wasi_unstable::WHENCE_SET, &mut newoffset);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"seeking to the beginning of the file"
);
assert_eq!(
newoffset, 0,
"offset after seeking to the beginning of the file should be at 0"
);
// Seek beyond the file should be possible
status = wasi_fd_seek(file_fd, 1000, wasi_unstable::WHENCE_CUR, &mut newoffset);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"seeking beyond the end of the file"
);
// Seek before byte 0 is an error though
status = wasi_fd_seek(file_fd, -2000, wasi_unstable::WHENCE_CUR, &mut newoffset);
assert_eq!(
status,
wasi_unstable::raw::__WASI_EINVAL,
"seeking before byte 0 is an error"
);
close_fd(file_fd);
cleanup_file(dir_fd, "file");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_file_seek_tell(dir_fd) }
}

View File

@@ -0,0 +1,115 @@
use more_asserts::assert_gt;
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_file, close_fd, create_file};
use wasi_tests::wasi_wrappers::{wasi_fd_read, wasi_fd_write, wasi_path_open};
unsafe fn test_file_unbuffered_write(dir_fd: wasi_unstable::Fd) {
// Create file
create_file(dir_fd, "file");
// Open file for reading
let mut fd_read = wasi_unstable::Fd::max_value() - 1;
let mut status = wasi_path_open(
dir_fd,
0,
"file",
0,
wasi_unstable::RIGHT_FD_READ,
0,
0,
&mut fd_read,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a file"
);
assert_gt!(
fd_read,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
// Open the same file but for writing
let mut fd_write = wasi_unstable::Fd::max_value() - 1;
status = wasi_path_open(
dir_fd,
0,
"file",
0,
wasi_unstable::RIGHT_FD_WRITE,
0,
0,
&mut fd_write,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a file"
);
assert_gt!(
fd_write,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
// Write to file
let contents = &[1u8];
let ciovec = wasi_unstable::CIoVec {
buf: contents.as_ptr() as *const libc::c_void,
buf_len: contents.len(),
};
let mut nwritten = 0;
status = wasi_fd_write(fd_write, &[ciovec], &mut nwritten);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"writing byte to file"
);
assert_eq!(nwritten, 1, "nwritten bytes check");
// Read from file
let contents = &mut [0u8; 1];
let iovec = wasi_unstable::IoVec {
buf: contents.as_mut_ptr() as *mut libc::c_void,
buf_len: contents.len(),
};
let mut nread = 0;
status = wasi_fd_read(fd_read, &[iovec], &mut nread);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading bytes from file"
);
assert_eq!(nread, 1, "nread bytes check");
assert_eq!(contents, &[1u8], "written bytes equal read bytes");
// Clean up
close_fd(fd_write);
close_fd(fd_read);
cleanup_file(dir_fd, "file");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_file_unbuffered_write(dir_fd) }
}

View File

@@ -0,0 +1,173 @@
use libc;
use more_asserts::assert_gt;
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{close_fd, create_dir, create_file};
use wasi_tests::wasi_wrappers::{
wasi_path_open, wasi_path_remove_directory, wasi_path_unlink_file,
};
unsafe fn test_interesting_paths(dir_fd: wasi_unstable::Fd, arg: &str) {
// Create a directory in the scratch directory.
create_dir(dir_fd, "dir");
// Create a directory in the directory we just created.
create_dir(dir_fd, "dir/nested");
// Create a file in the nested directory.
create_file(dir_fd, "dir/nested/file");
// Now open it with an absolute path.
let mut file_fd: wasi_unstable::Fd = wasi_unstable::Fd::max_value() - 1;
let mut status = wasi_path_open(dir_fd, 0, "/dir/nested/file", 0, 0, 0, 0, &mut file_fd);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ENOTCAPABLE,
"opening a file with an absolute path"
);
assert_eq!(
file_fd,
wasi_unstable::Fd::max_value(),
"failed open should set the file descriptor to -1",
);
// Now open it with a path containing "..".
status = wasi_path_open(
dir_fd,
0,
"dir/.//nested/../../dir/nested/../nested///./file",
0,
0,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a file with \"..\" in the path"
);
assert_gt!(
file_fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
close_fd(file_fd);
// Now open it with a trailing NUL.
status = wasi_path_open(dir_fd, 0, "dir/nested/file\0", 0, 0, 0, 0, &mut file_fd);
assert_eq!(
status,
wasi_unstable::raw::__WASI_EILSEQ,
"opening a file with a trailing NUL"
);
assert_eq!(
file_fd,
wasi_unstable::Fd::max_value(),
"failed open should set the file descriptor to -1",
);
// Now open it with a trailing slash.
status = wasi_path_open(dir_fd, 0, "dir/nested/file/", 0, 0, 0, 0, &mut file_fd);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ENOTDIR,
"opening a file with a trailing slash"
);
assert_eq!(
file_fd,
wasi_unstable::Fd::max_value(),
"failed open should set the file descriptor to -1",
);
// Now open it with trailing slashes.
status = wasi_path_open(dir_fd, 0, "dir/nested/file///", 0, 0, 0, 0, &mut file_fd);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ENOTDIR,
"opening a file with trailing slashes"
);
assert_eq!(
file_fd,
wasi_unstable::Fd::max_value(),
"failed open should set the file descriptor to -1",
);
// Now open the directory with a trailing slash.
status = wasi_path_open(dir_fd, 0, "dir/nested/", 0, 0, 0, 0, &mut file_fd);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a directory with a trailing slash"
);
assert_gt!(
file_fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
close_fd(file_fd);
// Now open the directory with trailing slashes.
status = wasi_path_open(dir_fd, 0, "dir/nested///", 0, 0, 0, 0, &mut file_fd);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a directory with trailing slashes"
);
assert_gt!(
file_fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
close_fd(file_fd);
// Now open it with a path containing too many ".."s.
let bad_path = format!("dir/nested/../../../{}/dir/nested/file", arg);
status = wasi_path_open(dir_fd, 0, &bad_path, 0, 0, 0, 0, &mut file_fd);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ENOTCAPABLE,
"opening a file with too many \"..\"s in the path"
);
assert_eq!(
file_fd,
wasi_unstable::Fd::max_value(),
"failed open should set the file descriptor to -1",
);
assert!(
wasi_path_unlink_file(dir_fd, "dir/nested/file").is_ok(),
"unlink_file on a symlink should succeed"
);
assert!(
wasi_path_remove_directory(dir_fd, "dir/nested").is_ok(),
"remove_directory on a directory should succeed"
);
assert!(
wasi_path_remove_directory(dir_fd, "dir").is_ok(),
"remove_directory on a directory should succeed"
);
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_interesting_paths(dir_fd, &arg) }
}

View File

@@ -0,0 +1,62 @@
use more_asserts::assert_gt;
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_file, close_fd};
use wasi_tests::wasi_wrappers::wasi_path_open;
unsafe fn test_isatty(dir_fd: wasi_unstable::Fd) {
// Create a file in the scratch directory and test if it's a tty.
let mut file_fd: wasi_unstable::Fd = wasi_unstable::Fd::max_value() - 1;
let status = wasi_path_open(
dir_fd,
0,
"file",
wasi_unstable::O_CREAT,
0,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a file"
);
assert_gt!(
file_fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
assert_eq!(
libc::isatty(file_fd as std::os::raw::c_int),
0,
"file is a tty"
);
close_fd(file_fd);
cleanup_file(dir_fd, "file");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_isatty(dir_fd) }
}

View File

@@ -0,0 +1,175 @@
use libc;
use more_asserts::assert_gt;
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_file, close_fd, create_dir, create_file};
use wasi_tests::wasi_wrappers::{wasi_path_open, wasi_path_remove_directory, wasi_path_symlink};
unsafe fn test_nofollow_errors(dir_fd: wasi_unstable::Fd) {
// Create a directory for the symlink to point to.
create_dir(dir_fd, "target");
// Create a symlink.
assert!(
wasi_path_symlink("target", dir_fd, "symlink").is_ok(),
"creating a symlink"
);
// Try to open it as a directory with O_NOFOLLOW again.
let mut file_fd: wasi_unstable::Fd = wasi_unstable::Fd::max_value() - 1;
let mut status = wasi_path_open(
dir_fd,
0,
"symlink",
wasi_unstable::O_DIRECTORY,
0,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ELOOP,
"opening a directory symlink as a directory",
);
assert_eq!(
file_fd,
wasi_unstable::Fd::max_value(),
"failed open should set the file descriptor to -1",
);
// Try to open it with just O_NOFOLLOW.
status = wasi_path_open(dir_fd, 0, "symlink", 0, 0, 0, 0, &mut file_fd);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ELOOP,
"opening a symlink with O_NOFOLLOW should return ELOOP",
);
assert_eq!(
file_fd,
wasi_unstable::Fd::max_value(),
"failed open should set the file descriptor to -1",
);
// Try to open it as a directory without O_NOFOLLOW.
status = wasi_path_open(
dir_fd,
wasi_unstable::LOOKUP_SYMLINK_FOLLOW,
"symlink",
wasi_unstable::O_DIRECTORY,
0,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a symlink as a directory"
);
assert_gt!(
file_fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
close_fd(file_fd);
// Replace the target directory with a file.
cleanup_file(dir_fd, "symlink");
assert!(
wasi_path_remove_directory(dir_fd, "target").is_ok(),
"remove_directory on a directory should succeed"
);
create_file(dir_fd, "target");
assert!(
wasi_path_symlink("target", dir_fd, "symlink").is_ok(),
"creating a symlink"
);
// Try to open it as a directory with O_NOFOLLOW again.
status = wasi_path_open(
dir_fd,
0,
"symlink",
wasi_unstable::O_DIRECTORY,
0,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ELOOP,
"opening a directory symlink as a directory",
);
assert_eq!(
file_fd,
wasi_unstable::Fd::max_value(),
"failed open should set the file descriptor to -1",
);
// Try to open it with just O_NOFOLLOW.
status = wasi_path_open(dir_fd, 0, "symlink", 0, 0, 0, 0, &mut file_fd);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ELOOP,
"opening a symlink with O_NOFOLLOW should return ELOOP",
);
assert_eq!(
file_fd,
wasi_unstable::Fd::max_value(),
"failed open should set the file descriptor to -1",
);
// Try to open it as a directory without O_NOFOLLOW.
status = wasi_path_open(
dir_fd,
wasi_unstable::LOOKUP_SYMLINK_FOLLOW,
"symlink",
wasi_unstable::O_DIRECTORY,
0,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ENOTDIR,
"opening a symlink to a file as a directory",
);
assert_eq!(
file_fd,
wasi_unstable::Fd::max_value(),
"failed open should set the file descriptor to -1",
);
// Clean up.
cleanup_file(dir_fd, "target");
cleanup_file(dir_fd, "symlink");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_nofollow_errors(dir_fd) }
}

View File

@@ -0,0 +1,183 @@
use more_asserts::assert_gt;
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_file, close_fd};
use wasi_tests::wasi_wrappers::{
wasi_fd_fdstat_get, wasi_path_filestat_get, wasi_path_filestat_set_times, wasi_path_open,
};
unsafe fn test_path_filestat(dir_fd: wasi_unstable::Fd) {
let mut fdstat: wasi_unstable::FdStat = std::mem::zeroed();
let status = wasi_fd_fdstat_get(dir_fd, &mut fdstat);
assert_eq!(status, wasi_unstable::raw::__WASI_ESUCCESS, "fd_fdstat_get");
assert_ne!(
fdstat.fs_rights_base & wasi_unstable::RIGHT_PATH_FILESTAT_GET,
0,
"the scratch directory should have RIGHT_PATH_FILESTAT_GET as base right",
);
assert_ne!(
fdstat.fs_rights_inheriting & wasi_unstable::RIGHT_PATH_FILESTAT_GET,
0,
"the scratch directory should have RIGHT_PATH_FILESTAT_GET as base right",
);
// Create a file in the scratch directory.
let mut file_fd = wasi_unstable::Fd::max_value() - 1;
let filename = "file";
let status = wasi_path_open(
dir_fd,
0,
filename,
wasi_unstable::O_CREAT,
wasi_unstable::RIGHT_FD_READ
| wasi_unstable::RIGHT_FD_WRITE
| wasi_unstable::RIGHT_PATH_FILESTAT_GET,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a file"
);
assert_gt!(
file_fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
let status = wasi_fd_fdstat_get(file_fd, &mut fdstat);
assert_eq!(status, wasi_unstable::raw::__WASI_ESUCCESS, "fd_fdstat_get");
assert_eq!(
fdstat.fs_rights_base & wasi_unstable::RIGHT_PATH_FILESTAT_GET,
0,
"files shouldn't have rights for path_* syscalls even if manually given",
);
assert_eq!(
fdstat.fs_rights_inheriting & wasi_unstable::RIGHT_PATH_FILESTAT_GET,
0,
"files shouldn't have rights for path_* syscalls even if manually given",
);
// Check file size
let mut stat = wasi_unstable::FileStat {
st_dev: 0,
st_ino: 0,
st_filetype: 0,
st_nlink: 0,
st_size: 0,
st_atim: 0,
st_mtim: 0,
st_ctim: 0,
};
let status = wasi_path_filestat_get(dir_fd, 0, filename, filename.len(), &mut stat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading file stats"
);
assert_eq!(stat.st_size, 0, "file size should be 0");
// Check path_filestat_set_times
let old_atim = stat.st_atim;
let new_mtim = stat.st_mtim - 100;
assert!(
wasi_path_filestat_set_times(
dir_fd,
0,
filename,
// on purpose: the syscall should not touch atim, because
// neither of the ATIM flags is set
new_mtim,
new_mtim,
wasi_unstable::FILESTAT_SET_MTIM,
)
.is_ok(),
"path_filestat_set_times should succeed"
);
let status = wasi_path_filestat_get(dir_fd, 0, filename, filename.len(), &mut stat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading file stats after path_filestat_set_times"
);
assert_eq!(stat.st_mtim, new_mtim, "mtim should change");
assert_eq!(stat.st_atim, old_atim, "atim should not change");
assert_eq!(
wasi_path_filestat_set_times(
dir_fd,
0,
filename,
new_mtim,
new_mtim,
wasi_unstable::FILESTAT_SET_MTIM | wasi_unstable::FILESTAT_SET_MTIM_NOW,
),
Err(wasi_unstable::EINVAL),
"MTIM & MTIM_NOW can't both be set"
);
// check if the times were untouched
let status = wasi_path_filestat_get(dir_fd, 0, filename, filename.len(), &mut stat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading file stats after EINVAL fd_filestat_set_times"
);
assert_eq!(stat.st_mtim, new_mtim, "mtim should not change");
assert_eq!(stat.st_atim, old_atim, "atim should not change");
let new_atim = old_atim - 100;
assert_eq!(
wasi_path_filestat_set_times(
dir_fd,
0,
filename,
new_atim,
new_atim,
wasi_unstable::FILESTAT_SET_ATIM | wasi_unstable::FILESTAT_SET_ATIM_NOW,
),
Err(wasi_unstable::EINVAL),
"ATIM & ATIM_NOW can't both be set"
);
// check if the times were untouched
let status = wasi_path_filestat_get(dir_fd, 0, filename, filename.len(), &mut stat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading file stats after EINVAL path_filestat_set_times"
);
assert_eq!(stat.st_mtim, new_mtim, "mtim should not change");
assert_eq!(stat.st_atim, old_atim, "atim should not change");
close_fd(file_fd);
cleanup_file(dir_fd, "file");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_path_filestat(dir_fd) }
}

View File

@@ -0,0 +1,271 @@
use more_asserts::assert_gt;
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_dir, cleanup_file, create_dir, create_file};
use wasi_tests::wasi_wrappers::{
wasi_fd_fdstat_get, wasi_fd_filestat_get, wasi_path_link, wasi_path_open, wasi_path_symlink,
};
unsafe fn create_or_open(
dir_fd: wasi_unstable::Fd,
name: &str,
flags: wasi_unstable::OFlags,
) -> wasi_unstable::Fd {
let mut file_fd = wasi_unstable::Fd::max_value() - 1;
let mut status = wasi_path_open(dir_fd, 0, name, flags, 0, 0, 0, &mut file_fd);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening '{}'",
name
);
assert_gt!(
file_fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
file_fd
}
unsafe fn open_link(dir_fd: wasi_unstable::Fd, name: &str) -> wasi_unstable::Fd {
let mut file_fd = wasi_unstable::Fd::max_value() - 1;
let mut status = wasi_path_open(dir_fd, 0, name, 0, 0, 0, 0, &mut file_fd);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a link '{}'",
name
);
assert_gt!(
file_fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
file_fd
}
unsafe fn check_rights(orig_fd: wasi_unstable::Fd, link_fd: wasi_unstable::Fd) {
use std::mem::MaybeUninit;
// Compare FileStats
let mut orig_filestat: wasi_unstable::FileStat = MaybeUninit::zeroed().assume_init();
let mut link_filestat: wasi_unstable::FileStat = MaybeUninit::zeroed().assume_init();
let mut status = wasi_fd_filestat_get(orig_fd, &mut orig_filestat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading filestat of the source"
);
status = wasi_fd_filestat_get(link_fd, &mut link_filestat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading filestat of the link"
);
assert_eq!(orig_filestat, link_filestat, "filestats should match");
// Compare FdStats
let mut orig_fdstat: wasi_unstable::FdStat = MaybeUninit::zeroed().assume_init();
let mut link_fdstat: wasi_unstable::FdStat = MaybeUninit::zeroed().assume_init();
status = wasi_fd_fdstat_get(orig_fd, &mut orig_fdstat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading fdstat of the source"
);
status = wasi_fd_fdstat_get(link_fd, &mut link_fdstat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading fdstat of the link"
);
assert_eq!(orig_fdstat, link_fdstat, "fdstats should match");
}
unsafe fn test_path_link(dir_fd: wasi_unstable::Fd) {
// Create a file
let file_fd = create_or_open(dir_fd, "file", wasi_unstable::O_CREAT);
// Create a link in the same directory and compare rights
assert!(
wasi_path_link(dir_fd, 0, "file", dir_fd, "link").is_ok(),
"creating a link in the same directory"
);
let mut link_fd = open_link(dir_fd, "link");
check_rights(file_fd, link_fd);
cleanup_file(dir_fd, "link");
// Create a link in a different directory and compare rights
create_dir(dir_fd, "subdir");
let subdir_fd = create_or_open(dir_fd, "subdir", wasi_unstable::O_DIRECTORY);
assert!(
wasi_path_link(dir_fd, 0, "file", subdir_fd, "link").is_ok(),
"creating a link in subdirectory"
);
link_fd = open_link(subdir_fd, "link");
check_rights(file_fd, link_fd);
cleanup_file(subdir_fd, "link");
cleanup_dir(dir_fd, "subdir");
// Create a link to a path that already exists
create_file(dir_fd, "link");
assert_eq!(
wasi_path_link(dir_fd, 0, "file", dir_fd, "link"),
Err(wasi_unstable::EEXIST),
"creating a link to existing path"
);
cleanup_file(dir_fd, "link");
// Create a link to itself
assert_eq!(
wasi_path_link(dir_fd, 0, "file", dir_fd, "file"),
Err(wasi_unstable::EEXIST),
"creating a link to itself"
);
// Create a link where target is a directory
create_dir(dir_fd, "link");
assert_eq!(
wasi_path_link(dir_fd, 0, "file", dir_fd, "link"),
Err(wasi_unstable::EEXIST),
"creating a link where target is a directory"
);
cleanup_dir(dir_fd, "link");
// Create a link to a directory
create_dir(dir_fd, "subdir");
let subdir_fd = create_or_open(dir_fd, "subdir", wasi_unstable::O_DIRECTORY);
assert_eq!(
wasi_path_link(dir_fd, 0, "subdir", dir_fd, "link"),
Err(wasi_unstable::EPERM),
"creating a link to a directory"
);
cleanup_dir(dir_fd, "subdir");
// Create a link to a file with trailing slash
assert_eq!(
wasi_path_link(dir_fd, 0, "file", dir_fd, "link/"),
Err(wasi_unstable::ENOENT),
"creating a link to a file with trailing slash"
);
// Create a link to a dangling symlink
assert!(
wasi_path_symlink("target", dir_fd, "symlink").is_ok(),
"creating a dangling symlink"
);
assert_eq!(
wasi_path_link(dir_fd, 0, "symlink", dir_fd, "link"),
Err(wasi_unstable::ENOENT),
"creating a link to a dangling symlink"
);
cleanup_file(dir_fd, "symlink");
// Create a link to a symlink loop
assert!(
wasi_path_symlink("symlink", dir_fd, "symlink").is_ok(),
"creating a symlink loop"
);
assert_eq!(
wasi_path_link(dir_fd, 0, "symlink", dir_fd, "link"),
Err(wasi_unstable::ELOOP),
"creating a link to a symlink loop"
);
cleanup_file(dir_fd, "symlink");
// Create a link where target is a dangling symlink
assert!(
wasi_path_symlink("target", dir_fd, "symlink").is_ok(),
"creating a dangling symlink"
);
assert_eq!(
wasi_path_link(dir_fd, 0, "file", dir_fd, "symlink"),
Err(wasi_unstable::EEXIST),
"creating a link where target is a dangling symlink"
);
cleanup_file(dir_fd, "symlink");
// Create a link to a file following symlinks
assert!(
wasi_path_symlink("file", dir_fd, "symlink").is_ok(),
"creating a valid symlink"
);
assert!(
wasi_path_link(
dir_fd,
wasi_unstable::LOOKUP_SYMLINK_FOLLOW,
"symlink",
dir_fd,
"link"
)
.is_ok(),
"creating a link to a file following symlinks",
);
link_fd = open_link(dir_fd, "link");
check_rights(file_fd, link_fd);
cleanup_file(dir_fd, "link");
cleanup_file(dir_fd, "symlink");
// Create a link where target is a dangling symlink following symlinks
assert!(
wasi_path_symlink("target", dir_fd, "symlink").is_ok(),
"creating a dangling symlink"
);
assert_eq!(
wasi_path_link(
dir_fd,
wasi_unstable::LOOKUP_SYMLINK_FOLLOW,
"symlink",
dir_fd,
"link"
),
Err(wasi_unstable::ENOENT),
"creating a link where target is a dangling symlink following symlinks"
);
cleanup_file(dir_fd, "symlink");
// Create a link to a symlink loop following symlinks
assert!(
wasi_path_symlink("symlink", dir_fd, "symlink").is_ok(),
"creating a symlink loop"
);
assert_eq!(
wasi_path_link(
dir_fd,
wasi_unstable::LOOKUP_SYMLINK_FOLLOW,
"symlink",
dir_fd,
"link"
),
Err(wasi_unstable::ELOOP),
"creating a link to a symlink loop following symlinks"
);
cleanup_file(dir_fd, "symlink");
// Clean up.
cleanup_file(dir_fd, "file");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_path_link(dir_fd) }
}

View File

@@ -0,0 +1,67 @@
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::close_fd;
use wasi_tests::wasi_wrappers::wasi_path_open;
unsafe fn test_dirfd_not_dir(dir_fd: wasi_unstable::Fd) {
// Open a file.
let mut file_fd: wasi_unstable::Fd = wasi_unstable::Fd::max_value() - 1;
let mut status = wasi_path_open(
dir_fd,
0,
"file",
wasi_unstable::O_CREAT,
0,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a file"
);
// Now try to open a file underneath it as if it were a directory.
let mut new_file_fd: wasi_unstable::Fd = wasi_unstable::Fd::max_value() - 1;
status = wasi_path_open(
file_fd,
0,
"foo",
wasi_unstable::O_CREAT,
0,
0,
0,
&mut new_file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ENOTDIR,
"non-directory base fd should get ENOTDIR"
);
close_fd(file_fd);
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_dirfd_not_dir(dir_fd) }
}

View File

@@ -0,0 +1,258 @@
use more_asserts::assert_gt;
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_dir, cleanup_file, close_fd, create_dir, create_file};
use wasi_tests::wasi_wrappers::{wasi_path_open, wasi_path_rename};
unsafe fn test_path_rename(dir_fd: wasi_unstable::Fd) {
// First, try renaming a dir to nonexistent path
// Create source directory
create_dir(dir_fd, "source");
// Try renaming the directory
assert!(
wasi_path_rename(dir_fd, "source", dir_fd, "target").is_ok(),
"renaming a directory"
);
// Check that source directory doesn't exist anymore
let mut fd: wasi_unstable::Fd = wasi_unstable::Fd::max_value() - 1;
let mut status = wasi_path_open(
dir_fd,
0,
"source",
wasi_unstable::O_DIRECTORY,
0,
0,
0,
&mut fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ENOENT,
"opening a nonexistent path as a directory"
);
assert_eq!(
fd,
wasi_unstable::Fd::max_value(),
"failed open should set the file descriptor to -1",
);
// Check that target directory exists
status = wasi_path_open(
dir_fd,
0,
"target",
wasi_unstable::O_DIRECTORY,
0,
0,
0,
&mut fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening renamed path as a directory"
);
assert_gt!(
fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
close_fd(fd);
cleanup_dir(dir_fd, "target");
// Now, try renaming renaming a dir to existing empty dir
create_dir(dir_fd, "source");
create_dir(dir_fd, "target");
assert!(
wasi_path_rename(dir_fd, "source", dir_fd, "target").is_ok(),
"renaming a directory"
);
// Check that source directory doesn't exist anymore
fd = wasi_unstable::Fd::max_value() - 1;
status = wasi_path_open(
dir_fd,
0,
"source",
wasi_unstable::O_DIRECTORY,
0,
0,
0,
&mut fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ENOENT,
"opening a nonexistent path as a directory"
);
assert_eq!(
fd,
wasi_unstable::Fd::max_value(),
"failed open should set the file descriptor to -1",
);
// Check that target directory exists
status = wasi_path_open(
dir_fd,
0,
"target",
wasi_unstable::O_DIRECTORY,
0,
0,
0,
&mut fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening renamed path as a directory"
);
assert_gt!(
fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
close_fd(fd);
cleanup_dir(dir_fd, "target");
// Now, try renaming a dir to existing non-empty dir
create_dir(dir_fd, "source");
create_dir(dir_fd, "target");
create_file(dir_fd, "target/file");
assert_eq!(
wasi_path_rename(dir_fd, "source", dir_fd, "target"),
Err(wasi_unstable::ENOTEMPTY),
"renaming directory to a nonempty directory"
);
// Try renaming dir to a file
assert_eq!(
wasi_path_rename(dir_fd, "source", dir_fd, "target/file"),
Err(wasi_unstable::ENOTDIR),
"renaming directory to a file"
);
cleanup_file(dir_fd, "target/file");
cleanup_dir(dir_fd, "target");
cleanup_dir(dir_fd, "source");
// Now, try renaming a file to a nonexistent path
create_file(dir_fd, "source");
assert!(
wasi_path_rename(dir_fd, "source", dir_fd, "target").is_ok(),
"renaming a file"
);
// Check that source file doesn't exist anymore
fd = wasi_unstable::Fd::max_value() - 1;
status = wasi_path_open(dir_fd, 0, "source", 0, 0, 0, 0, &mut fd);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ENOENT,
"opening a nonexistent path"
);
assert_eq!(
fd,
wasi_unstable::Fd::max_value(),
"failed open should set the file descriptor to -1",
);
// Check that target file exists
status = wasi_path_open(dir_fd, 0, "target", 0, 0, 0, 0, &mut fd);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening renamed path"
);
assert_gt!(
fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
close_fd(fd);
cleanup_file(dir_fd, "target");
// Now, try renaming file to an existing file
create_file(dir_fd, "source");
create_file(dir_fd, "target");
assert!(
wasi_path_rename(dir_fd, "source", dir_fd, "target").is_ok(),
"renaming file to another existing file"
);
// Check that source file doesn't exist anymore
fd = wasi_unstable::Fd::max_value() - 1;
status = wasi_path_open(dir_fd, 0, "source", 0, 0, 0, 0, &mut fd);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ENOENT,
"opening a nonexistent path"
);
assert_eq!(
fd,
wasi_unstable::Fd::max_value(),
"failed open should set the file descriptor to -1",
);
// Check that target file exists
status = wasi_path_open(dir_fd, 0, "target", 0, 0, 0, 0, &mut fd);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening renamed path"
);
assert_gt!(
fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
close_fd(fd);
cleanup_file(dir_fd, "target");
// Try renaming to an (empty) directory instead
create_file(dir_fd, "source");
create_dir(dir_fd, "target");
assert_eq!(
wasi_path_rename(dir_fd, "source", dir_fd, "target"),
Err(wasi_unstable::EISDIR),
"renaming file to existing directory"
);
cleanup_dir(dir_fd, "target");
cleanup_file(dir_fd, "source");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_path_rename(dir_fd) }
}

View File

@@ -0,0 +1,68 @@
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_dir, cleanup_file, create_dir, create_file};
use wasi_tests::wasi_wrappers::wasi_path_rename;
unsafe fn test_path_rename_trailing_slashes(dir_fd: wasi_unstable::Fd) {
// Test renaming a file with a trailing slash in the name.
create_file(dir_fd, "source");
assert_eq!(
wasi_path_rename(dir_fd, "source/", dir_fd, "target"),
Err(wasi_unstable::ENOTDIR),
"renaming a file with a trailing slash in the source name"
);
assert_eq!(
wasi_path_rename(dir_fd, "source", dir_fd, "target/"),
Err(wasi_unstable::ENOTDIR),
"renaming a file with a trailing slash in the destination name"
);
assert_eq!(
wasi_path_rename(dir_fd, "source/", dir_fd, "target/"),
Err(wasi_unstable::ENOTDIR),
"renaming a file with a trailing slash in the source and destination names"
);
cleanup_file(dir_fd, "source");
// Test renaming a directory with a trailing slash in the name.
create_dir(dir_fd, "source");
assert_eq!(
wasi_path_rename(dir_fd, "source/", dir_fd, "target"),
Ok(()),
"renaming a directory with a trailing slash in the source name"
);
assert_eq!(
wasi_path_rename(dir_fd, "target", dir_fd, "source/"),
Ok(()),
"renaming a directory with a trailing slash in the destination name"
);
assert_eq!(
wasi_path_rename(dir_fd, "source/", dir_fd, "target/"),
Ok(()),
"renaming a directory with a trailing slash in the source and destination names"
);
cleanup_dir(dir_fd, "target");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_path_rename_trailing_slashes(dir_fd) }
}

View File

@@ -0,0 +1,81 @@
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_dir, cleanup_file, create_dir, create_file};
use wasi_tests::wasi_wrappers::wasi_path_symlink;
unsafe fn test_path_symlink_trailing_slashes(dir_fd: wasi_unstable::Fd) {
// Link destination shouldn't end with a slash.
assert_eq!(
wasi_path_symlink("source", dir_fd, "target/"),
Err(wasi_unstable::ENOENT),
"link destination ending with a slash"
);
// Without the trailing slash, this should succeed.
assert_eq!(
wasi_path_symlink("source", dir_fd, "target"),
Ok(()),
"link destination ending with a slash"
);
cleanup_file(dir_fd, "target");
// Link destination already exists, target has trailing slash.
create_dir(dir_fd, "target");
assert_eq!(
wasi_path_symlink("source", dir_fd, "target/"),
Err(wasi_unstable::EEXIST),
"link destination already exists"
);
cleanup_dir(dir_fd, "target");
// Link destination already exists, target has no trailing slash.
create_dir(dir_fd, "target");
assert_eq!(
wasi_path_symlink("source", dir_fd, "target"),
Err(wasi_unstable::EEXIST),
"link destination already exists"
);
cleanup_dir(dir_fd, "target");
// Link destination already exists, target has trailing slash.
create_file(dir_fd, "target");
assert_eq!(
wasi_path_symlink("source", dir_fd, "target/"),
Err(wasi_unstable::EEXIST),
"link destination already exists"
);
cleanup_file(dir_fd, "target");
// Link destination already exists, target has no trailing slash.
create_file(dir_fd, "target");
assert_eq!(
wasi_path_symlink("source", dir_fd, "target"),
Err(wasi_unstable::EEXIST),
"link destination already exists"
);
cleanup_file(dir_fd, "target");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_path_symlink_trailing_slashes(dir_fd) }
}

View File

@@ -0,0 +1,270 @@
use more_asserts::assert_gt;
use std::{env, mem::MaybeUninit, process};
use wasi::wasi_unstable;
use wasi_tests::{
open_scratch_directory,
utils::{cleanup_file, close_fd},
wasi_wrappers::wasi_path_open,
};
const CLOCK_ID: wasi_unstable::Userdata = 0x0123_45678;
unsafe fn poll_oneoff_impl(
in_: &[wasi_unstable::Subscription],
nexpected: usize,
) -> Vec<wasi_unstable::Event> {
let mut out: Vec<wasi_unstable::Event> = Vec::new();
out.resize_with(in_.len(), || {
MaybeUninit::<wasi_unstable::Event>::zeroed().assume_init()
});
let res = wasi_unstable::poll_oneoff(&in_, out.as_mut_slice());
let res = res.expect("poll_oneoff should succeed");
assert_eq!(
res, nexpected,
"poll_oneoff should return {} events",
nexpected
);
out
}
unsafe fn test_timeout() {
let clock = wasi_unstable::raw::__wasi_subscription_u_clock_t {
identifier: CLOCK_ID,
clock_id: wasi_unstable::CLOCK_MONOTONIC,
timeout: 5_000_000u64, // 5 milliseconds
precision: 0,
flags: 0,
};
let in_ = [wasi_unstable::Subscription {
userdata: CLOCK_ID,
type_: wasi_unstable::EVENTTYPE_CLOCK,
u: wasi_unstable::raw::__wasi_subscription_u { clock },
}];
let out = poll_oneoff_impl(&in_, 1);
let event = &out[0];
assert_eq!(
event.userdata, CLOCK_ID,
"the event.userdata should contain clock_id specified by the user"
);
assert_eq!(
event.error,
wasi_unstable::raw::__WASI_ESUCCESS,
"the event.error should be set to ESUCCESS"
);
assert_eq!(
event.type_,
wasi_unstable::EVENTTYPE_CLOCK,
"the event.type_ should equal clock"
);
}
unsafe fn test_stdin_read() {
let clock = wasi_unstable::raw::__wasi_subscription_u_clock_t {
identifier: CLOCK_ID,
clock_id: wasi_unstable::CLOCK_MONOTONIC,
timeout: 5_000_000u64, // 5 milliseconds
precision: 0,
flags: 0,
};
let fd_readwrite = wasi_unstable::raw::__wasi_subscription_u_fd_readwrite_t {
fd: wasi_unstable::STDIN_FD,
};
let in_ = [
wasi_unstable::Subscription {
userdata: CLOCK_ID,
type_: wasi_unstable::EVENTTYPE_CLOCK,
u: wasi_unstable::raw::__wasi_subscription_u { clock },
},
wasi_unstable::Subscription {
userdata: 1,
type_: wasi_unstable::EVENTTYPE_FD_READ,
u: wasi_unstable::raw::__wasi_subscription_u { fd_readwrite },
},
];
let out = poll_oneoff_impl(&in_, 1);
let event = &out[0];
assert_eq!(
event.userdata, CLOCK_ID,
"the event.userdata should contain clock_id specified by the user"
);
assert_eq!(
event.error,
wasi_unstable::raw::__WASI_ESUCCESS,
"the event.error should be set to ESUCCESS"
);
assert_eq!(
event.type_,
wasi_unstable::EVENTTYPE_CLOCK,
"the event.type_ should equal clock"
);
}
unsafe fn test_stdout_stderr_write() {
let stdout_readwrite = wasi_unstable::raw::__wasi_subscription_u_fd_readwrite_t {
fd: wasi_unstable::STDOUT_FD,
};
let stderr_readwrite = wasi_unstable::raw::__wasi_subscription_u_fd_readwrite_t {
fd: wasi_unstable::STDERR_FD,
};
let in_ = [
wasi_unstable::Subscription {
userdata: 1,
type_: wasi_unstable::EVENTTYPE_FD_WRITE,
u: wasi_unstable::raw::__wasi_subscription_u {
fd_readwrite: stdout_readwrite,
},
},
wasi_unstable::Subscription {
userdata: 2,
type_: wasi_unstable::EVENTTYPE_FD_WRITE,
u: wasi_unstable::raw::__wasi_subscription_u {
fd_readwrite: stderr_readwrite,
},
},
];
let out = poll_oneoff_impl(&in_, 2);
assert_eq!(
out[0].userdata, 1,
"the event.userdata should contain fd userdata specified by the user"
);
assert_eq!(
out[0].error,
wasi_unstable::raw::__WASI_ESUCCESS,
"the event.error should be set to {}",
wasi_unstable::raw::__WASI_ESUCCESS
);
assert_eq!(
out[0].type_,
wasi_unstable::EVENTTYPE_FD_WRITE,
"the event.type_ should equal FD_WRITE"
);
assert_eq!(
out[1].userdata, 2,
"the event.userdata should contain fd userdata specified by the user"
);
assert_eq!(
out[1].error,
wasi_unstable::raw::__WASI_ESUCCESS,
"the event.error should be set to {}",
wasi_unstable::raw::__WASI_ESUCCESS
);
assert_eq!(
out[1].type_,
wasi_unstable::EVENTTYPE_FD_WRITE,
"the event.type_ should equal FD_WRITE"
);
}
unsafe fn test_fd_readwrite(fd: wasi_unstable::Fd, error_code: wasi_unstable::raw::__wasi_errno_t) {
let fd_readwrite = wasi_unstable::raw::__wasi_subscription_u_fd_readwrite_t { fd };
let in_ = [
wasi_unstable::Subscription {
userdata: 1,
type_: wasi_unstable::EVENTTYPE_FD_READ,
u: wasi_unstable::raw::__wasi_subscription_u { fd_readwrite },
},
wasi_unstable::Subscription {
userdata: 2,
type_: wasi_unstable::EVENTTYPE_FD_WRITE,
u: wasi_unstable::raw::__wasi_subscription_u { fd_readwrite },
},
];
let out = poll_oneoff_impl(&in_, 2);
assert_eq!(
out[0].userdata, 1,
"the event.userdata should contain fd userdata specified by the user"
);
assert_eq!(
out[0].error, error_code,
"the event.error should be set to {}",
error_code
);
assert_eq!(
out[0].type_,
wasi_unstable::EVENTTYPE_FD_READ,
"the event.type_ should equal FD_READ"
);
assert_eq!(
out[1].userdata, 2,
"the event.userdata should contain fd userdata specified by the user"
);
assert_eq!(
out[1].error, error_code,
"the event.error should be set to {}",
error_code
);
assert_eq!(
out[1].type_,
wasi_unstable::EVENTTYPE_FD_WRITE,
"the event.type_ should equal FD_WRITE"
);
}
unsafe fn test_fd_readwrite_valid_fd(dir_fd: wasi_unstable::Fd) {
// Create a file in the scratch directory.
let mut file_fd = wasi_unstable::Fd::max_value() - 1;
let status = wasi_path_open(
dir_fd,
0,
"file",
wasi_unstable::O_CREAT,
wasi_unstable::RIGHT_FD_READ | wasi_unstable::RIGHT_FD_WRITE,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a file"
);
assert_gt!(
file_fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
test_fd_readwrite(file_fd, wasi_unstable::raw::__WASI_ESUCCESS);
close_fd(file_fd);
cleanup_file(dir_fd, "file");
}
unsafe fn test_fd_readwrite_invalid_fd() {
test_fd_readwrite(
wasi_unstable::Fd::max_value(),
wasi_unstable::raw::__WASI_EBADF,
)
}
unsafe fn test_poll_oneoff(dir_fd: wasi_unstable::Fd) {
test_timeout();
// NB we assume that stdin/stdout/stderr are valid and open
// for the duration of the test case
test_stdin_read();
test_stdout_stderr_write();
test_fd_readwrite_valid_fd(dir_fd);
test_fd_readwrite_invalid_fd();
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_poll_oneoff(dir_fd) }
}

View File

@@ -0,0 +1,72 @@
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_file, create_file};
use wasi_tests::wasi_wrappers::{wasi_path_readlink, wasi_path_symlink};
unsafe fn test_readlink(dir_fd: wasi_unstable::Fd) {
// Create a file in the scratch directory.
create_file(dir_fd, "target");
// Create a symlink
assert!(
wasi_path_symlink("target", dir_fd, "symlink").is_ok(),
"creating a symlink"
);
// Read link into the buffer
let buf = &mut [0u8; 10];
let mut bufused: usize = 0;
let mut status = wasi_path_readlink(dir_fd, "symlink", buf, &mut bufused);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"readlink should succeed"
);
assert_eq!(bufused, 6, "should use 6 bytes of the buffer");
assert_eq!(&buf[..6], b"target", "buffer should contain 'target'");
assert_eq!(
&buf[6..],
&[0u8; 4],
"the remaining bytes should be untouched"
);
// Read link into smaller buffer than the actual link's length
let buf = &mut [0u8; 4];
let mut bufused: usize = 0;
status = wasi_path_readlink(dir_fd, "symlink", buf, &mut bufused);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"readlink should succeed"
);
assert_eq!(bufused, 4, "should use all 4 bytes of the buffer");
assert_eq!(buf, b"targ", "buffer should contain 'targ'");
// Clean up.
cleanup_file(dir_fd, "target");
cleanup_file(dir_fd, "symlink");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_readlink(dir_fd) }
}

View File

@@ -0,0 +1,51 @@
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::cleanup_file;
use wasi_tests::wasi_wrappers::{wasi_path_readlink, wasi_path_symlink};
unsafe fn test_readlink_no_buffer(dir_fd: wasi_unstable::Fd) {
// First create a dangling symlink.
assert!(
wasi_path_symlink("target", dir_fd, "symlink").is_ok(),
"creating a symlink"
);
// Readlink it into a non-existent buffer.
let mut bufused: usize = 1;
let status = wasi_path_readlink(dir_fd, "symlink", &mut [], &mut bufused);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"readlink with a 0-sized buffer should succeed"
);
assert_eq!(
bufused, 0,
"readlink with a 0-sized buffer should return 'bufused' 0"
);
// Clean up.
cleanup_file(dir_fd, "symlink");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_readlink_no_buffer(dir_fd) }
}

View File

@@ -0,0 +1,68 @@
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_file, create_dir, create_file};
use wasi_tests::wasi_wrappers::wasi_path_remove_directory;
unsafe fn test_remove_directory_trailing_slashes(dir_fd: wasi_unstable::Fd) {
// Create a directory in the scratch directory.
create_dir(dir_fd, "dir");
// Test that removing it succeeds.
assert_eq!(
wasi_path_remove_directory(dir_fd, "dir"),
Ok(()),
"remove_directory on a directory should succeed"
);
create_dir(dir_fd, "dir");
// Test that removing it with a trailing flash succeeds.
assert_eq!(
wasi_path_remove_directory(dir_fd, "dir/"),
Ok(()),
"remove_directory with a trailing slash on a directory should succeed"
);
// Create a temporary file.
create_file(dir_fd, "file");
// Test that removing it with no trailing flash fails.
assert_eq!(
wasi_path_remove_directory(dir_fd, "file"),
Err(wasi_unstable::ENOTDIR),
"remove_directory without a trailing slash on a file should fail"
);
// Test that removing it with a trailing flash fails.
assert_eq!(
wasi_path_remove_directory(dir_fd, "file/"),
Err(wasi_unstable::ENOTDIR),
"remove_directory with a trailing slash on a file should fail"
);
cleanup_file(dir_fd, "file");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_remove_directory_trailing_slashes(dir_fd) }
}

View File

@@ -0,0 +1,50 @@
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_dir, create_dir};
use wasi_tests::wasi_wrappers::wasi_path_remove_directory;
unsafe fn test_remove_nonempty_directory(dir_fd: wasi_unstable::Fd) {
// Create a directory in the scratch directory.
create_dir(dir_fd, "dir");
// Create a directory in the directory we just created.
create_dir(dir_fd, "dir/nested");
// Test that attempting to unlink the first directory returns the expected error code.
assert_eq!(
wasi_path_remove_directory(dir_fd, "dir"),
Err(wasi_unstable::ENOTEMPTY),
"remove_directory on a directory should return ENOTEMPTY",
);
// Removing the directories.
assert!(
wasi_path_remove_directory(dir_fd, "dir/nested").is_ok(),
"remove_directory on a nested directory should succeed",
);
cleanup_dir(dir_fd, "dir");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_remove_nonempty_directory(dir_fd) }
}

View File

@@ -0,0 +1,131 @@
use libc;
use more_asserts::assert_gt;
use std::{env, mem, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::close_fd;
use wasi_tests::wasi_wrappers::{wasi_fd_fdstat_get, wasi_path_open};
unsafe fn test_renumber(dir_fd: wasi_unstable::Fd) {
let pre_fd: wasi_unstable::Fd = (libc::STDERR_FILENO + 1) as wasi_unstable::Fd;
assert_gt!(dir_fd, pre_fd, "dir_fd number");
// Create a file in the scratch directory.
let mut fd_from = wasi_unstable::Fd::max_value() - 1;
let mut status = wasi_path_open(
dir_fd,
0,
"file1",
wasi_unstable::O_CREAT,
wasi_unstable::RIGHT_FD_READ | wasi_unstable::RIGHT_FD_WRITE,
0,
0,
&mut fd_from,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a file"
);
assert_gt!(
fd_from,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
// Get fd_from fdstat attributes
let mut fdstat_from: wasi_unstable::FdStat = mem::zeroed();
status = wasi_fd_fdstat_get(fd_from, &mut fdstat_from);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"calling fd_fdstat on the open file descriptor"
);
// Create another file in the scratch directory.
let mut fd_to = wasi_unstable::Fd::max_value() - 1;
status = wasi_path_open(
dir_fd,
0,
"file2",
wasi_unstable::O_CREAT,
wasi_unstable::RIGHT_FD_READ | wasi_unstable::RIGHT_FD_WRITE,
0,
0,
&mut fd_to,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"opening a file"
);
assert_gt!(
fd_to,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
// Renumber fd of file1 into fd of file2
assert!(
wasi_unstable::fd_renumber(fd_from, fd_to).is_ok(),
"renumbering two descriptors",
);
// Ensure that fd_from is closed
assert_eq!(
wasi_unstable::fd_close(fd_from),
Err(wasi_unstable::EBADF),
"closing already closed file descriptor"
);
// Ensure that fd_to is still open.
let mut fdstat_to: wasi_unstable::FdStat = mem::zeroed();
status = wasi_fd_fdstat_get(fd_to, &mut fdstat_to);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"calling fd_fdstat on the open file descriptor"
);
assert_eq!(
fdstat_from.fs_filetype, fdstat_to.fs_filetype,
"expected fd_to have the same fdstat as fd_from"
);
assert_eq!(
fdstat_from.fs_flags, fdstat_to.fs_flags,
"expected fd_to have the same fdstat as fd_from"
);
assert_eq!(
fdstat_from.fs_rights_base, fdstat_to.fs_rights_base,
"expected fd_to have the same fdstat as fd_from"
);
assert_eq!(
fdstat_from.fs_rights_inheriting, fdstat_to.fs_rights_inheriting,
"expected fd_to have the same fdstat as fd_from"
);
close_fd(fd_to);
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_renumber(dir_fd) }
}

View File

@@ -0,0 +1,10 @@
use wasi::wasi_unstable;
fn test_sched_yield() {
assert!(wasi_unstable::sched_yield().is_ok(), "sched_yield");
}
fn main() {
// Run tests
test_sched_yield()
}

View File

@@ -0,0 +1,47 @@
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::cleanup_file;
use wasi_tests::wasi_wrappers::{wasi_path_open, wasi_path_symlink};
unsafe fn test_symlink_loop(dir_fd: wasi_unstable::Fd) {
// Create a self-referencing symlink.
assert!(
wasi_path_symlink("symlink", dir_fd, "symlink").is_ok(),
"creating a symlink"
);
// Try to open it.
let mut file_fd: wasi_unstable::Fd = wasi_unstable::Fd::max_value() - 1;
assert_eq!(
wasi_path_open(dir_fd, 0, "symlink", 0, 0, 0, 0, &mut file_fd),
wasi_unstable::raw::__WASI_ELOOP,
"opening a self-referencing symlink",
);
// Clean up.
cleanup_file(dir_fd, "symlink");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_symlink_loop(dir_fd) }
}

View File

@@ -0,0 +1,157 @@
use std::{env, mem, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_file, close_fd, create_file};
use wasi_tests::wasi_wrappers::{wasi_fd_fdstat_get, wasi_path_open};
unsafe fn test_truncation_rights(dir_fd: wasi_unstable::Fd) {
// Create a file in the scratch directory.
create_file(dir_fd, "file");
// Get the rights for the scratch directory.
let mut dir_fdstat: wasi_unstable::FdStat = mem::zeroed();
let mut status = wasi_fd_fdstat_get(dir_fd, &mut dir_fdstat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"calling fd_fdstat on the scratch directory"
);
assert_eq!(
dir_fdstat.fs_filetype,
wasi_unstable::FILETYPE_DIRECTORY,
"expected the scratch directory to be a directory",
);
assert_eq!(
dir_fdstat.fs_flags, 0,
"expected the scratch directory to have no special flags",
);
assert_eq!(
dir_fdstat.fs_rights_base & wasi_unstable::RIGHT_FD_FILESTAT_SET_SIZE,
0,
"directories shouldn't have the fd_filestat_set_size right",
);
// If we have the right to set sizes from paths, test that it works.
if (dir_fdstat.fs_rights_base & wasi_unstable::RIGHT_PATH_FILESTAT_SET_SIZE) == 0 {
eprintln!("implementation doesn't support setting file sizes, skipping");
} else {
// Test that we can truncate the file.
let mut file_fd: wasi_unstable::Fd = wasi_unstable::Fd::max_value() - 1;
status = wasi_path_open(
dir_fd,
0,
"file",
wasi_unstable::O_TRUNC,
0,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"truncating a file"
);
close_fd(file_fd);
let mut rights_base: wasi_unstable::Rights = dir_fdstat.fs_rights_base;
let mut rights_inheriting: wasi_unstable::Rights = dir_fdstat.fs_rights_inheriting;
if (rights_inheriting & wasi_unstable::RIGHT_FD_FILESTAT_SET_SIZE) == 0 {
eprintln!("implementation doesn't support setting file sizes through file descriptors, skipping");
} else {
rights_inheriting &= !wasi_unstable::RIGHT_FD_FILESTAT_SET_SIZE;
assert!(
wasi_unstable::fd_fdstat_set_rights(dir_fd, rights_base, rights_inheriting).is_ok(),
"droping fd_filestat_set_size inheriting right on a directory",
);
}
// Test that we can truncate the file without the
// wasi_unstable::RIGHT_FD_FILESTAT_SET_SIZE right.
status = wasi_path_open(
dir_fd,
0,
"file",
wasi_unstable::O_TRUNC,
0,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"truncating a file without fd_filestat_set_size right",
);
close_fd(file_fd);
rights_base &= !wasi_unstable::RIGHT_PATH_FILESTAT_SET_SIZE;
assert!(
wasi_unstable::fd_fdstat_set_rights(dir_fd, rights_base, rights_inheriting).is_ok(),
"droping path_filestat_set_size base right on a directory",
);
// Test that clearing wasi_unstable::RIGHT_PATH_FILESTAT_SET_SIZE actually
// took effect.
status = wasi_fd_fdstat_get(dir_fd, &mut dir_fdstat);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"reading the fdstat from a directory",
);
assert_eq!(
(dir_fdstat.fs_rights_base & wasi_unstable::RIGHT_PATH_FILESTAT_SET_SIZE),
0,
"reading the fdstat from a directory",
);
// Test that we can't truncate the file without the
// wasi_unstable::RIGHT_PATH_FILESTAT_SET_SIZE right.
status = wasi_path_open(
dir_fd,
0,
"file",
wasi_unstable::O_TRUNC,
0,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ENOTCAPABLE,
"truncating a file without path_filestat_set_size right",
);
assert_eq!(
file_fd,
wasi_unstable::Fd::max_value(),
"failed open should set the file descriptor to -1",
);
}
cleanup_file(dir_fd, "file");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_truncation_rights(dir_fd) }
}

View File

@@ -0,0 +1,67 @@
use std::{env, process};
use wasi::wasi_unstable;
use wasi_tests::open_scratch_directory;
use wasi_tests::utils::{cleanup_dir, create_dir, create_file};
use wasi_tests::wasi_wrappers::wasi_path_unlink_file;
unsafe fn test_unlink_file_trailing_slashes(dir_fd: wasi_unstable::Fd) {
// Create a directory in the scratch directory.
create_dir(dir_fd, "dir");
// Test that unlinking it fails.
assert_eq!(
wasi_path_unlink_file(dir_fd, "dir"),
Err(wasi_unstable::EISDIR),
"unlink_file on a directory should fail"
);
// Test that unlinking it with a trailing flash fails.
assert_eq!(
wasi_path_unlink_file(dir_fd, "dir/"),
Err(wasi_unstable::EISDIR),
"unlink_file on a directory should fail"
);
// Clean up.
cleanup_dir(dir_fd, "dir");
// Create a temporary file.
create_file(dir_fd, "file");
// Test that unlinking it with a trailing flash fails.
assert_eq!(
wasi_path_unlink_file(dir_fd, "file/"),
Err(wasi_unstable::ENOTDIR),
"unlink_file with a trailing slash should fail"
);
// Test that unlinking it with no trailing flash succeeds.
assert_eq!(
wasi_path_unlink_file(dir_fd, "file"),
Ok(()),
"unlink_file with no trailing slash should succeed"
);
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", 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)
}
};
// Run the tests.
unsafe { test_unlink_file_trailing_slashes(dir_fd) }
}

View File

@@ -0,0 +1,25 @@
pub mod utils;
pub mod wasi_wrappers;
use libc;
use std::ffi::CString;
use std::io;
use wasi::wasi_unstable;
pub fn open_scratch_directory(path: &str) -> Result<wasi_unstable::Fd, String> {
// Open the scratch directory.
let dir_fd: wasi_unstable::Fd = unsafe {
let cstr = CString::new(path.as_bytes()).unwrap();
libc::open(cstr.as_ptr(), libc::O_RDONLY | libc::O_DIRECTORY)
} as wasi_unstable::Fd;
if (dir_fd as std::os::raw::c_int) < 0 {
Err(format!(
"error opening scratch directory '{}': {}",
path,
io::Error::last_os_error()
))
} else {
Ok(dir_fd)
}
}

View File

@@ -0,0 +1,54 @@
use crate::wasi_wrappers::*;
use more_asserts::assert_gt;
use wasi::wasi_unstable;
pub unsafe fn create_dir(dir_fd: wasi_unstable::Fd, dir_name: &str) {
assert!(
wasi_path_create_directory(dir_fd, dir_name).is_ok(),
"creating a directory"
);
}
pub unsafe fn cleanup_dir(dir_fd: wasi_unstable::Fd, dir_name: &str) {
assert!(
wasi_path_remove_directory(dir_fd, dir_name).is_ok(),
"remove_directory on an empty directory should succeed"
);
}
/// Create an empty file with the given name.
pub unsafe fn create_file(dir_fd: wasi_unstable::Fd, file_name: &str) {
let mut file_fd = wasi_unstable::Fd::max_value() - 1;
let status = wasi_path_open(
dir_fd,
0,
file_name,
wasi_unstable::O_CREAT,
0,
0,
0,
&mut file_fd,
);
assert_eq!(
status,
wasi_unstable::raw::__WASI_ESUCCESS,
"creating a file"
);
assert_gt!(
file_fd,
libc::STDERR_FILENO as wasi_unstable::Fd,
"file descriptor range check",
);
close_fd(file_fd);
}
pub unsafe fn cleanup_file(dir_fd: wasi_unstable::Fd, file_name: &str) {
assert!(
wasi_path_unlink_file(dir_fd, file_name).is_ok(),
"unlink_file on a symlink should succeed"
);
}
pub unsafe fn close_fd(fd: wasi_unstable::Fd) {
assert!(wasi_unstable::fd_close(fd).is_ok(), "closing a file");
}

View File

@@ -0,0 +1,233 @@
//! Minimal wrappers around WASI functions to allow use of `&str` rather than
//! pointer-length pairs.
//!
//! Where possible, we use the idiomatic wasi_unstable wrappers rather than the
//! raw interfaces, however for functions with out parameters, we use the raw
//! interfaces so that we can test whether they are stored to. In the future,
//! WASI should switch to multi-value and eliminate out parameters altogether.
use wasi::wasi_unstable;
pub unsafe fn wasi_path_create_directory(
dir_fd: wasi_unstable::Fd,
dir_name: &str,
) -> Result<(), wasi_unstable::Error> {
wasi_unstable::path_create_directory(dir_fd, dir_name.as_bytes())
}
pub unsafe fn wasi_path_remove_directory(
dir_fd: wasi_unstable::Fd,
dir_name: &str,
) -> Result<(), wasi_unstable::Error> {
wasi_unstable::path_remove_directory(dir_fd, dir_name.as_bytes())
}
pub unsafe fn wasi_path_unlink_file(
dir_fd: wasi_unstable::Fd,
file_name: &str,
) -> Result<(), wasi_unstable::Error> {
wasi_unstable::path_unlink_file(dir_fd, file_name.as_bytes())
}
#[allow(clippy::too_many_arguments)]
pub unsafe fn wasi_path_open(
dirfd: wasi_unstable::Fd,
dirflags: wasi_unstable::LookupFlags,
path: &str,
oflags: wasi_unstable::OFlags,
fs_rights_base: wasi_unstable::Rights,
fs_rights_inheriting: wasi_unstable::Rights,
fs_flags: wasi_unstable::FdFlags,
fd: &mut wasi_unstable::Fd,
) -> wasi_unstable::Errno {
wasi_unstable::raw::__wasi_path_open(
dirfd,
dirflags,
path.as_ptr(),
path.len(),
oflags,
fs_rights_base,
fs_rights_inheriting,
fs_flags,
fd,
)
}
pub unsafe fn wasi_path_symlink(
old_path: &str,
dirfd: wasi_unstable::Fd,
new_path: &str,
) -> Result<(), wasi_unstable::Error> {
wasi_unstable::path_symlink(old_path.as_bytes(), dirfd, new_path.as_bytes())
}
pub unsafe fn wasi_path_link(
old_fd: wasi_unstable::Fd,
old_flags: wasi_unstable::LookupFlags,
old_path: &str,
new_fd: wasi_unstable::Fd,
new_path: &str,
) -> Result<(), wasi_unstable::Error> {
wasi_unstable::path_link(
old_fd,
old_flags,
old_path.as_bytes(),
new_fd,
new_path.as_bytes(),
)
}
pub unsafe fn wasi_path_readlink(
dirfd: wasi_unstable::Fd,
path: &str,
buf: &mut [u8],
bufused: &mut usize,
) -> wasi_unstable::Errno {
wasi_unstable::raw::__wasi_path_readlink(
dirfd,
path.as_ptr(),
path.len(),
buf.as_mut_ptr(),
buf.len(),
bufused,
)
}
pub unsafe fn wasi_path_rename(
old_dirfd: wasi_unstable::Fd,
old_path: &str,
new_dirfd: wasi_unstable::Fd,
new_path: &str,
) -> Result<(), wasi_unstable::Error> {
wasi_unstable::path_rename(
old_dirfd,
old_path.as_bytes(),
new_dirfd,
new_path.as_bytes(),
)
}
pub unsafe fn wasi_fd_fdstat_get(
fd: wasi_unstable::Fd,
fdstat: &mut wasi_unstable::FdStat,
) -> wasi_unstable::Errno {
wasi_unstable::raw::__wasi_fd_fdstat_get(fd, fdstat)
}
pub unsafe fn wasi_fd_seek(
fd: wasi_unstable::Fd,
offset: wasi_unstable::FileDelta,
whence: wasi_unstable::Whence,
newoffset: &mut wasi_unstable::FileSize,
) -> wasi_unstable::Errno {
wasi_unstable::raw::__wasi_fd_seek(fd, offset, whence, newoffset)
}
pub unsafe fn wasi_fd_tell(
fd: wasi_unstable::Fd,
offset: &mut wasi_unstable::FileSize,
) -> wasi_unstable::Errno {
wasi_unstable::raw::__wasi_fd_tell(fd, offset)
}
pub unsafe fn wasi_clock_time_get(
clock_id: wasi_unstable::ClockId,
precision: wasi_unstable::Timestamp,
time: &mut wasi_unstable::Timestamp,
) -> wasi_unstable::Errno {
wasi_unstable::raw::__wasi_clock_time_get(clock_id, precision, time)
}
pub unsafe fn wasi_fd_filestat_get(
fd: wasi_unstable::Fd,
filestat: &mut wasi_unstable::FileStat,
) -> wasi_unstable::Errno {
wasi_unstable::raw::__wasi_fd_filestat_get(fd, filestat)
}
pub unsafe fn wasi_fd_write(
fd: wasi_unstable::Fd,
iovs: &[wasi_unstable::CIoVec],
nwritten: &mut libc::size_t,
) -> wasi_unstable::Errno {
wasi_unstable::raw::__wasi_fd_write(fd, iovs.as_ptr(), iovs.len(), nwritten)
}
pub unsafe fn wasi_fd_read(
fd: wasi_unstable::Fd,
iovs: &[wasi_unstable::IoVec],
nread: &mut libc::size_t,
) -> wasi_unstable::Errno {
wasi_unstable::raw::__wasi_fd_read(fd, iovs.as_ptr(), iovs.len(), nread)
}
pub unsafe fn wasi_fd_pread(
fd: wasi_unstable::Fd,
iovs: &[wasi_unstable::IoVec],
offset: wasi_unstable::FileSize,
nread: &mut usize,
) -> wasi_unstable::Errno {
wasi_unstable::raw::__wasi_fd_pread(fd, iovs.as_ptr(), iovs.len(), offset, nread)
}
pub unsafe fn wasi_fd_pwrite(
fd: wasi_unstable::Fd,
iovs: &mut [wasi_unstable::CIoVec],
offset: wasi_unstable::FileSize,
nwritten: &mut usize,
) -> wasi_unstable::Errno {
wasi_unstable::raw::__wasi_fd_pwrite(fd, iovs.as_ptr(), iovs.len(), offset, nwritten)
}
pub unsafe fn wasi_path_filestat_get(
fd: wasi_unstable::Fd,
dirflags: wasi_unstable::LookupFlags,
path: &str,
path_len: usize,
filestat: &mut wasi_unstable::FileStat,
) -> wasi_unstable::Errno {
wasi_unstable::raw::__wasi_path_filestat_get(fd, dirflags, path.as_ptr(), path_len, filestat)
}
pub unsafe fn wasi_path_filestat_set_times(
fd: wasi_unstable::Fd,
dirflags: wasi_unstable::LookupFlags,
path: &str,
st_atim: wasi_unstable::Timestamp,
st_mtim: wasi_unstable::Timestamp,
fst_flags: wasi_unstable::FstFlags,
) -> Result<(), wasi_unstable::Error> {
wasi_unstable::path_filestat_set_times(
fd,
dirflags,
path.as_bytes(),
st_atim,
st_mtim,
fst_flags,
)
}
pub unsafe fn wasi_fd_readdir(
fd: wasi_unstable::Fd,
buf: &mut [u8],
buf_len: usize,
cookie: wasi_unstable::DirCookie,
buf_used: &mut usize,
) -> wasi_unstable::Errno {
wasi_unstable::raw::__wasi_fd_readdir(
fd,
buf.as_mut_ptr() as *mut libc::c_void,
buf_len,
cookie,
buf_used,
)
}
pub unsafe fn wasi_fd_advise(
fd: wasi_unstable::Fd,
offset: wasi_unstable::FileSize,
len: wasi_unstable::FileSize,
advice: wasi_unstable::Advice,
) -> wasi_unstable::Errno {
wasi_unstable::raw::__wasi_fd_advise(fd, offset, len, advice)
}