1 #![expect(unsafe_op_in_unsafe_fn, reason = "old code, not worth updating yet")]
2
3 use std::{env, process};
4 use test_programs::preview1::open_scratch_directory;
5
test_file_read_write(dir_fd: wasip1::Fd)6 unsafe fn test_file_read_write(dir_fd: wasip1::Fd) {
7 // Create a file in the scratch directory.
8 let file_fd = wasip1::path_open(
9 dir_fd,
10 0,
11 "file",
12 wasip1::OFLAGS_CREAT,
13 wasip1::RIGHTS_FD_READ | wasip1::RIGHTS_FD_WRITE,
14 0,
15 0,
16 )
17 .expect("opening a file");
18 assert!(
19 file_fd > libc::STDERR_FILENO as wasip1::Fd,
20 "file descriptor range check",
21 );
22
23 let contents = &[0u8, 1, 2, 3];
24 let ciovec = wasip1::Ciovec {
25 buf: contents.as_ptr() as *const _,
26 buf_len: contents.len(),
27 };
28 let mut nwritten = wasip1::fd_write(file_fd, &[ciovec]).expect("writing bytes at offset 0");
29 assert_eq!(nwritten, 4, "nwritten bytes check");
30
31 let contents = &mut [0u8; 4];
32 let iovec = wasip1::Iovec {
33 buf: contents.as_mut_ptr() as *mut _,
34 buf_len: contents.len(),
35 };
36 wasip1::fd_seek(file_fd, 0, wasip1::WHENCE_SET).expect("seeking to offset 0");
37 let mut nread = wasip1::fd_read(file_fd, &[iovec]).expect("reading bytes at offset 0");
38 assert_eq!(nread, 4, "nread bytes check");
39 assert_eq!(contents, &[0u8, 1, 2, 3], "written bytes equal read bytes");
40
41 // Write all the data through multiple iovecs.
42 //
43 // Note that this needs to be done with a loop, because some
44 // platforms do not support writing multiple iovecs at once.
45 // See https://github.com/rust-lang/rust/issues/74825.
46 let contents = &[0u8, 1, 2, 3];
47 let mut offset = 0usize;
48 wasip1::fd_seek(file_fd, 0, wasip1::WHENCE_SET).expect("seeking to offset 0");
49 loop {
50 let mut ciovecs: Vec<wasip1::Ciovec> = Vec::new();
51 let mut remaining = contents.len() - offset;
52 if remaining > 2 {
53 ciovecs.push(wasip1::Ciovec {
54 buf: contents[offset..].as_ptr() as *const _,
55 buf_len: 2,
56 });
57 remaining -= 2;
58 }
59 ciovecs.push(wasip1::Ciovec {
60 buf: contents[contents.len() - remaining..].as_ptr() as *const _,
61 buf_len: remaining,
62 });
63
64 nwritten =
65 wasip1::fd_write(file_fd, ciovecs.as_slice()).expect("writing bytes at offset 0");
66
67 offset += nwritten;
68 if offset == contents.len() {
69 break;
70 }
71 }
72 assert_eq!(offset, 4, "nread bytes check");
73
74 // Read all the data through multiple iovecs.
75 //
76 // Note that this needs to be done with a loop, because some
77 // platforms do not support reading multiple iovecs at once.
78 // See https://github.com/rust-lang/rust/issues/74825.
79 let contents = &mut [0u8; 4];
80 let mut offset = 0usize;
81 wasip1::fd_seek(file_fd, 0, wasip1::WHENCE_SET).expect("seeking to offset 0");
82 loop {
83 let buffer = &mut [0u8; 4];
84 let iovecs = &[
85 wasip1::Iovec {
86 buf: buffer.as_mut_ptr() as *mut _,
87 buf_len: 2,
88 },
89 wasip1::Iovec {
90 buf: buffer[2..].as_mut_ptr() as *mut _,
91 buf_len: 2,
92 },
93 ];
94 nread = wasip1::fd_read(file_fd, iovecs).expect("reading bytes at offset 0");
95 if nread == 0 {
96 break;
97 }
98 contents[offset..offset + nread].copy_from_slice(&buffer[0..nread]);
99 offset += nread;
100 }
101 assert_eq!(offset, 4, "nread bytes check");
102 assert_eq!(contents, &[0u8, 1, 2, 3], "file cursor was overwritten");
103
104 let contents = &mut [0u8; 4];
105 let iovec = wasip1::Iovec {
106 buf: contents.as_mut_ptr() as *mut _,
107 buf_len: contents.len(),
108 };
109 wasip1::fd_seek(file_fd, 2, wasip1::WHENCE_SET).expect("seeking to offset 2");
110 nread = wasip1::fd_read(file_fd, &[iovec]).expect("reading bytes at offset 2");
111 assert_eq!(nread, 2, "nread bytes check");
112 assert_eq!(contents, &[2u8, 3, 0, 0], "file cursor was overwritten");
113
114 let contents = &[1u8, 0];
115 let ciovec = wasip1::Ciovec {
116 buf: contents.as_ptr() as *const _,
117 buf_len: contents.len(),
118 };
119 wasip1::fd_seek(file_fd, 2, wasip1::WHENCE_SET).expect("seeking to offset 2");
120 nwritten = wasip1::fd_write(file_fd, &[ciovec]).expect("writing bytes at offset 2");
121 assert_eq!(nwritten, 2, "nwritten bytes check");
122
123 let contents = &mut [0u8; 4];
124 let iovec = wasip1::Iovec {
125 buf: contents.as_mut_ptr() as *mut _,
126 buf_len: contents.len(),
127 };
128 wasip1::fd_seek(file_fd, 0, wasip1::WHENCE_SET).expect("seeking to offset 0");
129 nread = wasip1::fd_read(file_fd, &[iovec]).expect("reading bytes at offset 0");
130 assert_eq!(nread, 4, "nread bytes check");
131 assert_eq!(contents, &[0u8, 1, 1, 0], "file cursor was overwritten");
132
133 wasip1::fd_close(file_fd).expect("closing a file");
134 wasip1::path_unlink_file(dir_fd, "file").expect("removing a file");
135 }
136
test_file_write_and_file_pos(dir_fd: wasip1::Fd)137 unsafe fn test_file_write_and_file_pos(dir_fd: wasip1::Fd) {
138 let path = "file2";
139 let file_fd = wasip1::path_open(
140 dir_fd,
141 0,
142 path,
143 wasip1::OFLAGS_CREAT,
144 wasip1::RIGHTS_FD_READ | wasip1::RIGHTS_FD_WRITE,
145 0,
146 0,
147 )
148 .expect("opening a file");
149 assert!(
150 file_fd > libc::STDERR_FILENO as wasip1::Fd,
151 "file descriptor range check",
152 );
153
154 // Perform a 0-sized pwrite at an offset beyond the end of the file. Unix
155 // semantics should pop out where nothing is actually written and the size
156 // of the file isn't modified.
157 assert_eq!(wasip1::fd_tell(file_fd).unwrap(), 0);
158 let ciovec = wasip1::Ciovec {
159 buf: [].as_ptr(),
160 buf_len: 0,
161 };
162 wasip1::fd_seek(file_fd, 2, wasip1::WHENCE_SET).expect("seeking to offset 2");
163 let n = wasip1::fd_write(file_fd, &[ciovec]).expect("writing bytes at offset 2");
164 assert_eq!(n, 0);
165
166 assert_eq!(wasip1::fd_tell(file_fd).unwrap(), 2);
167 let stat = wasip1::fd_filestat_get(file_fd).unwrap();
168 assert_eq!(stat.size, 0);
169
170 // Now write a single byte and make sure it actually works
171 let buf = [0];
172 let ciovec = wasip1::Ciovec {
173 buf: buf.as_ptr(),
174 buf_len: buf.len(),
175 };
176 wasip1::fd_seek(file_fd, 50, wasip1::WHENCE_SET).expect("seeking to offset 50");
177 let n = wasip1::fd_write(file_fd, &[ciovec]).expect("writing bytes at offset 50");
178 assert_eq!(n, 1);
179
180 assert_eq!(wasip1::fd_tell(file_fd).unwrap(), 51);
181 let stat = wasip1::fd_filestat_get(file_fd).unwrap();
182 assert_eq!(stat.size, 51);
183
184 wasip1::fd_close(file_fd).expect("closing a file");
185 wasip1::path_unlink_file(dir_fd, path).expect("removing a file");
186 }
187
main()188 fn main() {
189 let mut args = env::args();
190 let prog = args.next().unwrap();
191 let arg = if let Some(arg) = args.next() {
192 arg
193 } else {
194 eprintln!("usage: {prog} <scratch directory>");
195 process::exit(1);
196 };
197
198 // Open scratch directory
199 let dir_fd = match open_scratch_directory(&arg) {
200 Ok(dir_fd) => dir_fd,
201 Err(err) => {
202 eprintln!("{err}");
203 process::exit(1)
204 }
205 };
206
207 // Run the tests.
208 unsafe {
209 test_file_read_write(dir_fd);
210 test_file_write_and_file_pos(dir_fd);
211 }
212 }
213