Skip to main content

std/sys/path/
unix.rs

1use crate::ffi::OsStr;
2use crate::path::{Path, PathBuf, Prefix};
3use crate::{env, io};
4
5pub const SEPARATORS: &[char] = &[b'/' as char];
pub const SEPARATORS_STR: &[&str] =
    &[match str::from_utf8(&[b'/']) {
                    Ok(s) => s,
                    Err(_) => {
                        ::core::panicking::panic_fmt(format_args!("path_separator_bytes must be ASCII bytes"));
                    }
                }];
#[inline]
pub const fn is_sep_byte(b: u8) -> bool { b == b'/' }path_separator_bytes!(b'/');
6
7#[inline]
8pub const fn is_verbatim_sep(b: u8) -> bool {
9    is_sep_byte(b)
10}
11
12#[inline]
13pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
14    None
15}
16
17pub const HAS_PREFIXES: bool = false;
18
19/// Make a POSIX path absolute without changing its semantics.
20pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
21    // This is mostly a wrapper around collecting `Path::components`, with
22    // exceptions made where this conflicts with the POSIX specification.
23    // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017
24    // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
25
26    // Get the components, skipping the redundant leading "." component if it exists.
27    let mut components = path.strip_prefix(".").unwrap_or(path).components();
28    let path_os = path.as_os_str().as_encoded_bytes();
29
30    let mut normalized = if path.is_absolute() {
31        // "If a pathname begins with two successive <slash> characters, the
32        // first component following the leading <slash> characters may be
33        // interpreted in an implementation-defined manner, although more than
34        // two leading <slash> characters shall be treated as a single <slash>
35        // character."
36        if path_os.starts_with(b"//") && !path_os.starts_with(b"///") {
37            components.next();
38            PathBuf::from("//")
39        } else {
40            PathBuf::new()
41        }
42    } else {
43        env::current_dir()?
44    };
45    normalized.extend(components);
46
47    // "Interfaces using pathname resolution may specify additional constraints
48    // when a pathname that does not name an existing directory contains at
49    // least one non- <slash> character and contains one or more trailing
50    // <slash> characters".
51    // A trailing <slash> is also meaningful if "a symbolic link is
52    // encountered during pathname resolution".
53    if path_os.ends_with(b"/") {
54        normalized.push("");
55    }
56
57    Ok(normalized)
58}
59
60pub(crate) fn is_absolute(path: &Path) -> bool {
61    if truecfg!(any(unix, target_os = "hermit", target_os = "wasi", target_os = "motor")) {
62        path.has_root()
63    } else {
64        path.has_root() && path.prefix().is_some()
65    }
66}