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::{assert_errno, open_scratch_directory};
5
test_nofollow_errors(dir_fd: wasip1::Fd)6 unsafe fn test_nofollow_errors(dir_fd: wasip1::Fd) {
7 // Create a directory for the symlink to point to.
8 wasip1::path_create_directory(dir_fd, "target").expect("creating a dir");
9
10 // Create a symlink.
11 wasip1::path_symlink("target", dir_fd, "symlink").expect("creating a symlink");
12
13 // Try to open it as a directory with O_NOFOLLOW again.
14 assert_errno!(
15 wasip1::path_open(dir_fd, 0, "symlink", wasip1::OFLAGS_DIRECTORY, 0, 0, 0)
16 .expect_err("opening a directory symlink as a directory should fail"),
17 wasip1::ERRNO_LOOP,
18 wasip1::ERRNO_NOTDIR
19 );
20
21 // Try to open it with just O_NOFOLLOW.
22 assert_errno!(
23 wasip1::path_open(dir_fd, 0, "symlink", 0, 0, 0, 0)
24 .expect_err("opening a symlink with O_NOFOLLOW should fail"),
25 wasip1::ERRNO_LOOP,
26 wasip1::ERRNO_ACCES
27 );
28
29 // Try to open it as a directory without O_NOFOLLOW.
30 let file_fd = wasip1::path_open(
31 dir_fd,
32 wasip1::LOOKUPFLAGS_SYMLINK_FOLLOW,
33 "symlink",
34 wasip1::OFLAGS_DIRECTORY,
35 0,
36 0,
37 0,
38 )
39 .expect("opening a symlink as a directory");
40 assert!(
41 file_fd > libc::STDERR_FILENO as wasip1::Fd,
42 "file descriptor range check",
43 );
44 wasip1::fd_close(file_fd).expect("closing a file");
45
46 // Replace the target directory with a file.
47 wasip1::path_unlink_file(dir_fd, "symlink").expect("removing a file");
48 wasip1::path_remove_directory(dir_fd, "target")
49 .expect("remove_directory on a directory should succeed");
50
51 let file_fd = wasip1::path_open(dir_fd, 0, "target", wasip1::OFLAGS_CREAT, 0, 0, 0)
52 .expect("creating a file");
53 wasip1::fd_close(file_fd).expect("closing a file");
54 wasip1::path_symlink("target", dir_fd, "symlink").expect("creating a symlink");
55
56 // Try to open it as a directory with O_NOFOLLOW again.
57 assert_errno!(
58 wasip1::path_open(dir_fd, 0, "symlink", wasip1::OFLAGS_DIRECTORY, 0, 0, 0)
59 .expect_err("opening a directory symlink as a directory should fail"),
60 wasip1::ERRNO_LOOP,
61 wasip1::ERRNO_NOTDIR
62 );
63
64 // Try to open it with just O_NOFOLLOW.
65 assert_errno!(
66 wasip1::path_open(dir_fd, 0, "symlink", 0, 0, 0, 0)
67 .expect_err("opening a symlink with NOFOLLOW should fail"),
68 wasip1::ERRNO_LOOP
69 );
70
71 // Try to open it as a directory without O_NOFOLLOW.
72 assert_errno!(
73 wasip1::path_open(
74 dir_fd,
75 wasip1::LOOKUPFLAGS_SYMLINK_FOLLOW,
76 "symlink",
77 wasip1::OFLAGS_DIRECTORY,
78 0,
79 0,
80 0,
81 )
82 .expect_err("opening a symlink to a file as a directory"),
83 wasip1::ERRNO_NOTDIR
84 );
85
86 // Clean up.
87 wasip1::path_unlink_file(dir_fd, "target").expect("removing a file");
88 wasip1::path_unlink_file(dir_fd, "symlink").expect("removing a file");
89 }
90
main()91 fn main() {
92 let mut args = env::args();
93 let prog = args.next().unwrap();
94 let arg = if let Some(arg) = args.next() {
95 arg
96 } else {
97 eprintln!("usage: {prog} <scratch directory>");
98 process::exit(1);
99 };
100
101 // Open scratch directory
102 let dir_fd = match open_scratch_directory(&arg) {
103 Ok(dir_fd) => dir_fd,
104 Err(err) => {
105 eprintln!("{err}");
106 process::exit(1)
107 }
108 };
109
110 // Run the tests.
111 unsafe { test_nofollow_errors(dir_fd) }
112 }
113