1 use std::{env, process};
2 use wasi_tests::{create_file, open_scratch_directory};
3 
test_truncation_rights(dir_fd: wasi::Fd)4 unsafe fn test_truncation_rights(dir_fd: wasi::Fd) {
5     // Create a file in the scratch directory.
6     create_file(dir_fd, "file");
7 
8     // Get the rights for the scratch directory.
9     let mut dir_fdstat =
10         wasi::fd_fdstat_get(dir_fd).expect("calling fd_fdstat on the scratch directory");
11     assert_eq!(
12         dir_fdstat.fs_filetype,
13         wasi::FILETYPE_DIRECTORY,
14         "expected the scratch directory to be a directory",
15     );
16     assert_eq!(
17         dir_fdstat.fs_flags, 0,
18         "expected the scratch directory to have no special flags",
19     );
20     assert_eq!(
21         dir_fdstat.fs_rights_base & wasi::RIGHTS_FD_FILESTAT_SET_SIZE,
22         0,
23         "directories shouldn't have the fd_filestat_set_size right",
24     );
25 
26     // If we have the right to set sizes from paths, test that it works.
27     if (dir_fdstat.fs_rights_base & wasi::RIGHTS_PATH_FILESTAT_SET_SIZE) == 0 {
28         eprintln!("implementation doesn't support setting file sizes, skipping");
29     } else {
30         // Test that we can truncate the file.
31         let mut file_fd = wasi::path_open(dir_fd, 0, "file", wasi::OFLAGS_TRUNC, 0, 0, 0)
32             .expect("truncating a file");
33         wasi::fd_close(file_fd).expect("closing a file");
34 
35         let mut rights_base: wasi::Rights = dir_fdstat.fs_rights_base;
36         let mut rights_inheriting: wasi::Rights = dir_fdstat.fs_rights_inheriting;
37 
38         if (rights_inheriting & wasi::RIGHTS_FD_FILESTAT_SET_SIZE) == 0 {
39             eprintln!("implementation doesn't support setting file sizes through file descriptors, skipping");
40         } else {
41             rights_inheriting &= !wasi::RIGHTS_FD_FILESTAT_SET_SIZE;
42             wasi::fd_fdstat_set_rights(dir_fd, rights_base, rights_inheriting)
43                 .expect("droping fd_filestat_set_size inheriting right on a directory");
44         }
45 
46         // Test that we can truncate the file without the
47         // wasi_unstable::RIGHT_FD_FILESTAT_SET_SIZE right.
48         file_fd = wasi::path_open(dir_fd, 0, "file", wasi::OFLAGS_TRUNC, 0, 0, 0)
49             .expect("truncating a file without fd_filestat_set_size right");
50         wasi::fd_close(file_fd).expect("closing a file");
51 
52         rights_base &= !wasi::RIGHTS_PATH_FILESTAT_SET_SIZE;
53         wasi::fd_fdstat_set_rights(dir_fd, rights_base, rights_inheriting)
54             .expect("droping path_filestat_set_size base right on a directory");
55 
56         // Test that clearing wasi_unstable::RIGHT_PATH_FILESTAT_SET_SIZE actually
57         // took effect.
58         dir_fdstat = wasi::fd_fdstat_get(dir_fd).expect("reading the fdstat from a directory");
59         assert_eq!(
60             (dir_fdstat.fs_rights_base & wasi::RIGHTS_PATH_FILESTAT_SET_SIZE),
61             0,
62             "reading the fdstat from a directory",
63         );
64 
65         // Test that we can't truncate the file without the
66         // wasi_unstable::RIGHT_PATH_FILESTAT_SET_SIZE right.
67         assert_eq!(
68             wasi::path_open(dir_fd, 0, "file", wasi::OFLAGS_TRUNC, 0, 0, 0)
69                 .expect_err("truncating a file without path_filestat_set_size right")
70                 .raw_error(),
71             wasi::ERRNO_NOTCAPABLE,
72             "errno should be ERRNO_NOTCAPABLE",
73         );
74     }
75 
76     wasi::path_unlink_file(dir_fd, "file").expect("removing a file");
77 }
78 
main()79 fn main() {
80     let mut args = env::args();
81     let prog = args.next().unwrap();
82     let arg = if let Some(arg) = args.next() {
83         arg
84     } else {
85         eprintln!("usage: {} <scratch directory>", prog);
86         process::exit(1);
87     };
88 
89     // Open scratch directory
90     let dir_fd = match open_scratch_directory(&arg) {
91         Ok(dir_fd) => dir_fd,
92         Err(err) => {
93             eprintln!("{}", err);
94             process::exit(1)
95         }
96     };
97 
98     // Run the tests.
99     unsafe { test_truncation_rights(dir_fd) }
100 }
101