Skip to content

Commit 869e215

Browse files
committed
wasi:filesystem@0.3.0-rc-2025-09-16: Add tests for symbolic links
1 parent 0df2144 commit 869e215

File tree

2 files changed

+118
-0
lines changed

2 files changed

+118
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"dirs": ["fs-tests.dir"]
3+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use std::process;
2+
extern crate wit_bindgen;
3+
4+
wit_bindgen::generate!({
5+
inline: r"
6+
package test:test;
7+
8+
world test {
9+
include wasi:filesystem/imports@0.3.0-rc-2025-09-16;
10+
include wasi:cli/command@0.3.0-rc-2025-09-16;
11+
}
12+
",
13+
additional_derives: [PartialEq, Eq, Hash, Clone],
14+
// Work around https://github.com/bytecodealliance/wasm-tools/issues/2285.
15+
features:["clocks-timezone"],
16+
generate_all
17+
});
18+
19+
use wasi::filesystem::types::Descriptor;
20+
use wasi::filesystem::types::{DescriptorFlags, ErrorCode, OpenFlags, PathFlags};
21+
22+
async fn test_symbolic_links(dir: &Descriptor) {
23+
let ln_s = |from: &str, to: &str| -> _ { dir.symlink_at(from.to_string(), to.to_string()) };
24+
let readlink = |path: &str| dir.readlink_at(path.to_string());
25+
let stat_with_flags = |flags: PathFlags, path: &str| dir.stat_at(flags, path.to_string());
26+
let stat_follow = |path: &str| stat_with_flags(PathFlags::SYMLINK_FOLLOW, path);
27+
let open_r_follow = |path: &str| -> _ {
28+
dir.open_at(
29+
PathFlags::SYMLINK_FOLLOW,
30+
path.to_string(),
31+
OpenFlags::empty(),
32+
DescriptorFlags::READ,
33+
)
34+
};
35+
let open_r = |path: &str| -> _ {
36+
dir.open_at(
37+
PathFlags::empty(),
38+
path.to_string(),
39+
OpenFlags::empty(),
40+
DescriptorFlags::READ,
41+
)
42+
};
43+
let rm = |path: &str| dir.unlink_file_at(path.to_string());
44+
45+
// readlink-at: async func(path: string) -> result<string, error-code>;
46+
assert_eq!(readlink("").await, Err(ErrorCode::NoEntry));
47+
assert_eq!(readlink(".").await, Err(ErrorCode::Invalid));
48+
assert_eq!(readlink("a.txt").await, Err(ErrorCode::Invalid));
49+
assert_eq!(readlink("z.txt").await, Err(ErrorCode::NoEntry));
50+
assert_eq!(readlink("./../").await, Err(ErrorCode::NotPermitted));
51+
assert_eq!(readlink("..").await, Err(ErrorCode::NotPermitted));
52+
assert_eq!(readlink("/").await, Err(ErrorCode::NotPermitted));
53+
assert_eq!(readlink("parent").await, Ok("..".to_string()));
54+
55+
let afd = open_r("a.txt").await.unwrap();
56+
assert_eq!(
57+
afd.readlink_at(".".to_string()).await,
58+
Err(ErrorCode::NotDirectory)
59+
);
60+
61+
// https://github.com/WebAssembly/wasi-filesystem/issues/186
62+
assert_eq!(
63+
open_r("parent")
64+
.await
65+
.expect_err("open symlink with NOFOLLOW"),
66+
ErrorCode::Loop
67+
);
68+
69+
ln_s("parent", "parent-link").await.unwrap();
70+
assert_eq!(open_r("parent-link").await.unwrap_err(), ErrorCode::Loop);
71+
assert_eq!(
72+
open_r_follow("parent-link").await.unwrap_err(),
73+
ErrorCode::NotPermitted
74+
);
75+
assert_eq!(
76+
stat_follow("parent-link").await.unwrap_err(),
77+
ErrorCode::NotPermitted
78+
);
79+
assert_eq!(open_r("parent-link").await.unwrap_err(), ErrorCode::Loop);
80+
assert_eq!(
81+
ln_s("a.txt", "parent-link/a.txt").await,
82+
Err(ErrorCode::NotPermitted)
83+
);
84+
rm("parent-link").await.unwrap();
85+
86+
ln_s("self", "self").await.unwrap();
87+
assert_eq!(open_r_follow("self").await.unwrap_err(), ErrorCode::Loop);
88+
assert_eq!(stat_follow("self").await.unwrap_err(), ErrorCode::Loop);
89+
rm("self").await.unwrap();
90+
91+
assert_eq!(ln_s("whatever", "").await, Err(ErrorCode::NoEntry));
92+
assert_eq!(ln_s("", "whatever").await, Err(ErrorCode::NoEntry));
93+
// symlink-at: async func(old-path: string, new-path: string) -> result<_, error-code>;
94+
}
95+
96+
struct Component;
97+
export!(Component);
98+
impl exports::wasi::cli::run::Guest for Component {
99+
async fn run() -> Result<(), ()> {
100+
match &wasi::filesystem::preopens::get_directories()[..] {
101+
[(dir, dirname)] if dirname == "fs-tests.dir" => {
102+
test_symbolic_links(dir).await;
103+
}
104+
[..] => {
105+
eprintln!("usage: run with one open dir named 'fs-tests.dir'");
106+
process::exit(1)
107+
}
108+
};
109+
Ok(())
110+
}
111+
}
112+
113+
fn main() {
114+
unreachable!("main is a stub");
115+
}

0 commit comments

Comments
 (0)