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 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 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