diff options
| author | bors <bors@rust-lang.org> | 2022-02-13 12:03:52 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-02-13 12:03:52 +0000 |
| commit | 1f4681ad7a132755452c32a987ad0f0d075aa6aa (patch) | |
| tree | 078e06add300f2bacb4b586e544f391bb9583f63 /library/std/src/sys | |
| parent | c26fbf857f82b2d0cb919c633ba0e3a90e5b9426 (diff) | |
| parent | 81cc3afe20d994d9c7cba4e75c3eed92bf98a402 (diff) | |
| download | rust-1f4681ad7a132755452c32a987ad0f0d075aa6aa.tar.gz rust-1f4681ad7a132755452c32a987ad0f0d075aa6aa.zip | |
Auto merge of #91673 - ChrisDenton:path-absolute, r=Mark-Simulacrum
`std::path::absolute` Implements #59117 by adding a `std::path::absolute` function that creates an absolute path without reading the filesystem. This is intended to be a drop-in replacement for [`std::fs::canonicalize`](https://doc.rust-lang.org/std/fs/fn.canonicalize.html) in cases where it isn't necessary to resolve symlinks. It can be used on paths that don't exist or where resolving symlinks is unwanted. It can also be used to avoid circumstances where `canonicalize` might otherwise fail. On Windows this is a wrapper around [`GetFullPathNameW`](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew). On Unix it partially implements the POSIX [pathname resolution](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13) specification, stopping just short of actually resolving symlinks.
Diffstat (limited to 'library/std/src/sys')
| -rw-r--r-- | library/std/src/sys/sgx/path.rs | 8 | ||||
| -rw-r--r-- | library/std/src/sys/solid/path.rs | 8 | ||||
| -rw-r--r-- | library/std/src/sys/unix/path.rs | 44 | ||||
| -rw-r--r-- | library/std/src/sys/windows/path.rs | 16 |
4 files changed, 73 insertions, 3 deletions
diff --git a/library/std/src/sys/sgx/path.rs b/library/std/src/sys/sgx/path.rs index 840a7ae0426..c805c15e702 100644 --- a/library/std/src/sys/sgx/path.rs +++ b/library/std/src/sys/sgx/path.rs @@ -1,5 +1,7 @@ use crate::ffi::OsStr; -use crate::path::Prefix; +use crate::io; +use crate::path::{Path, PathBuf, Prefix}; +use crate::sys::unsupported; #[inline] pub fn is_sep_byte(b: u8) -> bool { @@ -17,3 +19,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..7045c9be25b 100644 --- a/library/std/src/sys/solid/path.rs +++ b/library/std/src/sys/solid/path.rs @@ -1,5 +1,7 @@ use crate::ffi::OsStr; -use crate::path::Prefix; +use crate::io; +use crate::path::{Path, PathBuf, Prefix}; +use crate::sys::unsupported; #[inline] pub fn is_sep_byte(b: u8) -> bool { @@ -17,3 +19,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..6d6f4c8b8dc 100644 --- a/library/std/src/sys/unix/path.rs +++ b/library/std/src/sys/unix/path.rs @@ -1,5 +1,7 @@ +use crate::env; use crate::ffi::OsStr; -use crate::path::Prefix; +use crate::io; +use crate::path::{Path, PathBuf, Prefix}; #[inline] pub fn is_sep_byte(b: u8) -> bool { @@ -18,3 +20,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().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, + ) +} |
