Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support Windows Device Paths in WASI (#766)
Turns out that Windows paths are very complicated. There's all sorts of relative paths and various device paths and UNC paths. Here's a TL;DR of how it all works: 1. Win32 paths may be in one of various relative forms that depend on hidden environment variables, such as `C:\Windows` (absolute on C drive), `Windows\System32\user32.dll` (relative to current dir on current drive), `C:Windows` (relative to current dir on C drive), or `\Windows` (absolute on current drive). There's also `\\server\share` paths that are called UNC paths. 2. These paths then get converted into a form that's rooted in a device (called device path) starting with `\\.\` followed by a device name. UNC paths get mapped to `\\.\UNC\server\share`. If a reserved device is part of the path, it takes precedence and becomes the device path (`C:\some\dir\COM1.txt` -> `\\.\COM1`). 3. The paths then get normalized / canonicalized (forward slashes converted, .. and . resolved, some spaces and dots get removed) into the `\\?\` form (normalized device path). Because this is the step that replaces forward slashes by backward slashes, all previous forms mentioned may use forward slashes instead. `Path::canonicalize` handles all three steps, meaning a path returned by it starts with `\\?\` and skips all these three steps when used. 4. The `\\?\` form gets passed almost directly to NT, though it gets replaced with `\??\`. At this point it is an NT path. The NT path `\??\` matches `\GLOBAL??\` where the devices are then looked up. The device names may actually be "symbolic links" in the NT object namespace to other devices (so a symbolic link from one NT path to another). So for example `C:` is actually a symbolic link at `\GLOBAL??\C:` to `\Device\HarddiskVolume1` (or any other number). Various other forms of NT paths are also possible, but you can't get to them from a Win32 path (except via the device symlink called `GLOBALROOT`). The driver is then chosen based on the device that it resolves to. Depending on what kind of Win32 path you have, you may skip some of the steps on the way. References: - https://chrisdenton.github.io/omnipath/ - https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html - https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file - https://stackoverflow.com/a/46019856 - https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats - https://medium.com/walmartglobaltech/dos-file-path-magic-tricks-5eda7a7a85fa - https://reverseengineering.stackexchange.com/a/3799 We now map the `\\?\` paths, which are the lowest level before the NT paths directly to `/mnt/device` in WASI. This should allow you to access everything that's currently not accessible.
- Loading branch information