about summary refs log tree commit diff
path: root/library/std/src/sys
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys')
-rw-r--r--library/std/src/sys/sgx/path.rs7
-rw-r--r--library/std/src/sys/solid/path.rs7
-rw-r--r--library/std/src/sys/unix/path.rs45
-rw-r--r--library/std/src/sys/windows/path.rs16
4 files changed, 72 insertions, 3 deletions
diff --git a/library/std/src/sys/sgx/path.rs b/library/std/src/sys/sgx/path.rs
index 840a7ae0426..9cfc61bf174 100644
--- a/library/std/src/sys/sgx/path.rs
+++ b/library/std/src/sys/sgx/path.rs
@@ -1,5 +1,6 @@
 use crate::ffi::OsStr;
-use crate::path::Prefix;
+use crate::path::{Path, PathBuf, Prefix};
+use crate::sys::unsupported;
 
 #[inline]
 pub fn is_sep_byte(b: u8) -> bool {
@@ -17,3 +18,7 @@ pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
 
 pub const MAIN_SEP_STR: &str = "/";
 pub const MAIN_SEP: char = '/';
+
+pub(crate) fn absolute(_path: &Path) -> io::Result<PathBuf> {
+    unsupported()
+}
diff --git a/library/std/src/sys/solid/path.rs b/library/std/src/sys/solid/path.rs
index 4a14332d499..ed532dc989b 100644
--- a/library/std/src/sys/solid/path.rs
+++ b/library/std/src/sys/solid/path.rs
@@ -1,5 +1,6 @@
 use crate::ffi::OsStr;
-use crate::path::Prefix;
+use crate::path::{Path, PathBuf, Prefix};
+use crate::sys::unsupported;
 
 #[inline]
 pub fn is_sep_byte(b: u8) -> bool {
@@ -17,3 +18,7 @@ pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
 
 pub const MAIN_SEP_STR: &str = "\\";
 pub const MAIN_SEP: char = '\\';
+
+pub(crate) fn absolute(_path: &Path) -> io::Result<PathBuf> {
+    unsupported()
+}
diff --git a/library/std/src/sys/unix/path.rs b/library/std/src/sys/unix/path.rs
index 717add9ec48..1fdabab4598 100644
--- a/library/std/src/sys/unix/path.rs
+++ b/library/std/src/sys/unix/path.rs
@@ -1,5 +1,8 @@
+use crate::env;
 use crate::ffi::OsStr;
-use crate::path::Prefix;
+use crate::io;
+use crate::os::unix::ffi::OsStrExt;
+use crate::path::{Path, PathBuf, Prefix};
 
 #[inline]
 pub fn is_sep_byte(b: u8) -> bool {
@@ -18,3 +21,43 @@ pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
 
 pub const MAIN_SEP_STR: &str = "/";
 pub const MAIN_SEP: char = '/';
+
+/// Make a POSIX path absolute without changing its semantics.
+pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
+    // This is mostly a wrapper around collecting `Path::components`, with
+    // exceptions made where this conflicts with the POSIX specification.
+    // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017
+    // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
+
+    let mut components = path.components();
+    let path_os = path.as_os_str().as_bytes();
+
+    let mut normalized = if path.is_absolute() {
+        // "If a pathname begins with two successive <slash> characters, the
+        // first component following the leading <slash> characters may be
+        // interpreted in an implementation-defined manner, although more than
+        // two leading <slash> characters shall be treated as a single <slash>
+        // character."
+        if path_os.starts_with(b"//") && !path_os.starts_with(b"///") {
+            components.next();
+            PathBuf::from("//")
+        } else {
+            PathBuf::new()
+        }
+    } else {
+        env::current_dir()?
+    };
+    normalized.extend(components);
+
+    // "Interfaces using pathname resolution may specify additional constraints
+    // when a pathname that does not name an existing directory contains at
+    // least one non- <slash> character and contains one or more trailing
+    // <slash> characters".
+    // A trailing <slash> is also meaningful if "a symbolic link is
+    // encountered during pathname resolution".
+    if path_os.ends_with(b"/") {
+        normalized.push("");
+    }
+
+    Ok(normalized)
+}
diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs
index 79e0eaf6c34..e54fcaed495 100644
--- a/library/std/src/sys/windows/path.rs
+++ b/library/std/src/sys/windows/path.rs
@@ -260,3 +260,19 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
     )?;
     Ok(path)
 }
+
+/// Make a Windows path absolute.
+pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
+    if path.as_os_str().bytes().starts_with(br"\\?\") {
+        return Ok(path.into());
+    }
+    let path = to_u16s(path)?;
+    let lpfilename = path.as_ptr();
+    fill_utf16_buf(
+        // SAFETY: `fill_utf16_buf` ensures the `buffer` and `size` are valid.
+        // `lpfilename` is a pointer to a null terminated string that is not
+        // invalidated until after `GetFullPathNameW` returns successfully.
+        |buffer, size| unsafe { c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()) },
+        super::os2path,
+    )
+}