Skip to content

Correcting Path::components on non-"Unix" platforms #52331

Open
@jackpot51

Description

@jackpot51

Path::components is incorrect on Redox. I would like to develop the solution
here: #51537.

The following is a description of the problem.

Suppose you have the following path:

file:/home/user/foo/bar.txt

You split the path into components using Path::components

Path::new("file:/home/user/foo/bar.txt").components().collect::<Vec<()>>()

In Linux, this would be equivalent to the following:

vec![
    Component::Normal("file:"),
    Component::Normal("home"),
    Component::Normal("user"),
    Component::Normal("foo"),
    Component::Normal("bar.txt"),
]

Joining the components with the current directory would give you a path such as
this:

./file:/home/user/foo/bar.txt

In Redox, we want to be able to get from the original path to components back to
the original path without any modifications. Here are examples of this usage of
Path::components:

https://github.com/uutils/coreutils/search?q=components

In Redox, we have the following options for the file: component:

  1. Component::Normal("file:")
  2. Component::Normal("file:") followed by Component::RootDir
  3. Component::Prefix(Prefix::Verbatim("file:"))
  4. Component::Prefix(Prefix::Scheme("file:"))

Option 1

Component::Normal("file:")

The path mentioned above would end up being the following after being rebuilt
from its components:

./file:/home/user/foo/bar.txt

This is the old way of doing things. It not only makes Path::components
useless on Redox. Canonicalizing a path will always add a scheme like file:
to the beginning, so it is likely that path handling will be incorrect.
Absolute paths would always be interpreted as relative.

❌ This option is unusable for Redox.

Option 2

Component::Normal("file:") followed by Component::RootDir

This would preserve the original meaning of the path, such that it could be
rebuilt from its components as follows:

file:/home/user/foo/bar.txt

However, this may require a large amount of work to handle, as it seems likely
that code exists that only checks the first component for being
Component::RootDir or Component::Prefix in order to identify an absolute
path.

The documentation for Prefix provides one such example, which has likely
inspired similar usage:

https://doc.rust-lang.org/std/path/enum.Prefix.html#examples

❌ This option would likely break the expectations of many consumers of the
Prefix enum.

Option 3

Component::Prefix(Prefix::Verbatim("file:"))

This option preserves the original meaning of the path, a rebuilt path would be
this:

file:/home/user/foo/bar.txt

This, however, is overloading a variant meant to be used on Windows, for a path
looking like this:

\\?\home\user\foo\bar.txt

This means different code will be needed when running on Redox to correctly
parse paths to components and turn components into paths.

✔️ This does leave the enum untouched, while allowing for the
correct parsing of paths on Redox. The only downside is a possible lack of
clarity due to overloading the meaning of the Prefix::Verbatim variant.

Option 4

Component::Prefix(Prefix::Scheme("file:"))

This option also preserves the original meaning of the path, a rebuilt path
would be this:

file:/home/user/foo/bar.txt

This is the most clear option, having separate code to handle specifically the
Redox scheme abstraction.

This has the downside of changing a stable enum, Prefix. There is, however,
the possibility of having the extra enum variant be
#[cfg(target_os = "redox")], so as to preserve the Prefix enum on other
platforms.

✔️ This option could be used to have correct path parsing
without affecting the stability of the Prefix enum on non-Redox platforms,
if a cfg attribute is used.

Conclusion

Potentially the Prefix enum would be done different after a major version bump,
perhaps using extension traits that are platform specific. I would think that
there would be an opaque Prefix struct, and something like .into_os_prefix()
would provide you with an os-specific enum to match against.

For the time being, options 3 and 4 seem to be possible, with some caveats, and
would allow code using stable Rust to quickly do-the-right-thing on Redox.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ioArea: `std::io`, `std::fs`, `std::net` and `std::path`C-bugCategory: This is a bug.O-UEFIUEFIO-nintendo3dsTarget: ninTENdoooooO-windowsOperating system: WindowsT-libsRelevant to the library team, which will review and decide on the PR/issue.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions