println!("\n\n{}\n\n", s);
std::process::exit(1);
}
+
+/// Copied from `std::path::absolute` until it stabilizes.
+///
+/// FIXME: this shouldn't exist.
+pub(crate) fn absolute(path: &Path) -> PathBuf {
+ if path.as_os_str().is_empty() {
+ panic!("can't make empty path absolute");
+ }
+ #[cfg(unix)]
+ {
+ t!(absolute_unix(path), format!("could not make path absolute: {}", path.display()))
+ }
+ #[cfg(windows)]
+ {
+ t!(absolute_windows(path), format!("could not make path absolute: {}", path.display()))
+ }
+ #[cfg(not(any(unix, windows)))]
+ {
+ println!("warning: bootstrap is not supported on non-unix platforms");
+ t!(std::fs::canonicalize(t!(std::env::current_dir()))).join(path)
+ }
+}
+
+#[cfg(unix)]
+/// Make a POSIX path absolute without changing its semantics.
+fn absolute_unix(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
+
+ use std::os::unix::prelude::OsStrExt;
+ 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)
+}
+
+#[cfg(windows)]
+fn absolute_windows(path: &std::path::Path) -> std::io::Result<std::path::PathBuf> {
+ use std::ffi::OsString;
+ use std::io::Error;
+ use std::os::windows::ffi::{OsStrExt, OsStringExt};
+ use std::ptr::null_mut;
+ #[link(name = "kernel32")]
+ extern "system" {
+ fn GetFullPathNameW(
+ lpFileName: *const u16,
+ nBufferLength: u32,
+ lpBuffer: *mut u16,
+ lpFilePart: *mut *const u16,
+ ) -> u32;
+ }
+
+ unsafe {
+ // encode the path as UTF-16
+ let path: Vec<u16> = path.as_os_str().encode_wide().chain([0]).collect();
+ let mut buffer = Vec::new();
+ // Loop until either success or failure.
+ loop {
+ // Try to get the absolute path
+ let len = GetFullPathNameW(
+ path.as_ptr(),
+ buffer.len().try_into().unwrap(),
+ buffer.as_mut_ptr(),
+ null_mut(),
+ );
+ match len as usize {
+ // Failure
+ 0 => return Err(Error::last_os_error()),
+ // Buffer is too small, resize.
+ len if len > buffer.len() => buffer.resize(len, 0),
+ // Success!
+ len => {
+ buffer.truncate(len);
+ return Ok(OsString::from_wide(&buffer).into());
+ }
+ }
+ }
+ }
+}