How to enable full filesystem access to WASM?
As far as I know, we can use preopened_dir to preopen some directories and give WASM binary a limited filesystem access. However, I can't find a simple way to give the binary a full filesystem access. The following code doesn't work (with wasi-cap-std-sync) on Windows:
WasiCtxBuilder::new().preopened_dir(cap_std::fs::Dir::from_std_file(std::fs::File::open("/")?), "/")?.build()
I would also like a cross-platform way to give full filesystem access.
Could you say more about your use case? What would you like to do that requires using both Wasm and full filesystem access?
I'm writing a software that includes a plugin framework. The plugins are WASM. Some of the plugins need to access files from the user input, and I cannot know about the input before creating the WASM runtime. The design of the software also tries to decouple the host and the plugins, so the host even don't know what the plugins will do. Therefore I need to give full filesystem access to the WASMs. If there are some files the host cannot access, it's OK. I only want to enable the same accessibility as the host runtime.
Some of the plugins need to access files from the user input, and I cannot know about the input before creating the WASM runtime.
Assuming your software has a gui, selecting files likely uses a file dialog presented by the host. You could make the host use wasi_ctx.table().push(Box::new(FileEntry::new(caps, file))) after the user picked a file and then pass the returned fd to the guest I think.
@bjorn3 What about this case: the user input is a JSON with some paths, and the JSON plugin parses the JSON and go to find the files. The host cannot know about the paths except parsing the JSON itself. However the user input may be TOML or XML or YAML besides JSON. The format is defined by plugins but not host. Therefore the host cannot preopen the directory this time.
I see. In that case try something like
let mut builder = WasiCtxBuilder::new();
for drive in some_function_that_lists_all_drives() {
builder.preopened_dir(cap_std::fs::Dir::from_std_file(std::fs::File::open(format!("{drive}:"))?), format!("/{drive}"))?;
}
let ctx = builder.build();
Then you can access C:\foo\bar.txt as /c/foo/bar.txt inside the guest.
A passable solution anyway, but I would appreciate a much prettier one. This solution needs platform-specific code, and the user input path should be change from C:\foo\bar.txt to /c/foo/bar.txt, which may make the following code much more complicated.
@Berrysoft It's a little unclear from your message; is that your actual use case, or is it a hypothetical use case?
@sunfishcode It is nearly the same as my actual use case. In the actual case, the difference between user input is not the format, but the custom (YAML) properties. Only the plugins know the specific property name, and go to find the files. However not all the custom properties are paths, and even the paths are relative ones to other properties, therefore the host runtime cannot try to parse all the values and try to preopen the files.
@Berrysoft Do users know that all the paths will have a common parent directory that isn't a root directory? If so, they could add pre-opens for the parent directory (or directories).
If not, that is indeed something the sandboxing model doesn't handle well. In order to make Wasm components composable with other Wasm components, we're trying to avoid depending on filesystem namespaces being implicitly shared between programs. That's difficult to do if a component expects to read from something on the outside which assumes it's in the same filesystem namespace and can resolve path names.