Create a `cm::PathResolver` helper to compute normalized paths.
Provide a common implementation with compile-time dispatch to
select details w.r.t. symbolic links, existence, and matching
the on-disk case of existing paths. Later we can use this to
implement:
* `ToNormalizedPathOnDisk`: Normalizes paths while resolving symlinks
only when followed by `..` components. Does not require paths to
exist, but reads on-disk case of paths that do exist (on Windows).
* `GetRealPath`: Normalizes paths while resolving all symlinks.
Requires paths to exist, and reads their on-disk case (on Windows).
* `CollapseFullPath`: Normalizes paths in memory without disk access.
Assumes components followed by `..` components are not symlinks.
Abstract filesystem access through runtime dispatch so that we can test
Windows symbolic link and network path behavior without relying on real
environments. The overhead of runtime dispatch should be insignificant
during real filesystem access.
Issue: #16228
Issue: #17206