mod common;
use common::{create_empty_test_file, create_test_file, libc};
use ic_wasi_polyfill::wasi::CLOCKID_MONOTONIC;
use ic_wasi_polyfill::{init, wasi};
#[test]
fn test_interesting_paths() {
init(&[], &[]);
let dir_fd = 3;
unsafe {
wasi::path_create_directory(dir_fd, "dir").expect("creating dir");
wasi::path_create_directory(dir_fd, "dir/nested").expect("creating a nested dir");
let file_fd = create_test_file(dir_fd, "dir/nested/file");
wasi::fd_close(file_fd).expect("closing a file");
assert_eq!(
wasi::path_open(dir_fd, 0, "/dir/nested/file", 0, 0, 0, 0)
.expect_err("opening a file with an absolute path"),
wasi::ERRNO_PERM
);
let mut file_fd = wasi::path_open(
dir_fd,
0,
"dir/.//nested/../../dir/nested/../nested///./file",
0,
0,
0,
0,
)
.expect("opening a file with \"..\" in the path");
assert!(
file_fd > libc::STDERR_FILENO as wasi::Fd,
"file descriptor range check",
);
wasi::fd_close(file_fd).expect("closing a file");
file_fd = wasi::path_open(dir_fd, 0, "dir/nested/", 0, 0, 0, 0)
.expect("opening a directory with a trailing slash");
assert!(
file_fd > libc::STDERR_FILENO as wasi::Fd,
"file descriptor range check",
);
wasi::fd_close(file_fd).expect("closing a file");
file_fd = wasi::path_open(dir_fd, 0, "dir/nested///", 0, 0, 0, 0)
.expect("opening a directory with trailing slashes");
assert!(
file_fd > libc::STDERR_FILENO as wasi::Fd,
"file descriptor range check",
);
wasi::fd_close(file_fd).expect("closing a file");
let bad_path = "dir/nested/../../../some_path/dir/nested/file";
assert_eq!(
wasi::path_open(dir_fd, 0, bad_path, 0, 0, 0, 0)
.expect_err("opening a file with too many \"..\"s in the path should fail"),
wasi::ERRNO_PERM
);
wasi::path_unlink_file(dir_fd, "dir/nested/file")
.expect("unlink_file on a symlink should succeed");
wasi::path_remove_directory(dir_fd, "dir/nested")
.expect("remove_directory on a directory should succeed");
wasi::path_remove_directory(dir_fd, "dir")
.expect("remove_directory on a directory should succeed");
}
}
#[test]
fn test_path_exists() {
init(&[], &[]);
let dir_fd = 3;
unsafe {
wasi::path_create_directory(dir_fd, "subdir").expect("create directory");
let file_stat = wasi::path_filestat_get(dir_fd, 0, "subdir").expect("reading file stats");
assert_eq!(file_stat.filetype, wasi::FILETYPE_DIRECTORY);
let file_stat = wasi::path_filestat_get(dir_fd, wasi::LOOKUPFLAGS_SYMLINK_FOLLOW, "subdir")
.expect("reading file stats");
assert_eq!(file_stat.filetype, wasi::FILETYPE_DIRECTORY);
let fd = create_test_file(dir_fd, "subdir/file");
wasi::fd_close(fd).unwrap();
let file_stat =
wasi::path_filestat_get(dir_fd, 0, "subdir/file").expect("reading file stats");
assert_eq!(file_stat.filetype, wasi::FILETYPE_REGULAR_FILE);
let file_stat =
wasi::path_filestat_get(dir_fd, wasi::LOOKUPFLAGS_SYMLINK_FOLLOW, "subdir/file")
.expect("reading file stats");
assert_eq!(file_stat.filetype, wasi::FILETYPE_REGULAR_FILE);
wasi::path_unlink_file(dir_fd, "subdir/file").expect("clean up");
wasi::path_remove_directory(dir_fd, "subdir").expect("clean up");
}
}
#[test]
fn test_path_filestat() {
init(&[], &[]);
let dir_fd = 3;
unsafe {
let precission = wasi::clock_res_get(CLOCKID_MONOTONIC).unwrap();
let fdflags = wasi::FDFLAGS_APPEND;
let file_fd = wasi::path_open(
dir_fd,
0,
"file",
wasi::OFLAGS_CREAT,
wasi::RIGHTS_FD_READ | wasi::RIGHTS_FD_WRITE,
0,
fdflags,
)
.expect("opening a file");
assert!(
file_fd > libc::STDERR_FILENO as wasi::Fd,
"file descriptor range check",
);
let fdstat = wasi::fd_fdstat_get(file_fd).expect("fd_fdstat_get");
assert_eq!(
fdstat.fs_flags & wasi::FDFLAGS_APPEND,
wasi::FDFLAGS_APPEND,
"file should have the APPEND fdflag used to create the file"
);
let file_stat = wasi::path_filestat_get(dir_fd, 0, "file").expect("reading file stats");
assert_eq!(file_stat.size, 0, "file size should be 0");
let new_mtim = file_stat.mtim - 2 * precission;
wasi::path_filestat_set_times(dir_fd, 0, "file", 0, new_mtim as u64, wasi::FSTFLAGS_MTIM)
.expect("path_filestat_set_times should succeed");
let modified_file_stat = wasi::path_filestat_get(dir_fd, 0, "file")
.expect("reading file stats after path_filestat_set_times");
assert_eq!(modified_file_stat.mtim, new_mtim, "mtim should change");
assert_eq!(
wasi::path_filestat_set_times(
dir_fd,
0,
"file",
0,
new_mtim as u64,
wasi::FSTFLAGS_MTIM | wasi::FSTFLAGS_MTIM_NOW,
)
.expect_err("MTIM and MTIM_NOW can't both be set"),
wasi::ERRNO_INVAL
);
let unmodified_file_stat = wasi::path_filestat_get(dir_fd, 0, "file")
.expect("reading file stats after ERRNO_INVAL fd_filestat_set_times");
assert_eq!(
unmodified_file_stat.mtim, new_mtim,
"mtim should not change"
);
assert_eq!(
wasi::path_filestat_set_times(
dir_fd,
0,
"file",
0,
0,
wasi::FSTFLAGS_ATIM | wasi::FSTFLAGS_ATIM_NOW,
)
.expect_err("ATIM & ATIM_NOW can't both be set"),
wasi::ERRNO_INVAL
);
wasi::fd_close(file_fd).expect("closing a file");
wasi::path_unlink_file(dir_fd, "file").expect("removing a file");
}
}
#[test]
fn test_path_rename_trailing_slashes() {
init(&[], &[]);
let dir_fd = 3;
unsafe {
wasi::path_create_directory(dir_fd, "source").expect("creating a directory");
wasi::path_rename(dir_fd, "source/", dir_fd, "target")
.expect("renaming a directory with a trailing slash in the source name");
wasi::path_rename(dir_fd, "target", dir_fd, "source/")
.expect("renaming a directory with a trailing slash in the destination name");
wasi::path_rename(dir_fd, "source/", dir_fd, "target/").expect(
"renaming a directory with a trailing slash in the source and destination names",
);
wasi::path_rename(dir_fd, "target", dir_fd, "source")
.expect("renaming a directory with no trailing slashes at all should work");
wasi::path_remove_directory(dir_fd, "source").expect("removing the directory");
}
}
#[test]
fn test_path_rename() {
init(&[], &[]);
let dir_fd = 3;
unsafe {
wasi::path_create_directory(dir_fd, "source").expect("creating a directory");
wasi::path_rename(dir_fd, "source", dir_fd, "target").expect("renaming a directory");
assert_eq!(
wasi::path_open(dir_fd, 0, "source", wasi::OFLAGS_DIRECTORY, 0, 0, 0)
.expect_err("opening a nonexistent path as a directory should fail"),
wasi::ERRNO_NOENT
);
let mut fd = wasi::path_open(dir_fd, 0, "target", wasi::OFLAGS_DIRECTORY, 0, 0, 0)
.expect("opening renamed path as a directory");
assert!(
fd > libc::STDERR_FILENO as wasi::Fd,
"file descriptor range check",
);
wasi::fd_close(fd).expect("closing a file");
wasi::path_remove_directory(dir_fd, "target").expect("removing a directory");
wasi::path_create_directory(dir_fd, "source").expect("creating a directory");
wasi::path_create_directory(dir_fd, "target").expect("creating a directory");
wasi::path_rename(dir_fd, "source", dir_fd, "target").expect("renaming a directory");
assert_eq!(
wasi::path_open(dir_fd, 0, "source", wasi::OFLAGS_DIRECTORY, 0, 0, 0)
.expect_err("opening a nonexistent path as a directory"),
wasi::ERRNO_NOENT
);
fd = wasi::path_open(dir_fd, 0, "target", wasi::OFLAGS_DIRECTORY, 0, 0, 0)
.expect("opening renamed path as a directory");
assert!(
fd > libc::STDERR_FILENO as wasi::Fd,
"file descriptor range check",
);
wasi::fd_close(fd).expect("closing a file");
wasi::path_remove_directory(dir_fd, "target").expect("removing a directory");
wasi::path_create_directory(dir_fd, "source").expect("creating a directory");
wasi::path_create_directory(dir_fd, "target").expect("creating a directory");
wasi::path_remove_directory(dir_fd, "target").expect("removing a directory");
wasi::path_remove_directory(dir_fd, "source").expect("removing a directory");
wasi::path_create_directory(dir_fd, "source").expect("creating a directory");
wasi::path_create_directory(dir_fd, "target").expect("creating a directory");
create_empty_test_file(dir_fd, "target/file");
assert_eq!(
wasi::path_rename(dir_fd, "source", dir_fd, "target")
.expect_err("renaming directory to a nonempty directory"),
wasi::ERRNO_NOTEMPTY
);
assert_eq!(
wasi::path_rename(dir_fd, "source", dir_fd, "target/file")
.expect_err("renaming a directory to a file"),
wasi::ERRNO_NOTDIR
);
wasi::path_unlink_file(dir_fd, "target/file").expect("removing a file");
wasi::path_remove_directory(dir_fd, "source").expect("removing a directory");
wasi::path_remove_directory(dir_fd, "target").expect("removing a directory");
create_empty_test_file(dir_fd, "source");
wasi::path_rename(dir_fd, "source", dir_fd, "target").expect("renaming a file");
assert_eq!(
wasi::path_open(dir_fd, 0, "source", 0, 0, 0, 0)
.expect_err("opening a nonexistent path should fail"),
wasi::ERRNO_NOENT
);
fd = wasi::path_open(dir_fd, 0, "target", 0, 0, 0, 0).expect("opening renamed path");
assert!(
fd > libc::STDERR_FILENO as wasi::Fd,
"file descriptor range check",
);
wasi::fd_close(fd).expect("closing a file");
wasi::path_unlink_file(dir_fd, "target").expect("removing a file");
create_empty_test_file(dir_fd, "source");
create_empty_test_file(dir_fd, "target");
wasi::path_rename(dir_fd, "source", dir_fd, "target")
.expect("renaming file to another existing file");
assert_eq!(
wasi::path_open(dir_fd, 0, "source", 0, 0, 0, 0)
.expect_err("opening a nonexistent path"),
wasi::ERRNO_NOENT
);
fd = wasi::path_open(dir_fd, 0, "target", 0, 0, 0, 0).expect("opening renamed path");
assert!(
fd > libc::STDERR_FILENO as wasi::Fd,
"file descriptor range check",
);
wasi::fd_close(fd).expect("closing a file");
wasi::path_unlink_file(dir_fd, "target").expect("removing a file");
create_empty_test_file(dir_fd, "source");
wasi::path_create_directory(dir_fd, "target").expect("creating a directory");
assert_eq!(
wasi::path_rename(dir_fd, "source", dir_fd, "target")
.expect_err("renaming a file to existing directory should fail"),
wasi::ERRNO_ACCES,
);
wasi::path_remove_directory(dir_fd, "target").expect("removing a directory");
wasi::path_unlink_file(dir_fd, "source").expect("removing a file");
}
}