std/sys/path/unix.rs
1use crate::ffi::OsStr;
2use crate::path::{Path, PathBuf, Prefix};
3use crate::{env, io};
4
5path_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 cfg!(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}